cycle breaker (#13593)

* cycle breaking as an alternative to cycle detection
This commit is contained in:
Andreas Rumpf 2020-03-19 22:58:16 +01:00 • committed by GitHub
commit 35fb38629f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 298 additions and 41 deletions

View file

@ -1606,10 +1606,33 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
a.storage)
gcUsage(p.config, e)
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
result = rdLoc(a)
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
if t.kind notin {tyVar, tyLent}: nilCheck = result
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
result = "(*$1)" % [result]
t = skipTypes(t.lastSon, abstractInst)
discard getTypeDesc(p.module, t)
if not p.module.compileToCpp:
while t.kind == tyObject and t[0] != nil:
result.add(".Sup")
t = skipTypes(t[0], skipPtrs)
result.add ".m_type"
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
discard cgsym(p.module, "TNimType")
let t = e[1].typ
putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo":
# ordinary static type information
putIntoDest(p, d, e, genTypeInfo(p.module, t, e.info))
else:
var a: TLoc
initLocExpr(p, e[1], a)
var nilCheck = Rope(nil)
# use the dynamic type stored at offset 0:
putIntoDest(p, d, e, rdMType(p, a, nilCheck))
template genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
@ -2113,21 +2136,6 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
n[0] = newSymNode(toStrProc)
expr(p, n, d)
proc rdMType(p: BProc; a: TLoc; nilCheck: var Rope): Rope =
result = rdLoc(a)
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
if t.kind notin {tyVar, tyLent}: nilCheck = result
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
result = "(*$1)" % [result]
t = skipTypes(t.lastSon, abstractInst)
discard getTypeDesc(p.module, t)
if not p.module.compileToCpp:
while t.kind == tyObject and t[0] != nil:
result.add(".Sup")
t = skipTypes(t[0], skipPtrs)
result.add ".m_type"
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
case op
of mOr, mAnd: genAndOr(p, e, d, op)

View file

@ -1291,6 +1291,11 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope =
genProc(m, theProc)
result = theProc.loc.r
else:
if op == attachedTrace and m.config.selectedGC == gcOrc and
containsGarbageCollectedRef(t):
when false:
# re-enable this check
internalError(m.config, info, "no attached trace proc found")
result = rope("NIM_NIL")
proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo) =

View file

@ -484,10 +484,10 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if isFinal(elemType):
let typInfo = genBuiltin(c.g, mGetTypeInfo, "getTypeInfo", newNodeIT(nkType, x.info, elemType))
typInfo.typ = getSysType(c.g, c.info, tyPointer)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, x, typInfo, y)
body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x), typInfo, y)
else:
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, x, y)
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x), y)
of attachedDispose:
# this is crucial! dispose is like =destroy but we don't follow refs
# as that is dealt within the cycle collector.
@ -530,7 +530,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, xenv, y)
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv), y)
of attachedDispose:
# this is crucial! dispose is like =destroy but we don't follow refs
# as that is dealt within the cycle collector.
@ -778,7 +778,6 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
# register this operation already:
typ.attachedOps[kind] = result
if kind == attachedSink and typ.attachedOps[attachedDestructor] != nil and
sfOverriden in typ.attachedOps[attachedDestructor].flags:
## compiler can use a combination of `=destroy` and memCopy for sink op

View file

@ -36,7 +36,7 @@ type
warnUnusedImportX,
warnInheritFromException,
warnEachIdentIsTuple,
warnProveInit, warnProveField, warnProveIndex,
warnProveInit, warnProveField, warnProveIndex,
warnStaticIndexCheck, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnCaseTransition, warnCycleCreated, warnUser,

View file

@ -696,8 +696,16 @@ proc checkRange(c: PEffects; value: PNode; typ: PType) =
checkLe(c, value, highBound)
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil: return
let realType = typ.skipTypes(abstractInst)
when false:
# XXX fix this in liftdestructors instead
if realType.kind == tyRef and
optSeqDestructors in tracked.config.globalOptions:
createTypeBoundOps(tracked.graph, tracked.c, realType.lastSon, info)
createTypeBoundOps(tracked.graph, tracked.c, typ, info)
if (typ != nil and tfHasAsgn in typ.flags) or
if (tfHasAsgn in typ.flags) or
optSeqDestructors in tracked.config.globalOptions:
tracked.owner.flags.incl sfInjectDestructors