diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-09-16 14:57:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-16 14:57:01 +0200 |
commit | fd31e8ff6f96527cc52125d01311d022ff82fead (patch) | |
tree | da6f772f157a34fc80316a6ba4888f8cbd730971 | |
parent | 0aaf4e2dfa2d06a71202bd283e99bb017c781f2c (diff) | |
download | Nim-fd31e8ff6f96527cc52125d01311d022ff82fead.tar.gz |
allow old styled RTTI for arc/orc (#15331)
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 83 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 8 | ||||
-rw-r--r-- | compiler/ccgtrav.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 164 | ||||
-rw-r--r-- | compiler/cgen.nim | 9 | ||||
-rw-r--r-- | compiler/cgendata.nim | 2 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 4 | ||||
-rw-r--r-- | compiler/options.nim | 5 | ||||
-rw-r--r-- | lib/core/typeinfo.nim | 167 | ||||
-rw-r--r-- | lib/pure/marshal.nim | 11 | ||||
-rw-r--r-- | lib/system.nim | 59 | ||||
-rw-r--r-- | lib/system/arc.nim | 22 | ||||
-rw-r--r-- | lib/system/assign.nim | 136 | ||||
-rw-r--r-- | lib/system/cellseqs_v2.nim | 6 | ||||
-rw-r--r-- | lib/system/cyclebreaker.nim | 14 | ||||
-rw-r--r-- | lib/system/deepcopy.nim | 52 | ||||
-rw-r--r-- | lib/system/hti.nim | 2 | ||||
-rw-r--r-- | lib/system/mm/malloc.nim | 6 | ||||
-rw-r--r-- | lib/system/orc.nim | 24 | ||||
-rw-r--r-- | lib/system/seqs_v2.nim | 14 | ||||
-rw-r--r-- | lib/system/seqs_v2_reimpl.nim | 17 | ||||
-rw-r--r-- | tests/stdlib/tmarshal.nim | 6 |
23 files changed, 512 insertions, 303 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 8baf49265..4d37b284c 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -680,7 +680,7 @@ type mNBindSym, mNCallSite, mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl, mNGenSym, mNHint, mNWarning, mNError, - mInstantiationInfo, mGetTypeInfo, + mInstantiationInfo, mGetTypeInfo, mGetTypeInfoV2, mNimvm, mIntDefine, mStrDefine, mBoolDefine, mRunnableExamples, mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf, mSymIsInstantiationOf, mNodeId diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 8f45452bf..0d235f62e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -266,10 +266,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = [addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)]) else: 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: 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) = assert d.k != locNone @@ -318,7 +318,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", [addrLoc(p.config, dest), rdLoc(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tyString: if optSeqDestructors in p.config.globalOptions: 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? "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [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: linefmt(p, cpsStmts, # bug #4799, keep the nimCopyMem for a while @@ -425,16 +425,21 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = # XXX optimize this linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", [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: - linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n", - [addrLoc(p.config, dest), rdLoc(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + if optTinyRtti in p.config.globalOptions: + linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n", + [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: linefmt(p, cpsStmts, "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n", [addrLoc(p.config, dest), addrLocOrTemp(src), - genTypeInfo(p.module, dest.t, dest.lode.info)]) + genTypeInfoV1(p.module, dest.t, dest.lode.info)]) of tySet: if mapSetType(p.config, ty) == ctArray: 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)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), getTypeDesc(p.module, e[1].typ), - genTypeInfo(p.module, seqType, e.info)]) + genTypeInfoV1(p.module, seqType, e.info)]) else: const seqAppendPattern = "($2) #incrSeqV3($1, $3)" call.r = ropecg(p.module, seqAppendPattern, [rdLoc(a), 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 # use 'genRefAssign' for the seq. genRefAssign(p, a, call) @@ -1254,7 +1259,7 @@ proc genReset(p: BProc, n: PNode) = when false: linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", [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) = 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]) genAssignment(p, a, b, {}) 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): # 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 @@ -1339,18 +1344,18 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = if p.config.selectedGC == gcGo: # we need the write barrier 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]) else: 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]) else: if lenIsZero: call.r = rope"NIM_NIL" else: 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, {}) 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, "($1)#nimNewSeqOfCap($2, $3)", [ getTypeDesc(p.module, seqtype), - genTypeInfo(p.module, seqtype, e.info), a.rdLoc])) + genTypeInfoV1(p.module, seqtype, e.info), a.rdLoc])) gcUsage(p.config, e) 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[2], f) 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)]) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ 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)", [a, genTypeInfo2Name(p.module, dest)]) 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: - 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 tfObjHasKids notin dest.flags): result = "$1.m_type == $2" % [a, ti] @@ -1583,7 +1591,7 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope = when false: # former version: 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) = var a: TLoc @@ -1633,12 +1641,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyEnum, tyOrdinal: putIntoDest(p, d, e, 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: putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage) of tySet: 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: var b: TLoc 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()") putIntoDest(p, d, e, 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: putIntoDest(p, d, e, 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: localError(p.config, e.info, "'repr' doesn't support 'void' type") else: 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) 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) var t = skipTypes(a.t, abstractInst) 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") t = skipTypes(t[0], skipPtrs) result.add ".m_type" + if optTinyRtti in p.config.globalOptions and enforceV1: + result.add "->typeInfoV1" proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) = 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 if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo": # 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: var a: TLoc 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)" call.r = ropecg(p.module, setLenPattern, [ 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: const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" call.r = ropecg(p.module, setLenPattern, [ 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, {}) 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 mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) + of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d) of mSwap: genSwap(p, e, d) of mInc, mDec: 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: genTypeInfo2Name(p.module, dest) else: - genTypeInfo(p.module, dest, n.info) + genTypeInfoV1(p.module, dest, n.info) if nilCheck != nil: linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); $4}$n", [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) result.add "}" 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 getNullValueAux(p, t, obj, constOrNil, result, count, isConst, info) # do not emit '{}' as that is not valid C: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 48c024b1f..5bed7cf32 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1040,7 +1040,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let checkFor = if optTinyRtti in p.config.globalOptions: genTypeInfo2Name(p.module, typeNode.typ) 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" 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: genTypeInfo2Name(p.module, t[i][j].typ) 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" 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: genTypeInfo2Name(p.module, t[i][j].typ) 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" 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) = var t = skipTypes(objtype, abstractVar) 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): appcg(p.module, cfsVars, "extern $1", [discriminatorTableDecl(p.module, t, field)]) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 63b1cb88a..29b93e530 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -173,7 +173,7 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash): Rope = [result, markerName, getModuleDllPath(m)]) 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 p = newProc(nil, m) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index aa92b8534..771e1ede9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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: appcg(m, result, " {$n", []) 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 elif m.compileToCpp: appcg(m, result, " : public $1 {$n", @@ -1004,7 +1007,7 @@ proc genProcHeader(m: BModule, prc: PSym, asPtr: bool = false): Rope = # ------------------ 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 = result = "$1[$2]" % [m.typeNodesName, rope(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): base = rope("0") else: - base = genTypeInfo(m, x, info) + base = genTypeInfoV1(m, x, info) else: base = rope("0") 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.name = $5;$n" & "$1.sons = &$6[0];$n" & "$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), tmp, rope(L)]) 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" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$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") 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.typ = $4;$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", [expr, rope(typ.len), tmp]) else: @@ -1255,7 +1258,7 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) = [tmp, rope(firstOrd(m.config, typ)), tiNameForHcr(m, name)]) 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 = # 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", [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: - m.s[cfsData].addf("static TNimType* $1;$n", [str]) - m.s[cfsTypeInit1].addf("\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n", - [str, getModuleDllPath(m, ownerModule)]) + m.s[cfsData].addf("static $2* $1;$n", [str, nr]) + m.s[cfsTypeInit1].addf("\t$1 = ($3*)hcrGetGlobal($2, \"$1\");$n", + [str, getModuleDllPath(m, ownerModule), nr]) 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 = 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") 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 if t.kind == tyObject: if incompleteType(t): @@ -1337,8 +1341,8 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) else: typeName = rope("NIM_NIL") - discard cgsym(m, "TNimType") - m.s[cfsData].addf("N_LIB_PRIVATE TNimType $1;$n", [name]) + discard cgsym(m, "TNimTypeV2") + m.s[cfsData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name]) let destroyImpl = genHook(m, t, info, attachedDestructor) let traceImpl = genHook(m, t, info, attachedTrace) 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, 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 var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses) @@ -1362,7 +1402,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = if marker.str != nil: discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") - declareNimType(m, marker.str, marker.owner) + declareNimType(m, "TNimType", marker.str, marker.owner) # also store in local type section: m.typeInfoMarker[sig] = marker.str return prefixTI.rope & marker.str & ")".rope @@ -1374,63 +1414,65 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = if owner != m.module: # make sure the type info is created in the owner module 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 discard cgsym(m, "TNimType") discard cgsym(m, "TNimNode") - declareNimType(m, result, owner) + declareNimType(m, "TNimType", result, owner) return prefixTI.rope & result & ")".rope m.g.typeInfoMarker[sig] = (str: result, owner: owner) - if optTinyRtti in m.config.globalOptions: - genTypeInfoV2(m, t, origType, result, info) - else: - case t.kind - of tyEmpty, tyVoid: result = rope"0" - of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + case t.kind + of tyEmpty, tyVoid: result = rope"0" + of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar, tyLent: + genTypeInfoAuxBase(m, t, t, result, rope"0", info) + of tyStatic: + 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) - of tyStatic: - if t.n != nil: result = genTypeInfo(m, lastSon t, info) - else: internalError(m.config, "genTypeInfo(" & $t.kind & ')') - of tyUserTypeClasses: - internalAssert m.config, t.isResolvedUserTypeClass - return genTypeInfo(m, t.lastSon, info) - of tyProc: - if t.callConv != ccClosure: - genTypeInfoAuxBase(m, t, t, result, rope"0", info) - else: - let x = fakeClosureType(m, t.owner) - genTupleInfo(m, x, x, result, info) - of tySequence: - genTypeInfoAux(m, t, t, result, info) - if optSeqDestructors notin m.config.globalOptions: - if m.config.selectedGC >= gcMarkAndSweep: - let markerProc = genTraverseProc(m, origType, sig) - m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) - of tyRef: - genTypeInfoAux(m, t, t, result, info) - if m.config.selectedGC >= gcMarkAndSweep: - let markerProc = genTraverseProc(m, origType, sig) - m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) - of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) - of tyArray: genArrayInfo(m, t, result, info) - of tySet: genSetInfo(m, t, result, info) - 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 & ')') + else: + let x = fakeClosureType(m, t.owner) + genTupleInfo(m, x, x, result, info) + of tySequence: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyRef: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc]) + of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info) + of tyArray: genArrayInfo(m, t, result, info) + of tySet: genSetInfo(m, t, result, info) + 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, "genTypeInfoV1(" & $t.kind & ')') if t.attachedOps[attachedDeepCopy] != nil: genDeepCopyProc(m, t.attachedOps[attachedDeepCopy], result) elif origType.attachedOps[attachedDeepCopy] != nil: 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 proc genTypeSection(m: BModule, n: PNode) = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index d5e1e020c..242d1f89b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -360,7 +360,10 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, while s.kind == tyObject and s[0] != nil: r.add(".Sup") 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: if optTinyRtti in p.config.globalOptions: var tmp: TLoc @@ -376,7 +379,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc, else: # worst case for performance: 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): var r = rdLoc(a) @@ -417,7 +420,7 @@ proc resetLoc(p: BProc, loc: var TLoc) = specializeReset(p, loc) when false: 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 # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, constructObj) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 3384558f8..8e5094336 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -122,6 +122,7 @@ type forwardedProcs*: seq[PSym] # proc:s that did not yet have a body generatedHeader*: BModule typeInfoMarker*: TypeCacheWithOwner + typeInfoMarkerV2*: TypeCacheWithOwner config*: ConfigRef graph*: ModuleGraph 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 headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information + typeInfoMarkerV2*: TypeCache initProc*: BProc # code for init procedure preInitProc*: BProc # code executed before the init proc hcrCreateTypeInfosProc*: Rope # type info globals are in here when HCR=on diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index 3d0635761..dd5332b38 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -523,7 +523,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = var cond: PNode if isCyclic: 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) cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, x, typInfo) else: @@ -546,7 +546,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDeepCopy: assert(false, "cannot happen") of attachedTrace: 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) body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y) else: diff --git a/compiler/options.nim b/compiler/options.nim index 5b23ac9af..03418d953 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -136,9 +136,8 @@ type cmdCompileToBackend, # compile to backend in TBackend TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcArc, gcOrc, - gcHooks, - gcRefc, gcV2, gcGo + gcUnselected, gcNone, gcBoehm, gcRegions, gcArc, gcOrc, + gcMarkAndSweep, gcHooks, gcRefc, gcV2, gcGo # gcRefc and the GCs that follow it use a write barrier, # as far as usesWriteBarrier() is concerned diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 01588e9eb..b1b9bcb27 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -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. diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index b6ad2e20f..e74e68b05 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -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"], diff --git a/lib/system.nim b/lib/system.nim index 0a8c52908..c05ca24dc 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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 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 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] 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`. diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 7fe17d3ea..68376cdab 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -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") diff --git a/lib/system/assign.nim b/lib/system/assign.nim index ff4ac021e..d332124cd 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -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) diff --git a/lib/system/cellseqs_v2.nim b/lib/system/cellseqs_v2.nim index b2ae41d73..fdd9e3099 100644 --- a/lib/system/cellseqs_v2.nim +++ b/lib/system/cellseqs_v2.nim @@ -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 diff --git a/lib/system/cyclebreaker.nim b/lib/system/cyclebreaker.nim index 3d01eeb9d..c4d802a92 100644 --- a/lib/system/cyclebreaker.nim +++ b/lib/system/cyclebreaker.nim @@ -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: diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index 801821d26..5905b5785 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -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' diff --git a/lib/system/hti.nim b/lib/system/hti.nim index b77f7ccde..3dbcd7615 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -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 diff --git a/lib/system/mm/malloc.nim b/lib/system/mm/malloc.nim index 3dad98e93..2ba5c0fec 100644 --- a/lib/system/mm/malloc.nim +++ b/lib/system/mm/malloc.nim @@ -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, diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 7500ba374..4ba462c1f 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -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: diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim index 3c94a03f9..111299fff 100644 --- a/lib/system/seqs_v2.nim +++ b/lib/system/seqs_v2.nim @@ -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 +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: [].} = + noSideEffect, raises: [], compilerRtl.} = {.noSideEffect.}: - template `+!`(p: pointer, s: int): pointer = - cast[pointer](cast[int](p) +% s) - let headerSize = align(sizeof(NimSeqPayloadBase), elemAlign) if addlen <= 0: result = p diff --git a/lib/system/seqs_v2_reimpl.nim b/lib/system/seqs_v2_reimpl.nim new file mode 100644 index 000000000..750f78c0d --- /dev/null +++ b/lib/system/seqs_v2_reimpl.nim @@ -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 diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 118d0ae02..fc5703a03 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -14,7 +14,7 @@ joinable: false pending https://github.com/nim-lang/Nim/issues/9754 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]] = [ ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], @@ -89,8 +89,8 @@ var instance1 = Person(name: "Cletus", age: 12, bio: "Я Cletus", blob: "ABC\x80") echo($$instance1) -echo(to[Person]($$instance1).bio == instance1.bio) -echo(to[Person]($$instance1).blob == instance1.blob) +echo(to[Person]($$instance1).bio == instance1.bio) # true +echo(to[Person]($$instance1).blob == instance1.blob) # true # bug 5757 |