diff options
-rw-r--r-- | compiler/passes.nim | 98 | ||||
-rw-r--r-- | compiler/transf.nim | 264 | ||||
-rw-r--r-- | lib/system.nim | 204 | ||||
-rw-r--r-- | lib/system/gc.nim | 82 | ||||
-rw-r--r-- | todo.txt | 1 |
5 files changed, 326 insertions, 323 deletions
diff --git a/compiler/passes.nim b/compiler/passes.nim index 96088bd88..129d8ad47 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -10,15 +10,15 @@ # This module implements the passes functionality. A pass must implement the # `TPass` interface. -import - strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, - condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, +import + strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, + condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, nimsets, syntaxes, times, rodread, idgen -type +type TPassContext* = object of RootObj # the pass's context fromCache*: bool # true if created by "openCached" - + PPassContext* = ref TPassContext TPassOpen* = proc (module: PSym): PPassContext {.nimcall.} @@ -33,8 +33,8 @@ type TPassData* = tuple[input: PNode, closeOutput: PNode] TPasses* = openArray[TPass] -# a pass is a tuple of procedure vars ``TPass.close`` may produce additional -# nodes. These are passed to the other close procedures. +# a pass is a tuple of procedure vars ``TPass.close`` may produce additional +# nodes. These are passed to the other close procedures. # This mechanism used to be used for the instantiation of generics. proc makePass*(open: TPassOpen = nil, @@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil, proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader) # the semantic checker needs these: -var +var gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.} gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.} # implementation -proc skipCodegen*(n: PNode): bool {.inline.} = - # can be used by codegen passes to determine whether they should do +proc skipCodegen*(n: PNode): bool {.inline.} = + # can be used by codegen passes to determine whether they should do # something with `n`. Currently, this ignores `n` and uses the global # error count instead. result = msgs.gErrorCounter > 0 -proc astNeeded*(s: PSym): bool = +proc astNeeded*(s: PSym): bool = # The ``rodwrite`` module uses this to determine if the body of a proc # needs to be stored. The passes manager frees s.sons[codePos] when # appropriate to free the procedure body's memory. This is important # to keep memory usage down. if (s.kind in {skMethod, skProc}) and ({sfCompilerProc, sfCompileTime} * s.flags == {}) and - (s.typ.callConv != ccInline) and - (s.ast.sons[genericParamsPos].kind == nkEmpty): + (s.typ.callConv != ccInline) and + (s.ast.sons[genericParamsPos].kind == nkEmpty): result = false # XXX this doesn't really make sense with excessive CTFE else: result = true - -const + +const maxPasses = 10 -type +type TPassContextArray = array[0..maxPasses - 1, PPassContext] -var +var gPasses: array[0..maxPasses - 1, TPass] gPassesLen*: int proc clearPasses* = gPassesLen = 0 -proc registerPass*(p: TPass) = +proc registerPass*(p: TPass) = gPasses[gPassesLen] = p inc(gPassesLen) @@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) = passdata = carryPass(pass, module, passdata) proc openPasses(a: var TPassContextArray, module: PSym) = - for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].open): + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].open): a[i] = gPasses[i].open(module) else: a[i] = nil - + proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) = - for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].openCached): + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].openCached): a[i] = gPasses[i].openCached(module, rd) - if a[i] != nil: + if a[i] != nil: a[i].fromCache = true else: a[i] = nil - -proc closePasses(a: var TPassContextArray) = + +proc closePasses(a: var TPassContextArray) = var m: PNode = nil - for i in countup(0, gPassesLen - 1): + for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) a[i] = nil # free the memory here - -proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = + +proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = # this implements the code transformation pipeline var m = n - for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].process): + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].process): m = gPasses[i].process(a[i], m) if isNil(m): return false result = true - -proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = + +proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = # this implements the code transformation pipeline var m = n - for i in countup(0, gPassesLen - 1): + for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m) - -proc closePassesCached(a: var TPassContextArray) = + +proc closePassesCached(a: var TPassContextArray) = var m: PNode = nil - for i in countup(0, gPassesLen - 1): - if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): + for i in countup(0, gPassesLen - 1): + if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m) a[i] = nil # free the memory here - + proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, a: var TPassContextArray) = for module in items(implicits): @@ -159,45 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, str.info = gCmdLineInfo importStmt.addSon str if not processTopLevelStmt(importStmt, a): break - + proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) = - var + var p: TParsers a: TPassContextArray s: PLLStream fileIdx = module.fileIdx - if rd == nil: + if rd == nil: openPasses(a, module) - if stream == nil: + if stream == nil: let filename = fileIdx.toFullPathConsiderDirty if module.name.s == "-": module.name.s = "stdinfile" s = llStreamOpen(stdin) else: s = llStreamOpen(filename, fmRead) - if s == nil: + if s == nil: rawMessage(errCannotOpenFile, filename) return else: s = stream - while true: + while true: openParsers(p, fileIdx, s) if sfSystemModule notin module.flags: - # XXX what about caching? no processing then? what if I change the + # XXX what about caching? no processing then? what if I change the # modules to include between compilation runs? we'd need to track that # in ROD files. I think we should enable this feature only # for the interactive mode. processImplicits implicitImports, nkImportStmt, a processImplicits implicitIncludes, nkIncludeStmt, a - while true: + while true: var n = parseTopLevelStmt(p) - if n.kind == nkEmpty: break + if n.kind == nkEmpty: break if not processTopLevelStmt(n, a): break closeParsers(p) - if s.kind != llsStdIn: break + if s.kind != llsStdIn: break closePasses(a) # id synchronization point for more consistent code generation: idSynchronizationPoint(1000) diff --git a/compiler/transf.nim b/compiler/transf.nim index 2f520aa20..e5e3bbe63 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -17,27 +17,27 @@ # * introduces method dispatchers # * performs lambda lifting for closure support -import - intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, +import + intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, lambdalifting, sempass2, lowerings # implementation -type +type PTransNode* = distinct PNode - + PTransCon = ref TTransCon TTransCon{.final.} = object # part of TContext; stackable mapping: TIdNodeTable # mapping from symbols to nodes owner: PSym # current owner forStmt: PNode # current for stmt - forLoopBody: PTransNode # transformed for loop body - yieldStmts: int # we count the number of yield statements, + forLoopBody: PTransNode # transformed for loop body + yieldStmts: int # we count the number of yield statements, # because we need to introduce new variables # if we encounter the 2nd yield statement next: PTransCon # for stacking - + TTransfContext = object of passes.TPassContext module: PSym transCon: PTransCon # top of a TransCon stack @@ -46,52 +46,52 @@ type contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break' PTransf = ref TTransfContext -proc newTransNode(a: PNode): PTransNode {.inline.} = +proc newTransNode(a: PNode): PTransNode {.inline.} = result = PTransNode(shallowCopy(a)) -proc newTransNode(kind: TNodeKind, info: TLineInfo, - sons: int): PTransNode {.inline.} = +proc newTransNode(kind: TNodeKind, info: TLineInfo, + sons: int): PTransNode {.inline.} = var x = newNodeI(kind, info) newSeq(x.sons, sons) result = x.PTransNode -proc newTransNode(kind: TNodeKind, n: PNode, - sons: int): PTransNode {.inline.} = +proc newTransNode(kind: TNodeKind, n: PNode, + sons: int): PTransNode {.inline.} = var x = newNodeIT(kind, n.info, n.typ) newSeq(x.sons, sons) x.typ = n.typ result = x.PTransNode -proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} = +proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} = var n = PNode(a) n.sons[i] = PNode(x) -proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} = +proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} = var n = PNode(a) result = n.sons[i].PTransNode - + proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b)) proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode) -proc newTransCon(owner: PSym): PTransCon = +proc newTransCon(owner: PSym): PTransCon = assert owner != nil new(result) initIdNodeTable(result.mapping) result.owner = owner -proc pushTransCon(c: PTransf, t: PTransCon) = +proc pushTransCon(c: PTransf, t: PTransCon) = t.next = c.transCon c.transCon = t -proc popTransCon(c: PTransf) = +proc popTransCon(c: PTransf) = if (c.transCon == nil): internalError("popTransCon") c.transCon = c.transCon.next -proc getCurrOwner(c: PTransf): PSym = +proc getCurrOwner(c: PTransf): PSym = if c.transCon != nil: result = c.transCon.owner else: result = c.module - -proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = + +proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info) result.typ = skipTypes(typ, {tyGenericInst}) incl(result.flags, sfFromGeneric) @@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode proc transformSons(c: PTransf, n: PNode): PTransNode = result = newTransNode(n) - for i in countup(0, sonsLen(n)-1): + for i in countup(0, sonsLen(n)-1): result[i] = transform(c, n.sons[i]) -proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = +proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = result = newTransNode(nkFastAsgn, PNode(ri).info, 2) result[0] = PTransNode(le) result[1] = ri @@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = # return liftIterSym(n) var b: PNode var tc = c.transCon - if sfBorrow in n.sym.flags: + if sfBorrow in n.sym.flags: # simply exchange the symbol: b = n.sym.getBody if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol") b = newSymNode(b.sym) b.info = n.info - else: + else: b = n - while tc != nil: + while tc != nil: result = idNodeTableGet(tc.mapping, b.sym) if result != nil: return tc = tc.next result = b -proc transformSym(c: PTransf, n: PNode): PTransNode = +proc transformSym(c: PTransf, n: PNode): PTransNode = result = PTransNode(transformSymAux(c, n)) proc transformVarSection(c: PTransf, v: PNode): PTransNode = result = newTransNode(v) for i in countup(0, sonsLen(v)-1): var it = v.sons[i] - if it.kind == nkCommentStmt: + if it.kind == nkCommentStmt: result[i] = PTransNode(it) - elif it.kind == nkIdentDefs: + elif it.kind == nkIdentDefs: if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection") internalAssert(it.len == 3) var newVar = copySym(it.sons[0].sym) @@ -153,12 +153,12 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode = defs[1] = it.sons[1].PTransNode defs[2] = transform(c, it.sons[2]) result[i] = defs - else: - if it.kind != nkVarTuple: + else: + if it.kind != nkVarTuple: internalError(it.info, "transformVarSection: not nkVarTuple") var L = sonsLen(it) var defs = newTransNode(it.kind, it.info, L) - for j in countup(0, L-3): + for j in countup(0, L-3): var newVar = copySym(it.sons[j].sym) incl(newVar.flags, sfFromGeneric) newVar.owner = getCurrOwner(c) @@ -188,12 +188,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode = else: result[i] = PTransNode(it) -proc hasContinue(n: PNode): bool = +proc hasContinue(n: PNode): bool = case n.kind of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard of nkContinueStmt: result = true - else: - for i in countup(0, sonsLen(n) - 1): + else: + for i in countup(0, sonsLen(n) - 1): if hasContinue(n.sons[i]): return true proc newLabel(c: PTransf, n: PNode): PSym = @@ -224,10 +224,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode = discard c.breakSyms.pop result[0] = newSymNode(labl).PTransNode -proc transformLoopBody(c: PTransf, n: PNode): PTransNode = - # What if it contains "continue" and "break"? "break" needs +proc transformLoopBody(c: PTransf, n: PNode): PTransNode = + # What if it contains "continue" and "break"? "break" needs # an explicit label too, but not the same! - + # We fix this here by making every 'break' belong to its enclosing loop # and changing all breaks that belong to a 'block' by annotating it with # a label (if it hasn't one already). @@ -239,7 +239,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode = result[0] = newSymNode(labl).PTransNode result[1] = transform(c, n) discard c.contSyms.pop() - else: + else: result = transform(c, n) proc transformWhile(c: PTransf; n: PNode): PTransNode = @@ -273,27 +273,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode = result = transformSons(c, n) result[0] = newSymNode(labl).PTransNode -proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = +proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = # XXX: BUG: what if `n` is an expression with side-effects? - for i in countup(0, sonsLen(c.transCon.forStmt) - 3): - add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], + for i in countup(0, sonsLen(c.transCon.forStmt) - 3): + add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], transform(c, newTupleAccess(n, i)))) -proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = +proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = case n.kind - of nkSym: + of nkSym: result = transformSym(c, n) - of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: # nothing to be done for leaves: result = PTransNode(n) of nkVarSection, nkLetSection: result = transformVarSection(c, n) else: result = newTransNode(n) - for i in countup(0, sonsLen(n)-1): + for i in countup(0, sonsLen(n)-1): result[i] = introduceNewLocalVars(c, n.sons[i]) -proc transformYield(c: PTransf, n: PNode): PTransNode = +proc transformYield(c: PTransf, n: PNode): PTransNode = result = newTransNode(nkStmtList, n.info, 0) var e = n.sons[0] # c.transCon.forStmt.len == 3 means that there is one for loop variable @@ -301,21 +301,21 @@ proc transformYield(c: PTransf, n: PNode): PTransNode = if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and c.transCon.forStmt.len != 3: e = skipConv(e) - if e.kind == nkPar: - for i in countup(0, sonsLen(e) - 1): - add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], + if e.kind == nkPar: + for i in countup(0, sonsLen(e) - 1): + add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], transform(c, e.sons[i]))) - else: + else: unpackTuple(c, e, result) - else: + else: var x = transform(c, e) add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x)) - + inc(c.transCon.yieldStmts) if c.transCon.yieldStmts <= 1: # common case add(result, c.transCon.forLoopBody) - else: + else: # we need to introduce new local variables: add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode)) @@ -340,25 +340,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = if n.sons[0].kind == a or n.sons[0].kind == b: # addr ( deref ( x )) --> x result = PTransNode(n.sons[0].sons[0]) - -proc transformConv(c: PTransf, n: PNode): PTransNode = + +proc transformConv(c: PTransf, n: PNode): PTransNode = # numeric types need range checks: var dest = skipTypes(n.typ, abstractVarRange) var source = skipTypes(n.sons[1].typ, abstractVarRange) case dest.kind - of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: + of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: # we don't include uint and uint64 here as these are no ordinal types ;-) if not isOrdinalType(source): # float -> int conversions. ugh. result = transformSons(c, n) elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and - lastOrd(n.sons[1].typ) <= lastOrd(n.typ): + lastOrd(n.sons[1].typ) <= lastOrd(n.typ): # BUGFIX: simply leave n as it is; we need a nkConv node, # but no range check: result = transformSons(c, n) - else: + else: # generate a range check: - if dest.kind == tyInt64 or source.kind == tyInt64: + if dest.kind == tyInt64 or source.kind == tyInt64: result = newTransNode(nkChckRange64, n, 3) else: result = newTransNode(nkChckRange, n, 3) @@ -368,7 +368,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode of tyFloat..tyFloat128: # XXX int64 -> float conversion? - if skipTypes(n.typ, abstractVar).kind == tyRange: + if skipTypes(n.typ, abstractVar).kind == tyRange: result = newTransNode(nkChckRangeF, n, 3) dest = skipTypes(n.typ, abstractVar) result[0] = transform(c, n.sons[1]) @@ -378,81 +378,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result = transformSons(c, n) of tyOpenArray, tyVarargs: result = transform(c, n.sons[1]) - of tyCString: - if source.kind == tyString: + of tyCString: + if source.kind == tyString: result = newTransNode(nkStringToCString, n, 1) result[0] = transform(c, n.sons[1]) else: result = transformSons(c, n) - of tyString: - if source.kind == tyCString: + of tyString: + if source.kind == tyCString: result = newTransNode(nkCStringToString, n, 1) result[0] = transform(c, n.sons[1]) else: result = transformSons(c, n) - of tyRef, tyPtr: + of tyRef, tyPtr: dest = skipTypes(dest, abstractPtrs) source = skipTypes(source, abstractPtrs) - if source.kind == tyObject: + if source.kind == tyObject: var diff = inheritanceDiff(dest, source) - if diff < 0: + if diff < 0: result = newTransNode(nkObjUpConv, n, 1) result[0] = transform(c, n.sons[1]) - elif diff > 0: + elif diff > 0: result = newTransNode(nkObjDownConv, n, 1) result[0] = transform(c, n.sons[1]) - else: + else: result = transform(c, n.sons[1]) else: result = transformSons(c, n) - of tyObject: + of tyObject: var diff = inheritanceDiff(dest, source) - if diff < 0: + if diff < 0: result = newTransNode(nkObjUpConv, n, 1) result[0] = transform(c, n.sons[1]) - elif diff > 0: + elif diff > 0: result = newTransNode(nkObjDownConv, n, 1) result[0] = transform(c, n.sons[1]) - else: + else: result = transform(c, n.sons[1]) of tyGenericParam, tyOrdinal: result = transform(c, n.sons[1]) # happens sometimes for generated assignments, etc. - else: + else: result = transformSons(c, n) - -type - TPutArgInto = enum + +type + TPutArgInto = enum paDirectMapping, paFastAsgn, paVarAsgn -proc putArgInto(arg: PNode, formal: PType): TPutArgInto = +proc putArgInto(arg: PNode, formal: PType): TPutArgInto = # This analyses how to treat the mapping "formal <-> arg" in an # inline context. if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}: return paDirectMapping # XXX really correct? # what if ``arg`` has side-effects? case arg.kind - of nkEmpty..nkNilLit: + of nkEmpty..nkNilLit: result = paDirectMapping - of nkPar, nkCurly, nkBracket: + of nkPar, nkCurly, nkBracket: result = paFastAsgn - for i in countup(0, sonsLen(arg) - 1): - if putArgInto(arg.sons[i], formal) != paDirectMapping: return + for i in countup(0, sonsLen(arg) - 1): + if putArgInto(arg.sons[i], formal) != paDirectMapping: return result = paDirectMapping - else: + else: if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn else: result = paFastAsgn - + proc findWrongOwners(c: PTransf, n: PNode) = if n.kind == nkVarSection: let x = n.sons[0].sons[0] if x.kind == nkSym and x.sym.owner != getCurrOwner(c): - internalError(x.info, "bah " & x.sym.name.s & " " & + internalError(x.info, "bah " & x.sym.name.s & " " & x.sym.owner.name.s & " " & getCurrOwner(c).name.s) else: for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i]) -proc transformFor(c: PTransf, n: PNode): PTransNode = +proc transformFor(c: PTransf, n: PNode): PTransNode = # generate access statements for the parameters (unless they are constant) # put mapping from formal parameters to actual parameters if n.kind != nkForStmt: internalError(n.info, "transformFor") @@ -466,26 +466,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = result[0] = newSymNode(labl).PTransNode if call.typ.kind != tyIter and - (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or + (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or call.sons[0].sym.kind != skIterator): n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode result[1] = lambdalifting.liftForLoop(n).PTransNode discard c.breakSyms.pop return result - + #echo "transforming: ", renderTree(n) var stmtList = newTransNode(nkStmtList, n.info, 0) - + var loopBody = transformLoopBody(c, n.sons[length-1]) result[1] = stmtList discard c.breakSyms.pop var v = newNodeI(nkVarSection, n.info) - for i in countup(0, length - 3): + for i in countup(0, length - 3): addVar(v, copyTree(n.sons[i])) # declare new vars add(stmtList, v.PTransNode) - + # Bugfix: inlined locals belong to the invoking routine, not to the invoked # iterator! let iter = call.sons[0].sym @@ -496,9 +496,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = if iter.kind != skIterator: return result # generate access statements for the parameters (unless they are constant) pushTransCon(c, newC) - for i in countup(1, sonsLen(call) - 1): + for i in countup(1, sonsLen(call) - 1): var arg = transform(c, call.sons[i]).PNode - var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym + var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym if arg.typ.kind == tyIter: continue case putArgInto(arg, formal.typ) of paDirectMapping: @@ -527,20 +527,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = popInfoContext() popTransCon(c) # echo "transformed: ", stmtList.PNode.renderTree - -proc getMagicOp(call: PNode): TMagic = + +proc getMagicOp(call: PNode): TMagic = if call.sons[0].kind == nkSym and - call.sons[0].sym.kind in {skProc, skMethod, skConverter}: + call.sons[0].sym.kind in {skProc, skMethod, skConverter}: result = call.sons[0].sym.magic else: result = mNone -proc transformCase(c: PTransf, n: PNode): PTransNode = +proc transformCase(c: PTransf, n: PNode): PTransNode = # removes `elif` branches of a case stmt # adds ``else: nil`` if needed for the code generator result = newTransNode(nkCaseStmt, n, 0) var ifs = PTransNode(nil) - for i in 0 .. sonsLen(n)-1: + for i in 0 .. sonsLen(n)-1: var it = n.sons[i] var e = transform(c, it) case it.kind @@ -564,8 +564,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode = var elseBranch = newTransNode(nkElse, n.info, 1) elseBranch[0] = newTransNode(nkNilLit, n.info, 0) add(result, elseBranch) - -proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = + +proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = # XXX this is really bad; transf should use a proper AST visitor if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType: result = n.PTransNode @@ -573,45 +573,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = result = newTransNode(n) for i in 0 .. < n.len: result[i] = transform(c, skipConv(n.sons[i])) - -proc getMergeOp(n: PNode): PSym = + +proc getMergeOp(n: PNode): PSym = case n.kind - of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: + of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, + nkCallStrLit: if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and - (sfMerge in n.sons[0].sym.flags): + (sfMerge in n.sons[0].sym.flags): result = n.sons[0].sym else: discard -proc flattenTreeAux(d, a: PNode, op: PSym) = +proc flattenTreeAux(d, a: PNode, op: PSym) = let op2 = getMergeOp(a) if op2 != nil and - (op2.id == op.id or op.magic != mNone and op2.magic == op.magic): + (op2.id == op.id or op.magic != mNone and op2.magic == op.magic): for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op) - else: + else: addSon(d, copyTree(a)) - -proc flattenTree(root: PNode): PNode = + +proc flattenTree(root: PNode): PNode = let op = getMergeOp(root) - if op != nil: + if op != nil: result = copyNode(root) addSon(result, copyTree(root.sons[0])) flattenTreeAux(result, root, op) - else: + else: result = root -proc transformCall(c: PTransf, n: PNode): PTransNode = +proc transformCall(c: PTransf, n: PNode): PTransNode = var n = flattenTree(n) let op = getMergeOp(n) let magic = getMagic(n) - if op != nil and op.magic != mNone and n.len >= 3: + if op != nil and op.magic != mNone and n.len >= 3: result = newTransNode(nkCall, n, 0) add(result, transform(c, n.sons[0])) var j = 1 - while j < sonsLen(n): + while j < sonsLen(n): var a = transform(c, n.sons[j]).PNode inc(j) - if isConstExpr(a): + if isConstExpr(a): while (j < sonsLen(n)): let b = transform(c, n.sons[j]).PNode if not isConstExpr(b): break @@ -640,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} = # symbols that expand to a complex constant (array, etc.) should not be # inlined, unless it's the empty array: - result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and + result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and cnst.len != 0 proc commonOptimizations*(c: PSym, n: PNode): PNode = @@ -673,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode = else: result = n -proc transform(c: PTransf, n: PNode): PTransNode = +proc transform(c: PTransf, n: PNode): PTransNode = case n.kind - of nkSym: + of nkSym: result = transformSym(c, n) - of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: # nothing to be done for leaves: result = PTransNode(n) of nkBracketExpr: result = transformArrayAccess(c, n) @@ -702,7 +702,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = n.sons[bodyPos] = PNode(transform(c, s.getBody)) if n.kind == nkMethodDef: methodDef(s, false) result = PTransNode(n) - of nkForStmt: + of nkForStmt: result = transformFor(c, n) of nkParForStmt: result = transformSons(c, n) @@ -713,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode = add(result, PTransNode(newSymNode(labl))) of nkBreakStmt: result = transformBreak(c, n) of nkWhileStmt: result = transformWhile(c, n) - of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, - nkCallStrLit: + of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, + nkCallStrLit: result = transformCall(c, n) - of nkAddr, nkHiddenAddr: + of nkAddr, nkHiddenAddr: result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref) - of nkDerefExpr, nkHiddenDeref: + of nkDerefExpr, nkHiddenDeref: result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr) - of nkHiddenStdConv, nkHiddenSubConv, nkConv: + of nkHiddenStdConv, nkHiddenSubConv, nkConv: result = transformConv(c, n) of nkDiscardStmt: result = PTransNode(n) @@ -730,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = # ensure that e.g. discard "some comment" gets optimized away # completely: result = PTransNode(newNode(nkCommentStmt)) - of nkCommentStmt, nkTemplateDef: + of nkCommentStmt, nkTemplateDef: return n.PTransNode of nkConstSection: # do not replace ``const c = 3`` with ``const 3 = 3`` @@ -744,10 +744,10 @@ proc transform(c: PTransf, n: PNode): PTransNode = result = transformVarSection(c, n) else: result = transformSons(c, n) - of nkYieldStmt: + of nkYieldStmt: if c.inlining > 0: result = transformYield(c, n) - else: + else: result = transformSons(c, n) of nkBlockStmt, nkBlockExpr: result = transformBlock(c, n) @@ -764,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode = if cnst != nil and not dontInlineConstant(n, cnst): result = PTransNode(cnst) # do not miss an optimization -proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = +proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip # this step! We have to rely that the semantic pass transforms too errornous # nodes into an empty node. @@ -774,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = popTransCon(c) incl(result.flags, nfTransf) -proc openTransf(module: PSym, filename: string): PTransf = +proc openTransf(module: PSym, filename: string): PTransf = new(result) result.contSyms = @[] result.breakSyms = @[] diff --git a/lib/system.nim b/lib/system.nim index abf31c821..4180f24f9 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -89,7 +89,7 @@ type SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32 ## type class matching all ordinal types; however this includes enums with ## holes. - + SomeReal* = float|float32|float64 ## type class matching all floating point number types @@ -181,7 +181,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. ## freeing the object. Note: The `finalizer` refers to the type `T`, not to ## the object! This means that for each object of type `T` the finalizer ## will be called! - + proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.} ## resets an object `obj` to its initial (binary zero) value. This needs to ## be called before any possible `object branch transition`:idx:. @@ -348,7 +348,7 @@ type ## This field is filled automatically in the ## ``raise`` statement. msg* {.exportc: "message".}: string ## the exception's message. Not - ## providing an exception message + ## providing an exception message ## is bad style. trace: string @@ -483,7 +483,7 @@ type E_Base: Exception, ESystem: SystemError, EIO: IOError, EOS: OSError, EInvalidLibrary: LibraryError, - EResourceExhausted: ResourceExhaustedError, + EResourceExhausted: ResourceExhaustedError, EArithmetic: ArithmeticError, EDivByZero: DivByZeroError, EOverflow: OverflowError, EAccessViolation: AccessViolationError, EAssertionFailed: AssertionError, EInvalidValue: ValueError, @@ -494,7 +494,7 @@ type EInvalidObjectAssignment: ObjectAssignmentError, EInvalidObjectConversion: ObjectConversionError, EDeadThread: DeadThreadError, - EFloatInexact: FloatInexactError, + EFloatInexact: FloatInexactError, EFloatUnderflow: FloatUnderflowError, EFloatingPoint: FloatingPointError, EFloatInvalidOp: FloatInvalidOpError, @@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.} proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.} ## unary ``<`` that can be used for nice looking excluding ranges: - ## + ## ## .. code-block:: nim ## for i in 0 .. <10: echo i ## - ## Semantically this is the same as ``pred``. + ## Semantically this is the same as ``pred``. proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.} ## returns the ``y``-th successor of the value ``x``. ``T`` has to be @@ -536,7 +536,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect. ## decrements the ordinal ``x`` by ``y``. If such a value does not ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a ## short notation for: ``x = pred(x, y)``. - + proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.} ## creates a new sequence of type ``seq[T]`` with length ``len``. ## This is equivalent to ``s = @[]; setlen(s, len)``, but more @@ -636,7 +636,7 @@ when not defined(JS): proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.} ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits - ## from `x`. + ## from `x`. proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.} ## treats `x` as unsigned and converts it to an ``int16`` by taking the last ## 16 bits from `x`. @@ -800,7 +800,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.} ## The result is truncated to fit into the result. ## This implements modulo arithmetic. ## No overflow errors are possible. - + proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.} ## treats `x` and `y` as unsigned and compares them. @@ -889,7 +889,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x) proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## Checks if T is of the same type as S - ## + ## ## .. code-block:: Nim ## proc test[T](a: T): int = ## when (T is int): @@ -924,7 +924,7 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.} proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {. magic: "ArrToSeq", nosideeffect.} ## turns an array into a sequence. This most often useful for constructing - ## sequences with the array constructor: ``@[1, 2, 3]`` has the type + ## sequences with the array constructor: ``@[1, 2, 3]`` has the type ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``. proc setLen*[T](s: var seq[T], newlen: int) {. @@ -933,14 +933,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {. ## ``T`` may be any sequence type. ## If the current length is greater than the new length, ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with - ## a size, use ``newSeq`` instead. + ## a size, use ``newSeq`` instead. proc setLen*(s: var string, newlen: int) {. magic: "SetLengthStr", noSideEffect.} ## sets the length of `s` to `newlen`. ## If the current length is greater than the new length, ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with - ## a size, use ``newString`` instead. + ## a size, use ``newString`` instead. proc newString*(len: int): string {. magic: "NewString", importc: "mnewString", noSideEffect.} @@ -953,7 +953,7 @@ proc newString*(len: int): string {. proc newStringOfCap*(cap: int): string {. magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.} ## returns a new string of length ``0`` but with capacity `cap`.This - ## procedure exists only for optimization purposes; the same effect can + ## procedure exists only for optimization purposes; the same effect can ## be achieved with the ``&`` operator or with ``add``. proc `&` * (x: string, y: char): string {. @@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {. ## assert('a' & "bc" == "abc") # implementation note: These must all have the same magic value "ConStrStr" so -# that the merge optimization works properly. +# that the merge optimization works properly. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} ## Appends `y` to `x` in place @@ -1039,15 +1039,15 @@ proc compileOption*(option: string): bool {. ## can be used to determine an on|off compile-time option. Example: ## ## .. code-block:: nim - ## when compileOption("floatchecks"): + ## when compileOption("floatchecks"): ## echo "compiled with floating point NaN and Inf checks" - + proc compileOption*(option, arg: string): bool {. magic: "CompileOptionArg", noSideEffect.} ## can be used to determine an enum compile-time option. Example: ## ## .. code-block:: nim - ## when compileOption("opt", "size") and compileOption("gc", "boehm"): + ## when compileOption("opt", "size") and compileOption("gc", "boehm"): ## echo "compiled with optimization for size and uses Boehm's GC" const @@ -1056,16 +1056,16 @@ const taintMode = compileOption("taintmode") when taintMode: - type TaintedString* = distinct string ## a distinct string type that + type TaintedString* = distinct string ## a distinct string type that ## is `tainted`:idx:. It is an alias for ## ``string`` if the taint mode is not ## turned on. Use the ``-d:taintMode`` ## command line switch to turn the taint ## mode on. - + proc len*(s: TaintedString): int {.borrow.} else: - type TaintedString* = string ## a distinct string type that + type TaintedString* = string ## a distinct string type that ## is `tainted`:idx:. It is an alias for ## ``string`` if the taint mode is not ## turned on. Use the ``-d:taintMode`` @@ -1136,25 +1136,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy ## only changes the semantics for sequences and strings (and types which - ## contain those). Be careful with the changed semantics though! There + ## contain those). Be careful with the changed semantics though! There ## is a reason why the default assignment does a deep copy of sequences ## and strings. -proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = +proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. ## This is an O(1) operation. let xl = x.len shallowCopy(x[i], x[xl-1]) setLen(x, xl-1) - -proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = + +proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = ## deletes the item at index `i` by moving ``x[i+1..]`` by one position. ## This is an O(n) operation. let xl = x.len - for j in i..xl-2: shallowCopy(x[j], x[j+1]) + for j in i..xl-2: shallowCopy(x[j], x[j+1]) setLen(x, xl-1) - -proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = + +proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = ## inserts `item` into `x` at position `i`. let xl = x.len setLen(x, xl+1) @@ -1233,7 +1233,7 @@ type # these work for most platforms: ## This is binary compatible to the type ``char**`` in *C*. The array's ## high value is large enough to disable bounds checking in practice. ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``. - + PFloat32* = ptr float32 ## an alias for ``ptr float32`` PFloat64* = ptr float64 ## an alias for ``ptr float64`` PInt64* = ptr int64 ## an alias for ``ptr int64`` @@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {. proc copy*(s: string, first = 0): string {. magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.} proc copy*(s: string, first, last: int): string {. - magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, + magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, deprecated.} ## copies a slice of `s` into a new string and returns this new ## string. The bounds `first` and `last` denote the indices of @@ -1358,7 +1358,7 @@ when not defined(nimrodVM): ## The allocated memory belongs to its allocating thread! ## Use `createShared` to allocate from a shared heap. cast[ptr T](alloc0(T.sizeof * size)) - proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], + proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], benign.} ## grows or shrinks a given memory block. If p is **nil** then a new ## memory block is returned. In either way the block has at least @@ -1381,7 +1381,7 @@ when not defined(nimrodVM): ## ``realloc``. This procedure is dangerous! If one forgets to ## free the memory a leak occurs; if one tries to access freed ## memory (or just freeing it twice!) a core dump may happen - ## or other memory may be corrupted. + ## or other memory may be corrupted. ## The freed memory must belong to its allocating thread! ## Use `deallocShared` to deallocate from a shared heap. proc free*[T](p: ptr T) {.inline, benign.} = @@ -1390,30 +1390,30 @@ when not defined(nimrodVM): ## allocates a new memory block on the shared heap with at ## least ``size`` bytes. The block has to be freed with ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block - ## is not initialized, so reading from it before writing to it is + ## is not initialized, so reading from it before writing to it is ## undefined behaviour! - proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, + proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign.} = ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block - ## is not initialized, so reading from it before writing to it is + ## is not initialized, so reading from it before writing to it is ## undefined behaviour! cast[ptr T](allocShared(T.sizeof * size)) proc allocShared0*(size: int): pointer {.noconv, rtl, benign.} - ## allocates a new memory block on the shared heap with at + ## allocates a new memory block on the shared heap with at ## least ``size`` bytes. The block has to be freed with ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``allocShared``. proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = - ## allocates a new memory block on the shared heap with at + ## allocates a new memory block on the shared heap with at ## least ``T.sizeof * size`` bytes. The block has to be freed with ## ``resizeShared(block, 0)`` or ``freeShared(block)``. ## The block is initialized with all bytes ## containing zero, so it is somewhat safer than ``createSharedU``. cast[ptr T](allocShared0(T.sizeof * size)) - proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, + proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, benign.} ## grows or shrinks a given memory block on the heap. If p is **nil** ## then a new memory block is returned. In either way the block has at @@ -1525,7 +1525,7 @@ const NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch ## is the version of Nim as a string. -{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, +{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].} # GC interface: @@ -1805,7 +1805,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool = return result = true -proc `@`*[T](a: openArray[T]): seq[T] = +proc `@`*[T](a: openArray[T]): seq[T] = ## turns an openarray into a sequence. This is not as efficient as turning ## a fixed length array into a sequence as it always copies every element ## of `a`. @@ -1853,7 +1853,7 @@ when not defined(NimrodVM): else: proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} = asm """return `x`""" - + proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} = ## Generic equals operator for sequences: relies on a equals operator for ## the element type `T`. @@ -1879,7 +1879,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}= ## for ``find(a, item) >= 0``. return find(a, item) >= 0 -proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = +proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = ## returns the last item of `s` and decreases ``s.len`` by one. This treats ## `s` as a stack and implements the common *pop* operation. var L = s.len-1 @@ -1941,7 +1941,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {. iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {. magic: "Fields", noSideEffect.} ## iterates over every field of `x` and `y`. - ## Warning: This is really transforms the 'for' and unrolls the loop. + ## Warning: This is really transforms the 'for' and unrolls the loop. ## The current implementation also has a bug that affects symbol binding ## in the loop body. iterator fieldPairs*[T: tuple|object](x: T): RootObj {. @@ -1982,18 +1982,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ a, b: expr] {. magic: "FieldPairs", noSideEffect.} ## iterates over every field of `x` and `y`. - ## Warning: This really transforms the 'for' and unrolls the loop. + ## Warning: This really transforms the 'for' and unrolls the loop. ## The current implementation also has a bug that affects symbol binding ## in the loop body. -proc `==`*[T: tuple|object](x, y: T): bool = +proc `==`*[T: tuple|object](x, y: T): bool = ## generic ``==`` operator for tuples that is lifted from the components ## of `x` and `y`. for a, b in fields(x, y): if a != b: return false return true -proc `<=`*[T: tuple](x, y: T): bool = +proc `<=`*[T: tuple](x, y: T): bool = ## generic ``<=`` operator for tuples that is lifted from the components ## of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): @@ -2002,7 +2002,7 @@ proc `<=`*[T: tuple](x, y: T): bool = if c > 0: return false return true -proc `<`*[T: tuple](x, y: T): bool = +proc `<`*[T: tuple](x, y: T): bool = ## generic ``<`` operator for tuples that is lifted from the components ## of `x` and `y`. This implementation uses `cmp`. for a, b in fields(x, y): @@ -2011,7 +2011,7 @@ proc `<`*[T: tuple](x, y: T): bool = if c > 0: return false return false -proc `$`*[T: tuple|object](x: T): string = +proc `$`*[T: tuple|object](x: T): string = ## generic ``$`` operator for tuples that is lifted from the components ## of `x`. Example: ## @@ -2021,13 +2021,13 @@ proc `$`*[T: tuple|object](x: T): string = result = "(" var firstElement = true for name, value in fieldPairs(x): - if not(firstElement): result.add(", ") + if not firstElement: result.add(", ") result.add(name) result.add(": ") result.add($value) firstElement = false result.add(")") - + proc collectionToString[T](x: T, b, e: string): string = result = b var firstElement = true @@ -2037,7 +2037,7 @@ proc collectionToString[T](x: T, b, e: string): string = firstElement = false result.add(e) -proc `$`*[T](x: set[T]): string = +proc `$`*[T](x: set[T]): string = ## generic ``$`` operator for sets that is lifted from the components ## of `x`. Example: ## @@ -2045,7 +2045,7 @@ proc `$`*[T](x: set[T]): string = ## ${23, 45} == "{23, 45}" collectionToString(x, "{", "}") -proc `$`*[T](x: seq[T]): string = +proc `$`*[T](x: seq[T]): string = ## generic ``$`` operator for seqs that is lifted from the components ## of `x`. Example: ## @@ -2056,7 +2056,7 @@ proc `$`*[T](x: seq[T]): string = when false: # causes bootstrapping to fail as we use array of chars and cstring should # match better ... - proc `$`*[T, IDX](x: array[IDX, T]): string = + proc `$`*[T, IDX](x: array[IDX, T]): string = collectionToString(x, "[", "]") # ----------------- GC interface --------------------------------------------- @@ -2098,14 +2098,14 @@ when not defined(nimrodVM) and hostOS != "standalone": proc GC_getStatistics*(): string {.rtl, benign.} ## returns an informative string about the GC's activity. This may be useful ## for tweaking. - + proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.} proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.} proc GC_ref*(x: string) {.magic: "GCref", benign.} ## marks the object `x` as referenced, so that it will not be freed until ## it is unmarked via `GC_unref`. If called n-times for the same object `x`, - ## n calls to `GC_unref` are needed to unmark `x`. - + ## n calls to `GC_unref` are needed to unmark `x`. + proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.} proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.} proc GC_unref*(x: string) {.magic: "GCunref", benign.} @@ -2141,19 +2141,19 @@ var ## application code should never set this hook! You better know what you ## do when setting this. If ``localRaiseHook`` returns false, the exception ## is caught and does not propagate further through the call stack. - + outOfMemHook*: proc () {.nimcall, tags: [], benign.} - ## set this variable to provide a procedure that should be called + ## set this variable to provide a procedure that should be called ## in case of an `out of memory`:idx: event. The standard handler ## writes an error message and terminates the program. `outOfMemHook` can ## be used to raise an exception in case of OOM like so: - ## + ## ## .. code-block:: nim ## ## var gOutOfMem: ref EOutOfMemory ## new(gOutOfMem) # need to be allocated *before* OOM really happened! ## gOutOfMem.msg = "out of memory" - ## + ## ## proc handleOOM() = ## raise gOutOfMem ## @@ -2210,7 +2210,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_ ## instead. -proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, +proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, tags: [], raises: [].} ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho`` ## pretends to be free of side effects, so that it can be used for debugging @@ -2262,7 +2262,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} = proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} = if x < 0: -x else: x proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} = - ## returns the absolute value of `x`. If `x` is ``low(x)`` (that + ## returns the absolute value of `x`. If `x` is ``low(x)`` (that ## is -MININT for its type), an overflow exception is thrown (if overflow ## checking is turned on). if x < 0: -x else: x @@ -2318,14 +2318,14 @@ when not defined(JS): #and not defined(NimrodVM): # we use binary mode in Windows: setmode(fileno(c_stdin), O_BINARY) setmode(fileno(c_stdout), O_BINARY) - + when defined(endb): proc endbStep() # ----------------- IO Part ------------------------------------------------ when hostOS != "standalone": type - CFile {.importc: "FILE", header: "<stdio.h>", + CFile {.importc: "FILE", header: "<stdio.h>", final, incompletestruct.} = object File* = ptr CFile ## The type representing a file handle. @@ -2375,9 +2375,9 @@ when not defined(JS): #and not defined(NimrodVM): ## Creates a ``TFile`` from a `filehandle` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. - + proc open*(filename: string, - mode: FileMode = fmRead, bufSize: int = -1): File = + mode: FileMode = fmRead, bufSize: int = -1): File = ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Raises an ``IO`` exception if the file @@ -2387,7 +2387,7 @@ when not defined(JS): #and not defined(NimrodVM): proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. tags: [], benign.} - ## reopens the file `f` with given `filename` and `mode`. This + ## reopens the file `f` with given `filename` and `mode`. This ## is often used to redirect the `stdin`, `stdout` or `stderr` ## file variables. ## @@ -2398,7 +2398,7 @@ when not defined(JS): #and not defined(NimrodVM): proc endOfFile*(f: File): bool {.tags: [], benign.} ## Returns true iff `f` is at the end. - + proc readChar*(f: File): char {. importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].} ## Reads a single character from the stream `f`. @@ -2411,7 +2411,7 @@ when not defined(JS): #and not defined(NimrodVM): ## ## Raises an IO exception in case of an error. It is an error if the ## current file position is not at the beginning of the file. - + proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} ## Opens a file named `filename` for reading. ## @@ -2440,8 +2440,8 @@ when not defined(JS): #and not defined(NimrodVM): ## reads a line of text from the file `f`. May throw an IO exception. ## A line of text may be delimited by ``CR``, ``LF`` or ## ``CRLF``. The newline character(s) are not part of the returned string. - - proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], + + proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], benign.} ## reads a line of text from the file `f` into `line`. `line` must not be ## ``nil``! May throw an IO exception. @@ -2450,7 +2450,7 @@ when not defined(JS): #and not defined(NimrodVM): ## Returns ``false`` if the end of the file has been reached, ``true`` ## otherwise. If ``false`` is returned `line` contains no new data. - proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} ## writes the values `x` to `f` and then writes "\n". ## May throw an IO exception. @@ -2544,11 +2544,11 @@ when not defined(JS): #and not defined(NimrodVM): dealloc(a) when not defined(NimrodVM): - proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, + proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, benign.} ## atomic increment of `memLoc`. Returns the value after the operation. - - proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, + + proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable, benign.} ## atomic decrement of `memLoc`. Returns the value after the operation. @@ -2562,7 +2562,7 @@ when not defined(JS): #and not defined(NimrodVM): context: C_JmpBuf hasRaiseAction: bool raiseAction: proc (e: ref Exception): bool {.closure.} - + when declared(initAllocator): initAllocator() when hasThreadSupport: @@ -2576,7 +2576,7 @@ when not defined(JS): #and not defined(NimrodVM): proc setControlCHook*(hook: proc () {.noconv.} not nil) ## allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. - + proc writeStackTrace*() {.tags: [WriteIOEffect].} ## writes the current stack trace to ``stderr``. This is only works ## for debug builds. @@ -2587,20 +2587,20 @@ when not defined(JS): #and not defined(NimrodVM): proc getStackTrace*(e: ref Exception): string ## gets the stack trace associated with `e`, which is the stack that ## lead to the ``raise`` statement. This only works for debug builds. - + {.push stack_trace: off, profiler:off.} when hostOS == "standalone": include "system/embedded" else: include "system/excpt" include "system/chcks" - + # we cannot compile this with stack tracing on # as it would recurse endlessly! include "system/arithm" {.pop.} # stack trace {.pop.} # stack trace - + when hostOS != "standalone" and not defined(NimrodVM): include "system/dyncalls" when not defined(NimrodVM): @@ -2608,7 +2608,7 @@ when not defined(JS): #and not defined(NimrodVM): const GenericSeqSize = (2 * sizeof(int)) - + proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") var d: int @@ -2728,7 +2728,7 @@ when not defined(JS): #and not defined(NimrodVM): ## process(value) ## else: ## echo "Value too big!" - + proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} ## Hints the optimizer that `val` is likely going to be false. ## @@ -2742,7 +2742,7 @@ when not defined(JS): #and not defined(NimrodVM): ## echo "Value too big!" ## else: ## process(value) - + proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = ## retrieves the raw proc pointer of the closure `x`. This is ## useful for interfacing closures with C. @@ -2774,7 +2774,7 @@ elif defined(JS): proc GC_enableMarkAndSweep() = discard proc GC_disableMarkAndSweep() = discard proc GC_getStatistics(): string = return "" - + proc getOccupiedMem(): int = return -1 proc getFreeMem(): int = return -1 proc getTotalMem(): int = return -1 @@ -2797,7 +2797,7 @@ elif defined(JS): if x == y: return 0 if x < y: return -1 return 1 - + when defined(nimffi): include "system/sysio" @@ -2831,14 +2831,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # cut down: setLen(s, newLen) # fill the hole: - for i in 0 .. <b.len: s[i+a] = b[i] + for i in 0 .. <b.len: s[i+a] = b[i] when hostOS != "standalone": proc `[]`*(s: string, x: Slice[int]): string {.inline.} = ## slice operation for strings. Negative indexes are supported. result = s.substr(x.a-|s, x.b-|s) - proc `[]=`*(s: var string, x: Slice[int], b: string) = + proc `[]=`*(s: var string, x: Slice[int], b: string) = ## slice assignment for strings. Negative indexes are supported. If ## ``b.len`` is not exactly the number of elements that are referred to ## by `x`, a `splice`:idx: is performed: @@ -2880,7 +2880,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] = var L = ord(x.b) - ord(x.a) + 1 newSeq(result, L) var j = x.a - for i in 0.. <L: + for i in 0.. <L: result[i] = a[j] inc(j) @@ -2890,23 +2890,23 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = var L = ord(x.b) - ord(x.a) + 1 if L == b.len: var j = x.a - for i in 0 .. <L: + for i in 0 .. <L: a[j] = b[i] inc(j) else: sysFatal(RangeError, "different lengths for slice assignment") -proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = +proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = ## slice operation for sequences. Negative indexes are supported. var a = x.a-|s var L = x.b-|s - a + 1 newSeq(result, L) for i in 0.. <L: result[i] = s[i + a] -proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = +proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = ## slice assignment for sequences. Negative indexes are supported. If ## ``b.len`` is not exactly the number of elements that are referred to - ## by `x`, a `splice`:idx: is performed. + ## by `x`, a `splice`:idx: is performed. var a = x.a-|s var L = x.b-|s - a + 1 if L == b.len: @@ -2937,7 +2937,7 @@ proc staticExec*(command: string, input = ""): string {. ## to the executed program. ## ## .. code-block:: nim - ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & + ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & ## "\nCompiled on " & staticExec("uname -v") ## ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use @@ -2979,7 +2979,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} ## converts the AST of `x` into a string representation. This is very useful ## for debugging. - + proc instantiationInfo*(index = -1, fullPaths = false): tuple[ filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.} ## provides access to the compiler's instantiation stack line information. @@ -3090,16 +3090,16 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} = ## Sets an assertion failure handler that will intercept any assert ## statements following `onFailedAssert` in the current lexical scope. ## Can be defined multiple times in a single function. - ## + ## ## .. code-block:: nim ## ## proc example(x: int): TErrorCode = ## onFailedAssert(msg): ## log msg ## return E_FAIL - ## + ## ## assert(...) - ## + ## ## onFailedAssert(msg): ## raise newException(EMyException, msg) ## @@ -3111,7 +3111,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} = proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not - ## perform deep copies of `s`. This is only useful for optimization + ## perform deep copies of `s`. This is only useful for optimization ## purposes. when not defined(JS) and not defined(NimrodVM): var s = cast[PGenericSeq](s) @@ -3119,7 +3119,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = proc shallow*(s: var string) {.noSideEffect, inline.} = ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not - ## perform deep copies of `s`. This is only useful for optimization + ## perform deep copies of `s`. This is only useful for optimization ## purposes. when not defined(JS) and not defined(NimrodVM): var s = cast[PGenericSeq](s) @@ -3141,13 +3141,13 @@ else: when false: template eval*(blk: stmt): stmt = ## executes a block of code at compile time just as if it was a macro - ## optionally, the block can return an AST tree that will replace the + ## optionally, the block can return an AST tree that will replace the ## eval expression macro payload: stmt {.gensym.} = blk payload() when hostOS != "standalone": - proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = + proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = ## inserts `item` into `x` at position `i`. var xl = x.len setLen(x, xl+item.len) diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 9de0c6503..bbf8cbf66 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -48,7 +48,7 @@ type TWalkOp = enum waMarkGlobal, # part of the backup/debug mark&sweep waMarkPrecise, # part of the backup/debug mark&sweep - waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, + waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, waCollectWhite #, waDebug TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} @@ -61,9 +61,9 @@ type maxThreshold: int # max threshold that has been set maxStackSize: int # max stack size maxStackCells: int # max stack cells in ``decStack`` - cycleTableSize: int # max entries in cycle table + cycleTableSize: int # max entries in cycle table maxPause: int64 # max measured GC pause in nanoseconds - + TGcHeap {.final, pure.} = object # this contains the zero count and # non-zero count table stackBottom: pointer @@ -88,11 +88,11 @@ var when not defined(useNimRtl): instantiateForRegion(gch.region) -template acquire(gch: TGcHeap) = +template acquire(gch: TGcHeap) = when hasThreadSupport and hasSharedHeap: acquireSys(HeapLock) -template release(gch: TGcHeap) = +template release(gch: TGcHeap) = when hasThreadSupport and hasSharedHeap: releaseSys(HeapLock) @@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap: template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement) else: - template `--`(x: expr): expr = + template `--`(x: expr): expr = dec(x, rcIncrement) x <% rcIncrement template `++`(x: expr): stmt = inc(x, rcIncrement) @@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) = (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell)) dec(gch.recGcLock) -proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = +proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = # we MUST access gch as a global here, because this crosses DLL boundaries! when hasThreadSupport and hasSharedHeap: acquireSys(HeapLock) @@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} = rtlAddCycleRoot(c) #writeCell("decRef", c) -proc incRef(c: PCell) {.inline.} = +proc incRef(c: PCell) {.inline.} = gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr") c.refcount = c.refcount +% rcIncrement # and not colorMask @@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} = dest[] = src proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} = - # the code generator calls this proc if it is known at compile time that no + # the code generator calls this proc if it is known at compile time that no # cycle is possible. if src != nil: var c = usrToCell(src) ++c.refcount - if dest[] != nil: + if dest[] != nil: var c = usrToCell(dest[]) if --c.refcount: rtlAddZCT(c) @@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} = if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[])) else: # can't be an interior pointer if it's a stack location! - gcAssert(interiorAllocatedPtr(gch.region, dest) == nil, + gcAssert(interiorAllocatedPtr(gch.region, dest) == nil, "stack loc AND interior pointer") dest[] = src @@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc: echo "[GC] cannot register global variable; too many global variables" quit 1 -proc cellsetReset(s: var TCellSet) = +proc cellsetReset(s: var TCellSet) = deinit(s) init(s) @@ -336,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} = if n.sons[i].typ.kind in {tyRef, tyString, tySequence}: doOperation(cast[PPointer](d +% n.sons[i].offset)[], op) else: - forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), + forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), n.sons[i].typ, op) else: forAllSlotsAux(dest, n.sons[i], op) @@ -384,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} = # we check the last 8 entries (cache line) for a slot that could be reused. # In 63% of all cases we succeed here! But we have to optimize the heck # out of this small linear search so that ``newObj`` is not slowed down. - # + # # Slots to try cache hit # 1 32% # 4 59% @@ -481,7 +481,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) sysAssert(allocInv(gch.region), "newObjRC1 after collectCT") - + var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc") sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") @@ -510,7 +510,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} = cast[PGenericSeq](result).len = len cast[PGenericSeq](result).reserved = len when defined(memProfiler): nimProfile(size) - + proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = acquire(gch) collectCT(gch) @@ -522,7 +522,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell))) var elemSize = 1 if ol.typ.kind != tyString: elemSize = ol.typ.base.size - + var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize copyMem(res, ol, oldsize + sizeof(TCell)) zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)), @@ -536,7 +536,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = writeCell("growObj new cell", res) gcTrace(ol, csZctFreed) gcTrace(res, csAllocated) - when reallyDealloc: + when reallyDealloc: sysAssert(allocInv(gch.region), "growObj before dealloc") if ol.refcount shr rcShift <=% 1: # free immediately to save space: @@ -580,7 +580,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) = prepareDealloc(c) gcTrace(c, csCycFreed) when logGC: writeCell("cycle collector dealloc cell", c) - when reallyDealloc: + when reallyDealloc: sysAssert(allocInv(gch.region), "free cyclic cell") rawDealloc(gch.region, c) else: @@ -767,7 +767,7 @@ proc collectCycles(gch: var TGcHeap) = gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots" gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell" if canBeCycleRoot(c): - #if c notin gch.cycleRoots: + #if c notin gch.cycleRoots: inc cycleRootsLen incl(gch.cycleRoots, c) gcAssert c.typ != nil, "addBackStackRoots 2" @@ -794,12 +794,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = add(gch.decStack, cell) sysAssert(allocInv(gch.region), "gcMark end") -proc markThreadStacks(gch: var TGcHeap) = +proc markThreadStacks(gch: var TGcHeap) = when hasThreadSupport and hasSharedHeap: {.error: "not fully implemented".} var it = threadList while it != nil: - # mark registers: + # mark registers: for i in 0 .. high(it.registers): gcMark(gch, it.registers[i]) var sp = cast[TAddress](it.stackBottom) var max = cast[TAddress](it.stackTop) @@ -933,7 +933,7 @@ else: while sp <=% max: gcMark(gch, cast[PPointer](sp)[]) sp = sp +% sizeof(pointer) - + proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = forEachStackSlot(gch, gcMark) @@ -946,13 +946,13 @@ when useMarkForDebug or useBackupGc: # ---------------------------------------------------------------------------- proc collectZCT(gch: var TGcHeap): bool = - # Note: Freeing may add child objects to the ZCT! So essentially we do - # deep freeing, which is bad for incremental operation. In order to + # Note: Freeing may add child objects to the ZCT! So essentially we do + # deep freeing, which is bad for incremental operation. In order to # avoid a deep stack, we move objects to keep the ZCT small. # This is performance critical! const workPackage = 100 var L = addr(gch.zct.len) - + when withRealTime: var steps = workPackage var t0: TTicks @@ -962,15 +962,15 @@ proc collectZCT(gch: var TGcHeap): bool = sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr") # remove from ZCT: gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT") - + c.refcount = c.refcount and not ZctFlag gch.zct.d[0] = gch.zct.d[L[] - 1] dec(L[]) when withRealTime: dec steps - if c.refcount <% rcIncrement: + if c.refcount <% rcIncrement: # It may have a RC > 0, if it is in the hardware stack or # it has not been removed yet from the ZCT. This is because - # ``incref`` does not bother to remove the cell from the ZCT + # ``incref`` does not bother to remove the cell from the ZCT # as this might be too slow. # In any case, it should be removed from the ZCT. But not # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!** @@ -983,7 +983,7 @@ proc collectZCT(gch: var TGcHeap): bool = # access invalid memory. This is done by prepareDealloc(): prepareDealloc(c) forAllChildren(c, waZctDecRef) - when reallyDealloc: + when reallyDealloc: sysAssert(allocInv(gch.region), "collectZCT: rawDealloc") rawDealloc(gch.region, c) else: @@ -994,7 +994,7 @@ proc collectZCT(gch: var TGcHeap): bool = steps = workPackage if gch.maxPause > 0: let duration = getticks() - t0 - # the GC's measuring is not accurate and needs some cleanup actions + # the GC's measuring is not accurate and needs some cleanup actions # (stack unmarking), so subtract some short amount of time in # order to miss deadlines less often: if duration >= gch.maxPause - 50_000: @@ -1017,7 +1017,7 @@ proc collectCTBody(gch: var TGcHeap) = when withRealTime: let t0 = getticks() sysAssert(allocInv(gch.region), "collectCT: begin") - + gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize()) sysAssert(gch.decStack.len == 0, "collectCT") prepareForInteriorPointerChecking(gch.region) @@ -1036,7 +1036,7 @@ proc collectCTBody(gch: var TGcHeap) = gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold) unmarkStackAndRegisters(gch) sysAssert(allocInv(gch.region), "collectCT: end") - + when withRealTime: let duration = getticks() - t0 gch.stat.maxPause = max(gch.stat.maxPause, duration) @@ -1050,8 +1050,12 @@ when useMarkForDebug or useBackupGc: markGlobals(gch) proc collectCT(gch: var TGcHeap) = - if (gch.zct.len >= ZctThreshold or (cycleGC and - getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and + # stackMarkCosts prevents some pathological behaviour: Stack marking + # becomes more expensive with large stacks and large stacks mean that + # cells with RC=0 are more likely to be kept alive by the stack. + let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold) + if (gch.zct.len >= stackMarkCosts or (cycleGC and + getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and gch.recGcLock == 0: when useMarkForDebug: prepareForInteriorPointerChecking(gch.region) @@ -1070,7 +1074,7 @@ when withRealTime: acquire(gch) gch.maxPause = us.toNano if (gch.zct.len >= ZctThreshold or (cycleGC and - getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or + getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or strongAdvice: collectCTBody(gch) release(gch) @@ -1078,13 +1082,13 @@ when withRealTime: proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice) when not defined(useNimRtl): - proc GC_disable() = + proc GC_disable() = when hasThreadSupport and hasSharedHeap: discard atomicInc(gch.recGcLock, 1) else: inc(gch.recGcLock) proc GC_enable() = - if gch.recGcLock > 0: + if gch.recGcLock > 0: when hasThreadSupport and hasSharedHeap: discard atomicDec(gch.recGcLock, 1) else: diff --git a/todo.txt b/todo.txt index 1d180f737..69674f019 100644 --- a/todo.txt +++ b/todo.txt @@ -53,7 +53,6 @@ Bugs - VM: Pegs do not work at compile-time - VM: ptr/ref T cannot work in general - scopes are still broken for generic instantiation! -- compilation of niminst takes way too long. looks like a regression - blocks can "export" an identifier but the CCG generates {} for them ... |