allow old styled RTTI for arc/orc (#15331)

This commit is contained in:
Andreas Rumpf 2020-09-16 14:57:01 +02:00 • committed by GitHub
commit fd31e8ff6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 512 additions and 303 deletions

View file

@ -19,8 +19,6 @@
## work with the types' AST representation at compile time. See, for example,
## the `getTypeImpl proc<macros.html#getTypeImpl,NimNode>`_. As an alternative
## approach to storing arbitrary types at runtime, consider using generics.
##
##
{.push hints: off.}
@ -77,11 +75,21 @@ type
ppointer = ptr pointer
pbyteArray = ptr array[0xffff, int8]
TGenericSeq {.importc.} = object
len, space: int
when defined(gogc):
elemSize: int
PGenSeq = ptr TGenericSeq
when not defined(gcDestructors):
type
TGenericSeq {.importc.} = object
len, space: int
when defined(gogc):
elemSize: int
PGenSeq = ptr TGenericSeq
when defined(gogc):
const GenericSeqSize = (3 * sizeof(int))
else:
const GenericSeqSize = (2 * sizeof(int))
else:
include system/seqs_v2_reimpl
when not defined(js):
template rawType(x: Any): PNimType =
@ -90,18 +98,20 @@ when not defined(js):
template `rawType=`(x: var Any, p: PNimType) =
x.rawTypePtr = cast[pointer](p)
when defined(gogc):
const GenericSeqSize = (3 * sizeof(int))
else:
const GenericSeqSize = (2 * sizeof(int))
proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.
importCompilerProc.}
proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.}
proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
when not defined(gcDestructors):
proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.
importCompilerProc.}
proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.}
proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
else:
proc nimNewObj(size: int): pointer {.importCompilerProc.}
proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.importCompilerProc.}
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
importCompilerProc.}
template `+!!`(a, b): untyped = cast[pointer](cast[ByteAddress](a) + b)
@ -167,29 +177,47 @@ proc baseTypeSize*(x: Any): int {.inline.} =
proc invokeNew*(x: Any) =
## performs ``new(x)``. `x` needs to represent a ``ref``.
assert x.rawType.kind == tyRef
var z = newObj(x.rawType, x.rawType.base.size)
genericAssign(x.value, addr(z), x.rawType)
when defined(gcDestructors):
cast[ppointer](x.value)[] = nimNewObj(x.rawType.base.size)
else:
var z = newObj(x.rawType, x.rawType.base.size)
genericAssign(x.value, addr(z), x.rawType)
proc invokeNewSeq*(x: Any, len: int) =
## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var z = newSeq(x.rawType, len)
genericShallowAssign(x.value, addr(z), x.rawType)
when defined(gcDestructors):
var s = cast[ptr NimSeqV2Reimpl](x.value)
s.len = len
let elem = x.rawType.base
s.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(len, elem.size, elem.align))
else:
var z = newSeq(x.rawType, len)
genericShallowAssign(x.value, addr(z), x.rawType)
proc extendSeq*(x: Any) =
## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var y = cast[ptr PGenSeq](x.value)[]
var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align)
# 'incrSeq' already freed the memory for us and copied over the RC!
# So we simply copy the raw pointer into 'x.value':
cast[ppointer](x.value)[] = z
#genericShallowAssign(x.value, addr(z), x.rawType)
when defined(gcDestructors):
var s = cast[ptr NimSeqV2Reimpl](x.value)
let elem = x.rawType.base
s.p = cast[ptr NimSeqPayloadReimpl](prepareSeqAdd(s.len, s.p, 1, elem.size, elem.align))
inc s.len
else:
var y = cast[ptr PGenSeq](x.value)[]
var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align)
# 'incrSeq' already freed the memory for us and copied over the RC!
# So we simply copy the raw pointer into 'x.value':
cast[ppointer](x.value)[] = z
#genericShallowAssign(x.value, addr(z), x.rawType)
proc setObjectRuntimeType*(x: Any) =
## this needs to be called to set `x`'s runtime object type field.
assert x.rawType.kind == tyObject
objectInit(x.value, x.rawType)
when defined(gcDestructors):
cast[ppointer](x.value)[] = x.rawType.typeInfoV2
else:
objectInit(x.value, x.rawType)
proc skipRange(x: PNimType): PNimType {.inline.} =
result = x
@ -202,17 +230,26 @@ proc `[]`*(x: Any, i: int): Any =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
of tyArray:
var bs = x.rawType.base.size
let bs = x.rawType.base.size
if i >=% x.rawType.size div bs:
raise newException(IndexDefect, formatErrorIndexBound(i, x.rawType.size div bs))
return newAny(x.value +!! i*bs, x.rawType.base)
of tySequence:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
when defined(gcDestructors):
var s = cast[ptr NimSeqV2Reimpl](x.value)
if i >=% s.len:
raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1))
let bs = x.rawType.base.size
let ba = x.rawType.base.align
let headerSize = align(sizeof(int), ba)
return newAny(s.p +!! (headerSize+i*bs), x.rawType.base)
else:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
let bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
else: assert false
proc `[]=`*(x: Any, i: int, y: Any) =
@ -225,13 +262,23 @@ proc `[]=`*(x: Any, i: int, y: Any) =
assert y.rawType == x.rawType.base
genericAssign(x.value +!! i*bs, y.value, y.rawType)
of tySequence:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
assert y.rawType == x.rawType.base
genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
when defined(gcDestructors):
var s = cast[ptr NimSeqV2Reimpl](x.value)
if i >=% s.len:
raise newException(IndexDefect, formatErrorIndexBound(i, s.len-1))
let bs = x.rawType.base.size
let ba = x.rawType.base.align
let headerSize = align(sizeof(int), ba)
assert y.rawType == x.rawType.base
genericAssign(s.p +!! (headerSize+i*bs), y.value, y.rawType)
else:
var s = cast[ppointer](x.value)[]
if s == nil: raise newException(ValueError, "sequence is nil")
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexDefect, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
assert y.rawType == x.rawType.base
genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
else: assert false
proc len*(x: Any): int =
@ -240,11 +287,14 @@ proc len*(x: Any): int =
of tyArray:
result = x.rawType.size div x.rawType.base.size
of tySequence:
let pgenSeq = cast[PGenSeq](cast[ppointer](x.value)[])
if isNil(pgenSeq):
result = 0
when defined(gcDestructors):
result = cast[ptr NimSeqV2Reimpl](x.value).len
else:
result = pgenSeq.len
let pgenSeq = cast[PGenSeq](cast[ppointer](x.value)[])
if isNil(pgenSeq):
result = 0
else:
result = pgenSeq.len
else: assert false
@ -260,21 +310,27 @@ proc isNil*(x: Any): bool =
assert x.rawType.kind in {tyCString, tyRef, tyPtr, tyPointer, tyProc}
result = isNil(cast[ppointer](x.value)[])
const
pointerLike = when defined(gcDestructors): {tyCString, tyRef, tyPtr, tyPointer, tyProc}
else: {tyString, tyCString, tyRef, tyPtr, tyPointer,
tySequence, tyProc}
proc getPointer*(x: Any): pointer =
## retrieve the pointer value out of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer,
tySequence, tyProc}
assert x.rawType.kind in pointerLike
result = cast[ppointer](x.value)[]
proc setPointer*(x: Any, y: pointer) =
## sets the pointer value of `x`. ``x`` needs to be of kind
## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``,
## ``akPointer``, ``akSequence``.
assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer,
tySequence, tyProc}
cast[ppointer](x.value)[] = y
assert x.rawType.kind in pointerLike
when defined(gcDestructors):
genericAssign(x.value, y, x.rawType)
else:
cast[ppointer](x.value)[] = y
proc fieldsAux(p: pointer, n: ptr TNimNode,
ret: var seq[tuple[name: cstring, any: Any]]) =
@ -607,13 +663,16 @@ proc setBiggestFloat*(x: Any, y: BiggestFloat) =
proc getString*(x: Any): string =
## retrieve the string value out of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
if not isNil(cast[ptr pointer](x.value)[]):
when defined(gcDestructors):
result = cast[ptr string](x.value)[]
else:
if not isNil(cast[ptr pointer](x.value)[]):
result = cast[ptr string](x.value)[]
proc setString*(x: Any, y: string) =
## sets the string value of `x`. `x` needs to represent a string.
assert x.rawType.kind == tyString
cast[ptr string](x.value)[] = y
cast[ptr string](x.value)[] = y # also correct for gcDestructors
proc getCString*(x: Any): cstring =
## retrieve the cstring value out of `x`. `x` needs to represent a cstring.

View file

@ -51,16 +51,15 @@
## * `json module <json.html>`_
const unsupportedPlatform =
when defined(nimV2): "new runtime"
elif defined(js): "javascript"
when defined(js): "javascript"
elif defined(nimscript): "nimscript"
else: ""
when unsupportedPlatform != "":
{.error: "marshal module is not supported in " & unsupportedPlatform & """.
Please use alternative packages for serialization.
It is possible to reimplement this module using generics and type traits.
Please contribute new implementation.""".}
Please use alternative packages for serialization.
It is possible to reimplement this module using generics and type traits.
Please contribute a new implementation.""".}
import streams, typeinfo, json, intsets, tables, unicode
@ -345,7 +344,7 @@ proc to*[T](data: string): T =
when not defined(testing) and isMainModule:
template testit(x: untyped) = echo($$to[type(x)]($$x))
template testit(x: untyped) = echo($$to[typeof(x)]($$x))
var x: array[0..4, array[0..4, string]] = [
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],

View file

@ -537,7 +537,7 @@ when notJSnotNims and not defined(nimSeqsV2):
template space(s: PGenericSeq): int {.dirty.} =
s.reserved and not (seqShallowFlag or strlitFlag)
when notJSnotNims and not defined(nimV2):
when notJSnotNims:
include "system/hti"
type
@ -1718,16 +1718,16 @@ when not defined(js) and hasThreadSupport and hostOS != "standalone":
when not defined(js) and defined(nimV2):
type
TNimNode {.compilerproc.} = object # to keep the code generator simple
DestructorProc = proc (p: pointer) {.nimcall, benign, raises: [].}
TNimType {.compilerproc.} = object
TNimTypeV2 {.compilerproc.} = object
destructor: pointer
size: int
align: int
name: cstring
traceImpl: pointer
disposeImpl: pointer
PNimType = ptr TNimType
typeInfoV1: pointer # for backwards compat, usually nil
PNimTypeV2 = ptr TNimTypeV2
when notJSnotNims and defined(nimSeqsV2):
include "system/strs_v2"
@ -2271,29 +2271,28 @@ when notJSnotNims:
else:
const GenericSeqSize = (2 * sizeof(int))
when not defined(nimV2):
proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint =
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
var d: uint
var a = cast[uint](aa)
case n.typ.size
of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[])
of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[])
of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[])
of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[])
else:
d = 0'u
sysAssert(false, "getDiscriminant: invalid n.typ.size")
return d
proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint =
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
var d: uint
var a = cast[uint](aa)
case n.typ.size
of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[])
of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[])
of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[])
of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[])
else:
d = 0'u
sysAssert(false, "getDiscriminant: invalid n.typ.size")
return d
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr < cast[uint](n.len):
result = n.sons[discr]
if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil)
else:
result = n.sons[n.len]
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr < cast[uint](n.len):
result = n.sons[discr]
if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil)
else:
result = n.sons[n.len]
when notJSnotNims and hasAlloc:
{.push profiler: off.}
@ -2305,8 +2304,8 @@ when notJSnotNims and hasAlloc:
{.pop.}
include "system/strmantle"
when not usesDestructors:
include "system/assign"
include "system/assign"
when not defined(nimV2):
include "system/repr"
@ -2862,7 +2861,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
## # -> B is 1
discard
when hasAlloc and notJSnotNims and not usesDestructors:
when hasAlloc and notJSnotNims:
# XXX how to implement 'deepCopy' is an open problem.
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
## Performs a deep copy of `y` and copies it into `x`.

View file

@ -59,12 +59,6 @@ type
Cell = ptr RefHeader
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): Cell =
cast[Cell](cast[int](p) -% sizeof(RefHeader))
@ -132,6 +126,14 @@ proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
when traceCollector:
cprintf("[INCREF] %p\n", head(p))
proc unsureAsgnRef(dest: ptr pointer, src: pointer) {.inline.} =
# This is only used by the old RTTI mechanism and we know
# that 'dest[]' is nil and needs no destruction. Which is really handy
# as we cannot destroy the object reliably if it's an object of unknown
# compile-time type.
dest[] = src
if src != nil: nimIncRef src
when not defined(nimscript) and defined(nimArcDebug):
proc deallocatedRefId*(p: pointer): int =
## Returns the ref's ID if the ref was already deallocated. This
@ -165,10 +167,10 @@ template dispose*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x))
#proc dispose*(x: pointer) = nimRawDispose(x)
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} =
let d = cast[ptr PNimType](p)[].destructor
let d = cast[ptr PNimTypeV2](p)[].destructor
if d != nil: cast[DestructorProc](d)(p)
when false:
cstderr.rawWrite cast[ptr PNimType](p)[].name
cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name
cstderr.rawWrite "\n"
if d == nil:
cstderr.rawWrite "bah, nil\n"
@ -226,11 +228,11 @@ template tearDownForeignThreadGc* =
## With ``--gc:arc`` a nop.
discard
proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} =
proc isObj(obj: PNimTypeV2, subclass: cstring): bool {.compilerRtl, inl.} =
proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
result = strstr(obj.name, subclass) != nil
proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} =
proc chckObj(obj: PNimTypeV2, subclass: cstring) {.compilerRtl.} =
# checks if obj is of type subclass:
if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion")

View file

@ -7,6 +7,8 @@
# distribution, for details about the copyright.
#
include seqs_v2_reimpl
proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.}
proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.}
@ -38,6 +40,20 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
# echo "ugh memory corruption! ", n.kind
# quit 1
template deepSeqAssignImpl(operation, additionalArg) {.dirty.} =
var d = cast[ptr NimSeqV2Reimpl](dest)
var s = cast[ptr NimSeqV2Reimpl](src)
d.len = s.len
let elem = mt.base
d.p = cast[ptr NimSeqPayloadReimpl](newSeqPayload(s.len, elem.size, elem.align))
let bs = elem.size
let ba = elem.align
let headerSize = align(sizeof(NimSeqPayloadBase), ba)
for i in 0..d.len-1:
operation(d.p +! (headerSize+i*bs), s.p +! (headerSize+i*bs), mt.base, additionalArg)
proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
var
d = cast[ByteAddress](dest)
@ -45,38 +61,46 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
sysAssert(mt != nil, "genericAssignAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil or shallow or (
cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
unsureAsgnRef(x, s2)
when defined(nimSeqsV2):
var x = cast[ptr NimStringV2](dest)
var s2 = cast[ptr NimStringV2](s)[]
nimAsgnStrV2(x[], s2)
else:
unsureAsgnRef(x, copyString(cast[NimString](s2)))
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil or shallow or (
cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyString(cast[NimString](s2)))
of tySequence:
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
# this can happen! nil sequences are allowed
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericAssignAux 3")
if ntfNoRefs in mt.base.flags:
var ss = nimNewSeqOfCap(mt, seq.len)
cast[PGenericSeq](ss).len = seq.len
unsureAsgnRef(x, ss)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)),
seq.len *% mt.base.size)
when defined(nimSeqsV2):
deepSeqAssignImpl(genericAssignAux, shallow)
else:
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
mt.base, shallow)
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
# this can happen! nil sequences are allowed
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericAssignAux 3")
if ntfNoRefs in mt.base.flags:
var ss = nimNewSeqOfCap(mt, seq.len)
cast[PGenericSeq](ss).len = seq.len
unsureAsgnRef(x, ss)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)),
seq.len *% mt.base.size)
else:
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
mt.base, shallow)
of tyObject:
var it = mt.base
# don't use recursion here on the PNimType because the subtype
@ -87,14 +111,19 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
genericAssignAux(dest, src, mt.node, shallow)
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
var pint = cast[ptr PNimType](dest)
# We need to copy the *static* type not the dynamic type:
# if p of TB:
# var tbObj = TB(p)
# tbObj of TC # needs to be false!
#c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
chckObjAsgn(cast[ptr PNimType](src)[], mt)
pint[] = mt # cast[ptr PNimType](src)[]
when defined(nimSeqsV2):
var pint = cast[ptr PNimTypeV2](dest)
#chckObjAsgn(cast[ptr PNimTypeV2](src)[].typeInfoV2, mt)
pint[] = cast[PNimTypeV2](mt.typeInfoV2)
else:
var pint = cast[ptr PNimType](dest)
# We need to copy the *static* type not the dynamic type:
# if p of TB:
# var tbObj = TB(p)
# tbObj of TC # needs to be false!
#c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
chckObjAsgn(cast[ptr PNimType](src)[], mt)
pint[] = mt # cast[ptr PNimType](src)[]
of tyTuple:
genericAssignAux(dest, src, mt.node, shallow)
of tyArray, tyArrayConstr:
@ -175,8 +204,12 @@ proc objectInit(dest: pointer, typ: PNimType) =
of tyObject:
# iterate over any structural type
# here we have to init the type field:
var pint = cast[ptr PNimType](dest)
pint[] = typ
when defined(nimSeqsV2):
var pint = cast[ptr PNimTypeV2](dest)
pint[] = cast[PNimTypeV2](typ.typeInfoV2)
else:
var pint = cast[ptr PNimType](dest)
pint[] = typ
objectInitAux(dest, typ.node)
of tyTuple:
objectInitAux(dest, typ.node)
@ -204,15 +237,34 @@ proc genericReset(dest: pointer, mt: PNimType) =
var d = cast[ByteAddress](dest)
sysAssert(mt != nil, "genericReset 2")
case mt.kind
of tyString, tyRef, tySequence:
of tyRef:
unsureAsgnRef(cast[PPointer](dest), nil)
of tyString:
when defined(nimSeqsV2):
var s = cast[ptr NimStringV2](dest)
frees(s[])
zeroMem(dest, mt.size)
else:
unsureAsgnRef(cast[PPointer](dest), nil)
of tySequence:
when defined(nimSeqsV2):
var s = cast[ptr NimSeqV2Reimpl](dest)
if s.p != nil:
deallocShared(s.p)
zeroMem(dest, mt.size)
else:
unsureAsgnRef(cast[PPointer](dest), nil)
of tyTuple:
genericResetAux(dest, mt.node)
of tyObject:
genericResetAux(dest, mt.node)
# also reset the type field for tyObject, for correct branch switching!
var pint = cast[ptr PNimType](dest)
pint[] = nil
when defined(nimSeqsV2):
var pint = cast[ptr PNimTypeV2](dest)
pint[] = nil
else:
var pint = cast[ptr PNimType](dest)
pint[] = nil
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
genericReset(cast[pointer](d +% i *% mt.base.size), mt.base)

View file

@ -10,13 +10,13 @@
# Cell seqs for cyclebreaker and cyclicrefs_v2.
type
CellTuple = (PT, PNimType)
CellTuple = (PT, PNimTypeV2)
CellArray = ptr UncheckedArray[CellTuple]
CellSeq = object
len, cap: int
d: CellArray
proc add(s: var CellSeq, c: PT; t: PNimType) {.inline.} =
proc add(s: var CellSeq, c: PT; t: PNimTypeV2) {.inline.} =
if s.len >= s.cap:
s.cap = s.cap * 3 div 2
when defined(useMalloc):
@ -51,6 +51,6 @@ proc deinit(s: var CellSeq) =
s.len = 0
s.cap = 0
proc pop(s: var CellSeq): (PT, PNimType) =
proc pop(s: var CellSeq): (PT, PNimTypeV2) =
result = s.d[s.len-1]
dec s.len

View file

@ -78,14 +78,14 @@ type
GcEnv = object
traceStack: CellSeq
proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} =
proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
when false:
cprintf("[Trace] desc: %p %p\n", desc, p)
cprintf("[Trace] trace: %p\n", desc.traceImpl)
if desc.traceImpl != nil:
cast[TraceProc](desc.traceImpl)(p, addr(j))
proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} =
proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} =
let p = cast[ptr pointer](q)
when traceCollector:
cprintf("[Trace] raw: %p\n", p)
@ -101,11 +101,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
cprintf("[TraceDyn] deref: %p\n", p[])
if p[] != nil:
var j = cast[ptr GcEnv](env)
j.traceStack.add(p, cast[ptr PNimType](p[])[])
j.traceStack.add(p, cast[ptr PNimTypeV2](p[])[])
var markerGeneration: int
proc breakCycles(s: Cell; desc: PNimType) =
proc breakCycles(s: Cell; desc: PNimTypeV2) =
let markerColor = if (markerGeneration and 1) == 0: colRed
else: colYellow
atomicInc markerGeneration
@ -147,7 +147,7 @@ proc thinout*[T](x: ref T) {.inline.} =
## and thus would keep the graph from being freed are `nil`'ed.
## This is a form of cycle collection that works well with Nim's ARC
## and its associated cost model.
proc getDynamicTypeInfo[T](x: T): PNimType {.magic: "GetTypeInfo", noSideEffect, locks: 0.}
proc getDynamicTypeInfo[T](x: T): PNimTypeV2 {.magic: "GetTypeInfoV2", noSideEffect, locks: 0.}
breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[]))
@ -158,7 +158,7 @@ proc thinout*[T: proc](x: T) {.inline.} =
""".}
let p = rawEnv(x)
breakCycles(head(p), cast[ptr PNimType](p)[])
breakCycles(head(p), cast[ptr PNimTypeV2](p)[])
proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
if p != nil:
@ -171,7 +171,7 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
# According to Lins it's correct to do nothing else here.
#cprintf("[DeCREF] %p\n", p)
proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} =
proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
if p != nil:
var cell = head(p)
if (cell.rc and not rcMask) == 0:

View file

@ -90,27 +90,35 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil:
unsureAsgnRef(x, s2)
when defined(nimSeqsV2):
var x = cast[ptr NimStringV2](dest)
var s2 = cast[ptr NimStringV2](s)[]
nimAsgnStrV2(x[], s2)
else:
unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil:
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
of tySequence:
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil:
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericDeepCopyAux 3")
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
mt.base, tab)
when defined(nimSeqsV2):
deepSeqAssignImpl(genericDeepCopyAux, tab)
else:
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil:
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericDeepCopyAux 3")
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
mt.base, tab)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
@ -151,7 +159,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
sysAssert realType == mt, " types do differ"
# this version should work for any possible GC:
let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base
let z = newObj(mt, typ.size)
let z = when defined(nimSeqsV2): nimNewObj(typ.size) else: newObj(mt, typ.size)
unsureAsgnRef(cast[PPointer](dest), z)
tab.put(s2, z)
genericDeepCopyAux(z, s2, typ, tab)
@ -168,11 +176,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
copyMem(dest, src, mt.size)
proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
GC_disable()
when not defined(nimSeqsV2): GC_disable()
var tab = initPtrTable()
genericDeepCopyAux(dest, src, mt, tab)
deinit tab
GC_enable()
when not defined(nimSeqsV2): GC_enable()
proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
# also invoked for 'string'

