newruntime: progress

This commit is contained in:
Araq 2019-04-01 16:51:18 +02:00
commit c3067e36bb
12 changed files with 57 additions and 46 deletions

View file

@ -12,6 +12,14 @@
# included from sempass2.nim # included from sempass2.nim
# Todo:
# - specialize destructors for constant arrays of strings
# (they don't require any)
# - use openArray instead of array to avoid over-specializations
# - make 'owned' mean 'sink' in parameters
import sighashes
type type
TLiftCtx = object TLiftCtx = object
graph: ModuleGraph graph: ModuleGraph
@ -286,25 +294,10 @@ proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
doAssert t.destructor != nil doAssert t.destructor != nil
moveCall.add destructorCall(c.graph, t.destructor, x) moveCall.add destructorCall(c.graph, t.destructor, x)
body.add moveCall body.add moveCall
when false:
# we generate:
# if a.len != 0 and a.p != b.p:
# `=destroy`(x)
# a.len = b.len
# a.p = b.p
# Note: '@' is either '.' or '->'.
body.add genIf(c, genVerbatim("dest@len != 0 && dest@p != src.p", c.info),
destructorCall(c.graph, t.destructor, x))
body.add genVerbatim("dest@len=src.len; dest@p=src.p;", c.info)
of attachedDestructor: of attachedDestructor:
# destroy all elements: # destroy all elements:
forallElements(c, t, body, x, y) forallElements(c, t, body, x, y)
body.add genBuiltin(c.graph, mDestroy, "destroy", x) body.add genBuiltin(c.graph, mDestroy, "destroy", x)
when false:
var deallocStmt = genVerbatim("dest@region->dealloc(dest@region, dest@p, " &
"(dest@p->cap * sizeof($)) + sizeof(NI) + sizeof(void*)); dest@len = 0;", c.info)
deallocStmt.typ = t.lastSon
body.add genIf(c, genVerbatim("dest@len != 0 && dest@region", c.info), deallocStmt)
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind case c.kind
@ -603,19 +596,29 @@ template inst(field, t) =
if field.ast != nil: if field.ast != nil:
patchBody(c, field.ast, info) patchBody(c, field.ast, info)
proc createTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) = proc createTypeBoundOps*(c: PContext; orig: PType; info: TLineInfo) =
## In the semantic pass this is called in strategic places ## In the semantic pass this is called in strategic places
## to ensure we lift assignment, destructors and moves properly. ## to ensure we lift assignment, destructors and moves properly.
## The later 'injectdestructors' pass depends on it. ## The later 'injectdestructors' pass depends on it.
if typ == nil or {tfCheckedForDestructor, tfHasMeta} * typ.flags != {}: return if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
incl typ.flags, tfCheckedForDestructor incl orig.flags, tfCheckedForDestructor
let h = sighashes.hashType(orig, {CoType, CoConsiderOwned})
var canon = c.graph.canonTypes.getOrDefault(h)
var overwrite = false
if canon == nil:
c.graph.canonTypes[h] = orig
canon = orig
elif canon != orig:
overwrite = true
# multiple cases are to distinguish here: # multiple cases are to distinguish here:
# 1. we don't know yet if 'typ' has a nontrival destructor. # 1. we don't know yet if 'typ' has a nontrival destructor.
# 2. we have a nop destructor. --> mDestroy # 2. we have a nop destructor. --> mDestroy
# 3. we have a lifted destructor. # 3. we have a lifted destructor.
# 4. We have a custom destructor. # 4. We have a custom destructor.
# 5. We have a (custom) generic destructor. # 5. We have a (custom) generic destructor.
let typ = typ.skipTypes({tyGenericInst, tyAlias}) let typ = canon.skipTypes({tyGenericInst, tyAlias})
# we generate the destructor first so that other operators can depend on it: # we generate the destructor first so that other operators can depend on it:
if typ.destructor == nil: if typ.destructor == nil:
liftBody(c, typ, attachedDestructor, info) liftBody(c, typ, attachedDestructor, info)
@ -629,3 +632,8 @@ proc createTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
liftBody(c, typ, attachedSink, info) liftBody(c, typ, attachedSink, info)
else: else:
inst(typ.sink, typ) inst(typ.sink, typ)
if overwrite:
orig.destructor = canon.destructor
orig.assignment = canon.assignment
orig.sink = canon.sink

View file

@ -26,7 +26,7 @@
## ##
import ast, intsets, tables, options, lineinfos, hashes, idents, import ast, intsets, tables, options, lineinfos, hashes, idents,
incremental, btrees incremental, btrees, sighashes
type type
ModuleGraph* = ref object ModuleGraph* = ref object
@ -57,6 +57,7 @@ type
opContains*, opNot*: PSym opContains*, opNot*: PSym
emptyNode*: PNode emptyNode*: PNode
incr*: IncrementalCtx incr*: IncrementalCtx
canonTypes*: Table[SigHash, PType]
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.} importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.} includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
@ -138,6 +139,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result.cacheSeqs = initTable[string, PNode]() result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]() result.cacheCounters = initTable[string, BiggestInt]()
result.cacheTables = initTable[string, BTree[string, PNode]]() result.cacheTables = initTable[string, BTree[string, PNode]]()
result.canonTypes = initTable[SigHash, PType]()
proc resetAllModules*(g: ModuleGraph) = proc resetAllModules*(g: ModuleGraph) =
initStrTable(g.packageSyms) initStrTable(g.packageSyms)

