--newruntime: work in progress
This commit is contained in:
parent
79b1eafa59
commit
2ab6b2c657
13 changed files with 566 additions and 233 deletions
|
|
@ -1165,9 +1165,13 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
assert refType.kind == tyRef
|
assert refType.kind == tyRef
|
||||||
let bt = refType.lastSon
|
let bt = refType.lastSon
|
||||||
if sizeExpr.isNil:
|
if sizeExpr.isNil:
|
||||||
sizeExpr = "sizeof($1)" %
|
sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)]
|
||||||
[getTypeDesc(p.module, bt)]
|
|
||||||
|
|
||||||
|
if optNimV2 in p.config.globalOptions:
|
||||||
|
b.r = ropecg(p.module, "($1) #nimNewObj($2)",
|
||||||
|
[getTypeDesc(p.module, typ), sizeExpr])
|
||||||
|
genAssignment(p, a, b, {})
|
||||||
|
else:
|
||||||
let ti = genTypeInfo(p.module, typ, a.lode.info)
|
let ti = genTypeInfo(p.module, typ, a.lode.info)
|
||||||
if bt.destructor != nil:
|
if bt.destructor != nil:
|
||||||
# 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
|
||||||
|
|
@ -1198,7 +1202,8 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
|
linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
|
||||||
else:
|
else:
|
||||||
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
||||||
genAssignment(p, a, b, {}) # set the object type:
|
genAssignment(p, a, b, {})
|
||||||
|
# set the object type:
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, false)
|
||||||
|
|
||||||
proc genNew(p: BProc, e: PNode) =
|
proc genNew(p: BProc, e: PNode) =
|
||||||
|
|
@ -1433,6 +1438,10 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
gcUsage(p.config, e)
|
gcUsage(p.config, e)
|
||||||
|
|
||||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
||||||
|
if optNimV2 in p.config.globalOptions:
|
||||||
|
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 'genTypeInfo' 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 = genTypeInfo(p.module, dest, info)
|
||||||
|
|
@ -1925,12 +1934,58 @@ proc genWasMoved(p: BProc; n: PNode) =
|
||||||
# addrLoc(p.config, a), getTypeDesc(p.module, a.t))
|
# addrLoc(p.config, a), getTypeDesc(p.module, a.t))
|
||||||
|
|
||||||
proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
proc genMove(p: BProc; n: PNode; d: var TLoc) =
|
||||||
if d.k == locNone: getTemp(p, n.typ, d)
|
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n[1].skipAddr, a)
|
initLocExpr(p, n[1].skipAddr, a)
|
||||||
|
if n.len == 4:
|
||||||
|
# generated by liftdestructors:
|
||||||
|
var src, destroyCall: TLoc
|
||||||
|
initLocExpr(p, n[2], src)
|
||||||
|
initLocExpr(p, n[3], destroyCall)
|
||||||
|
linefmt(p, cpsStmts, "if ($1.len && $1.p != $2.p) { $3; }$n" &
|
||||||
|
"$1.len = $2.len; $1.p = $2.p;$n",
|
||||||
|
[rdLoc(a), rdLoc(src), rdLoc(destroyCall)])
|
||||||
|
else:
|
||||||
|
if d.k == locNone: getTemp(p, n.typ, d)
|
||||||
genAssignment(p, d, a, {})
|
genAssignment(p, d, a, {})
|
||||||
resetLoc(p, a)
|
resetLoc(p, a)
|
||||||
|
|
||||||
|
proc genDestroy(p: BProc; n: PNode) =
|
||||||
|
if optNimV2 in p.config.globalOptions:
|
||||||
|
let t = n[1].typ.skipTypes(abstractInst)
|
||||||
|
case t.kind
|
||||||
|
of tyString:
|
||||||
|
var a: TLoc
|
||||||
|
initLocExpr(p, n[1].skipAddr, a)
|
||||||
|
linefmt(p, cpsStmts, "if ($1.len && $1.region) {$n" &
|
||||||
|
" $1.region->dealloc($1.region, $1.p, $1.p->cap + 1 + sizeof(NI) + sizeof(void*)); }$n",
|
||||||
|
[rdLoc(a)])
|
||||||
|
of tySequence:
|
||||||
|
var a: TLoc
|
||||||
|
initLocExpr(p, n[1].skipAddr, a)
|
||||||
|
linefmt(p, cpsStmts, "if ($1.len && $1.region) {$n" &
|
||||||
|
" $1.region->dealloc($1.region, $1.p, ($1.p->cap * sizeof($2)) + sizeof(NI) + sizeof(void*)); }$n",
|
||||||
|
[rdLoc(a), getTypeDesc(p.module, t.lastSon)])
|
||||||
|
else: discard "nothing to do"
|
||||||
|
else:
|
||||||
|
discard "ignore calls to the default destructor"
|
||||||
|
|
||||||
|
proc genDispose(p: BProc; n: PNode) =
|
||||||
|
when false:
|
||||||
|
let elemType = n[1].typ.skipTypes(abstractVarInst).lastSon
|
||||||
|
|
||||||
|
var a: TLoc
|
||||||
|
initLocExpr(p, n[1].skipAddr, a)
|
||||||
|
|
||||||
|
if isFinal(elemType):
|
||||||
|
if elemType.destructor != nil:
|
||||||
|
var destroyCall = newNodeI(nkCall, n.info)
|
||||||
|
genStmts(p, destroyCall)
|
||||||
|
lineCg(p, cpsStmts, "#nimRawDispose($#)", rdLoc(a))
|
||||||
|
else:
|
||||||
|
# ``nimRawDisposeVirtual`` calls the ``finalizer`` which is the same as the
|
||||||
|
# destructor, but it uses the runtime type. Afterwards the memory is freed:
|
||||||
|
lineCg(p, cpsStmts, "#nimDestroyAndDispose($#)", rdLoc(a))
|
||||||
|
|
||||||
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
case op
|
case op
|
||||||
of mOr, mAnd: genAndOr(p, e, d, op)
|
of mOr, mAnd: genAndOr(p, e, d, op)
|
||||||
|
|
@ -2090,7 +2145,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mDotDot, mEqCString: genCall(p, e, d)
|
of mDotDot, mEqCString: genCall(p, e, d)
|
||||||
of mWasMoved: genWasMoved(p, e)
|
of mWasMoved: genWasMoved(p, e)
|
||||||
of mMove: genMove(p, e, d)
|
of mMove: genMove(p, e, d)
|
||||||
of mDestroy: discard "ignore calls to the default destructor"
|
of mDestroy: genDestroy(p, e)
|
||||||
of mSlice:
|
of mSlice:
|
||||||
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
|
localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
|
||||||
" 'toOpenArray' is only valid within a call expression")
|
" 'toOpenArray' is only valid within a call expression")
|
||||||
|
|
@ -2250,12 +2305,16 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
while t.kind == tyObject and t.sons[0] != nil:
|
while t.kind == tyObject and t.sons[0] != nil:
|
||||||
add(r, ".Sup")
|
add(r, ".Sup")
|
||||||
t = skipTypes(t.sons[0], skipPtrs)
|
t = skipTypes(t.sons[0], skipPtrs)
|
||||||
|
let checkFor = if optNimV2 in p.config.globalOptions:
|
||||||
|
genTypeInfo2Name(p.module, dest)
|
||||||
|
else:
|
||||||
|
genTypeInfo(p.module, dest, n.info)
|
||||||
if nilCheck != nil:
|
if nilCheck != nil:
|
||||||
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
|
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
|
||||||
nilCheck, r, genTypeInfo(p.module, dest, n.info))
|
nilCheck, r, checkFor)
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
|
linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
|
||||||
r, genTypeInfo(p.module, dest, n.info))
|
r, checkFor)
|
||||||
if n.sons[0].typ.kind != tyObject:
|
if n.sons[0].typ.kind != tyObject:
|
||||||
putIntoDest(p, d, n,
|
putIntoDest(p, d, n,
|
||||||
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
|
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
|
||||||
|
|
|
||||||
|
|
@ -1039,8 +1039,12 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
let isObjFormat = if not p.module.compileToCpp:
|
let isObjFormat = if not p.module.compileToCpp:
|
||||||
"#isObj(#getCurrentException()->Sup.m_type, $1)"
|
"#isObj(#getCurrentException()->Sup.m_type, $1)"
|
||||||
else: "#isObj(#getCurrentException()->m_type, $1)"
|
else: "#isObj(#getCurrentException()->m_type, $1)"
|
||||||
appcg(p.module, orExpr, isObjFormat,
|
|
||||||
[genTypeInfo(p.module, t[i][j].typ, t[i][j].info)])
|
let checkFor = if optNimV2 in p.config.globalOptions:
|
||||||
|
genTypeInfo2Name(p.module, t[i][j].typ)
|
||||||
|
else:
|
||||||
|
genTypeInfo(p.module, t[i][j].typ, t[i][j].info)
|
||||||
|
appcg(p.module, orExpr, isObjFormat, [checkFor])
|
||||||
if i > 1: line(p, cpsStmts, "else ")
|
if i > 1: line(p, cpsStmts, "else ")
|
||||||
startBlock(p, "if ($1) {$n", [orExpr])
|
startBlock(p, "if ($1) {$n", [orExpr])
|
||||||
if not quirkyExceptions:
|
if not quirkyExceptions:
|
||||||
|
|
|
||||||
|
|
@ -1204,6 +1204,60 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||||
addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
addf(m.s[cfsTypeInit3], "$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) =
|
||||||
|
if m.hcrOn:
|
||||||
|
addf(m.s[cfsVars], "static TNimType* $1;$n", [str])
|
||||||
|
addf(m.s[cfsTypeInit1], "\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
|
||||||
|
[str, getModuleDllPath(m, ownerModule)])
|
||||||
|
else:
|
||||||
|
addf(m.s[cfsVars], "extern TNimType $1;$n", [str])
|
||||||
|
|
||||||
|
proc genTypeInfo2Name(m: BModule; t: PType): Rope =
|
||||||
|
var res = "|"
|
||||||
|
var it = t
|
||||||
|
while it != nil:
|
||||||
|
it = it.skipTypes(skipPtrs)
|
||||||
|
if it.sym != nil:
|
||||||
|
var m = t.sym.owner
|
||||||
|
while m != nil and m.kind != skModule: m = m.owner
|
||||||
|
if m == nil or sfSystemModule in m.flags:
|
||||||
|
# produce short names for system types:
|
||||||
|
res.add it.sym.name.s
|
||||||
|
else:
|
||||||
|
var p = m.owner
|
||||||
|
if p != nil and p.kind == skPackage:
|
||||||
|
res.add p.name.s & "."
|
||||||
|
res.add m.name.s & "."
|
||||||
|
res.add it.sym.name.s
|
||||||
|
else:
|
||||||
|
res.add $hashType(it)
|
||||||
|
res.add "|"
|
||||||
|
it = it.sons[0]
|
||||||
|
result = makeCString(res)
|
||||||
|
|
||||||
|
proc genObjectInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =
|
||||||
|
assert t.kind == tyObject
|
||||||
|
if incompleteType(t):
|
||||||
|
localError(m.config, info, "request for RTTI generation for incomplete object: " &
|
||||||
|
typeToString(t))
|
||||||
|
|
||||||
|
var d: Rope
|
||||||
|
if t.destructor != nil:
|
||||||
|
# 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
|
||||||
|
# convention at least:
|
||||||
|
if t.destructor.typ == nil or t.destructor.typ.callConv != ccDefault:
|
||||||
|
localError(m.config, info,
|
||||||
|
"the destructor that is turned into a finalizer needs " &
|
||||||
|
"to have the 'nimcall' calling convention")
|
||||||
|
genProc(m, t.destructor)
|
||||||
|
d = t.destructor.loc.r
|
||||||
|
else:
|
||||||
|
d = rope("NIM_NIL")
|
||||||
|
|
||||||
|
addf(m.s[cfsTypeInit3], "$1.destructor = $2; $1.size = sizeof($3); $1.name = $4;$n", [
|
||||||
|
name, d, getTypeDesc(m, t), genTypeInfo2Name(m, t)])
|
||||||
|
|
||||||
proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
proc genTypeInfo(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)
|
||||||
|
|
@ -1215,14 +1269,6 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||||
if result != nil:
|
if result != nil:
|
||||||
return prefixTI.rope & result & ")".rope
|
return prefixTI.rope & result & ")".rope
|
||||||
|
|
||||||
proc declareNimType(m: BModule, str: Rope, ownerModule: PSym) =
|
|
||||||
if m.hcrOn:
|
|
||||||
addf(m.s[cfsVars], "static TNimType* $1;$n", [str])
|
|
||||||
addf(m.s[cfsTypeInit1], "\t$1 = (TNimType*)hcrGetGlobal($2, \"$1\");$n",
|
|
||||||
[str, getModuleDllPath(m, ownerModule)])
|
|
||||||
else:
|
|
||||||
addf(m.s[cfsVars], "extern TNimType $1;$n", [str])
|
|
||||||
|
|
||||||
let marker = m.g.typeInfoMarker.getOrDefault(sig)
|
let marker = m.g.typeInfoMarker.getOrDefault(sig)
|
||||||
if marker.str != nil:
|
if marker.str != nil:
|
||||||
discard cgsym(m, "TNimType")
|
discard cgsym(m, "TNimType")
|
||||||
|
|
@ -1278,7 +1324,11 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
|
||||||
of tyArray: genArrayInfo(m, t, result, info)
|
of tyArray: genArrayInfo(m, t, result, info)
|
||||||
of tySet: genSetInfo(m, t, result, info)
|
of tySet: genSetInfo(m, t, result, info)
|
||||||
of tyEnum: genEnumInfo(m, t, result, info)
|
of tyEnum: genEnumInfo(m, t, result, info)
|
||||||
of tyObject: genObjectInfo(m, t, origType, result, info)
|
of tyObject:
|
||||||
|
if optNimV2 in m.config.globalOptions:
|
||||||
|
genObjectInfoV2(m, t, origType, result, info)
|
||||||
|
else:
|
||||||
|
genObjectInfo(m, t, origType, result, info)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
# if t.n != nil: genObjectInfo(m, t, result)
|
# if t.n != nil: genObjectInfo(m, t, result)
|
||||||
# else:
|
# else:
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||||
includeHeader(p.module, "<new>")
|
includeHeader(p.module, "<new>")
|
||||||
linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
|
linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
|
||||||
|
|
||||||
if optNimV2 in p.config.globalOptions: return
|
#if optNimV2 in p.config.globalOptions: return
|
||||||
case analyseObjectWithTypeField(t)
|
case analyseObjectWithTypeField(t)
|
||||||
of frNone:
|
of frNone:
|
||||||
discard
|
discard
|
||||||
|
|
|
||||||
|
|
@ -740,6 +740,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
incl(conf.features, destructor)
|
incl(conf.features, destructor)
|
||||||
incl(conf.globalOptions, optNimV2)
|
incl(conf.globalOptions, optNimV2)
|
||||||
defineSymbol(conf.symbols, "nimV2")
|
defineSymbol(conf.symbols, "nimV2")
|
||||||
|
conf.selectedGC = gcDestructors
|
||||||
|
defineSymbol(conf.symbols, "gcdestructors")
|
||||||
of "stylecheck":
|
of "stylecheck":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
|
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
|
||||||
|
|
|
||||||
|
|
@ -113,9 +113,13 @@ proc destructorCall(g: ModuleGraph; op: PSym; x: PNode): PNode =
|
||||||
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
||||||
result = newAsgnStmt(x, newOpCall(op, y))
|
result = newAsgnStmt(x, newOpCall(op, y))
|
||||||
|
|
||||||
|
proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
|
||||||
|
result = optNimV2 in c.graph.config.globalOptions and
|
||||||
|
(tfHasGCedMem in t.flags or t.isGCedMem)
|
||||||
|
|
||||||
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||||
field: PSym): bool =
|
field: PSym): bool =
|
||||||
if tfHasAsgn in t.flags:
|
if tfHasAsgn in t.flags or useNoGc(c, t):
|
||||||
var op: PSym
|
var op: PSym
|
||||||
if sameType(t, c.asgnForType):
|
if sameType(t, c.asgnForType):
|
||||||
# generate recursive call:
|
# generate recursive call:
|
||||||
|
|
@ -136,15 +140,28 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||||
body.add newAsgnCall(c.graph, op, x, y)
|
body.add newAsgnCall(c.graph, op, x, y)
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
proc addDestructorCall(c: var TLiftCtx; t: PType; body, x: PNode): bool =
|
||||||
case c.kind
|
|
||||||
of attachedDestructor:
|
|
||||||
let op = t.destructor
|
let op = t.destructor
|
||||||
if op != nil:
|
if op != nil:
|
||||||
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||||
onUse(c.info, op)
|
onUse(c.info, op)
|
||||||
body.add destructorCall(c.graph, op, x)
|
body.add destructorCall(c.graph, op, x)
|
||||||
result = true
|
result = true
|
||||||
|
elif useNoGc(c, t):
|
||||||
|
if sameType(t, c.asgnForType) and c.kind == attachedDestructor:
|
||||||
|
let op = c.fn
|
||||||
|
markUsed(c.graph.config, c.info, op, c.graph.usageSym)
|
||||||
|
onUse(c.info, op)
|
||||||
|
body.add destructorCall(c.graph, op, x)
|
||||||
|
result = true
|
||||||
|
else:
|
||||||
|
internalError(c.graph.config, c.info,
|
||||||
|
"type-bound operator could not be resolved")
|
||||||
|
|
||||||
|
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||||
|
case c.kind
|
||||||
|
of attachedDestructor:
|
||||||
|
result = addDestructorCall(c, t, body, x)
|
||||||
of attachedAsgn:
|
of attachedAsgn:
|
||||||
result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
|
result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
|
||||||
of attachedSink:
|
of attachedSink:
|
||||||
|
|
@ -185,12 +202,15 @@ proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
|
||||||
|
|
||||||
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
|
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
|
||||||
result = newNodeI(nkWhileStmt, c.info, 2)
|
result = newNodeI(nkWhileStmt, c.info, 2)
|
||||||
let cmp = genBuiltin(c.graph, mLeI, "<=", i)
|
let cmp = genBuiltin(c.graph, mLtI, "<", i)
|
||||||
cmp.add genHigh(c.graph, dest)
|
cmp.add genLen(c.graph, dest)
|
||||||
cmp.typ = getSysType(c.graph, c.info, tyBool)
|
cmp.typ = getSysType(c.graph, c.info, tyBool)
|
||||||
result.sons[0] = cmp
|
result.sons[0] = cmp
|
||||||
result.sons[1] = newNodeI(nkStmtList, c.info)
|
result.sons[1] = newNodeI(nkStmtList, c.info)
|
||||||
|
|
||||||
|
proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
|
||||||
|
result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
|
||||||
|
|
||||||
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
|
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
|
||||||
let incCall = genBuiltin(c.graph, mInc, "inc", i)
|
let incCall = genBuiltin(c.graph, mInc, "inc", i)
|
||||||
incCall.add lowerings.newIntLit(c.graph, c.info, 1)
|
incCall.add lowerings.newIntLit(c.graph, c.info, 1)
|
||||||
|
|
@ -203,42 +223,166 @@ proc newSeqCall(g: ModuleGraph; x, y: PNode): PNode =
|
||||||
lenCall.typ = getSysType(g, x.info, tyInt)
|
lenCall.typ = getSysType(g, x.info, tyInt)
|
||||||
result.add lenCall
|
result.add lenCall
|
||||||
|
|
||||||
|
proc setLenCall(g: ModuleGraph; x, y: PNode): PNode =
|
||||||
|
let lenCall = genBuiltin(g, mLengthSeq, "len", y)
|
||||||
|
lenCall.typ = getSysType(g, x.info, tyInt)
|
||||||
|
result = genBuiltin(g, mSetLengthSeq, "setLen", genAddr(g, x))
|
||||||
|
result.add lenCall
|
||||||
|
|
||||||
|
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
let i = declareCounter(c, body, firstOrd(c.graph.config, t))
|
||||||
|
let whileLoop = genWhileLoop(c, i, x)
|
||||||
|
let elemType = t.lastSon
|
||||||
|
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
|
||||||
|
y.at(i, elemType))
|
||||||
|
addIncStmt(c, whileLoop.sons[1], i)
|
||||||
|
body.add whileLoop
|
||||||
|
|
||||||
|
proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
case c.kind
|
||||||
|
of attachedAsgn, attachedDeepCopy:
|
||||||
|
# we generate:
|
||||||
|
# setLen(dest, y.len)
|
||||||
|
# var i = 0
|
||||||
|
# while i < y.len: dest[i] = y[i]; inc(i)
|
||||||
|
# This is usually more efficient than a destroy/create pair.
|
||||||
|
body.add setLenCall(c.graph, x, y)
|
||||||
|
forallElements(c, t, body, x, y)
|
||||||
|
of attachedSink:
|
||||||
|
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
||||||
|
moveCall.add y
|
||||||
|
doAssert t.destructor != nil
|
||||||
|
moveCall.add destructorCall(c.graph, t.destructor, x)
|
||||||
|
body.add moveCall
|
||||||
|
when false:
|
||||||
|
# we generate:
|
||||||
|
# if a.len != 0 and a.p != b.p:
|
||||||
|
# `=destroy`(x)
|
||||||
|
# a.len = b.len
|
||||||
|
# a.p = b.p
|
||||||
|
# Note: '@' is either '.' or '->'.
|
||||||
|
body.add genIf(c, genVerbatim("dest@len != 0 && dest@p != src.p", c.info),
|
||||||
|
destructorCall(c.graph, t.destructor, x))
|
||||||
|
body.add genVerbatim("dest@len=src.len; dest@p=src.p;", c.info)
|
||||||
|
of attachedDestructor:
|
||||||
|
# destroy all elements:
|
||||||
|
forallElements(c, t, body, x, y)
|
||||||
|
body.add genBuiltin(c.graph, mDestroy, "destroy", x)
|
||||||
|
when false:
|
||||||
|
var deallocStmt = genVerbatim("dest@region->dealloc(dest@region, dest@p, " &
|
||||||
|
"(dest@p->cap * sizeof($)) + sizeof(NI) + sizeof(void*)); dest@len = 0;", c.info)
|
||||||
|
deallocStmt.typ = t.lastSon
|
||||||
|
body.add genIf(c, genVerbatim("dest@len != 0 && dest@region", c.info), deallocStmt)
|
||||||
|
|
||||||
|
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
seqOp(c, t, body, x, y)
|
||||||
|
|
||||||
|
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
case c.kind
|
||||||
|
of attachedSink:
|
||||||
|
# we 'nil' y out afterwards so we *need* to take over its reference
|
||||||
|
# count value:
|
||||||
|
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||||
|
body.add newAsgnStmt(x, y)
|
||||||
|
of attachedAsgn:
|
||||||
|
body.add callCodegenProc(c.graph, "nimIncWeakRef", c.info, y)
|
||||||
|
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||||
|
body.add newAsgnStmt(x, y)
|
||||||
|
of attachedDestructor:
|
||||||
|
body.add genIf(c, x, callCodegenProc(c.graph, "nimDecWeakRef", c.info, x))
|
||||||
|
of attachedDeepCopy: assert(false, "cannot happen")
|
||||||
|
|
||||||
|
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
var actions = newNodeI(nkStmtList, c.info)
|
||||||
|
|
||||||
|
let elemType = t.lastSon
|
||||||
|
#liftBodyAux(c, elemType, actions, genDeref(x), genDeref(y))
|
||||||
|
#var disposeCall = genBuiltin(c.graph, mDispose, "dispose", x)
|
||||||
|
|
||||||
|
if isFinal(elemType):
|
||||||
|
discard addDestructorCall(c, elemType, actions, x)
|
||||||
|
actions.add callCodegenProc(c.graph, "nimRawDispose", c.info, x)
|
||||||
|
else:
|
||||||
|
discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), x)
|
||||||
|
actions.add callCodegenProc(c.graph, "nimDestroyAndDispose", c.info, x)
|
||||||
|
|
||||||
|
case c.kind
|
||||||
|
of attachedSink, attachedAsgn:
|
||||||
|
body.add genIf(c, x, actions)
|
||||||
|
body.add newAsgnStmt(x, y)
|
||||||
|
of attachedDestructor:
|
||||||
|
body.add genIf(c, x, actions)
|
||||||
|
of attachedDeepCopy: assert(false, "cannot happen")
|
||||||
|
|
||||||
|
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
if c.kind == attachedDeepCopy:
|
||||||
|
# a big problem is that we don't know the enviroment's type here, so we
|
||||||
|
# have to go through some indirection; we delegate this to the codegen:
|
||||||
|
let call = newNodeI(nkCall, c.info, 2)
|
||||||
|
call.typ = t
|
||||||
|
call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy))
|
||||||
|
call.sons[1] = y
|
||||||
|
body.add newAsgnStmt(x, call)
|
||||||
|
elif optNimV2 in c.graph.config.globalOptions:
|
||||||
|
case c.kind
|
||||||
|
of attachedSink, attachedAsgn: discard
|
||||||
|
of attachedDestructor: discard
|
||||||
|
of attachedDeepCopy: assert(false, "cannot happen")
|
||||||
|
|
||||||
|
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
|
discard "to implement"
|
||||||
|
|
||||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyNone, tyEmpty, tyVoid: discard
|
of tyNone, tyEmpty, tyVoid: discard
|
||||||
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
|
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
|
||||||
tyPtr, tyRef, tyOpt, tyUncheckedArray:
|
tyPtr, tyOpt, tyUncheckedArray:
|
||||||
defaultOp(c, t, body, x, y)
|
defaultOp(c, t, body, x, y)
|
||||||
|
of tyRef:
|
||||||
|
if optNimV2 in c.graph.config.globalOptions:
|
||||||
|
weakrefOp(c, t, body, x, y)
|
||||||
|
else:
|
||||||
|
defaultOp(c, t, body, x, y)
|
||||||
|
of tyProc:
|
||||||
|
if t.callConv == ccClosure:
|
||||||
|
closureOp(c, t, body, x, y)
|
||||||
|
else:
|
||||||
|
defaultOp(c, t, body, x, y)
|
||||||
|
of tyOwned:
|
||||||
|
let base = t.skipTypes(abstractInstOwned)
|
||||||
|
if optNimV2 in c.graph.config.globalOptions:
|
||||||
|
case base.kind
|
||||||
|
of tyRef:
|
||||||
|
ownedRefOp(c, base, body, x, y)
|
||||||
|
return
|
||||||
|
of tyProc:
|
||||||
|
if base.callConv == ccClosure:
|
||||||
|
ownedClosureOp(c, base, body, x, y)
|
||||||
|
return
|
||||||
|
else: discard
|
||||||
|
defaultOp(c, base, body, x, y)
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if tfHasAsgn in t.flags:
|
if tfHasAsgn in t.flags or useNoGc(c, t):
|
||||||
let i = declareCounter(c, body, firstOrd(c.graph.config, t))
|
forallElements(c, t, body, x, y)
|
||||||
let whileLoop = genWhileLoop(c, i, x)
|
|
||||||
let elemType = t.lastSon
|
|
||||||
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
|
|
||||||
y.at(i, elemType))
|
|
||||||
addIncStmt(c, whileLoop.sons[1], i)
|
|
||||||
body.add whileLoop
|
|
||||||
else:
|
else:
|
||||||
defaultOp(c, t, body, x, y)
|
defaultOp(c, t, body, x, y)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
if useNoGc(c, t):
|
||||||
|
seqOp(c, t, body, x, y)
|
||||||
|
elif c.graph.config.selectedGC == gcDestructors:
|
||||||
# note that tfHasAsgn is propagated so we need the check on
|
# note that tfHasAsgn is propagated so we need the check on
|
||||||
# 'selectedGC' here to determine if we have the new runtime.
|
# 'selectedGC' here to determine if we have the new runtime.
|
||||||
if c.graph.config.selectedGC == gcDestructors:
|
|
||||||
discard considerOverloadedOp(c, t, body, x, y)
|
discard considerOverloadedOp(c, t, body, x, y)
|
||||||
elif tfHasAsgn in t.flags:
|
elif tfHasAsgn in t.flags:
|
||||||
if c.kind != attachedDestructor:
|
if c.kind != attachedDestructor:
|
||||||
body.add newSeqCall(c.graph, x, y)
|
body.add newSeqCall(c.graph, x, y)
|
||||||
let i = declareCounter(c, body, firstOrd(c.graph.config, t))
|
forallElements(c, t, body, x, y)
|
||||||
let whileLoop = genWhileLoop(c, i, x)
|
|
||||||
let elemType = t.lastSon
|
|
||||||
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
|
|
||||||
y.at(i, elemType))
|
|
||||||
addIncStmt(c, whileLoop.sons[1], i)
|
|
||||||
body.add whileLoop
|
|
||||||
else:
|
else:
|
||||||
defaultOp(c, t, body, x, y)
|
defaultOp(c, t, body, x, y)
|
||||||
of tyString:
|
of tyString:
|
||||||
if tfHasAsgn in t.flags:
|
if useNoGc(c, t):
|
||||||
|
strOp(c, t, body, x, y)
|
||||||
|
elif tfHasAsgn in t.flags:
|
||||||
discard considerOverloadedOp(c, t, body, x, y)
|
discard considerOverloadedOp(c, t, body, x, y)
|
||||||
else:
|
else:
|
||||||
defaultOp(c, t, body, x, y)
|
defaultOp(c, t, body, x, y)
|
||||||
|
|
@ -250,17 +394,6 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y)
|
liftBodyAux(c, t.sons[0].skipTypes(skipPtrs), body, x, y)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
liftBodyTup(c, t, body, x, y)
|
liftBodyTup(c, t, body, x, y)
|
||||||
of tyProc:
|
|
||||||
if t.callConv != ccClosure or c.kind != attachedDeepCopy:
|
|
||||||
defaultOp(c, t, body, x, y)
|
|
||||||
else:
|
|
||||||
# a big problem is that we don't know the enviroment's type here, so we
|
|
||||||
# have to go through some indirection; we delegate this to the codegen:
|
|
||||||
let call = newNodeI(nkCall, c.info, 2)
|
|
||||||
call.typ = t
|
|
||||||
call.sons[0] = newSymNode(createMagic(c.graph, "deepCopy", mDeepCopy))
|
|
||||||
call.sons[1] = y
|
|
||||||
body.add newAsgnStmt(x, call)
|
|
||||||
of tyVarargs, tyOpenArray:
|
of tyVarargs, tyOpenArray:
|
||||||
localError(c.graph.config, c.info, "cannot copy openArray")
|
localError(c.graph.config, c.info, "cannot copy openArray")
|
||||||
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||||
|
|
@ -269,7 +402,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
tyTypeDesc, tyGenericInvocation, tyForward:
|
tyTypeDesc, tyGenericInvocation, tyForward:
|
||||||
internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
|
internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
|
||||||
of tyOrdinal, tyRange, tyInferred,
|
of tyOrdinal, tyRange, tyInferred,
|
||||||
tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink, tyOwned:
|
tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink:
|
||||||
liftBodyAux(c, lastSon(t), body, x, y)
|
liftBodyAux(c, lastSon(t), body, x, y)
|
||||||
|
|
||||||
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
||||||
|
|
|
||||||
|
|
@ -1600,7 +1600,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of mSet: result = semSet(c, n, prev)
|
of mSet: result = semSet(c, n, prev)
|
||||||
of mOrdinal: result = semOrdinal(c, n, prev)
|
of mOrdinal: result = semOrdinal(c, n, prev)
|
||||||
of mSeq:
|
of mSeq:
|
||||||
if c.config.selectedGc == gcDestructors:
|
if c.config.selectedGc == gcDestructors and optNimV2 notin c.config.globalOptions:
|
||||||
let s = c.graph.sysTypes[tySequence]
|
let s = c.graph.sysTypes[tySequence]
|
||||||
assert s != nil
|
assert s != nil
|
||||||
assert prev == nil
|
assert prev == nil
|
||||||
|
|
|
||||||
|
|
@ -593,7 +593,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and
|
if cl.isReturnType and cl.c.config.selectedGc == gcDestructors and result.destructor.isNil and
|
||||||
result[0].kind != tyEmpty:
|
result[0].kind != tyEmpty and optNimV2 notin cl.c.config.globalOptions:
|
||||||
let s = cl.c.graph.sysTypes[tySequence]
|
let s = cl.c.graph.sysTypes[tySequence]
|
||||||
var old = copyType(s, s.owner, keepId=false)
|
var old = copyType(s, s.owner, keepId=false)
|
||||||
# Remove the 'T' parameter from tySequence:
|
# Remove the 'T' parameter from tySequence:
|
||||||
|
|
|
||||||
78
lib/core/runtime_v2.nim
Normal file
78
lib/core/runtime_v2.nim
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#[
|
||||||
|
In this new runtime we simply the object layouts a bit: The runtime type
|
||||||
|
information is only accessed for the objects that have it and it's always
|
||||||
|
at offset 0 then. The ``ref`` object header is independent from the
|
||||||
|
runtime type and only contains a reference count.
|
||||||
|
|
||||||
|
Object subtyping is checked via the generated 'name'. This should have
|
||||||
|
comparable overhead to the old pointer chasing approach but has the benefit
|
||||||
|
that it works across DLL boundaries.
|
||||||
|
|
||||||
|
The generated name is a concatenation of the object names in the hierarchy
|
||||||
|
so that a subtype check becomes a substring check. For example::
|
||||||
|
|
||||||
|
type
|
||||||
|
ObjectA = object of RootObj
|
||||||
|
ObjectB = object of ObjectA
|
||||||
|
|
||||||
|
ObjectA's ``name`` is "|ObjectA|RootObj|".
|
||||||
|
ObjectB's ``name`` is "|ObjectB|ObjectA|RootObj|".
|
||||||
|
|
||||||
|
Now to check for ``x of ObjectB`` we need to check
|
||||||
|
for ``x.typ.name.hasSubstring("|ObjectB|")``. In the actual implementation,
|
||||||
|
however, we could also use a
|
||||||
|
hash of ``package & "." & module & "." & name`` to save space.
|
||||||
|
|
||||||
|
]#
|
||||||
|
|
||||||
|
type
|
||||||
|
TNimNode {.compilerProc.} = object # to keep the code generator simple
|
||||||
|
TNimType {.compilerProc.} = object
|
||||||
|
destructor: proc (p: pointer) {.nimcall, benign.}
|
||||||
|
size: int
|
||||||
|
name: cstring
|
||||||
|
PNimType = ptr TNimType
|
||||||
|
|
||||||
|
ObjHeader = object
|
||||||
|
rc: int # the object header is now a single RC field.
|
||||||
|
# we could remove it in non-debug builds but this seems
|
||||||
|
# unwise.
|
||||||
|
|
||||||
|
proc isObj(obj: PNimType, subclass: cstring): bool {.compilerproc.} =
|
||||||
|
proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.}
|
||||||
|
|
||||||
|
result = strstr(obj.name, subclass) != nil
|
||||||
|
|
||||||
|
proc chckObj(obj: PNimType, subclass: cstring) {.compilerproc.} =
|
||||||
|
# checks if obj is of type subclass:
|
||||||
|
if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion")
|
||||||
|
|
||||||
|
template `+!`(p: pointer, s: int): pointer =
|
||||||
|
cast[pointer](cast[int](p) +% s)
|
||||||
|
|
||||||
|
template `-!`(p: pointer, s: int): pointer =
|
||||||
|
cast[pointer](cast[int](p) -% s)
|
||||||
|
|
||||||
|
template head(p: pointer): ptr ObjHeader =
|
||||||
|
cast[ptr ObjHeader](cast[int](p) -% sizeof(ObjHeader))
|
||||||
|
|
||||||
|
proc nimNewObj(size: int): pointer {.compilerRtl.} =
|
||||||
|
result = alloc0(size + sizeof(ObjHeader)) +! sizeof(ObjHeader)
|
||||||
|
# XXX Respect defined(useMalloc) here!
|
||||||
|
|
||||||
|
proc nimDecWeakRef(p: pointer) {.compilerRtl.} =
|
||||||
|
dec head(p).rc
|
||||||
|
|
||||||
|
proc nimIncWeakRef(p: pointer) {.compilerRtl.} =
|
||||||
|
inc head(p).rc
|
||||||
|
|
||||||
|
proc nimRawDispose(p: pointer) {.compilerRtl.} =
|
||||||
|
if head(p).rc != 0:
|
||||||
|
cstderr.rawWrite "[FATAL] dangling references exist\n"
|
||||||
|
quit 1
|
||||||
|
dealloc(p -! sizeof(ObjHeader))
|
||||||
|
|
||||||
|
proc nimDestroyAndDispose(p: pointer) {.compilerRtl.} =
|
||||||
|
let d = cast[ptr PNimType](p)[].destructor
|
||||||
|
if d != nil: d(p)
|
||||||
|
nimRawDispose(p)
|
||||||
|
|
@ -44,6 +44,7 @@ This means the check for whether ``s.p`` needs to be freed should
|
||||||
be ``s.len == 0`` even though that feels slightly more awkward.
|
be ``s.len == 0`` even though that feels slightly more awkward.
|
||||||
]#
|
]#
|
||||||
|
|
||||||
|
when not defined(nimV2):
|
||||||
proc `=destroy`[T](s: var seq[T]) =
|
proc `=destroy`[T](s: var seq[T]) =
|
||||||
var x = cast[ptr NimSeqV2[T]](addr s)
|
var x = cast[ptr NimSeqV2[T]](addr s)
|
||||||
var p = x.p
|
var p = x.p
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ template isLiteral(s): bool = s.p == nil or s.p.region == nil
|
||||||
|
|
||||||
template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator)
|
template contentSize(cap): int = cap + 1 + sizeof(int) + sizeof(Allocator)
|
||||||
|
|
||||||
|
when not defined(nimV2):
|
||||||
|
|
||||||
template frees(s) =
|
template frees(s) =
|
||||||
if not isLiteral(s):
|
if not isLiteral(s):
|
||||||
s.p.region.dealloc(s.p.region, s.p, contentSize(s.p.cap))
|
s.p.region.dealloc(s.p.region, s.p, contentSize(s.p.cap))
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ proc chckNilDisp(p: pointer) {.compilerproc.} =
|
||||||
if p == nil:
|
if p == nil:
|
||||||
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
|
||||||
|
|
||||||
|
when not defined(nimV2):
|
||||||
|
|
||||||
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
|
proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
|
||||||
# checks if obj is of type subclass:
|
# checks if obj is of type subclass:
|
||||||
var x = obj
|
var x = obj
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,8 @@ else:
|
||||||
elif defined(gcRegions):
|
elif defined(gcRegions):
|
||||||
# XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here
|
# XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here
|
||||||
include "system/gc_regions"
|
include "system/gc_regions"
|
||||||
|
elif defined(nimV2):
|
||||||
|
include "core/runtime_v2"
|
||||||
elif defined(gcMarkAndSweep) or defined(gcDestructors):
|
elif defined(gcMarkAndSweep) or defined(gcDestructors):
|
||||||
# XXX use 'compileOption' here
|
# XXX use 'compileOption' here
|
||||||
include "system/gc_ms"
|
include "system/gc_ms"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue