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

@ -680,7 +680,7 @@ type
mNBindSym, mNCallSite, mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym,
mNHint, mNWarning, mNError, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo, mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2,
mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples,
mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
mSymIsInstantiationOf, mNodeId mSymIsInstantiationOf, mNodeId

View file

@ -266,10 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
[addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)])
else: else:
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
else: else:
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)]) [addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) = proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
assert d.k != locNone assert d.k != locNone
@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else: else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src), [addrLoc(p.config, dest), rdLoc(src),
genTypeInfo(p.module, dest.t, dest.lode.info)]) genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tyString: of tyString:
if optSeqDestructors in p.config.globalOptions: if optSeqDestructors in p.config.globalOptions:
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
@ -383,7 +383,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, # XXX: is this correct for arrays? linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), [addrLoc(p.config, dest), addrLoc(p.config, src),
genTypeInfo(p.module, dest.t, dest.lode.info)]) genTypeInfoV1(p.module, dest.t, dest.lode.info)])
else: else:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
# bug #4799, keep the nimCopyMem for a while # bug #4799, keep the nimCopyMem for a while
@ -425,16 +425,21 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
# XXX optimize this # XXX optimize this
linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src), [addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info)]) genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tySequence, tyString: of tySequence, tyString:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", if optTinyRtti in p.config.globalOptions:
[addrLoc(p.config, dest), rdLoc(src), linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
genTypeInfo(p.module, dest.t, dest.lode.info)]) [addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
else:
linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
[addrLoc(p.config, dest), rdLoc(src),
genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
[addrLoc(p.config, dest), addrLocOrTemp(src), [addrLoc(p.config, dest), addrLocOrTemp(src),
genTypeInfo(p.module, dest.t, dest.lode.info)]) genTypeInfoV1(p.module, dest.t, dest.lode.info)])
of tySet: of tySet:
if mapSetType(p.config, ty) == ctArray: if mapSetType(p.config, ty) == ctArray:
linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n",
@ -1229,12 +1234,12 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)" const seqAppendPattern = "($2) #incrSeqV3((TGenericSeq*)($1), $3)"
call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e[1].typ),
genTypeInfo(p.module, seqType, e.info)]) genTypeInfoV1(p.module, seqType, e.info)])
else: else:
const seqAppendPattern = "($2) #incrSeqV3($1, $3)" const seqAppendPattern = "($2) #incrSeqV3($1, $3)"
call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a),
getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e[1].typ),
genTypeInfo(p.module, seqType, e.info)]) genTypeInfoV1(p.module, seqType, e.info)])
# emit the write barrier if required, but we can always move here, so # emit the write barrier if required, but we can always move here, so
# use 'genRefAssign' for the seq. # use 'genRefAssign' for the seq.
genRefAssign(p, a, call) genRefAssign(p, a, call)
@ -1254,7 +1259,7 @@ proc genReset(p: BProc, n: PNode) =
when false: when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, a), [addrLoc(p.config, a),
genTypeInfo(p.module, skipTypes(a.t, {tyVar}), n.info)]) genTypeInfoV1(p.module, skipTypes(a.t, {tyVar}), n.info)])
proc genDefault(p: BProc; n: PNode; d: var TLoc) = proc genDefault(p: BProc; n: PNode; d: var TLoc) =
if d.k == locNone: getTemp(p, n.typ, d, needsInit=true) if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
@ -1280,7 +1285,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) =
[getTypeDesc(p.module, typ), sizeExpr]) [getTypeDesc(p.module, typ), sizeExpr])
genAssignment(p, a, b, {}) genAssignment(p, a, b, {})
else: else:
let ti = genTypeInfo(p.module, typ, a.lode.info) let ti = genTypeInfoV1(p.module, typ, a.lode.info)
if bt.destructor != nil and not isTrivialProc(bt.destructor): if bt.destructor != nil and not isTrivialProc(bt.destructor):
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a # the prototype of a destructor is ``=destroy(x: var T)`` and that of a
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling # finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
@ -1339,18 +1344,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) =
if p.config.selectedGC == gcGo: if p.config.selectedGC == gcGo:
# we need the write barrier # we need the write barrier
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype, dest.lode.info), length]) genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc]) linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", [addrLoc(p.config, dest), call.rdLoc])
else: else:
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype), call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype, dest.lode.info), length]) genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc]) linefmt(p, cpsStmts, "$1 = $2;$n", [dest.rdLoc, call.rdLoc])
else: else:
if lenIsZero: if lenIsZero:
call.r = rope"NIM_NIL" call.r = rope"NIM_NIL"
else: else:
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype), call.r = ropecg(p.module, "($1) #newSeq($2, $3)", [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype, dest.lode.info), length]) genTypeInfoV1(p.module, seqtype, dest.lode.info), length])
genAssignment(p, dest, call, {}) genAssignment(p, dest, call, {})
proc genNewSeq(p: BProc, e: PNode) = proc genNewSeq(p: BProc, e: PNode) =
@ -1383,7 +1388,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
putIntoDest(p, d, e, ropecg(p.module, putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [ "($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype), getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc]))
gcUsage(p.config, e) gcUsage(p.config, e)
proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) = proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
@ -1553,7 +1558,10 @@ proc genNewFinalize(p: BProc, e: PNode) =
initLocExpr(p, e[1], a) initLocExpr(p, e[1], a)
initLocExpr(p, e[2], f) initLocExpr(p, e[2], f)
initLoc(b, locExpr, a.lode, OnHeap) initLoc(b, locExpr, a.lode, OnHeap)
ti = genTypeInfo(p.module, refType, e.info) if optTinyRtti in p.config.globalOptions:
ti = genTypeInfoV2(p.module, refType, e.info)
else:
ti = genTypeInfoV1(p.module, refType, e.info)
p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) p.module.s[cfsTypeInit3].addf("$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType), getTypeDesc(p.module, refType),
@ -1568,9 +1576,9 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
result = ropecg(p.module, "#isObj($1.m_type, $2)", result = ropecg(p.module, "#isObj($1.m_type, $2)",
[a, genTypeInfo2Name(p.module, dest)]) [a, genTypeInfo2Name(p.module, dest)])
else: else:
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we # unfortunately 'genTypeInfoV1' sets tfObjHasKids as a side effect, so we
# have to call it here first: # have to call it here first:
let ti = genTypeInfo(p.module, dest, info) let ti = genTypeInfoV1(p.module, dest, info)
if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and if tfFinal in dest.flags or (objHasKidsValid in p.module.flags and
tfObjHasKids notin dest.flags): tfObjHasKids notin dest.flags):
result = "$1.m_type == $2" % [a, ti] result = "$1.m_type == $2" % [a, ti]
@ -1583,7 +1591,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
when false: when false:
# former version: # former version:
result = ropecg(p.module, "#isObj($1.m_type, $2)", result = ropecg(p.module, "#isObj($1.m_type, $2)",
[a, genTypeInfo(p.module, dest, info)]) [a, genTypeInfoV1(p.module, dest, info)])
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc var a: TLoc
@ -1633,12 +1641,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyEnum, tyOrdinal: of tyEnum, tyOrdinal:
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "#reprEnum((NI)$1, $2)", [ ropecg(p.module, "#reprEnum((NI)$1, $2)", [
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
of tyString: of tyString:
putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
of tySet: of tySet:
putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [ putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), a.storage) addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
var b: TLoc var b: TLoc
case skipTypes(a.t, abstractVarRange).kind case skipTypes(a.t, abstractVarRange).kind
@ -1653,20 +1661,20 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
else: internalError(p.config, e[0].info, "genRepr()") else: internalError(p.config, e[0].info, "genRepr()")
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t), e.info)]), a.storage) genTypeInfoV1(p.module, elemType(t), e.info)]), a.storage)
of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence: of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence:
putIntoDest(p, d, e, putIntoDest(p, d, e,
ropecg(p.module, "#reprAny($1, $2)", [ ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage) rdLoc(a), genTypeInfoV1(p.module, t, e.info)]), a.storage)
of tyEmpty, tyVoid: of tyEmpty, tyVoid:
localError(p.config, e.info, "'repr' doesn't support 'void' type") localError(p.config, e.info, "'repr' doesn't support 'void' type")
else: else:
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)", putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(p.config, a), genTypeInfo(p.module, t, e.info)]), [addrLoc(p.config, a), genTypeInfoV1(p.module, t, e.info)]),
a.storage) a.storage)
gcUsage(p.config, e) gcUsage(p.config, e)
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope = proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope; enforceV1 = false): Rope =
result = rdLoc(a) result = rdLoc(a)
var t = skipTypes(a.t, abstractInst) var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyLent, tyPtr, tyRef}: while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
@ -1680,13 +1688,20 @@ proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
result.add(".Sup") result.add(".Sup")
t = skipTypes(t[0], skipPtrs) t = skipTypes(t[0], skipPtrs)
result.add ".m_type" result.add ".m_type"
if optTinyRtti in p.config.globalOptions and enforceV1:
result.add "->typeInfoV1"
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
discard cgsym(p.module, "TNimType") discard cgsym(p.module, "TNimType")
let t = e[1].typ
# ordinary static type information
putIntoDest(p, d, e, genTypeInfoV1(p.module, t, e.info))
proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
let t = e[1].typ let t = e[1].typ
if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo":
# ordinary static type information # ordinary static type information
putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info)) putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info))
else: else:
var a: TLoc var a: TLoc
initLocExpr(p, e[1], a) initLocExpr(p, e[1], a)
@ -1779,13 +1794,13 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)" const setLenPattern = "($3) #setLengthSeqV2(&($1)->Sup, $4, $2)"
call.r = ropecg(p.module, setLenPattern, [ call.r = ropecg(p.module, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
else: else:
const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)"
call.r = ropecg(p.module, setLenPattern, [ call.r = ropecg(p.module, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)]) genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)])
genAssignment(p, a, call, {}) genAssignment(p, a, call, {})
gcUsage(p.config, e) gcUsage(p.config, e)
@ -2226,6 +2241,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAddI..mPred: binaryArithOverflow(p, e, d, op) of mAddI..mPred: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d) of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d)
of mSwap: genSwap(p, e, d) of mSwap: genSwap(p, e, d)
of mInc, mDec: of mInc, mDec:
const opr: array[mInc..mDec, string] = ["+=", "-="] const opr: array[mInc..mDec, string] = ["+=", "-="]
@ -2534,7 +2550,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, dest) genTypeInfo2Name(p.module, dest)
else: else:
genTypeInfo(p.module, dest, n.info) genTypeInfoV1(p.module, dest, n.info)
if nilCheck != nil: if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n", linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n",
[nilCheck, r, checkFor, raiseInstr(p)]) [nilCheck, r, checkFor, raiseInstr(p)])
@ -2951,7 +2967,10 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, constOrNil: PNode,
getNullValueAuxT(p, orig, base, base.n, constOrNil, result, count, isConst, info) getNullValueAuxT(p, orig, base, base.n, constOrNil, result, count, isConst, info)
result.add "}" result.add "}"
elif not isObjLackingTypeField(t): elif not isObjLackingTypeField(t):
result.add genTypeInfo(p.module, orig, obj.info) if optTinyRtti in p.config.globalOptions:
result.add genTypeInfoV2(p.module, orig, obj.info)
else:
result.add genTypeInfoV1(p.module, orig, obj.info)
inc count inc count
getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info) getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info)
# do not emit '{}' as that is not valid C: # do not emit '{}' as that is not valid C:

