summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xlib/system.nim1
-rwxr-xr-xlib/system/assign.nim31
-rwxr-xr-xlib/system/gc.nim5
-rwxr-xr-xrod/ccgexprs.nim31
-rwxr-xr-xrod/ccgstmts.nim7
-rwxr-xr-xrod/cgen.nim110
-rw-r--r--tests/gc/gcleak.nim2
-rw-r--r--tests/gc/gcleak2.nim20
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()
+