From 2ab6b2c657451c26100645446958671e195a5fb6 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 14 Mar 2019 07:59:35 +0100 Subject: --newruntime: work in progress --- lib/core/runtime_v2.nim | 78 +++++++++++++++++++++++++++++++++++++++++++ lib/core/seqs.nim | 69 +++++++++++++++++++------------------- lib/core/strs.nim | 74 +++++++++++++++++++++-------------------- lib/system/chcks.nim | 88 +++++++++++++++++++++++++------------------------ lib/system/mmdisp.nim | 2 ++ 5 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 lib/core/runtime_v2.nim (limited to 'lib') diff --git a/lib/core/runtime_v2.nim b/lib/core/runtime_v2.nim new file mode 100644 index 000000000..8a9068c37 --- /dev/null +++ b/lib/core/runtime_v2.nim @@ -0,0 +1,78 @@ +#[ +In this new runtime we simply the object layouts a bit: The runtime type +information is only accessed for the objects that have it and it's always +at offset 0 then. The ``ref`` object header is independent from the +runtime type and only contains a reference count. + +Object subtyping is checked via the generated 'name'. This should have +comparable overhead to the old pointer chasing approach but has the benefit +that it works across DLL boundaries. + +The generated name is a concatenation of the object names in the hierarchy +so that a subtype check becomes a substring check. For example:: + + type + ObjectA = object of RootObj + ObjectB = object of ObjectA + +ObjectA's ``name`` is "|ObjectA|RootObj|". +ObjectB's ``name`` is "|ObjectB|ObjectA|RootObj|". + +Now to check for ``x of ObjectB`` we need to check +for ``x.typ.name.hasSubstring("|ObjectB|")``. In the actual implementation, +however, we could also use a +hash of ``package & "." & module & "." & name`` to save space. + +]# + +type + TNimNode {.compilerProc.} = object # to keep the code generator simple + TNimType {.compilerProc.} = object + destructor: proc (p: pointer) {.nimcall, benign.} + size: int + name: cstring + PNimType = ptr TNimType + + ObjHeader = object + rc: int # the object header is now a single RC field. + # we could remove it in non-debug builds but this seems + # unwise. + +proc isObj(obj: PNimType, subclass: cstring): bool {.compilerproc.} = + proc strstr(s, sub: cstring): cstring {.header: "", importc.} + + result = strstr(obj.name, subclass) != nil + +proc chckObj(obj: PNimType, subclass: cstring) {.compilerproc.} = + # checks if obj is of type subclass: + if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion") + +template `+!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) +% s) + +template `-!`(p: pointer, s: int): pointer = + cast[pointer](cast[int](p) -% s) + +template head(p: pointer): ptr ObjHeader = + cast[ptr ObjHeader](cast[int](p) -% sizeof(ObjHeader)) + +proc nimNewObj(size: int): pointer {.compilerRtl.} = + result = alloc0(size + sizeof(ObjHeader)) +! sizeof(ObjHeader) + # XXX Respect defined(useMalloc) here! + +proc nimDecWeakRef(p: pointer) {.compilerRtl.} = + dec head(p).rc + +proc nimIncWeakRef(p: pointer) {.compilerRtl.} = + inc head(p).rc + +proc nimRawDispose(p: pointer) {.compilerRtl.} = + if head(p).rc != 0: + cstderr.rawWrite "[FATAL] dangling references exist\n" + quit 1 + dealloc(p -! sizeof(ObjHeader)) + +proc nimDestroyAndDispose(p: pointer) {.compilerRtl.} = + let d = cast[ptr PNimType](p)[].destructor + if d != nil: d(p) + nimRawDispose(p) diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index fd46b96eb..08c10962b 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -44,43 +44,44 @@ This means the check for whether ``s.p`` needs to be freed should be ``s.len == 0`` even though that feels slightly more awkward. ]# -proc `=destroy`[T](s: var seq[T]) = - var x = cast[ptr NimSeqV2[T]](addr s) - var p = x.p - if p != nil: +when not defined(nimV2): + proc `=destroy`[T](s: var seq[T]) = + var x = cast[ptr NimSeqV2[T]](addr s) + var p = x.p + if p != nil: + mixin `=destroy` + when not supportsCopyMem(T): + for i in 0.. 0: - copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T)) - else: - for i in 0.. 0: + copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T)) + else: + for i in 0..