View file

@ -1040,7 +1040,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, typeNode.typ) genTypeInfo2Name(p.module, typeNode.typ)
else: else:
genTypeInfo(p.module, typeNode.typ, typeNode.info) genTypeInfoV1(p.module, typeNode.typ, typeNode.info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@ -1255,7 +1255,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ) genTypeInfo2Name(p.module, t[i][j].typ)
else: else:
genTypeInfo(p.module, t[i][j].typ, t[i][j].info) genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@ -1383,7 +1383,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let checkFor = if optTinyRtti in p.config.globalOptions: let checkFor = if optTinyRtti in p.config.globalOptions:
genTypeInfo2Name(p.module, t[i][j].typ) genTypeInfo2Name(p.module, t[i][j].typ)
else: else:
genTypeInfo(p.module, t[i][j].typ, t[i][j].info) genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type" let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor]) appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@ -1508,7 +1508,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) = field: PSym) =
var t = skipTypes(objtype, abstractVar) var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject assert t.kind == tyObject
discard genTypeInfo(p.module, t, a.lode.info) discard genTypeInfoV1(p.module, t, a.lode.info)
if not containsOrIncl(p.module.declaredThings, field.id): if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1", appcg(p.module, cfsVars, "extern $1",
[discriminatorTableDecl(p.module, t, field)]) [discriminatorTableDecl(p.module, t, field)])

