summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/destroyer.nim3
-rw-r--r--lib/core/allocators.nim35
-rw-r--r--lib/core/refs.nim97
-rw-r--r--lib/core/seqs.nim117
-rw-r--r--lib/core/strs.nim111
-rw-r--r--lib/core/typelayouts.nim19
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".}