View file

@ -10,7 +10,7 @@
import import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, lineinfos, semfold, semdata, wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
modulegraphs, lowerings, sigmatch modulegraphs, lowerings, sigmatch, tables
when not defined(leanCompiler): when not defined(leanCompiler):
import writetracking import writetracking

View file

@ -90,6 +90,7 @@ type
CoType CoType
CoOwnerSig CoOwnerSig
CoIgnoreRange CoIgnoreRange
CoConsiderOwned
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag])
@ -165,7 +166,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
c.hashType t.sons[i], flags c.hashType t.sons[i], flags
else: else:
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
of tyAlias, tySink, tyUserTypeClasses, tyInferred, tyOwned: of tyAlias, tySink, tyUserTypeClasses, tyInferred:
c.hashType t.lastSon, flags
of tyOwned:
if CoConsiderOwned in flags:
c &= char(t.kind)
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
of tyBool, tyChar, tyInt..tyUInt64: of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is # no canonicalization for integral types, so that e.g. ``pid_t`` is

View file

@ -413,7 +413,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = typ.lastSon.size typ.size = typ.lastSon.size
typ.align = typ.lastSon.align typ.align = typ.lastSon.align
of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink: of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned:
computeSizeAlign(conf, typ.lastSon) computeSizeAlign(conf, typ.lastSon)
typ.size = typ.lastSon.size typ.size = typ.lastSon.size
typ.align = typ.lastSon.align typ.align = typ.lastSon.align

View file

@ -72,10 +72,7 @@ proc unloadLib*(lib: LibHandle) {.gcsafe.}
proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
## raises an `EInvalidLibrary` exception. ## raises an `EInvalidLibrary` exception.
var e: ref LibraryError raise newException(LibraryError, "could not find symbol: " & $name)
new(e)
e.msg = "could not find symbol: " & $name
raise e
proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.} proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.}
## retrieves the address of a procedure/variable from `lib`. Returns nil ## retrieves the address of a procedure/variable from `lib`. Returns nil

View file

@ -73,7 +73,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
## See also: ## See also:
## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_ ## * `osErrorMsg proc <#osErrorMsg,OSErrorCode>`_
## * `osLastError proc <#osLastError>`_ ## * `osLastError proc <#osLastError>`_
var e: ref OSError; new(e) var e: owned(ref OSError); new(e)
e.errorCode = errorCode.int32 e.errorCode = errorCode.int32
e.msg = osErrorMsg(errorCode) e.msg = osErrorMsg(errorCode)
if additionalInfo.len > 0: if additionalInfo.len > 0:

View file

@ -126,7 +126,7 @@ proc startProcess*(command: string,
args: openArray[string] = [], args: openArray[string] = [],
env: StringTableRef = nil, env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}): options: set[ProcessOption] = {poStdErrToStdOut}):
Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect, owned Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect,
RootEffect].} RootEffect].}
## Starts a process. `Command` is the executable file, `workingDir` is the ## Starts a process. `Command` is the executable file, `workingDir` is the
## process's working directory. If ``workingDir == ""`` the current directory ## process's working directory. If ``workingDir == ""`` the current directory
@ -470,7 +470,7 @@ when defined(Windows) and not defined(useNimRtl):
addr bytesWritten, nil) addr bytesWritten, nil)
if a == 0: raiseOSError(osLastError()) if a == 0: raiseOSError(osLastError())
proc newFileHandleStream(handle: Handle): FileHandleStream = proc newFileHandleStream(handle: Handle): owned FileHandleStream =
new(result) new(result)
result.handle = handle result.handle = handle
result.closeImpl = hsClose result.closeImpl = hsClose
@ -573,7 +573,7 @@ when defined(Windows) and not defined(useNimRtl):
workingDir: string = "", workingDir: string = "",
args: openArray[string] = [], args: openArray[string] = [],
env: StringTableRef = nil, env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}): Process = options: set[ProcessOption] = {poStdErrToStdOut}): owned Process =
var var
si: STARTUPINFO si: STARTUPINFO
procInfo: PROCESS_INFORMATION procInfo: PROCESS_INFORMATION
@ -840,7 +840,7 @@ elif not defined(useNimRtl):
workingDir: string = "", workingDir: string = "",
args: openArray[string] = [], args: openArray[string] = [],
env: StringTableRef = nil, env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut}): Process = options: set[ProcessOption] = {poStdErrToStdOut}): owned Process =
var var
pStdin, pStdout, pStderr: array[0..1, cint] pStdin, pStdout, pStderr: array[0..1, cint]
new(result) new(result)

View file