View file

@ -173,7 +173,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope =
[result, markerName, getModuleDllPath(m)]) [result, markerName, getModuleDllPath(m)])
proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope = proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
discard genTypeInfo(m, s.loc.t, info) discard genTypeInfoV1(m, s.loc.t, info)
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)

View file

@ -609,7 +609,10 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags: if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
appcg(m, result, " {$n", []) appcg(m, result, " {$n", [])
else: else:
appcg(m, result, " {$n#TNimType* m_type;$n", []) if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
hasField = true hasField = true
elif m.compileToCpp: elif m.compileToCpp:
appcg(m, result, " : public $1 {$n", appcg(m, result, " : public $1 {$n",
@ -1004,7 +1007,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope =
# ------------------ type info generation ------------------------------------- # ------------------ type info generation -------------------------------------
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope
proc getNimNode(m: BModule): Rope = proc getNimNode(m: BModule): Rope =
result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)] result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes) inc(m.typeNodes)
@ -1067,7 +1070,7 @@ proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope;
if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x): if typ.kind == tyPtr and x.kind == tyObject and incompleteType(x):
base = rope("0") base = rope("0")
else: else:
base = genTypeInfo(m, x, info) base = genTypeInfoV1(m, x, info)
else: else:
base = rope("0") base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base, info) genTypeInfoAuxBase(m, typ, origType, name, base, info)
@ -1126,7 +1129,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r, "$1.len = $7;$n", [expr, getTypeDesc(m, origType), field.loc.r,
genTypeInfo(m, field.typ, info), genTypeInfoV1(m, field.typ, info),
makeCString(field.name.s), makeCString(field.name.s),
tmp, rope(L)]) tmp, rope(L)])
m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)]) m.s[cfsData].addf("TNimNode* $1[$2];$n", [tmp, rope(L+1)])
@ -1163,7 +1166,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
m.s[cfsTypeInit3].addf("$1.kind = 1;$n" & m.s[cfsTypeInit3].addf("$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, origType), "$1.name = $5;$n", [expr, getTypeDesc(m, origType),
field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)]) field.loc.r, genTypeInfoV1(m, field.typ, info), makeCString(field.name.s)])
else: internalError(m.config, n.info, "genObjectFields") else: internalError(m.config, n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) = proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
@ -1198,7 +1201,7 @@ proc genTupleInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo)
"$1.offset = offsetof($2, Field$3);$n" & "$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" & "$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n", "$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, origType), rope(i), genTypeInfo(m, a, info)]) [tmp2, getTypeDesc(m, origType), rope(i), genTypeInfoV1(m, a, info)])
m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", m.s[cfsTypeInit3].addf("$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, rope(typ.len), tmp]) [expr, rope(typ.len), tmp])
else: else:
@ -1255,7 +1258,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
[tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)])
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ[1], info), info) genTypeInfoAuxBase(m, typ, typ, name, genTypeInfoV1(m, typ[1], info), info)
proc fakeClosureType(m: BModule; owner: PSym): PType = proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]] # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@ -1273,13 +1276,14 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", m.s[cfsTypeInit3].addf("$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r]) [result, s.loc.r])
proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) = proc declareNimType(m: BModule, name: string; str: Rope, ownerModule: PSym) =
let nr = rope(name)
if m.hcrOn: if m.hcrOn:
m.s[cfsData].addf("static TNimType* $1;$n", [str]) m.s[cfsData].addf("static $2* $1;$n", [str, nr])
m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n", m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n",
[str, getModuleDllPath(m, ownerModule)]) [str, getModuleDllPath(m, ownerModule), nr])
else: else:
m.s[cfsData].addf("extern TNimType $1;$n", [str]) m.s[cfsData].addf("extern $2 $1;$n", [str, nr])
proc genTypeInfo2Name(m: BModule; t: PType): Rope = proc genTypeInfo2Name(m: BModule; t: PType): Rope =
var res = "|" var res = "|"
@ -1327,7 +1331,7 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
internalError(m.config, info, "no attached trace proc found") internalError(m.config, info, "no attached trace proc found")
result = rope("NIM_NIL") result = rope("NIM_NIL")
proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) = proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
var typeName: Rope var typeName: Rope
if t.kind == tyObject: if t.kind == tyObject:
if incompleteType(t): if incompleteType(t):
@ -1337,8 +1341,8 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
else: else:
typeName = rope("NIM_NIL") typeName = rope("NIM_NIL")
discard cgsym(m, "TNimType") discard cgsym(m, "TNimTypeV2")
m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
let destroyImpl = genHook(m, t, info, attachedDestructor) let destroyImpl = genHook(m, t, info, attachedDestructor)
let traceImpl = genHook(m, t, info, attachedTrace) let traceImpl = genHook(m, t, info, attachedTrace)
let disposeImpl = genHook(m, t, info, attachedDispose) let disposeImpl = genHook(m, t, info, attachedDispose)
@ -1347,7 +1351,43 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
name, destroyImpl, getTypeDesc(m, t), typeName, name, destroyImpl, getTypeDesc(m, t), typeName,
traceImpl, disposeImpl]) traceImpl, disposeImpl])
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
let prefixTI = if m.hcrOn: "(" else: "(&"
let sig = hashType(origType)
result = m.typeInfoMarkerV2.getOrDefault(sig)
if result != nil:
return prefixTI.rope & result & ")".rope
let marker = m.g.typeInfoMarkerV2.getOrDefault(sig)
if marker.str != nil:
discard cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", marker.str, marker.owner)
# also store in local type section:
m.typeInfoMarkerV2[sig] = marker.str
return prefixTI.rope & marker.str & ")".rope
result = "NTIv2$1_" % [rope($sig)]
m.typeInfoMarkerV2[sig] = result
let owner = t.skipTypes(typedescPtrs).owner.getModule
if owner != m.module:
# make sure the type info is created in the owner module
assert m.g.modules[owner.position] != nil
discard genTypeInfoV2(m.g.modules[owner.position], origType, info)
# reference the type info as extern here
discard cgsym(m, "TNimTypeV2")
declareNimType(m, "TNimTypeV2", result, owner)
return prefixTI.rope & result & ")".rope
m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
genTypeInfoV2Impl(m, t, origType, result, info)
result = prefixTI.rope & result & ")".rope
proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
let origType = t let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
@ -1362,7 +1402,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
if marker.str != nil: if marker.str != nil:
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
declareNimType(m, marker.str, marker.owner) declareNimType(m, "TNimType", marker.str, marker.owner)
# also store in local type section: # also store in local type section:
m.typeInfoMarker[sig] = marker.str m.typeInfoMarker[sig] = marker.str
return prefixTI.rope & marker.str & ")".rope return prefixTI.rope & marker.str & ")".rope
@ -1374,63 +1414,65 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
if owner != m.module: if owner != m.module:
# make sure the type info is created in the owner module # make sure the type info is created in the owner module
assert m.g.modules[owner.position] != nil assert m.g.modules[owner.position] != nil
discard genTypeInfo(m.g.modules[owner.position], origType, info) discard genTypeInfoV1(m.g.modules[owner.position], origType, info)
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
declareNimType(m, result, owner) declareNimType(m, "TNimType", result, owner)
return prefixTI.rope & result & ")".rope return prefixTI.rope & result & ")".rope
m.g.typeInfoMarker[sig] = (str: result, owner: owner) m.g.typeInfoMarker[sig] = (str: result, owner: owner)
if optTinyRtti in m.config.globalOptions: case t.kind
genTypeInfoV2(m, t, origType, result, info) of tyEmpty, tyVoid: result = rope"0"
else: of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent:
case t.kind genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyEmpty, tyVoid: result = rope"0" of tyStatic:
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: if t.n != nil: result = genTypeInfoV1(m, lastSon t, info)
else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert m.config, t.isResolvedUserTypeClass
return genTypeInfoV1(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0", info) genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyStatic: else:
if t.n != nil: result = genTypeInfo(m, lastSon t, info) let x = fakeClosureType(m, t.owner)
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') genTupleInfo(m, x, x, result, info)
of tyUserTypeClasses: of tySequence:
internalAssert m.config, t.isResolvedUserTypeClass genTypeInfoAux(m, t, t, result, info)
return genTypeInfo(m, t.lastSon, info) if m.config.selectedGC >= gcMarkAndSweep:
of tyProc: let markerProc = genTraverseProc(m, origType, sig)
if t.callConv != ccClosure: m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
genTypeInfoAuxBase(m, t, t, result, rope"0", info) of tyRef:
else: genTypeInfoAux(m, t, t, result, info)
let x = fakeClosureType(m, t.owner) if m.config.selectedGC >= gcMarkAndSweep:
genTupleInfo(m, x, x, result, info) let markerProc = genTraverseProc(m, origType, sig)
of tySequence: m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
genTypeInfoAux(m, t, t, result, info) of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
if optSeqDestructors notin m.config.globalOptions: of tyArray: genArrayInfo(m, t, result, info)
if m.config.selectedGC >= gcMarkAndSweep: of tySet: genSetInfo(m, t, result, info)
let markerProc = genTraverseProc(m, origType, sig) of tyEnum: genEnumInfo(m, t, result, info)
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) of tyObject:
of tyRef: genObjectInfo(m, t, origType, result, info)
genTypeInfoAux(m, t, t, result, info) of tyTuple:
if m.config.selectedGC >= gcMarkAndSweep: # if t.n != nil: genObjectInfo(m, t, result)
let markerProc = genTraverseProc(m, origType, sig) # else:
m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) # BUGFIX: use consistently RTTI without proper field names; otherwise
of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) # results are not deterministic!
of tyArray: genArrayInfo(m, t, result, info) genTupleInfo(m, t, origType, result, info)
of tySet: genSetInfo(m, t, result, info) else: internalError(m.config, "genTypeInfoV1(" & $t.kind & ')')
of tyEnum: genEnumInfo(m, t, result, info)
of tyObject:
genObjectInfo(m, t, origType, result, info)
of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result)
# else:
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, origType, result, info)
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
if t.attachedOps[attachedDeepCopy] != nil: if t.attachedOps[attachedDeepCopy] != nil:
genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result) genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result)
elif origType.attachedOps[attachedDeepCopy] != nil: elif origType.attachedOps[attachedDeepCopy] != nil:
genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result) genDeepCopyProc(m, origType.attachedOps[attachedDeepCopy], result)
if optTinyRtti in m.config.globalOptions and t.kind == tyObject:
let v2info = genTypeInfoV2(m, origType, info)
addf(m.s[cfsTypeInit3], "$1->typeInfoV1 = (void*)&$2; $2.typeInfoV2 = (void*)$1;$n", [
v2info, result])
result = prefixTI.rope & result & ")".rope result = prefixTI.rope & result & ")".rope
proc genTypeSection(m: BModule, n: PNode) = proc genTypeSection(m: BModule, n: PNode) =

