diff options
-rw-r--r-- | compiler/destroyer.nim | 3 | ||||
-rw-r--r-- | lib/core/allocators.nim | 35 | ||||
-rw-r--r-- | lib/core/refs.nim | 97 | ||||
-rw-r--r-- | lib/core/seqs.nim | 117 | ||||
-rw-r--r-- | lib/core/strs.nim | 111 | ||||
-rw-r--r-- | lib/core/typelayouts.nim | 19 |
6 files changed, 381 insertions, 1 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index caa18af92..0fdeceba0 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -296,7 +296,8 @@ proc p(n: PNode; c: var Con): PNode = recurse(n, result) proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = - echo "injecting into ", n + when defined(nimDebugDestroys): + echo "injecting into ", n var c: Con c.owner = owner c.tmp = newSym(skTemp, getIdent":d", owner, n.info) diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim new file mode 100644 index 000000000..d6608a203 --- /dev/null +++ b/lib/core/allocators.nim @@ -0,0 +1,35 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +type + Allocator* {.inheritable.} = ptr object + alloc*: proc (a: Allocator; size: int; alignment = 8): pointer {.nimcall.} + dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.} + realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.} + +var + currentAllocator {.threadvar.}: Allocator + +proc getCurrentAllocator*(): Allocator = + result = currentAllocator + +proc setCurrentAllocator*(a: Allocator) = + currentAllocator = a + +proc alloc*(size: int): pointer = + let a = getCurrentAllocator() + result = a.alloc(a, size) + +proc dealloc*(p: pointer; size: int) = + let a = getCurrentAllocator() + a.dealloc(a, size) + +proc realloc*(p: pointer; oldSize, newSize: int): pointer = + let a = getCurrentAllocator() + result = a.realloc(a, oldSize, newSize) diff --git a/lib/core/refs.nim b/lib/core/refs.nim new file mode 100644 index 000000000..e1575b68c --- /dev/null +++ b/lib/core/refs.nim @@ -0,0 +1,97 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Default ref implementation used by Nim's core. + +# We cannot use the allocator interface here as we require a heap walker to +# exist. Thus we import 'alloc' directly here to get our own heap that is +# all under the GC's control and can use the ``allObjects`` iterator which +# is crucial for the "sweep" phase. +import typelayouts, alloc + +type + TracingGc = ptr object of Allocator + visit*: proc (fieldAddr: ptr pointer; a: Allocator) {.nimcall.} + + GcColor = enum + white = 0, black = 1, grey = 2 ## to flip the meaning of white/black + ## perform (1 - col) + + GcHeader = object + t: ptr TypeLayout + color: GcColor + Cell = ptr GcHeader + + GcFrame {.core.} = object + prev: ptr GcFrame + marker: proc (self: GcFrame; a: Allocator) + + Phase = enum + None, Marking, Sweeping + + GcHeap = object + r: MemRegion + phase: Phase + currBlack, currWhite: GcColor + greyStack: seq[Cell] + +var + gch {.threadvar.}: GcHeap + +proc `=trace`[T](a: ref T) = + if not marked(a): + mark(a) + `=trace`(a[]) + +template usrToCell(p: pointer): Cell = + +template cellToUsr(cell: Cell): pointer = + cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(GcHeader))) + +template usrToCell(usr: pointer): Cell = + cast[Cell](cast[ByteAddress](usr)-%ByteAddress(sizeof(GcHeader))) + +template markGrey(x: Cell) = + if x.color == gch.currWhite and phase == Marking: + x.color = grey + add(gch.greyStack, x) + +proc `=`[T](dest: var ref T; src: ref T) = + ## full write barrier implementation. + if src != nil: + let s = usrToCell(src) + markGrey(s) + system.`=`(dest, src) + +proc linkGcFrame(f: ptr GcFrame) {.core.} +proc unlinkGcFrame() {.core.} + +proc setGcFrame(f: ptr GcFrame) {.core.} + +proc registerGlobal(p: pointer; t: ptr TypeLayout) {.core.} +proc unregisterGlobal(p: pointer; t: ptr TypeLayout) {.core.} + +proc registerThreadvar(p: pointer; t: ptr TypeLayout) {.core.} +proc unregisterThreadvar(p: pointer; t: ptr TypeLayout) {.core.} + +proc newImpl(t: ptr TypeLayout): pointer = + let r = cast[Cell](rawAlloc(t.size + sizeof(GcHeader))) + r.typ = t + result = r +! sizeof(GcHeader) + +template new*[T](x: var ref T) = + x = newImpl(getTypeLayout(x)) + + +when false: + # implement these if your GC requires them: + proc writeBarrierLocal() {.core.} + proc writeBarrierGlobal() {.core.} + + proc writeBarrierGeneric() {.core.} diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim new file mode 100644 index 000000000..6be95a3bc --- /dev/null +++ b/lib/core/seqs.nim @@ -0,0 +1,117 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import allocators + +## Default seq implementation used by Nim's core. +type + seq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + +template frees(s) = dealloc(s.data, s.cap * sizeof(T)) + +# XXX make code memory safe for overflows in '*' +proc nimSeqLiteral[T](x: openArray[T]): seq[T] {.core.} = + seq[T](len: x.len, cap: x.len, data: x) + +when defined(nimHasTrace): + proc `=trace`[T](s: seq[T]; a: Allocator) = + for i in 0 ..< s.len: `=trace`(s.data[i], a) + +proc `=destroy`[T](x: var seq[T]) = + if x.data != nil: + when not supportsCopyMem(T): + for i in 0..<x.len: `=destroy`(x[i]) + frees(x) + x.data = nil + x.len = 0 + x.cap = 0 + +proc `=`[T](a: var seq[T]; b: seq[T]) = + if a.data == b.data: return + if a.data != nil: + frees(a) + a.data = nil + a.len = b.len + a.cap = b.cap + if b.data != nil: + a.data = cast[type(a.data)](alloc(a.cap * sizeof(T))) + when supportsCopyMem(T): + copyMem(a.data, b.data, a.cap * sizeof(T)) + else: + for i in 0..<a.len: + a.data[i] = b.data[i] + +proc `=sink`[T](a: var seq[T]; b: seq[T]) = + if a.data != nil and a.data != b.data: + frees(a) + a.len = b.len + a.cap = b.cap + a.data = b.data + +proc resize[T](s: var seq[T]) = + let old = s.cap + if old == 0: s.cap = 8 + else: s.cap = (s.cap * 3) shr 1 + s.data = cast[type(s.data)](realloc(s.data, old * sizeof(T), s.cap * sizeof(T))) + +proc reserveSlot[T](x: var seq[T]): ptr T = + if x.len >= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + +template add*[T](x: var seq[T]; y: T) = + reserveSlot(x)[] = y + +proc shrink*[T](x: var seq[T]; newLen: int) = + assert newLen <= x.len + assert newLen >= 0 + when not supportsCopyMem(T): + for i in countdown(x.len - 1, newLen - 1): + `=destroy`(x.data[i]) + x.len = newLen + +proc grow*[T](x: var seq[T]; newLen: int; value: T) = + if newLen <= x.len: return + assert newLen >= 0 + if x.cap == 0: x.cap = newLen + else: x.cap = max(newLen, (x.cap * 3) shr 1) + x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) + for i in x.len..<newLen: + x.data[i] = value + x.len = newLen + +template default[T](t: typedesc[T]): T = + var v: T + v + +proc setLen*[T](x: var seq[T]; newLen: int) {.deprecated.} = + if newlen < x.len: shrink(x, newLen) + else: grow(x, newLen, default(T)) + +template `[]`*[T](x: seq[T]; i: Natural): T = + assert i < x.len + x.data[i] + +template `[]=`*[T](x: seq[T]; i: Natural; y: T) = + assert i < x.len + x.data[i] = y + +proc `@`*[T](elems: openArray[T]): seq[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + when supportsCopyMem(T): + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) + else: + for i in 0..<result.len: + result.data[i] = elems[i] + +proc len*[T](x: seq[T]): int {.inline.} = x.len diff --git a/lib/core/strs.nim b/lib/core/strs.nim new file mode 100644 index 000000000..1958f4974 --- /dev/null +++ b/lib/core/strs.nim @@ -0,0 +1,111 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Default string implementation used by Nim's core. + +import allocators + +type + string {.core.} = object + len, cap: int + data: ptr UncheckedArray[char] + +proc nimStringLiteral(x: cstring; len: int): string {.core.} = + string(len: len, cap: len, data: x) + +template frees(s) = dealloc(s.data, s.cap + 1) + +proc `=destroy`(s: var string) = + if s.data != nil: + frees(s) + s.data = nil + s.len = 0 + s.cap = 0 + +proc `=sink`(a: var string, b: string) = + # we hope this is optimized away for not yet alive objects: + if a.data != nil and a.data != b.data: + frees(a) + a.len = b.len + a.cap = b.cap + a.data = b.data + +proc `=`(a: var string; b: string) = + if a.data != nil and a.data != b.data: + frees(a) + a.data = nil + a.len = b.len + a.cap = b.cap + if b.data != nil: + a.data = cast[type(a.data)](alloc(a.cap + 1)) + copyMem(a.data, b.data, a.cap+1) + +proc resize(s: var string) = + let old = s.cap + if old == 0: s.cap = 8 + else: s.cap = (s.cap * 3) shr 1 + s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1)) + +proc add*(s: var string; c: char) = + if s.len >= s.cap: resize(s) + s.data[s.len] = c + s.data[s.len+1] = '\0' + inc s.len + +proc ensure(s: var string; newLen: int) = + let old = s.cap + if newLen >= old: + s.cap = max((old * 3) shr 1, newLen) + if s.cap > 0: + s.data = cast[type(s.data)](realloc(s.data, old + 1, s.cap + 1)) + +proc add*(s: var string; y: string) = + if y.len != 0: + let newLen = s.len + y.len + ensure(s, newLen) + copyMem(addr s.data[len], y.data, y.data.len + 1) + s.len = newLen + +proc len*(s: string): int {.inline.} = s.len + +proc newString*(len: int): string = + result.len = len + result.cap = len + if len > 0: + result.data = alloc0(len+1) + +converter toCString(x: string): cstring {.core.} = + if x.len == 0: cstring"" else: cast[cstring](x.data) + +proc newStringOfCap*(cap: int): string = + result.len = 0 + result.cap = cap + if cap > 0: + result.data = alloc(cap+1) + +proc `&`*(a, b: string): string = + let sum = a.len + b.len + result = newStringOfCap(sum) + result.len = sum + copyMem(addr result.data[0], a.data, a.len) + copyMem(addr result.data[a.len], b.data, b.len) + if sum > 0: + result.data[sum] = '\0' + +proc concat(x: openArray[string]): string {.core.} = + ## used be the code generator to optimize 'x & y & z ...' + var sum = 0 + for i in 0 ..< x.len: inc(sum, x[i].len) + result = newStringOfCap(sum) + sum = 0 + for i in 0 ..< x.len: + let L = x[i].len + copyMem(addr result.data[sum], x[i].data, L) + inc(sum, L) + diff --git a/lib/core/typelayouts.nim b/lib/core/typelayouts.nim new file mode 100644 index 000000000..445ce77c4 --- /dev/null +++ b/lib/core/typelayouts.nim @@ -0,0 +1,19 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2017 Nim contributors +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +type + TypeLayout* = object + size*, alignment*: int + destructor*: proc (self: pointer; a: Allocator) {.nimcall.} + trace*: proc (self: pointer; a: Allocator) {.nimcall.} + when false: + construct*: proc (self: pointer; a: Allocator) {.nimcall.} + copy*, deepcopy*, sink*: proc (self, other: pointer; a: Allocator) {.nimcall.} + +proc getTypeLayout(t: typedesc): ptr TypeLayout {.magic: "getTypeLayout".} |