# # # Nim's Runtime Library # (c) Copyright 2016 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # Garbage Collector # # Refcounting + Mark&Sweep. Complex algorithms avoided. # Been there, done that, didn't work. {.push profiler:off.} const CycleIncrease = 2 # is a multiplicative increase InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow ZctThreshold = 500 # we collect garbage if the ZCT's size # reaches this threshold # this seems to be a good value withRealTime = defined(useRealtimeGC) when withRealTime and not declared(getTicks): include "system/timers" when defined(memProfiler): proc nimProfile(requestedSize: int) {.benign.} when hasThreadSupport: import sharedlist const rcIncrement = 0b1000 # so that lowest 3 bits are not touched rcBlack = 0b000 # cell is colored black; in use or free rcGray = 0b001 # possible member of a cycle rcWhite = 0b010 # member of a garbage cycle rcPurple = 0b011 # possible root of a cycle ZctFlag = 0b100 # in ZCT rcShift = 3 # shift by rcShift to get the reference counter colorMask = 0b011 type WalkOp = enum waMarkGlobal, # part of the backup/debug mark&sweep waMarkPrecise, # part of the backup/debug mark&sweep waZctDecRef, waPush #, waDebug Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} # A ref type can have a finalizer that is called before the object's # storage is freed. GcStat {.final, pure.} = object stackScans: int # number of performed stack scans (for statistics) cycleCollections: int # number of performed full collections 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 maxPause: int64 # max measured GC pause in nanoseconds GcStack {.final, pure.} = object when nimCoroutines: prev: ptr GcStack next: ptr GcStack maxStackSize: int # Used to track statistics because we can not use # GcStat.maxStackSize when multiple stacks exist. bottom: pointer when withRealTime or nimCoroutines: pos: pointer # Used with `withRealTime` only for code clarity, see GC_Step(). when withRealTime: bottomSaved: pointer GcHeap {.final, pure.} = object # this contains the zero count and # non-zero count table stack: GcStack when nimCoroutines: activeStack: ptr GcStack # current executing coroutine stack. cycleThreshold: int when useCellIds: idGenerator: int zct: CellSeq # the zero count table decStack: CellSeq # cells in the stack that are to decref again tempStack: CellSeq # temporary stack for recursion elimination recGcLock: int # prevent recursion via finalizers; no thread lock when withRealTime: maxPause: Nanos # max allowed pause in nanoseconds; active if > 0 region: MemRegion # garbage collected region stat: GcStat marked: CellSet additionalRoots: CellSeq # dummy roots for GC_ref/unref when hasThreadSupport: toDispose: SharedList[pointer] gcThreadId: int var gch {.rtlThreadVar.}: GcHeap when not defined(useNimRtl): instantiateForRegion(gch.region) template gcAssert(cond: bool, msg: string) = when defined(useGcAssert): if not cond: echo "[GCASSERT] ", msg GC_disable() writeStackTrace() #var x: ptr int #echo x[] quit 1 proc addZCT(s: var CellSeq, c: PCell) {.noinline.} = if (c.refcount and ZctFlag) == 0: c.refcount = c.refcount or ZctFlag add(s, c) proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging result = usrToCell(c).typ proc internRefcount(p: pointer): int {.exportc: "g
#
#
# Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Wrapper for the `console` object for the `JavaScript backend
## <backends.html#the-javascript-target>`_.
when not defined(js) and not defined(Nimdoc):
{.error: "This module only works on the JavaScript platform".}
import macros
type Console* {.importc.} = ref object of RootObj
proc convertToConsoleLoggable*[T](v: T): RootRef {.importcpp: "#".}
template convertToConsoleLoggable*(v: string): RootRef = cast[RootRef](cstring(v))
proc logImpl(console: Console) {.importcpp: "log", varargs.}
proc debugImpl(console: Console) {.importcpp: "debug", varargs.}
proc infoImpl(console: Console) {.importcpp: "info", varargs.}
proc errorImpl(console: Console) {.importcpp: "error", varargs.}
proc makeConsoleCall(console: NimNode, procName: NimNode, args: NimNode): NimNode =
result = newCall(procName, console)
for c in args: result.add(c)
macro log*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped =
makeConsoleCall(console, bindSym "logImpl", args)
macro debug*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped =
makeConsoleCall(console, bindSym "debugImpl", args)
macro info*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped =
makeConsoleCall(console, bindSym "infoImpl", args)
macro error*(console: Console, args: varargs[RootRef, convertToConsoleLoggable]): untyped =
makeConsoleCall(console, bindSym "errorImpl", args)
var console* {.importc, nodecl.}: Console