View file

@ -360,7 +360,10 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
while s.kind == tyObject and s[0] != nil: while s.kind == tyObject and s[0] != nil:
r.add(".Sup") r.add(".Sup")
s = skipTypes(s[0], skipPtrs) s = skipTypes(s[0], skipPtrs)
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)]) if optTinyRtti in p.config.globalOptions:
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV2(p.module, t, a.lode.info)])
else:
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded: of frEmbedded:
if optTinyRtti in p.config.globalOptions: if optTinyRtti in p.config.globalOptions:
var tmp: TLoc var tmp: TLoc
@ -376,7 +379,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
else: else:
# worst case for performance: # worst case for performance:
var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a) var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a)
linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)]) linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
if isException(t): if isException(t):
var r = rdLoc(a) var r = rdLoc(a)
@ -417,7 +420,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
specializeReset(p, loc) specializeReset(p, loc)
when false: when false:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)]) [addrLoc(p.config, loc), genTypeInfoV1(p.module, loc.t, loc.lode.info)])
# XXX: generated reset procs should not touch the m_type # XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe: # field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, constructObj) genObjectInit(p, cpsStmts, loc.t, loc, constructObj)

View file

@ -122,6 +122,7 @@ type
forwardedProcs*: seq[PSym] # proc:s that did not yet have a body forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
generatedHeader*: BModule generatedHeader*: BModule
typeInfoMarker*: TypeCacheWithOwner typeInfoMarker*: TypeCacheWithOwner
typeInfoMarkerV2*: TypeCacheWithOwner
config*: ConfigRef config*: ConfigRef
graph*: ModuleGraph graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use strVersion*, seqVersion*: int # version of the string/seq implementation to use
@ -155,6 +156,7 @@ type
declaredProtos*: IntSet # prototypes we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file
headerFiles*: seq[string] # needed headers to include headerFiles*: seq[string] # needed headers to include
typeInfoMarker*: TypeCache # needed for generating type information typeInfoMarker*: TypeCache # needed for generating type information
typeInfoMarkerV2*: TypeCache
initProc*: BProc # code for init procedure initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc preInitProc*: BProc # code executed before the init proc
hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on