View file

@ -98,6 +98,8 @@ type
finalizer*: pointer # the finalizer for the type
marker*: proc (p: pointer, op: int) {.nimcall, benign, tags: [], raises: [].} # marker proc for GC
deepcopy: proc (p: pointer): pointer {.nimcall, benign, tags: [], raises: [].}
when defined(nimSeqsV2):
typeInfoV2*: pointer
when defined(nimTypeNames):
name: cstring
nextType: ptr TNimType

View file

@ -65,8 +65,10 @@ proc growObj(old: pointer, newsize: int): pointer =
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
when not defined(gcDestructors):
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,

View file

@ -53,7 +53,7 @@ type
toFree: CellSeq
freed, touched: int
proc trace(s: Cell; desc: PNimType; j: var GcEnv) {.inline.} =
proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
if desc.traceImpl != nil:
var p = s +! sizeof(RefHeader)
cast[TraceProc](desc.traceImpl)(p, addr(j))
@ -65,7 +65,7 @@ else:
let p = s +! sizeof(RefHeader)
cprintf("[%s] name %s RC %ld\n", str, p, s.rc shr rcShift)
proc free(s: Cell; desc: PNimType) {.inline.} =
proc free(s: Cell; desc: PNimTypeV2) {.inline.} =
when traceCollector:
cprintf("[From ] %p rc %ld color %ld\n", s, s.rc shr rcShift, s.color)
let p = s +! sizeof(RefHeader)
@ -89,7 +89,7 @@ proc free(s: Cell; desc: PNimType) {.inline.} =
nimRawDispose(p)
proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} =
proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl.} =
let p = cast[ptr pointer](q)
if p[] != nil:
var j = cast[ptr GcEnv](env)
@ -99,7 +99,7 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
let p = cast[ptr pointer](q)
if p[] != nil:
var j = cast[ptr GcEnv](env)
j.traceStack.add(head p[], cast[ptr PNimType](p[])[])
j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[])
var
roots {.threadvar.}: CellSeq
@ -115,7 +115,7 @@ proc unregisterCycle(s: Cell) =
roots.d[idx][0].rootIdx = idx
dec roots.len
proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) =
proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
#[
proc scanBlack(s: Cell) =
setColor(s, colBlack)
@ -135,7 +135,7 @@ proc scanBlack(s: Cell; desc: PNimType; j: var GcEnv) =
t.setColor colBlack
trace(t, desc, j)
proc markGray(s: Cell; desc: PNimType; j: var GcEnv) =
proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
#[
proc markGray(s: Cell) =
if s.color != colGray:
@ -163,7 +163,7 @@ proc markGray(s: Cell; desc: PNimType; j: var GcEnv) =
inc j.touched
trace(t, desc, j)
proc scan(s: Cell; desc: PNimType; j: var GcEnv) =
proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
#[
proc scan(s: Cell) =
if s.color == colGray:
@ -226,7 +226,7 @@ when false:
cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n",
msg, s, s.rootIdx, s.rc shr rcShift, s.color)
proc collectWhite(s: Cell; desc: PNimType; j: var GcEnv) =
proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
#[
proc collectWhite(s: Cell) =
if s.color == colWhite and not buffered(s):
@ -315,7 +315,7 @@ proc collectCycles() =
when false:
cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold)
proc registerCycle(s: Cell; desc: PNimType) =
proc registerCycle(s: Cell; desc: PNimTypeV2) =
if roots.len >= rootsThreshold:
collectCycles()
if roots.d == nil: init(roots)
@ -334,7 +334,7 @@ proc GC_enableMarkAndSweep() =
proc GC_disableMarkAndSweep() =
rootsThreshold = high(int)
proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimType) {.noinline.} =
proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} =
if isDestroyAction:
if (s.rc and isCycleCandidate) != 0:
s.rc = s.rc and not isCycleCandidate
@ -356,9 +356,9 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
else:
dec cell.rc, rcIncrement
#if cell.color == colPurple:
rememberCycle(result, cell, cast[ptr PNimType](p)[])
rememberCycle(result, cell, cast[ptr PNimTypeV2](p)[])
proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} =
proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimTypeV2): bool {.compilerRtl, inl.} =
if p != nil:
var cell = head(p)
if (cell.rc and not rcMask) == 0:

View file

@ -22,7 +22,8 @@ type
cap: int
data: UncheckedArray[T]
NimSeqV2*[T] = object
NimSeqV2*[T] = object # \
# if you change this implementation, also change seqs_v2_reimpl.nim!
len: int
p: ptr NimSeqPayload[T]
@ -40,12 +41,15 @@ proc newSeqPayload(cap, elemSize, elemAlign: int): pointer {.compilerRtl, raises
else:
result = nil
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
noSideEffect, raises: [].} =
{.noSideEffect.}:
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 `-!`(p: pointer, s: int): pointer =
cast[pointer](cast[int](p) -% s)
proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): pointer {.
noSideEffect, raises: [], compilerRtl.} =
{.noSideEffect.}:
let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign)
if addlen <= 0:
result = p

View file

@ -0,0 +1,17 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2020 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
type
NimSeqPayloadReimpl = object
cap: int
data: pointer
NimSeqV2Reimpl = object
len: int
p: ptr NimSeqPayloadReimpl