diff options
-rw-r--r-- | compiler/ccgtypes.nim | 6 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 1 | ||||
-rw-r--r-- | compiler/lowerings.nim | 2 | ||||
-rw-r--r-- | lib/system/orc.nim | 23 | ||||
-rw-r--r-- | tests/arc/tasyncleak2.nim | 88 |
5 files changed, 111 insertions, 9 deletions
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 5b5720934..aa92b8534 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1319,9 +1319,9 @@ 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: + when false: + if op == attachedTrace and m.config.selectedGC == gcOrc and + containsGarbageCollectedRef(t): # unfortunately this check is wrong for an object type that only contains # .cursor fields like 'Node' inside 'cycleleak'. internalError(m.config, info, "no attached trace proc found") diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index b3300850e..3d0635761 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -448,6 +448,7 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = # follow all elements: forallElements(c, t, body, x, y) of attachedDispose: + forallElements(c, t, body, x, y) body.add genBuiltin(c.g, mDestroy, "destroy", x) proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index f6ca98196..2d96f8a60 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -158,7 +158,7 @@ proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType else: rawAddSon(result, getCompilerProc(g, "RootObj").typ) result.n = newNodeI(nkRecList, info) - let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info)), + let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s), owner, info, owner.options) incl s.flags, sfAnon s.typ = result diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 7c4cf9d98..7500ba374 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -40,7 +40,7 @@ template setColor(c, col) = proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} = let h = head(p) inc h.rc, rcIncrement - h.setColor colPurple # mark as potential cycle! + #h.setColor colPurple # mark as potential cycle! const useJumpStack = false # for thavlak the jump stack doesn't improve the performance at all @@ -74,6 +74,19 @@ proc free(s: Cell; desc: PNimType) {.inline.} = if desc.disposeImpl != nil: cast[DisposeProc](desc.disposeImpl)(p) + + when false: + cstderr.rawWrite desc.name + cstderr.rawWrite " " + if desc.disposeImpl == nil: + cstderr.rawWrite "lacks dispose" + if desc.traceImpl != nil: + cstderr.rawWrite ", but has trace\n" + else: + cstderr.rawWrite ", and lacks trace\n" + else: + cstderr.rawWrite "has dispose!\n" + nimRawDispose(p) proc nimTraceRef(q: pointer; desc: PNimType; env: pointer) {.compilerRtl.} = @@ -342,8 +355,8 @@ proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} = #cprintf("[DESTROY] %p\n", p) else: dec cell.rc, rcIncrement - if cell.color == colPurple: - rememberCycle(result, cell, cast[ptr PNimType](p)[]) + #if cell.color == colPurple: + rememberCycle(result, cell, cast[ptr PNimType](p)[]) proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl, inl.} = if p != nil: @@ -353,5 +366,5 @@ proc nimDecRefIsLastCyclicStatic(p: pointer; desc: PNimType): bool {.compilerRtl #cprintf("[DESTROY] %p %s\n", p, desc.name) else: dec cell.rc, rcIncrement - if cell.color == colPurple: - rememberCycle(result, cell, desc) + #if cell.color == colPurple: + rememberCycle(result, cell, desc) diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim new file mode 100644 index 000000000..4d8486b3b --- /dev/null +++ b/tests/arc/tasyncleak2.nim @@ -0,0 +1,88 @@ +discard """ + output: "success" + cmd: "nim c --gc:orc $file" +""" + +# issue #15076 +import deques, strutils, asyncdispatch + +proc doNothing(): Future[void] = + #[ + var + :env + :env_1 + try: + `=destroy`(:env) + internalNew(:env) + `=sink`(:env.retFuture1, newFuture("doNothing")) + + `=destroy_1`(:env_1) + internalNew(:env_1) + `=`(:env_1.:up, :env) + `=sink_1`(:env.nameIterVar2, (doNothingIter, :env_1)) + + (doNothingNimAsyncContinue, :env)() + return `=_1`(result, :env.retFuture1) + finally: + `=destroy`(:env) + ]# + + var retFuture = newFuture[void]("doNothing") + iterator doNothingIter(): FutureBase {.closure.} = + # inspected ARC code: looks correct! + block: + var qqq = initDeque[string]() + for i in 0 .. 1000: + qqq.addLast($i) + complete(retFuture) # env.up.retFuture1 + + var nameIterVar = doNothingIter # iter_Env -> retFuture -> + + proc doNothingNimAsyncContinue() {.closure.} = + # inspected ARC code: looks correct + if not nameIterVar.finished: + var next_gensym0 = nameIterVar() + while (not next_gensym0.isNil) and next_gensym0.finished: + next_gensym0 = nameIterVar() + if nameIterVar.finished: + break + if next_gensym0 != nil: + {.gcsafe.}: + next_gensym0.addCallback cast[proc () {.closure, gcsafe.}](doNothingNimAsyncContinue) + + doNothingNimAsyncContinue() + return retFuture + +proc main(): Future[void] = + template await[T](f_gensym12: Future[T]): auto {.used.} = + var internalTmpFuture_gensym12: FutureBase = f_gensym12 + yield internalTmpFuture_gensym12 + (cast[type(f_gensym12)](internalTmpFuture_gensym12)).read() + + var retFuture = newFuture[void]("main") + iterator mainIter(): FutureBase {.closure.} = + block: + for x in 0 .. 1000: + await doNothing() + complete(retFuture) + + var nameIterVar_gensym11 = mainIter + proc mainNimAsyncContinue() {.closure.} = + if not nameIterVar_gensym11.finished: + var next_gensym11 = unown nameIterVar_gensym11() + while (not next_gensym11.isNil) and next_gensym11.finished: + next_gensym11 = unown nameIterVar_gensym11() + if nameIterVar_gensym11.finished: + break + if next_gensym11 != nil: + {.gcsafe.}: + next_gensym11.addCallback cast[proc () {.closure, gcsafe.}](mainNimAsyncContinue) + + mainNimAsyncContinue() + return retFuture + +for i in 0..9: + waitFor main() + GC_fullCollect() + assert getOccupiedMem() < 1024 +echo "success" |