View file

@ -523,7 +523,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var cond: PNode var cond: PNode
if isCyclic: if isCyclic:
if isFinal(elemType): if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer) typInfo.typ = getSysType(c.g, c.info, tyPointer)
cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo) cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo)
else: else:
@ -546,7 +546,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedDeepCopy: assert(false, "cannot happen") of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: of attachedTrace:
if isFinal(elemType): if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType)) let typInfo = genBuiltin(c.g, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer) typInfo.typ = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y) body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
else: else:

View file

@ -136,9 +136,8 @@ type
cmdCompileToBackend, # compile to backend in TBackend cmdCompileToBackend, # compile to backend in TBackend
TStringSeq* = seq[string] TStringSeq* = seq[string]
TGCMode* = enum # the selected GC TGCMode* = enum # the selected GC
gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc, gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc,
gcHooks, gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo
gcRefc, gcV2, gcGo
# gcRefc and the GCs that follow it use a write barrier, # gcRefc and the GCs that follow it use a write barrier,
# as far as usesWriteBarrier() is concerned # as far as usesWriteBarrier() is concerned

View file

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

View file

@ -51,16 +51,15 @@
## * `json module <json.html>`_ ## * `json module <json.html>`_
const unsupportedPlatform = const unsupportedPlatform =
when defined(nimV2): "new runtime" when defined(js): "javascript"
elif defined(js): "javascript"
elif defined(nimscript): "nimscript" elif defined(nimscript): "nimscript"
else: "" else: ""
when unsupportedPlatform != "": when unsupportedPlatform != "":
{.error: "marshal module is not supported in " & unsupportedPlatform & """. {.error: "marshal module is not supported in " & unsupportedPlatform & """.
Please use alternative packages for serialization. Please use alternative packages for serialization.
It is possible to reimplement this module using generics and type traits. It is possible to reimplement this module using generics and type traits.
Please contribute new implementation.""".} Please contribute a new implementation.""".}
import streams, typeinfo, json, intsets, tables, unicode import streams, typeinfo, json, intsets, tables, unicode
@ -345,7 +344,7 @@ proc to*[T](data: string): T =
when not defined(testing) and isMainModule: 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]] = [ var x: array[0..4, array[0..4, string]] = [
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["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.} = template space(s: PGenericSeq): int {.dirty.} =
s.reserved and not (seqShallowFlag or strlitFlag) s.reserved and not (seqShallowFlag or strlitFlag)
when notJSnotNims and not defined(nimV2): when notJSnotNims:
include "system/hti" include "system/hti"
type type
@ -1718,16 +1718,16 @@ when not defined(js) and hasThreadSupport and hostOS != "standalone":
when not defined(js) and defined(nimV2): when not defined(js) and defined(nimV2):
type type
TNimNode {.compilerproc.} = object # to keep the code generator simple
DestructorProc = proc (p: pointer) {.nimcall, benign, raises: [].} DestructorProc = proc (p: pointer) {.nimcall, benign, raises: [].}
TNimType {.compilerproc.} = object TNimTypeV2 {.compilerproc.} = object
destructor: pointer destructor: pointer
size: int size: int
align: int align: int
name: cstring name: cstring
traceImpl: pointer traceImpl: pointer
disposeImpl: pointer disposeImpl: pointer
PNimType = ptr TNimType typeInfoV1: pointer # for backwards compat, usually nil
PNimTypeV2 = ptr TNimTypeV2
when notJSnotNims and defined(nimSeqsV2): when notJSnotNims and defined(nimSeqsV2):
include "system/strs_v2" include "system/strs_v2"
@ -2271,29 +2271,28 @@ when notJSnotNims:
else: else:
const GenericSeqSize = (2 * sizeof(int)) const GenericSeqSize = (2 * sizeof(int))
when not defined(nimV2): proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint =
proc getDiscriminant(aa: pointer, n: ptr TNimNode): uint = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") var d: uint
var d: uint var a = cast[uint](aa)
var a = cast[uint](aa) case n.typ.size
case n.typ.size of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[])
of 1: d = uint(cast[ptr uint8](a + uint(n.offset))[]) of 2: d = uint(cast[ptr uint16](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 4: d = uint(cast[ptr uint32](a + uint(n.offset))[]) of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[])
of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[]) else:
else: d = 0'u
d = 0'u sysAssert(false, "getDiscriminant: invalid n.typ.size")
sysAssert(false, "getDiscriminant: invalid n.typ.size") return d
return d
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n) var discr = getDiscriminant(aa, n)
if discr < cast[uint](n.len): if discr < cast[uint](n.len):
result = n.sons[discr] result = n.sons[discr]
if result == nil: result = n.sons[n.len] if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil) # n.sons[n.len] contains the ``else`` part (but may be nil)
else: else:
result = n.sons[n.len] result = n.sons[n.len]
when notJSnotNims and hasAlloc: when notJSnotNims and hasAlloc:
{.push profiler: off.} {.push profiler: off.}
@ -2305,8 +2304,8 @@ when notJSnotNims and hasAlloc:
{.pop.} {.pop.}
include "system/strmantle" include "system/strmantle"
when not usesDestructors: include "system/assign"
include "system/assign"
when not defined(nimV2): when not defined(nimV2):
include "system/repr" include "system/repr"
@ -2862,7 +2861,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
## # -> B is 1 ## # -> B is 1
discard discard
when hasAlloc and notJSnotNims and not usesDestructors: when hasAlloc and notJSnotNims:
# XXX how to implement 'deepCopy' is an open problem. # XXX how to implement 'deepCopy' is an open problem.
proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
## Performs a deep copy of `y` and copies it into `x`. ## Performs a deep copy of `y` and copies it into `x`.

