summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2017-01-15 10:12:18 +0100
committerAndreas Rumpf <rumpf_a@web.de>2017-01-15 10:12:28 +0100
commit03916fa3b1a07eb4cbd88cf3afe359695caf5446 (patch)
tree18785dd1ae6e70c2479843a865dddf3a197d62d8
parente216e0debda7efcaf9681a1233a38414c690e54f (diff)
downloadNim-03916fa3b1a07eb4cbd88cf3afe359695caf5446.tar.gz
M&S GC gets the heap dump feature
-rw-r--r--lib/system/gc.nim90
-rw-r--r--lib/system/gc_common.nim24
-rw-r--r--lib/system/gc_ms.nim31
3 files changed, 76 insertions, 69 deletions
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 2c971b35d..18d41219d 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -167,15 +167,6 @@ proc writeCell(msg: cstring, c: PCell) =
     c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; color=%ld\n",
               msg, c, kind, typName, c.refcount shr rcShift, c.color)
 
-
-when defined(nimTypeNames):
-  proc dumpNumberOfInstances* =
-    var it = nimTypeRoot
-    while it != nil:
-      if it.instances > 0:
-        c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
-      it = it.nextType
-
 template gcTrace(cell, state: expr): stmt {.immediate.} =
   when traceGC: traceCell(cell, state)
 
@@ -196,34 +187,16 @@ else:
     x <% rcIncrement
   template `++`(x: expr): stmt = inc(x, rcIncrement)
 
-proc prepareDealloc(cell: PCell) =
-  when useMarkForDebug:
-    gcAssert(cell notin gch.marked, "Cell still alive!")
-  let t = cell.typ
-  if t.finalizer != nil:
-    # the finalizer could invoke something that
-    # allocates memory; this could trigger a garbage
-    # collection. Since we are already collecting we
-    # prevend recursive entering here by a lock.
-    # XXX: we should set the cell's children to nil!
-    inc(gch.recGcLock)
-    (cast[Finalizer](t.finalizer))(cellToUsr(cell))
-    dec(gch.recGcLock)
-  when defined(nimTypeNames):
-    if t.kind in {tyString, tySequence}:
-      let len = cast[PGenericSeq](cellToUsr(cell)).len
-      let base = if t.kind == tyString: 1 else: t.base.size
-      let size = addInt(mulInt(len, base), GenericSeqSize)
-      dec t.sizes, size+sizeof(Cell)
-    else:
-      dec t.sizes, t.size+sizeof(Cell)
-    dec t.instances
+proc incRef(c: PCell) {.inline.} =
+  gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
+  c.refcount = c.refcount +% rcIncrement
+  # and not colorMask
+  #writeCell("incRef", c)
 
-template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
-  when false:
-    for i in 0..gch.decStack.len-1:
-      if gch.decStack.d[i] == c:
-        sysAssert(false, msg)
+proc nimGCref(p: pointer) {.compilerProc.} =
+  # we keep it from being collected by pretending it's not even allocated:
+  add(gch.additionalRoots, usrToCell(p))
+  incRef(usrToCell(p))
 
 proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
@@ -246,17 +219,6 @@ proc decRef(c: PCell) {.inline.} =
   if --c.refcount:
     rtlAddZCT(c)
 
-proc incRef(c: PCell) {.inline.} =
-  gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
-  c.refcount = c.refcount +% rcIncrement
-  # and not colorMask
-  #writeCell("incRef", c)
-
-proc nimGCref(p: pointer) {.compilerProc.} =
-  # we keep it from being collected by pretending it's not even allocated:
-  add(gch.additionalRoots, usrToCell(p))
-  incRef(usrToCell(p))
-
 proc nimGCunref(p: pointer) {.compilerProc.} =
   let cell = usrToCell(p)
   var L = gch.additionalRoots.len-1
@@ -270,6 +232,29 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
     dec(i)
   decRef(usrToCell(p))
 
+include gc_common
+
+proc prepareDealloc(cell: PCell) =
+  when useMarkForDebug:
+    gcAssert(cell notin gch.marked, "Cell still alive!")
+  let t = cell.typ
+  if t.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(gch.recGcLock)
+    (cast[Finalizer](t.finalizer))(cellToUsr(cell))
+    dec(gch.recGcLock)
+  decTypeSize(cell, t)
+
+template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
+  when false:
+    for i in 0..gch.decStack.len-1:
+      if gch.decStack.d[i] == c:
+        sysAssert(false, msg)
+
 proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
   ## adds 'p' to the cycle candidate set for the cycle collector. It is
   ## necessary if you used the 'acyclic' pragma for optimization
@@ -481,9 +466,7 @@ template setFrameInfo(c: PCell) =
 
 proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   # generates a new object and sets its reference counter to 0
-  when defined(nimTypeNames):
-    inc typ.instances
-    inc typ.sizes, size+sizeof(Cell)
+  incTypeSize typ, size
   sysAssert(allocInv(gch.region), "rawNewObj begin")
   acquire(gch)
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
@@ -531,9 +514,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
 
 proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   # generates a new object and sets its reference counter to 1
-  when defined(nimTypeNames):
-    inc typ.instances
-    inc typ.sizes, size+sizeof(Cell)
+  incTypeSize typ, size
   sysAssert(allocInv(gch.region), "newObjRC1 begin")
   acquire(gch)
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
@@ -578,6 +559,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+  incTypeSize ol.typ, newsize
 
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(Cell))
@@ -765,8 +747,6 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
         add(gch.decStack, cell)
   sysAssert(allocInv(gch.region), "gcMark end")
 
-include gc_common
-
 proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
   forEachStackSlot(gch, gcMark)
 
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
index 513ede173..64acb7b24 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -17,6 +17,30 @@ proc protect*(x: pointer): ForeignCell =
   result.data = x
   result.owner = addr(gch)
 
+when defined(nimTypeNames):
+  proc dumpNumberOfInstances* =
+    var it = nimTypeRoot
+    while it != nil:
+      if it.instances > 0:
+        c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
+      it = it.nextType
+
+template decTypeSize(cell, t) =
+  when defined(nimTypeNames):
+    if t.kind in {tyString, tySequence}:
+      let len = cast[PGenericSeq](cellToUsr(cell)).len
+      let base = if t.kind == tyString: 1 else: t.base.size
+      let size = addInt(mulInt(len, base), GenericSeqSize)
+      dec t.sizes, size+sizeof(Cell)
+    else:
+      dec t.sizes, t.size+sizeof(Cell)
+    dec t.instances
+
+template incTypeSize(typ, size) =
+  when defined(nimTypeNames):
+    inc typ.instances
+    inc typ.sizes, size+sizeof(Cell)
+
 proc dispose*(x: ForeignCell) =
   when hasThreadSupport:
     # if we own it we can free it directly:
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index ec69f6e5f..63ca94698 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -28,7 +28,7 @@ template mulThreshold(x): expr {.immediate.} = x * 2
 
 when defined(memProfiler):
   proc nimProfile(requestedSize: int)
-  
+
 when hasThreadSupport:
   import sharedlist
 
@@ -140,17 +140,6 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
 proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
 # we need the prototype here for debugging purposes
 
-proc prepareDealloc(cell: PCell) =
-  if cell.typ.finalizer != nil:
-    # the finalizer could invoke something that
-    # allocates memory; this could trigger a garbage
-    # collection. Since we are already collecting we
-    # prevend recursive entering here by a lock.
-    # XXX: we should set the cell's children to nil!
-    inc(gch.recGcLock)
-    (cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
-    dec(gch.recGcLock)
-
 proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
   when false:
@@ -173,6 +162,20 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
     when withBitvectors: incl(gch.allocated, usrToCell(p))
     else: usrToCell(p).refcount = rcWhite
 
+include gc_common
+
+proc prepareDealloc(cell: PCell) =
+  if cell.typ.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(gch.recGcLock)
+    (cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
+    dec(gch.recGcLock)
+  decTypeSize cell, cell.typ
+
 proc initGC() =
   when not defined(useNimRtl):
     gch.cycleThreshold = InitialThreshold
@@ -235,6 +238,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
 
 proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   # generates a new object and sets its reference counter to 0
+  incTypeSize typ, size
   acquire(gch)
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
@@ -300,6 +304,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+  incTypeSize ol.typ, newsize
 
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(Cell))
@@ -414,8 +419,6 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
     if objStart != nil:
       mark(gch, objStart)
 
-include gc_common
-
 proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
   forEachStackSlot(gch, gcMark)