gc.nim 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2016 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Garbage Collector
  10. #
  11. # Refcounting + Mark&Sweep. Complex algorithms avoided.
  12. # Been there, done that, didn't work.
  13. #[
  14. A *cell* is anything that is traced by the GC
  15. (sequences, refs, strings, closures).
  16. The basic algorithm is *Deferrent Reference Counting* with cycle detection.
  17. References on the stack are not counted for better performance and easier C
  18. code generation.
  19. Each cell has a header consisting of a RC and a pointer to its type
  20. descriptor. However the program does not know about these, so they are placed at
  21. negative offsets. In the GC code the type `PCell` denotes a pointer
  22. decremented by the right offset, so that the header can be accessed easily. It
  23. is extremely important that `pointer` is not confused with a `PCell`.
  24. In Nim the compiler cannot always know if a reference
  25. is stored on the stack or not. This is caused by var parameters.
  26. Consider this example:
  27. .. code-block:: Nim
  28. proc setRef(r: var ref TNode) =
  29. new(r)
  30. proc usage =
  31. var
  32. r: ref TNode
  33. setRef(r) # here we should not update the reference counts, because
  34. # r is on the stack
  35. setRef(r.left) # here we should update the refcounts!
  36. We have to decide at runtime whether the reference is on the stack or not.
  37. The generated code looks roughly like this:
  38. .. code-block:: C
  39. void setref(TNode** ref) {
  40. unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode)))
  41. }
  42. void usage(void) {
  43. setRef(&r)
  44. setRef(&r->left)
  45. }
  46. Note that for systems with a continuous stack (which most systems have)
  47. the check whether the ref is on the stack is very cheap (only two
  48. comparisons).
  49. ]#
  50. {.push profiler:off.}
  51. const
  52. CycleIncrease = 2 # is a multiplicative increase
  53. InitialCycleThreshold = when defined(nimCycleBreaker): high(int)
  54. else: 4*1024*1024 # X MB because cycle checking is slow
  55. InitialZctThreshold = 500 # we collect garbage if the ZCT's size
  56. # reaches this threshold
  57. # this seems to be a good value
  58. withRealTime = defined(useRealtimeGC)
  59. when withRealTime and not declared(getTicks):
  60. include "system/timers"
  61. when defined(memProfiler):
  62. proc nimProfile(requestedSize: int) {.benign.}
  63. when hasThreadSupport:
  64. import sharedlist
  65. const
  66. rcIncrement = 0b1000 # so that lowest 3 bits are not touched
  67. rcBlack = 0b000 # cell is colored black; in use or free
  68. rcGray = 0b001 # possible member of a cycle
  69. rcWhite = 0b010 # member of a garbage cycle
  70. rcPurple = 0b011 # possible root of a cycle
  71. ZctFlag = 0b100 # in ZCT
  72. rcShift = 3 # shift by rcShift to get the reference counter
  73. colorMask = 0b011
  74. type
  75. WalkOp = enum
  76. waMarkGlobal, # part of the backup/debug mark&sweep
  77. waMarkPrecise, # part of the backup/debug mark&sweep
  78. waZctDecRef, waPush
  79. #, waDebug
  80. Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign, raises: [].}
  81. # A ref type can have a finalizer that is called before the object's
  82. # storage is freed.
  83. GcStat {.final, pure.} = object
  84. stackScans: int # number of performed stack scans (for statistics)
  85. cycleCollections: int # number of performed full collections
  86. maxThreshold: int # max threshold that has been set
  87. maxStackSize: int # max stack size
  88. maxStackCells: int # max stack cells in ``decStack``
  89. cycleTableSize: int # max entries in cycle table
  90. maxPause: int64 # max measured GC pause in nanoseconds
  91. GcStack {.final, pure.} = object
  92. when nimCoroutines:
  93. prev: ptr GcStack
  94. next: ptr GcStack
  95. maxStackSize: int # Used to track statistics because we can not use
  96. # GcStat.maxStackSize when multiple stacks exist.
  97. bottom: pointer
  98. when withRealTime or nimCoroutines:
  99. pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step().
  100. when withRealTime:
  101. bottomSaved: pointer
  102. GcHeap {.final, pure.} = object # this contains the zero count and
  103. # non-zero count table
  104. stack: GcStack
  105. when nimCoroutines:
  106. activeStack: ptr GcStack # current executing coroutine stack.
  107. cycleThreshold: int
  108. zctThreshold: int
  109. when useCellIds:
  110. idGenerator: int
  111. zct: CellSeq # the zero count table
  112. decStack: CellSeq # cells in the stack that are to decref again
  113. tempStack: CellSeq # temporary stack for recursion elimination
  114. recGcLock: int # prevent recursion via finalizers; no thread lock
  115. when withRealTime:
  116. maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
  117. region: MemRegion # garbage collected region
  118. stat: GcStat
  119. marked: CellSet
  120. additionalRoots: CellSeq # dummy roots for GC_ref/unref
  121. when hasThreadSupport:
  122. toDispose: SharedList[pointer]
  123. gcThreadId: int
  124. var
  125. gch {.rtlThreadVar.}: GcHeap
  126. when not defined(useNimRtl):
  127. instantiateForRegion(gch.region)
  128. template gcAssert(cond: bool, msg: string) =
  129. when defined(useGcAssert):
  130. if not cond:
  131. cstderr.rawWrite "[GCASSERT] "
  132. cstderr.rawWrite msg
  133. when defined(logGC):
  134. cstderr.rawWrite "[GCASSERT] statistics:\L"
  135. cstderr.rawWrite GC_getStatistics()
  136. GC_disable()
  137. writeStackTrace()
  138. #var x: ptr int
  139. #echo x[]
  140. quit 1
  141. proc addZCT(s: var CellSeq, c: PCell) {.noinline.} =
  142. if (c.refcount and ZctFlag) == 0:
  143. c.refcount = c.refcount or ZctFlag
  144. add(s, c)
  145. proc cellToUsr(cell: PCell): pointer {.inline.} =
  146. # convert object (=pointer to refcount) to pointer to userdata
  147. result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell)))
  148. proc usrToCell(usr: pointer): PCell {.inline.} =
  149. # convert pointer to userdata to object (=pointer to refcount)
  150. result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell)))
  151. proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
  152. # used for code generation concerning debugging
  153. result = usrToCell(c).typ
  154. proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
  155. result = usrToCell(p).refcount shr rcShift
  156. # this that has to equals zero, otherwise we have to round up UnitsPerPage:
  157. when BitsPerPage mod (sizeof(int)*8) != 0:
  158. {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
  159. template color(c): untyped = c.refCount and colorMask
  160. template setColor(c, col) =
  161. when col == rcBlack:
  162. c.refcount = c.refcount and not colorMask
  163. else:
  164. c.refcount = c.refcount and not colorMask or col
  165. when defined(logGC):
  166. proc writeCell(msg: cstring, c: PCell) =
  167. var kind = -1
  168. var typName: cstring = "nil"
  169. if c.typ != nil:
  170. kind = ord(c.typ.kind)
  171. when defined(nimTypeNames):
  172. if not c.typ.name.isNil:
  173. typName = c.typ.name
  174. when leakDetector:
  175. c_printf("[GC] %s: %p %d %s rc=%ld from %s(%ld)\n",
  176. msg, c, kind, typName, c.refcount shr rcShift, c.filename, c.line)
  177. else:
  178. c_printf("[GC] %s: %p %d %s rc=%ld; thread=%ld\n",
  179. msg, c, kind, typName, c.refcount shr rcShift, gch.gcThreadId)
  180. template logCell(msg: cstring, c: PCell) =
  181. when defined(logGC):
  182. writeCell(msg, c)
  183. template gcTrace(cell, state: untyped) =
  184. when traceGC: traceCell(cell, state)
  185. # forward declarations:
  186. proc collectCT(gch: var GcHeap) {.benign, raises: [].}
  187. proc isOnStack(p: pointer): bool {.noinline, benign, raises: [].}
  188. proc forAllChildren(cell: PCell, op: WalkOp) {.benign, raises: [].}
  189. proc doOperation(p: pointer, op: WalkOp) {.benign, raises: [].}
  190. proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign, raises: [].}
  191. # we need the prototype here for debugging purposes
  192. proc incRef(c: PCell) {.inline.} =
  193. gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
  194. c.refcount = c.refcount +% rcIncrement
  195. # and not colorMask
  196. logCell("incRef", c)
  197. proc nimGCref(p: pointer) {.compilerproc.} =
  198. # we keep it from being collected by pretending it's not even allocated:
  199. let c = usrToCell(p)
  200. add(gch.additionalRoots, c)
  201. incRef(c)
  202. proc rtlAddZCT(c: PCell) {.rtl, inl.} =
  203. # we MUST access gch as a global here, because this crosses DLL boundaries!
  204. addZCT(gch.zct, c)
  205. proc decRef(c: PCell) {.inline.} =
  206. gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
  207. gcAssert(c.refcount >=% rcIncrement, "decRef")
  208. c.refcount = c.refcount -% rcIncrement
  209. if c.refcount <% rcIncrement:
  210. rtlAddZCT(c)
  211. logCell("decRef", c)
  212. proc nimGCunref(p: pointer) {.compilerproc.} =
  213. let cell = usrToCell(p)
  214. var L = gch.additionalRoots.len-1
  215. var i = L
  216. let d = gch.additionalRoots.d
  217. while i >= 0:
  218. if d[i] == cell:
  219. d[i] = d[L]
  220. dec gch.additionalRoots.len
  221. break
  222. dec(i)
  223. decRef(usrToCell(p))
  224. include gc_common
  225. template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
  226. when false:
  227. for i in 0..gch.decStack.len-1:
  228. if gch.decStack.d[i] == c:
  229. sysAssert(false, msg)
  230. proc nimGCunrefNoCycle(p: pointer) {.compilerproc, inline.} =
  231. sysAssert(allocInv(gch.region), "begin nimGCunrefNoCycle")
  232. decRef(usrToCell(p))
  233. sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
  234. proc nimGCunrefRC1(p: pointer) {.compilerproc, inline.} =
  235. decRef(usrToCell(p))
  236. proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
  237. # the code generator calls this proc!
  238. gcAssert(not isOnStack(dest), "asgnRef")
  239. # BUGFIX: first incRef then decRef!
  240. if src != nil: incRef(usrToCell(src))
  241. if dest[] != nil: decRef(usrToCell(dest[]))
  242. dest[] = src
  243. proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
  244. deprecated: "old compiler compat".} = asgnRef(dest, src)
  245. proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc.} =
  246. # unsureAsgnRef updates the reference counters only if dest is not on the
  247. # stack. It is used by the code generator if it cannot decide whether a
  248. # reference is in the stack or not (this can happen for var parameters).
  249. if not isOnStack(dest):
  250. if src != nil: incRef(usrToCell(src))
  251. # XXX finally use assembler for the stack checking instead!
  252. # the test for '!= nil' is correct, but I got tired of the segfaults
  253. # resulting from the crappy stack checking:
  254. if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
  255. else:
  256. # can't be an interior pointer if it's a stack location!
  257. gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
  258. "stack loc AND interior pointer")
  259. dest[] = src
  260. proc initGC() =
  261. when not defined(useNimRtl):
  262. when traceGC:
  263. for i in low(CellState)..high(CellState): init(states[i])
  264. gch.cycleThreshold = InitialCycleThreshold
  265. gch.zctThreshold = InitialZctThreshold
  266. gch.stat.stackScans = 0
  267. gch.stat.cycleCollections = 0
  268. gch.stat.maxThreshold = 0
  269. gch.stat.maxStackSize = 0
  270. gch.stat.maxStackCells = 0
  271. gch.stat.cycleTableSize = 0
  272. # init the rt
  273. init(gch.zct)
  274. init(gch.tempStack)
  275. init(gch.decStack)
  276. init(gch.marked)
  277. init(gch.additionalRoots)
  278. when hasThreadSupport:
  279. init(gch.toDispose)
  280. gch.gcThreadId = atomicInc(gHeapidGenerator) - 1
  281. gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID")
  282. proc cellsetReset(s: var CellSet) =
  283. deinit(s)
  284. init(s)
  285. {.push stacktrace:off.}
  286. proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
  287. var d = cast[ByteAddress](dest)
  288. case n.kind
  289. of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
  290. of nkList:
  291. for i in 0..n.len-1:
  292. # inlined for speed
  293. if n.sons[i].kind == nkSlot:
  294. if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
  295. doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
  296. else:
  297. forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
  298. n.sons[i].typ, op)
  299. else:
  300. forAllSlotsAux(dest, n.sons[i], op)
  301. of nkCase:
  302. var m = selectBranch(dest, n)
  303. if m != nil: forAllSlotsAux(dest, m, op)
  304. of nkNone: sysAssert(false, "forAllSlotsAux")
  305. proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
  306. var d = cast[ByteAddress](dest)
  307. if dest == nil: return # nothing to do
  308. if ntfNoRefs notin mt.flags:
  309. case mt.kind
  310. of tyRef, tyString, tySequence: # leaf:
  311. doOperation(cast[PPointer](d)[], op)
  312. of tyObject, tyTuple:
  313. forAllSlotsAux(dest, mt.node, op)
  314. of tyArray, tyArrayConstr, tyOpenArray:
  315. for i in 0..(mt.size div mt.base.size)-1:
  316. forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
  317. else: discard
  318. proc forAllChildren(cell: PCell, op: WalkOp) =
  319. gcAssert(cell != nil, "forAllChildren: cell is nil")
  320. gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: pointer not part of the heap")
  321. gcAssert(cell.typ != nil, "forAllChildren: cell.typ is nil")
  322. gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: unknown GC'ed type"
  323. let marker = cell.typ.marker
  324. if marker != nil:
  325. marker(cellToUsr(cell), op.int)
  326. else:
  327. case cell.typ.kind
  328. of tyRef: # common case
  329. forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
  330. of tySequence:
  331. var d = cast[ByteAddress](cellToUsr(cell))
  332. var s = cast[PGenericSeq](d)
  333. if s != nil:
  334. for i in 0..s.len-1:
  335. forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op)
  336. else: discard
  337. proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
  338. # we check the last 8 entries (cache line) for a slot that could be reused.
  339. # In 63% of all cases we succeed here! But we have to optimize the heck
  340. # out of this small linear search so that ``newObj`` is not slowed down.
  341. #
  342. # Slots to try cache hit
  343. # 1 32%
  344. # 4 59%
  345. # 8 63%
  346. # 16 66%
  347. # all slots 68%
  348. var L = gch.zct.len
  349. var d = gch.zct.d
  350. when true:
  351. # loop unrolled for performance:
  352. template replaceZctEntry(i: untyped) =
  353. c = d[i]
  354. if c.refcount >=% rcIncrement:
  355. c.refcount = c.refcount and not ZctFlag
  356. d[i] = res
  357. return
  358. if L > 8:
  359. var c: PCell
  360. replaceZctEntry(L-1)
  361. replaceZctEntry(L-2)
  362. replaceZctEntry(L-3)
  363. replaceZctEntry(L-4)
  364. replaceZctEntry(L-5)
  365. replaceZctEntry(L-6)
  366. replaceZctEntry(L-7)
  367. replaceZctEntry(L-8)
  368. add(gch.zct, res)
  369. else:
  370. d[L] = res
  371. inc(gch.zct.len)
  372. else:
  373. for i in countdown(L-1, max(0, L-8)):
  374. var c = d[i]
  375. if c.refcount >=% rcIncrement:
  376. c.refcount = c.refcount and not ZctFlag
  377. d[i] = res
  378. return
  379. add(gch.zct, res)
  380. {.push stackTrace: off, profiler:off.}
  381. proc gcInvariant*() =
  382. sysAssert(allocInv(gch.region), "injected")
  383. when declared(markForDebug):
  384. markForDebug(gch)
  385. {.pop.}
  386. template setFrameInfo(c: PCell) =
  387. when leakDetector:
  388. if framePtr != nil and framePtr.prev != nil:
  389. c.filename = framePtr.prev.filename
  390. c.line = framePtr.prev.line
  391. else:
  392. c.filename = nil
  393. c.line = 0
  394. proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
  395. # generates a new object and sets its reference counter to 0
  396. incTypeSize typ, size
  397. sysAssert(allocInv(gch.region), "rawNewObj begin")
  398. gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
  399. collectCT(gch)
  400. var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
  401. #gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small"
  402. gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
  403. # now it is buffered in the ZCT
  404. res.typ = typ
  405. setFrameInfo(res)
  406. # refcount is zero, color is black, but mark it to be in the ZCT
  407. res.refcount = ZctFlag
  408. sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
  409. # its refcount is zero, so add it to the ZCT:
  410. addNewObjToZCT(res, gch)
  411. logCell("new cell", res)
  412. track("rawNewObj", res, size)
  413. gcTrace(res, csAllocated)
  414. when useCellIds:
  415. inc gch.idGenerator
  416. res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
  417. result = cellToUsr(res)
  418. sysAssert(allocInv(gch.region), "rawNewObj end")
  419. {.pop.} # .stackTrace off
  420. {.pop.} # .profiler off
  421. proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
  422. result = rawNewObj(typ, size, gch)
  423. when defined(memProfiler): nimProfile(size)
  424. proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
  425. result = rawNewObj(typ, size, gch)
  426. zeroMem(result, size)
  427. when defined(memProfiler): nimProfile(size)
  428. {.push overflowChecks: on.}
  429. proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
  430. # `newObj` already uses locks, so no need for them here.
  431. let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
  432. result = newObj(typ, size)
  433. cast[PGenericSeq](result).len = len
  434. cast[PGenericSeq](result).reserved = len
  435. when defined(memProfiler): nimProfile(size)
  436. {.pop.}
  437. proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
  438. # generates a new object and sets its reference counter to 1
  439. incTypeSize typ, size
  440. sysAssert(allocInv(gch.region), "newObjRC1 begin")
  441. gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
  442. collectCT(gch)
  443. sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
  444. var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
  445. sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
  446. sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
  447. # now it is buffered in the ZCT
  448. res.typ = typ
  449. setFrameInfo(res)
  450. res.refcount = rcIncrement # refcount is 1
  451. sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
  452. logCell("new cell", res)
  453. track("newObjRC1", res, size)
  454. gcTrace(res, csAllocated)
  455. when useCellIds:
  456. inc gch.idGenerator
  457. res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
  458. result = cellToUsr(res)
  459. zeroMem(result, size)
  460. sysAssert(allocInv(gch.region), "newObjRC1 end")
  461. when defined(memProfiler): nimProfile(size)
  462. {.push overflowChecks: on.}
  463. proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
  464. let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
  465. result = newObjRC1(typ, size)
  466. cast[PGenericSeq](result).len = len
  467. cast[PGenericSeq](result).reserved = len
  468. when defined(memProfiler): nimProfile(size)
  469. {.pop.}
  470. proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
  471. collectCT(gch)
  472. var ol = usrToCell(old)
  473. sysAssert(ol.typ != nil, "growObj: 1")
  474. gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
  475. sysAssert(allocInv(gch.region), "growObj begin")
  476. var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
  477. var elemSize,elemAlign = 1
  478. if ol.typ.kind != tyString:
  479. elemSize = ol.typ.base.size
  480. elemAlign = ol.typ.base.align
  481. incTypeSize ol.typ, newsize
  482. var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize
  483. copyMem(res, ol, oldsize + sizeof(Cell))
  484. zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)),
  485. newsize-oldsize)
  486. sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
  487. # This can be wrong for intermediate temps that are nevertheless on the
  488. # heap because of lambda lifting:
  489. #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
  490. logCell("growObj old cell", ol)
  491. logCell("growObj new cell", res)
  492. gcTrace(ol, csZctFreed)
  493. gcTrace(res, csAllocated)
  494. track("growObj old", ol, 0)
  495. track("growObj new", res, newsize)
  496. # since we steal the old seq's contents, we set the old length to 0.
  497. cast[PGenericSeq](old).len = 0
  498. when useCellIds:
  499. inc gch.idGenerator
  500. res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
  501. result = cellToUsr(res)
  502. sysAssert(allocInv(gch.region), "growObj end")
  503. when defined(memProfiler): nimProfile(newsize-oldsize)
  504. proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
  505. result = growObj(old, newsize, gch)
  506. {.push profiler:off, stackTrace:off.}
  507. # ---------------- cycle collector -------------------------------------------
  508. proc freeCyclicCell(gch: var GcHeap, c: PCell) =
  509. prepareDealloc(c)
  510. gcTrace(c, csCycFreed)
  511. track("cycle collector dealloc cell", c, 0)
  512. logCell("cycle collector dealloc cell", c)
  513. when reallyDealloc:
  514. sysAssert(allocInv(gch.region), "free cyclic cell")
  515. beforeDealloc(gch, c, "freeCyclicCell: stack trash")
  516. rawDealloc(gch.region, c)
  517. else:
  518. gcAssert(c.typ != nil, "freeCyclicCell")
  519. zeroMem(c, sizeof(Cell))
  520. proc sweep(gch: var GcHeap) =
  521. for x in allObjects(gch.region):
  522. if isCell(x):
  523. # cast to PCell is correct here:
  524. var c = cast[PCell](x)
  525. if c notin gch.marked: freeCyclicCell(gch, c)
  526. proc markS(gch: var GcHeap, c: PCell) =
  527. gcAssert isAllocatedPtr(gch.region, c), "markS: foreign heap root detected A!"
  528. incl(gch.marked, c)
  529. gcAssert gch.tempStack.len == 0, "stack not empty!"
  530. forAllChildren(c, waMarkPrecise)
  531. while gch.tempStack.len > 0:
  532. dec gch.tempStack.len
  533. var d = gch.tempStack.d[gch.tempStack.len]
  534. gcAssert isAllocatedPtr(gch.region, d), "markS: foreign heap root detected B!"
  535. if not containsOrIncl(gch.marked, d):
  536. forAllChildren(d, waMarkPrecise)
  537. proc markGlobals(gch: var GcHeap) {.raises: [].} =
  538. if gch.gcThreadId == 0:
  539. for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
  540. for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
  541. let d = gch.additionalRoots.d
  542. for i in 0 .. gch.additionalRoots.len-1: markS(gch, d[i])
  543. when logGC:
  544. var
  545. cycleCheckA: array[100, PCell]
  546. cycleCheckALen = 0
  547. proc alreadySeen(c: PCell): bool =
  548. for i in 0 .. cycleCheckALen-1:
  549. if cycleCheckA[i] == c: return true
  550. if cycleCheckALen == len(cycleCheckA):
  551. gcAssert(false, "cycle detection overflow")
  552. quit 1
  553. cycleCheckA[cycleCheckALen] = c
  554. inc cycleCheckALen
  555. proc debugGraph(s: PCell) =
  556. if alreadySeen(s):
  557. writeCell("child cell (already seen) ", s)
  558. else:
  559. writeCell("cell {", s)
  560. forAllChildren(s, waDebug)
  561. c_printf("}\n")
  562. proc doOperation(p: pointer, op: WalkOp) =
  563. if p == nil: return
  564. var c: PCell = usrToCell(p)
  565. gcAssert(c != nil, "doOperation: 1")
  566. # the 'case' should be faster than function pointers because of easy
  567. # prediction:
  568. case op
  569. of waZctDecRef:
  570. #if not isAllocatedPtr(gch.region, c):
  571. # c_printf("[GC] decref bug: %p", c)
  572. gcAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef")
  573. gcAssert(c.refcount >=% rcIncrement, "doOperation 2")
  574. logCell("decref (from doOperation)", c)
  575. track("waZctDecref", p, 0)
  576. decRef(c)
  577. of waPush:
  578. add(gch.tempStack, c)
  579. of waMarkGlobal:
  580. markS(gch, c)
  581. of waMarkPrecise:
  582. add(gch.tempStack, c)
  583. #of waDebug: debugGraph(c)
  584. proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
  585. doOperation(d, WalkOp(op))
  586. proc collectZCT(gch: var GcHeap): bool {.benign, raises: [].}
  587. proc collectCycles(gch: var GcHeap) {.raises: [].} =
  588. when hasThreadSupport:
  589. for c in gch.toDispose:
  590. nimGCunref(c)
  591. # ensure the ZCT 'color' is not used:
  592. while gch.zct.len > 0: discard collectZCT(gch)
  593. cellsetReset(gch.marked)
  594. var d = gch.decStack.d
  595. for i in 0..gch.decStack.len-1:
  596. sysAssert isAllocatedPtr(gch.region, d[i]), "collectCycles"
  597. markS(gch, d[i])
  598. markGlobals(gch)
  599. sweep(gch)
  600. proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
  601. # the addresses are not as cells on the stack, so turn them to cells:
  602. sysAssert(allocInv(gch.region), "gcMark begin")
  603. var c = cast[ByteAddress](p)
  604. if c >% PageSize:
  605. # fast check: does it look like a cell?
  606. var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
  607. if objStart != nil:
  608. # mark the cell:
  609. incRef(objStart)
  610. add(gch.decStack, objStart)
  611. when false:
  612. let cell = usrToCell(p)
  613. if isAllocatedPtr(gch.region, cell):
  614. sysAssert false, "allocated pointer but not interior?"
  615. # mark the cell:
  616. incRef(cell)
  617. add(gch.decStack, cell)
  618. sysAssert(allocInv(gch.region), "gcMark end")
  619. #[
  620. This method is conditionally marked with an attribute so that it gets ignored by the LLVM ASAN
  621. (Address SANitizer) intrumentation as it will raise false errors due to the implementation of
  622. garbage collection that is used by Nim. For more information, please see the documentation of
  623. `CLANG_NO_SANITIZE_ADDRESS` in `lib/nimbase.h`.
  624. ]#
  625. proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl,
  626. codegenDecl: "CLANG_NO_SANITIZE_ADDRESS N_LIB_PRIVATE $# $#$#".} =
  627. forEachStackSlot(gch, gcMark)
  628. proc collectZCT(gch: var GcHeap): bool =
  629. # Note: Freeing may add child objects to the ZCT! So essentially we do
  630. # deep freeing, which is bad for incremental operation. In order to
  631. # avoid a deep stack, we move objects to keep the ZCT small.
  632. # This is performance critical!
  633. const workPackage = 100
  634. var L = addr(gch.zct.len)
  635. when withRealTime:
  636. var steps = workPackage
  637. var t0: Ticks
  638. if gch.maxPause > 0: t0 = getticks()
  639. while L[] > 0:
  640. var c = gch.zct.d[0]
  641. sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
  642. # remove from ZCT:
  643. gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
  644. c.refcount = c.refcount and not ZctFlag
  645. gch.zct.d[0] = gch.zct.d[L[] - 1]
  646. dec(L[])
  647. when withRealTime: dec steps
  648. if c.refcount <% rcIncrement:
  649. # It may have a RC > 0, if it is in the hardware stack or
  650. # it has not been removed yet from the ZCT. This is because
  651. # ``incref`` does not bother to remove the cell from the ZCT
  652. # as this might be too slow.
  653. # In any case, it should be removed from the ZCT. But not
  654. # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
  655. logCell("zct dealloc cell", c)
  656. track("zct dealloc cell", c, 0)
  657. gcTrace(c, csZctFreed)
  658. # We are about to free the object, call the finalizer BEFORE its
  659. # children are deleted as well, because otherwise the finalizer may
  660. # access invalid memory. This is done by prepareDealloc():
  661. prepareDealloc(c)
  662. forAllChildren(c, waZctDecRef)
  663. when reallyDealloc:
  664. sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
  665. beforeDealloc(gch, c, "collectZCT: stack trash")
  666. rawDealloc(gch.region, c)
  667. else:
  668. sysAssert(c.typ != nil, "collectZCT 2")
  669. zeroMem(c, sizeof(Cell))
  670. when withRealTime:
  671. if steps == 0:
  672. steps = workPackage
  673. if gch.maxPause > 0:
  674. let duration = getticks() - t0
  675. # the GC's measuring is not accurate and needs some cleanup actions
  676. # (stack unmarking), so subtract some short amount of time in
  677. # order to miss deadlines less often:
  678. if duration >= gch.maxPause - 50_000:
  679. return false
  680. result = true
  681. proc unmarkStackAndRegisters(gch: var GcHeap) =
  682. var d = gch.decStack.d
  683. for i in 0..gch.decStack.len-1:
  684. sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
  685. decRef(d[i])
  686. gch.decStack.len = 0
  687. proc collectCTBody(gch: var GcHeap) {.raises: [].} =
  688. when withRealTime:
  689. let t0 = getticks()
  690. sysAssert(allocInv(gch.region), "collectCT: begin")
  691. when nimCoroutines:
  692. for stack in gch.stack.items():
  693. gch.stat.maxStackSize = max(gch.stat.maxStackSize, stack.stackSize())
  694. else:
  695. gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
  696. sysAssert(gch.decStack.len == 0, "collectCT")
  697. prepareForInteriorPointerChecking(gch.region)
  698. markStackAndRegisters(gch)
  699. gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
  700. inc(gch.stat.stackScans)
  701. if collectZCT(gch):
  702. when cycleGC:
  703. if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
  704. collectCycles(gch)
  705. #discard collectZCT(gch)
  706. inc(gch.stat.cycleCollections)
  707. gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
  708. CycleIncrease)
  709. gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
  710. unmarkStackAndRegisters(gch)
  711. sysAssert(allocInv(gch.region), "collectCT: end")
  712. when withRealTime:
  713. let duration = getticks() - t0
  714. gch.stat.maxPause = max(gch.stat.maxPause, duration)
  715. when defined(reportMissedDeadlines):
  716. if gch.maxPause > 0 and duration > gch.maxPause:
  717. c_printf("[GC] missed deadline: %ld\n", duration)
  718. proc collectCT(gch: var GcHeap) =
  719. if (gch.zct.len >= gch.zctThreshold or (cycleGC and
  720. getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
  721. gch.recGcLock == 0:
  722. when false:
  723. prepareForInteriorPointerChecking(gch.region)
  724. cellsetReset(gch.marked)
  725. markForDebug(gch)
  726. collectCTBody(gch)
  727. gch.zctThreshold = max(InitialZctThreshold, gch.zct.len * CycleIncrease)
  728. proc GC_collectZct*() =
  729. ## Collect the ZCT (zero count table). Unstable, experimental API for
  730. ## testing purposes.
  731. ## DO NOT USE!
  732. collectCTBody(gch)
  733. when withRealTime:
  734. proc toNano(x: int): Nanos {.inline.} =
  735. result = x * 1000
  736. proc GC_setMaxPause*(MaxPauseInUs: int) =
  737. gch.maxPause = MaxPauseInUs.toNano
  738. proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
  739. gch.maxPause = us.toNano
  740. if (gch.zct.len >= gch.zctThreshold or (cycleGC and
  741. getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
  742. strongAdvice:
  743. collectCTBody(gch)
  744. gch.zctThreshold = max(InitialZctThreshold, gch.zct.len * CycleIncrease)
  745. proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
  746. if stackSize >= 0:
  747. var stackTop {.volatile.}: pointer
  748. gch.getActiveStack().pos = addr(stackTop)
  749. for stack in gch.stack.items():
  750. stack.bottomSaved = stack.bottom
  751. when stackIncreases:
  752. stack.bottom = cast[pointer](
  753. cast[ByteAddress](stack.pos) - sizeof(pointer) * 6 - stackSize)
  754. else:
  755. stack.bottom = cast[pointer](
  756. cast[ByteAddress](stack.pos) + sizeof(pointer) * 6 + stackSize)
  757. GC_step(gch, us, strongAdvice)
  758. if stackSize >= 0:
  759. for stack in gch.stack.items():
  760. stack.bottom = stack.bottomSaved
  761. when not defined(useNimRtl):
  762. proc GC_disable() =
  763. inc(gch.recGcLock)
  764. proc GC_enable() =
  765. when defined(nimDoesntTrackDefects):
  766. if gch.recGcLock <= 0:
  767. raise newException(AssertionDefect,
  768. "API usage error: GC_enable called but GC is already enabled")
  769. dec(gch.recGcLock)
  770. proc GC_setStrategy(strategy: GC_Strategy) =
  771. discard
  772. proc GC_enableMarkAndSweep() =
  773. gch.cycleThreshold = InitialCycleThreshold
  774. proc GC_disableMarkAndSweep() =
  775. gch.cycleThreshold = high(typeof(gch.cycleThreshold))-1
  776. # set to the max value to suppress the cycle detector
  777. proc GC_fullCollect() =
  778. var oldThreshold = gch.cycleThreshold
  779. gch.cycleThreshold = 0 # forces cycle collection
  780. collectCT(gch)
  781. gch.cycleThreshold = oldThreshold
  782. proc GC_getStatistics(): string =
  783. result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
  784. "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
  785. "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
  786. "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
  787. "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
  788. "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
  789. "[GC] zct capacity: " & $gch.zct.cap & "\n" &
  790. "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
  791. "[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000) & "\n"
  792. when nimCoroutines:
  793. result.add "[GC] number of stacks: " & $gch.stack.len & "\n"
  794. for stack in items(gch.stack):
  795. result.add "[GC] stack " & stack.bottom.repr & "[GC] max stack size " & cast[pointer](stack.maxStackSize).repr & "\n"
  796. else:
  797. # this caused memory leaks, see #10488 ; find a way without `repr`
  798. # maybe using a local copy of strutils.toHex or snprintf
  799. when defined(logGC):
  800. result.add "[GC] stack bottom: " & gch.stack.bottom.repr
  801. result.add "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
  802. {.pop.} # profiler: off, stackTrace: off