View file

@ -59,12 +59,6 @@ type
Cell = ptr RefHeader 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 = template head(p: pointer): Cell =
cast[Cell](cast[int](p) -% sizeof(RefHeader)) cast[Cell](cast[int](p) -% sizeof(RefHeader))
@ -132,6 +126,14 @@ proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
when traceCollector: when traceCollector:
cprintf("[INCREF] %p\n", head(p)) 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): when not defined(nimscript) and defined(nimArcDebug):
proc deallocatedRefId*(p: pointer): int = proc deallocatedRefId*(p: pointer): int =
## Returns the ref's ID if the ref was already deallocated. This ## 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 dispose*(x: pointer) = nimRawDispose(x)
proc nimDestroyAndDispose(p: pointer) {.compilerRtl, raises: [].} = 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) if d != nil: cast[DestructorProc](d)(p)
when false: when false:
cstderr.rawWrite cast[ptr PNimType](p)[].name cstderr.rawWrite cast[ptr PNimTypeV2](p)[].name
cstderr.rawWrite "\n" cstderr.rawWrite "\n"
if d == nil: if d == nil:
cstderr.rawWrite "bah, nil\n" cstderr.rawWrite "bah, nil\n"
@ -226,11 +228,11 @@ template tearDownForeignThreadGc* =
## With ``--gc:arc`` a nop. ## With ``--gc:arc`` a nop.
discard 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.} proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
result = strstr(obj.name, subclass) != nil 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: # checks if obj is of type subclass:
if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion") if not isObj(obj, subclass): sysFatal(ObjectConversionDefect, "invalid object conversion")

