diff options
-rwxr-xr-x | lib/system.nim | 1 | ||||
-rwxr-xr-x | lib/system/assign.nim | 31 | ||||
-rwxr-xr-x | lib/system/gc.nim | 5 | ||||
-rwxr-xr-x | rod/ccgexprs.nim | 31 | ||||
-rwxr-xr-x | rod/ccgstmts.nim | 7 | ||||
-rwxr-xr-x | rod/cgen.nim | 110 | ||||
-rw-r--r-- | tests/gc/gcleak.nim | 2 | ||||
-rw-r--r-- | tests/gc/gcleak2.nim | 20 |
8 files changed, 132 insertions, 75 deletions
diff --git a/lib/system.nim b/lib/system.nim index e1b6aeb4f..6909185e6 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -662,7 +662,6 @@ proc newString*(len: int): string {. ## optimization purposes; the same effect can be achieved with the ## ``&`` operator. -# concat operator: proc `&` * (x: string, y: char): string {. magic: "ConStrStr", noSideEffect, merge.} proc `&` * (x: char, y: char): string {. diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 44d2e5c64..9f0afb363 100755 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -118,3 +118,34 @@ proc objectInit(dest: Pointer, typ: PNimType) = for i in 0..(typ.size div typ.base.size)-1: objectInit(cast[pointer](d +% i * typ.base.size), typ.base) else: nil # nothing to do + +# ---------------------- assign zero ----------------------------------------- + +proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.} +proc genericResetAux(dest: Pointer, n: ptr TNimNode) = + var d = cast[TAddress](dest) + case n.kind + of nkNone: assert(false) + of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ) + of nkList: + for i in 0..n.len-1: genericResetAux(dest, n.sons[i]) + of nkCase: + zeroMem(cast[pointer](d +% n.offset), n.typ.size) + var m = selectBranch(dest, n) + if m != nil: genericResetAux(dest, m) + +proc genericReset(dest: Pointer, mt: PNimType) = + var d = cast[TAddress](dest) + assert(mt != nil) + case mt.Kind + of tyString, tyRef, tySequence: + unsureAsgnRef(cast[ppointer](dest), nil) + of tyObject, tyTuple, tyPureObject: + # we don't need to reset m_type field for tyObject + genericResetAux(dest, mt.node) + of tyArray, tyArrayConstr: + for i in 0..(mt.size div mt.base.size)-1: + genericReset(cast[pointer](d +% i*% mt.base.size), mt.base) + else: + zeroMem(dest, mt.size) # set raw bits to zero + diff --git a/lib/system/gc.nim b/lib/system/gc.nim index c5bd56b99..5288316f2 100755 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -74,8 +74,9 @@ var # we use a lock to prevent the garbage collector to be triggered in a # finalizer; the collector should not call itself this way! Thus every # object allocated by a finalizer will not trigger a garbage collection. - # This is wasteful but safe. This is a lock against recursive garbage - # collection, not a lock for threads! + # This is wasteful but safe and won't ever be a problem for sane + # finalizers. This is a lock against recursive garbage collection, not a + # lock for threads! proc aquire(gch: var TGcHeap) {.inline.} = when hasThreadSupport: diff --git a/rod/ccgexprs.nim b/rod/ccgexprs.nim index a0cbaeb03..c8404fef6 100755 --- a/rod/ccgexprs.nim +++ b/rod/ccgexprs.nim @@ -150,12 +150,6 @@ proc getStorageLoc(n: PNode): TStorageLoc = result = getStorageLoc(n.sons[0]) else: result = OnUnknown -type - TAssignmentFlag = enum - needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil, - afSrcIsNotNil - TAssignmentFlags = set[TAssignmentFlag] - proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions): appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) @@ -902,27 +896,6 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = dest.r = ropef("$1->data[$1->Sup.len-1]", [rdLoc(a)]) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) -proc genObjectInit(p: BProc, t: PType, a: TLoc, takeAddr: bool) = - var - r: PRope - s: PType - case analyseObjectWithTypeField(t) - of frNone: - nil - of frHeader: - r = rdLoc(a) - if not takeAddr: r = ropef("(*$1)", [r]) - s = t - while (s.kind == tyObject) and (s.sons[0] != nil): - app(r, ".Sup") - s = skipTypes(s.sons[0], abstractInst) - appf(p.s[cpsStmts], "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)]) - of frEmbedded: - # worst case for performance: - if takeAddr: r = addrLoc(a) - else: r = rdLoc(a) - appcg(p, cpsStmts, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)]) - proc genNew(p: BProc, e: PNode) = var a, b: TLoc @@ -936,7 +909,7 @@ proc genNew(p: BProc, e: PNode) = getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))]) genAssignment(p, a, b, {}) # set the object type: bt = skipTypes(refType.sons[0], abstractRange) - genObjectInit(p, bt, a, false) + genObjectInit(p, cpsStmts, bt, a, false) proc genNewSeq(p: BProc, e: PNode) = var @@ -1001,7 +974,7 @@ proc genNewFinalize(p: BProc, e: PNode) = ti, getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))]) genAssignment(p, a, b, {}) # set the object type: bt = skipTypes(refType.sons[0], abstractRange) - genObjectInit(p, bt, a, false) + genObjectInit(p, cpsStmts, bt, a, false) proc genRepr(p: BProc, e: PNode, d: var TLoc) = var a: TLoc diff --git a/rod/ccgstmts.nim b/rod/ccgstmts.nim index 2b649a270..572b60143 100755 --- a/rod/ccgstmts.nim +++ b/rod/ccgstmts.nim @@ -42,6 +42,7 @@ proc genVarTuple(p: BProc, n: PNode) = v = n.sons[i].sym if sfGlobal in v.flags: assignGlobalVar(p, v) + genObjectInit(p, cpsInit, v.typ, v.loc, true) else: assignLocalVar(p, v) initVariable(p, v) @@ -53,7 +54,6 @@ proc genVarTuple(p: BProc, n: PNode) = field.r = ropef("$1.$2", [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]) putLocIntoDest(p, v.loc, field) - genObjectInit(p, v.typ, v.loc, true) proc genVarStmt(p: BProc, n: PNode) = for i in countup(0, sonsLen(n) - 1): @@ -64,14 +64,13 @@ proc genVarStmt(p: BProc, n: PNode) = var v = a.sons[0].sym if sfGlobal in v.flags: assignGlobalVar(p, v) + genObjectInit(p, cpsInit, v.typ, v.loc, true) else: assignLocalVar(p, v) - initVariable(p, v) # XXX: this is not required if a.sons[2] != nil, - # unless it is a GC'ed pointer + initVariable(p, v) if a.sons[2].kind != nkEmpty: genLineDir(p, a) expr(p, a.sons[2], v.loc) - genObjectInit(p, v.typ, v.loc, true) # correct position else: genVarTuple(p, a) diff --git a/rod/cgen.nim b/rod/cgen.nim index f13f5991a..503cb8586 100755 --- a/rod/cgen.nim +++ b/rod/cgen.nim @@ -256,35 +256,75 @@ proc rdCharLoc(a: TLoc): PRope = if skipTypes(a.t, abstractRange).kind == tyChar: result = ropef("((NU8)($1))", [result]) -proc zeroLoc(p: BProc, loc: TLoc) = - if not (skipTypes(loc.t, abstractVarRange).Kind in - {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}): - if gCmd == cmdCompileToLLVM: - appf(p.s[cpsStmts], "store $2 0, $2* $1$n", - [addrLoc(loc), getTypeDesc(p.module, loc.t)]) - else: +proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, + takeAddr: bool) = + case analyseObjectWithTypeField(t) + of frNone: + nil + of frHeader: + var r = rdLoc(a) + if not takeAddr: r = ropef("(*$1)", [r]) + var s = t + while (s.kind == tyObject) and (s.sons[0] != nil): + app(r, ".Sup") + s = skipTypes(s.sons[0], abstractInst) + appcg(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)]) + of frEmbedded: + # worst case for performance: + var r = if takeAddr: addrLoc(a) else: rdLoc(a) + appcg(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)]) + +type + TAssignmentFlag = enum + needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil, + afSrcIsNotNil + TAssignmentFlags = set[TAssignmentFlag] + +proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) + +proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) = + if skipTypes(loc.t, abstractVarRange).Kind notin + {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: + if containsGcref: + appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)]) + var nilLoc: TLoc + initLoc(nilLoc, locTemp, loc.t, onStack) + nilLoc.r = toRope("NIM_NIL") + # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: + genRefAssign(p, loc, nilLoc, {afSrcIsNil}) + else: appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)]) else: - if gCmd == cmdCompileToLLVM: - app(p.module.s[cfsProcHeaders], - "declare void @llvm.memset.i32(i8*, i8, i32, i32)" & tnl) - inc(p.labels, 2) - appf(p.s[cpsStmts], "%LOC$3 = getelementptr $2* null, %NI 1$n" & - "%LOC$4 = cast $2* %LOC$3 to i32$n" & - "call void @llvm.memset.i32(i8* $1, i8 0, i32 %LOC$4, i32 0)$n", [ - addrLoc(loc), getTypeDesc(p.module, loc.t), toRope(p.labels), - toRope(p.labels - 1)]) - else: + if containsGcref: + appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", + [addrLoc(loc), rdLoc(loc)]) + appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(loc), genTypeInfo(p.module, loc.t)]) + else: appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", [addrLoc(loc), rdLoc(loc)]) + genObjectInit(p, cpsInit, loc.t, loc, true) + +proc zeroTemp(p: BProc, loc: TLoc) = + if skipTypes(loc.t, abstractVarRange).Kind notin + {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: + var nilLoc: TLoc + initLoc(nilLoc, locTemp, loc.t, onStack) + nilLoc.r = toRope("NIM_NIL") + # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``: + genRefAssign(p, loc, nilLoc, {afSrcIsNil}) + else: + appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", + [addrLoc(loc), genTypeInfo(p.module, loc.t)]) proc initVariable(p: BProc, v: PSym) = - if containsGarbageCollectedRef(v.typ) or (v.ast == nil): - zeroLoc(p, v.loc) + var b = containsGarbageCollectedRef(v.typ) + if b or v.ast == nil: + zeroVar(p, v.loc, b) proc initTemp(p: BProc, tmp: var TLoc) = if containsGarbageCollectedRef(tmp.t): - zeroLoc(p, tmp) + zeroTemp(p, tmp) proc getTemp(p: BProc, t: PType, result: var TLoc) = inc(p.labels) @@ -324,11 +364,10 @@ proc cstringLit(m: BModule, r: var PRope, s: string): PRope = result = makeCString(s) proc allocParam(p: BProc, s: PSym) = - var tmp: PRope assert(s.kind == skParam) if not (lfParamCopy in s.loc.flags): inc(p.labels) - tmp = con("%LOC", toRope(p.labels)) + var tmp = con("%LOC", toRope(p.labels)) incl(s.loc.flags, lfParamCopy) incl(s.loc.flags, lfIndirect) appf(p.s[cpsInit], "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", @@ -520,11 +559,7 @@ proc cgsym(m: BModule, name: string): PRope = # we used to exclude the system module from this check, but for DLL # generation support this sloppyness leads to hard to detect bugs, so # we're picky here for the system module too: - when false: - if not (sfSystemModule in m.module.flags): - rawMessage(errSystemNeeds, name) - else: - rawMessage(errSystemNeeds, name) + rawMessage(errSystemNeeds, name) result = sym.loc.r proc generateHeaders(m: BModule) = @@ -593,14 +628,13 @@ proc genProcAux(m: BModule, prc: PSym) = assignLocalVar(p, res) assert(res.loc.r != nil) returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)]) + initVariable(p, res) else: fillResult(res) assignParam(p, res) if skipTypes(res.typ, abstractInst).kind == tyArray: incl(res.loc.flags, lfIndirect) res.loc.s = OnUnknown - initVariable(p, res) - genObjectInit(p, res.typ, res.loc, true) for i in countup(1, sonsLen(prc.typ.n) - 1): param = prc.typ.n.sons[i].sym assignParam(p, param) @@ -644,23 +678,22 @@ proc genProcAux(m: BModule, prc: PSym) = proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) - if (lfNoDecl in sym.loc.Flags): return + if lfNoDecl in sym.loc.Flags: return if lfDynamicLib in sym.loc.Flags: - if (sym.owner.id != m.module.id) and + if sym.owner.id != m.module.id and not intSetContainsOrIncl(m.declaredThings, sym.id): appff(m.s[cfsVars], "extern $1 $2;$n", "@$2 = linkonce global $1 zeroinitializer$n", [getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)]) if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) - else: - if not IntSetContainsOrIncl(m.declaredProtos, sym.id): - appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)]) + elif not IntSetContainsOrIncl(m.declaredProtos, sym.id): + appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)]) proc genProcNoForward(m: BModule, prc: PSym) = fillProcLoc(prc) useHeader(m, prc) genProcPrototype(m, prc) - if (lfNoDecl in prc.loc.Flags): return + if lfNoDecl in prc.loc.Flags: return if prc.typ.callConv == ccInline: # We add inline procs to the calling module to enable C based inlining. # This also means that a check with ``gGeneratedSyms`` is wrong, we need @@ -771,7 +804,8 @@ proc genMainProc(m: BModule) = " NimMain();$n" & " return 0;$n" & "}$n" WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" & CommonMainBody & "}$n" - WinCDllMain = "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" & + WinCDllMain = + "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" & " LPVOID lpvReserved) {$n" & " NimMain();$n" & " return 1;$n" & "}$n" PosixNimDllMain = WinNimDllMain @@ -779,8 +813,8 @@ proc genMainProc(m: BModule) = "void NIM_POSIX_INIT NimMainInit(void) {$n" & " NimMain();$n}$n" var nimMain, otherMain: TFormatStr - if (platform.targetOS == osWindows) and - (gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}): + if platform.targetOS == osWindows and + gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}: if optGenGuiApp in gGlobalOptions: nimMain = WinNimMain otherMain = WinCMain diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim index 88aeda56d..a44c16f59 100644 --- a/tests/gc/gcleak.nim +++ b/tests/gc/gcleak.nim @@ -7,5 +7,5 @@ proc MakeObj(): TTestObj = while true: var obj = MakeObj() - +# echo GC_getstatistics() diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim new file mode 100644 index 000000000..5ab9da7c9 --- /dev/null +++ b/tests/gc/gcleak2.nim @@ -0,0 +1,20 @@ +type + TTestObj = object of TObject + x: string + s: seq[int] + +proc MakeObj(): TTestObj = + result.x = "Hello" + result.s = @[1,2,3] + +#while true: +# var obj = MakeObj() +# echo GC_getstatistics() + +proc inProc() = + while true: + var obj: TTestObj + obj = MakeObj() + +inProc() + |