@ -34,7 +34,7 @@
include "system/inclrtl" include "system/inclrtl"
proc newEIO(msg: string): ref IOError = proc newEIO(msg: string): owned(ref IOError) =
new(result) new(result)
result.msg = msg result.msg = msg
@ -403,7 +403,7 @@ when not defined(js):
else: else:
s.data = nil s.data = nil
proc newStringStream*(s: string = ""): StringStream = proc newStringStream*(s: string = ""): owned StringStream =
## creates a new stream from the string `s`. ## creates a new stream from the string `s`.
new(result) new(result)
result.data = s result.data = s
@ -446,7 +446,7 @@ when not defined(js):
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream") raise newEIO("cannot write to stream")
proc newFileStream*(f: File): FileStream = proc newFileStream*(f: File): owned FileStream =
## creates a new stream from the file `f`. ## creates a new stream from the file `f`.
new(result) new(result)
result.f = f result.f = f
@ -460,7 +460,7 @@ when not defined(js):
result.writeDataImpl = fsWriteData result.writeDataImpl = fsWriteData
result.flushImpl = fsFlush result.flushImpl = fsFlush
proc newFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): FileStream = proc newFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
## creates a new stream from the file named `filename` with the mode `mode`. ## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, nil is returned. See the `system ## If the file cannot be opened, nil is returned. See the `system
## <system.html>`_ module for a list of available FileMode enums. ## <system.html>`_ module for a list of available FileMode enums.
@ -469,7 +469,7 @@ when not defined(js):
var f: File var f: File
if open(f, filename, mode, bufSize): result = newFileStream(f) if open(f, filename, mode, bufSize): result = newFileStream(f)
proc openFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): FileStream = proc openFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
## creates a new stream from the file named `filename` with the mode `mode`. ## creates a new stream from the file named `filename` with the mode `mode`.
## If the file cannot be opened, an IO exception is raised. ## If the file cannot be opened, an IO exception is raised.
var f: File var f: File
@ -522,7 +522,7 @@ else:
raise newEIO("cannot write to stream") raise newEIO("cannot write to stream")
inc(s.pos, bufLen) inc(s.pos, bufLen)
proc newFileHandleStream*(handle: FileHandle): FileHandleStream = proc newFileHandleStream*(handle: FileHandle): owned FileHandleStream =
new(result) new(result)
result.handle = handle result.handle = handle
result.pos = 0 result.pos = 0
@ -535,7 +535,7 @@ else:
result.writeData = hsWriteData result.writeData = hsWriteData
proc newFileHandleStream*(filename: string, proc newFileHandleStream*(filename: string,
mode: FileMode): FileHandleStream = mode: FileMode): owned FileHandleStream =
when defined(windows): when defined(windows):
discard discard
else: else:

View file

@ -247,7 +247,7 @@ proc `[]=`*(t: StringTableRef, key, val: string) {.
rawInsert(t, t.data, key, val) rawInsert(t, t.data, key, val)
inc(t.counter) inc(t.counter)
proc newStringTable*(mode: StringTableMode): StringTableRef {. proc newStringTable*(mode: StringTableMode): owned StringTableRef {.
rtlFunc, extern: "nst$1".} = rtlFunc, extern: "nst$1".} =
## Creates a new empty string table. ## Creates a new empty string table.
## ##
@ -260,7 +260,7 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
newSeq(result.data, startSize) newSeq(result.data, startSize)
proc newStringTable*(keyValuePairs: varargs[string], proc newStringTable*(keyValuePairs: varargs[string],
mode: StringTableMode): StringTableRef {. mode: StringTableMode): owned StringTableRef {.
rtlFunc, extern: "nst$1WithPairs".} = rtlFunc, extern: "nst$1WithPairs".} =
## Creates a new string table with given `key, value` string pairs. ## Creates a new string table with given `key, value` string pairs.
## ##
@ -290,10 +290,7 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]],
for key, val in items(keyValuePairs): result[key] = val for key, val in items(keyValuePairs): result[key] = val
proc raiseFormatException(s: string) = proc raiseFormatException(s: string) =
var e: ref ValueError raise newException(ValueError, "format string: key not found: " & s)
new(e)
e.msg = "format string: key not found: " & s
raise e
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
if hasKey(t, key): return t.getOrDefault(key) if hasKey(t, key): return t.getOrDefault(key)

View file

@ -959,7 +959,7 @@ proc newTimezone*(
{.tags: [], raises: [], benign.}, {.tags: [], raises: [], benign.},
zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime zonedTimeFromAdjTimeImpl: proc (adjTime: Time): ZonedTime
{.tags: [], raises: [], benign.} {.tags: [], raises: [], benign.}
): Timezone = ): owned Timezone =
## Create a new ``Timezone``. ## Create a new ``Timezone``.
## ##
## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used ## ``zonedTimeFromTimeImpl`` and ``zonedTimeFromAdjTimeImpl`` is used

View file

@ -1638,6 +1638,8 @@ when defined(nimV2) and not defined(nimscript):
new(r) new(r)
return r return r
else: else:
template owned*(t: typeDesc): typedesc = t
proc new*[T](a: var ref T) {.magic: "New", noSideEffect.} proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
## Creates a new object of type ``T`` and returns a safe (traced) ## Creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. ## reference to it in ``a``.