View file

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

View file

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

View file

@ -78,14 +78,14 @@ type
GcEnv = object GcEnv = object
traceStack: CellSeq traceStack: CellSeq
proc trace(p: pointer; desc: PNimType; j: var GcEnv) {.inline.} = proc trace(p: pointer; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
when false: when false:
cprintf("[Trace] desc: %p %p\n", desc, p) cprintf("[Trace] desc: %p %p\n", desc, p)
cprintf("[Trace] trace: %p\n", desc.traceImpl) cprintf("[Trace] trace: %p\n", desc.traceImpl)
if desc.traceImpl != nil: if desc.traceImpl != nil:
cast[TraceProc](desc.traceImpl)(p, addr(j)) 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) let p = cast[ptr pointer](q)
when traceCollector: when traceCollector:
cprintf("[Trace] raw: %p\n", p) cprintf("[Trace] raw: %p\n", p)
@ -101,11 +101,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
cprintf("[TraceDyn] deref: %p\n", p[]) cprintf("[TraceDyn] deref: %p\n", p[])
if p[] != nil: if p[] != nil:
var j = cast[ptr GcEnv](env) 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 var markerGeneration: int
proc breakCycles(s: Cell; desc: PNimType) = proc breakCycles(s: Cell; desc: PNimTypeV2) =
let markerColor = if (markerGeneration and 1) == 0: colRed let markerColor = if (markerGeneration and 1) == 0: colRed
else: colYellow else: colYellow
atomicInc markerGeneration 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. ## 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 ## This is a form of cycle collection that works well with Nim's ARC
## and its associated cost model. ## 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[])) breakCycles(head(cast[pointer](x)), getDynamicTypeInfo(x[]))
@ -158,7 +158,7 @@ proc thinout*[T: proc](x: T) {.inline.} =
""".} """.}
let p = rawEnv(x) 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.} = proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =
if p != nil: 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. # According to Lins it's correct to do nothing else here.
#cprintf("[DeCREF] %p\n", p) #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: if p != nil:
var cell = head(p) var cell = head(p)
if (cell.rc and not rcMask) == 0: 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") sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind case mt.kind
of tyString: of tyString:
var x = cast[PPointer](dest) when defined(nimSeqsV2):
var s2 = cast[PPointer](s)[] var x = cast[ptr NimStringV2](dest)
if s2 == nil: var s2 = cast[ptr NimStringV2](s)[]
unsureAsgnRef(x, s2) nimAsgnStrV2(x[], s2)
else: 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: of tySequence:
var s2 = cast[PPointer](src)[] when defined(nimSeqsV2):
var seq = cast[PGenericSeq](s2) deepSeqAssignImpl(genericDeepCopyAux, tab)
var x = cast[PPointer](dest) else:
if s2 == nil: var s2 = cast[PPointer](src)[]
unsureAsgnRef(x, s2) var seq = cast[PGenericSeq](s2)
return var x = cast[PPointer](dest)
sysAssert(dest != nil, "genericDeepCopyAux 3") if s2 == nil:
unsureAsgnRef(x, newSeq(mt, seq.len)) unsureAsgnRef(x, s2)
var dst = cast[ByteAddress](cast[PPointer](dest)[]) return
for i in 0..seq.len-1: sysAssert(dest != nil, "genericDeepCopyAux 3")
genericDeepCopyAux( unsureAsgnRef(x, newSeq(mt, seq.len))
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), var dst = cast[ByteAddress](cast[PPointer](dest)[])
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size), for i in 0..seq.len-1:
mt.base, tab) 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: of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for # we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations: # sequence reallocations:
@ -151,7 +159,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
sysAssert realType == mt, " types do differ" sysAssert realType == mt, " types do differ"
# this version should work for any possible GC: # this version should work for any possible GC:
let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base 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) unsureAsgnRef(cast[PPointer](dest), z)
tab.put(s2, z) tab.put(s2, z)
genericDeepCopyAux(z, s2, typ, tab) genericDeepCopyAux(z, s2, typ, tab)
@ -168,11 +176,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
copyMem(dest, src, mt.size) copyMem(dest, src, mt.size)
proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
GC_disable() when not defined(nimSeqsV2): GC_disable()
var tab = initPtrTable() var tab = initPtrTable()
genericDeepCopyAux(dest, src, mt, tab) genericDeepCopyAux(dest, src, mt, tab)
deinit tab deinit tab
GC_enable() when not defined(nimSeqsV2): GC_enable()
proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} = proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerproc.} =
# also invoked for 'string' # also invoked for 'string'

View file

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

View file

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

View file

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

View file

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

View file

@ -14,7 +14,7 @@ joinable: false pending https://github.com/nim-lang/Nim/issues/9754
import marshal import marshal
template testit(x) = discard $$to[type(x)]($$x) template testit(x) = discard $$to[typeof(x)]($$x)
var x: array[0..4, array[0..4, string]] = [ var x: array[0..4, array[0..4, string]] = [
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
@ -89,8 +89,8 @@ var instance1 = Person(name: "Cletus", age: 12,
bio: "Я Cletus", bio: "Я Cletus",
blob: "ABC\x80") blob: "ABC\x80")
echo($$instance1) echo($$instance1)
echo(to[Person]($$instance1).bio == instance1.bio) echo(to[Person]($$instance1).bio == instance1.bio) # true
echo(to[Person]($$instance1).blob == instance1.blob) echo(to[Person]($$instance1).blob == instance1.blob) # true
# bug 5757 # bug 5757