diff options
-rw-r--r-- | compiler/btrees.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 11 | ||||
-rw-r--r-- | compiler/dfa.nim | 2 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 14 | ||||
-rw-r--r-- | compiler/semdata.nim | 4 | ||||
-rw-r--r-- | compiler/types.nim | 6 | ||||
-rw-r--r-- | compiler/vm.nim | 2 | ||||
-rw-r--r-- | compiler/vmdef.nim | 2 | ||||
-rw-r--r-- | lib/std/packedsets.nim | 2 | ||||
-rw-r--r-- | lib/system.nim | 1 | ||||
-rw-r--r-- | lib/system/orc.nim | 31 |
11 files changed, 50 insertions, 27 deletions
diff --git a/compiler/btrees.nim b/compiler/btrees.nim index 5f78c07fe..d5e7e8099 100644 --- a/compiler/btrees.nim +++ b/compiler/btrees.nim @@ -16,7 +16,7 @@ const Mhalf = M div 2 type - Node[Key, Val] = ref object + Node[Key, Val] {.acyclic.} = ref object entries: int keys: array[M, Key] case isInternal: bool diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 767525fd5..6e5ffeaa4 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1301,6 +1301,10 @@ proc genHook(m: BModule; t: PType; info: TLineInfo; op: TTypeAttachedOp): Rope = genProc(m, theProc) result = theProc.loc.r + + when false: + if not canFormAcycle(t) and op == attachedTrace: + echo "ayclic but has this =trace ", t, " ", theProc.ast else: when false: if op == attachedTrace and m.config.selectedGC == gcOrc and @@ -1326,9 +1330,12 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn let traceImpl = genHook(m, t, info, attachedTrace) let disposeImpl = genHook(m, t, info, attachedDispose) - addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6;", [ + var flags = 0 + if not canFormAcycle(t): flags = flags or 1 + + addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6; $1.flags = $7;", [ name, destroyImpl, getTypeDesc(m, t), typeName, - traceImpl, disposeImpl]) + traceImpl, disposeImpl, rope(flags)]) if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions: discard genTypeInfoV1(m, t, info) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index 501d39f45..ea60dbc59 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -467,7 +467,7 @@ proc genCase(c: var Con; n: PNode) = # treat the last branch as 'else' if this is an exhaustive case statement. c.gen(it.lastSon) if endings.len != 0: - c.patch(endings[^1]) + c.patch(endings[^1]) else: forkT(it.lastSon): c.gen(it.lastSon) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index de45beb52..43f87e179 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -513,8 +513,9 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = forallElements(c, t, body, x, y) body.add genBuiltin(c, mDestroy, "destroy", x) of attachedTrace: - # follow all elements: - forallElements(c, t, body, x, y) + if canFormAcycle(t.elemType): + # follow all elements: + forallElements(c, t, body, x, y) of attachedDispose: forallElements(c, t, body, x, y) body.add genBuiltin(c, mDestroy, "destroy", x) @@ -550,10 +551,11 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = doAssert t.destructor != nil body.add destructorCall(c, t.destructor, x) of attachedTrace: - let op = getAttachedOp(c.g, t, c.kind) - if op == nil: - return # protect from recursion - body.add newHookCall(c, op, x, y) + if t.kind != tyString and canFormAcycle(t.elemType): + let op = getAttachedOp(c.g, t, c.kind) + if op == nil: + return # protect from recursion + body.add newHookCall(c, op, x, y) of attachedDispose: let op = getAttachedOp(c.g, t, c.kind) if op == nil: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index d26e57320..f763a00e4 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -29,8 +29,8 @@ type POptionEntry* = ref TOptionEntry PProcCon* = ref TProcCon - TProcCon* = object # procedure context; also used for top-level - # statements + TProcCon* {.acyclic.} = object # procedure context; also used for top-level + # statements owner*: PSym # the symbol this context belongs to resultSym*: PSym # the result symbol (if we are in a proc) selfSym*: PSym # the 'self' symbol (if available) diff --git a/compiler/types.nim b/compiler/types.nim index cd67d1ad9..bc970a6d2 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -359,13 +359,13 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = if tfAcyclic in t.flags: return case t.kind of tyTuple, tyObject, tyRef, tySequence, tyArray, tyOpenArray, tyVarargs: - if not containsOrIncl(marker, t.id): + if t.id == startId: + result = true + elif not containsOrIncl(marker, t.id): for i in 0..<t.len: result = canFormAcycleAux(marker, t[i], startId) if result: return if t.n != nil: result = canFormAcycleNode(marker, t.n, startId) - else: - result = t.id == startId # Inheritance can introduce cyclic types, however this is not relevant # as the type that is passed to 'new' is statically known! # er but we use it also for the write barrier ... diff --git a/compiler/vm.nim b/compiler/vm.nim index e13fc5bb7..b540ac071 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -524,7 +524,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = # Used to keep track of where the execution is resumed. var savedPC = -1 var savedFrame: PStackFrame - when defined(gcArc): + when defined(gcArc) or defined(gcOrc): template updateRegsAlias = discard template regs: untyped = tos.slots else: diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 5c1d30a52..2044b860a 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -270,7 +270,7 @@ type procToCodePos*: Table[int, int] PStackFrame* = ref TStackFrame - TStackFrame* = object + TStackFrame* {.acyclic.} = object prc*: PSym # current prc; proc that is evaluated slots*: seq[TFullReg] # parameters passed to the proc + locals; # parameters come first diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim index 2b5896be0..e209d2aae 100644 --- a/lib/std/packedsets.nim +++ b/lib/std/packedsets.nim @@ -38,7 +38,7 @@ const IntMask = 1 shl IntShift - 1 type - Trunk = ref object + Trunk {.acyclic.} = ref object next: Trunk # all nodes are connected with this pointer key: int # start address at bit 0 bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector diff --git a/lib/system.nim b/lib/system.nim index aecda4a70..9317c3440 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1805,6 +1805,7 @@ when not defined(js) and defined(nimV2): traceImpl: pointer disposeImpl: pointer typeInfoV1: pointer # for backwards compat, usually nil + flags: int PNimTypeV2 = ptr TNimTypeV2 when notJSnotNims and defined(nimSeqsV2): diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 8a62ef4bb..df81afcf1 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -109,9 +109,21 @@ proc free(s: Cell; desc: PNimTypeV2) {.inline.} = nimRawDispose(p, desc.align) +template orcAssert(cond, msg) = + when logOrc: + if not cond: + cfprintf(cstderr, "[Bug!] %s\n", msg) + quit 1 + +when logOrc: + proc strstr(s, sub: cstring): cstring {.header: "<string.h>", importc.} + proc nimTraceRef(q: pointer; desc: PNimTypeV2; env: pointer) {.compilerRtl, inline.} = let p = cast[ptr pointer](q) if p[] != nil: + + orcAssert strstr(desc.name, "TType") == nil, "following a TType but it's acyclic!" + var j = cast[ptr GcEnv](env) j.traceStack.add(head p[], desc) @@ -121,12 +133,6 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl, inline.} = var j = cast[ptr GcEnv](env) j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[]) -template orcAssert(cond, msg) = - when logOrc: - if not cond: - cfprintf(cstderr, "[Bug!] %s\n", msg) - quit 1 - var roots {.threadvar.}: CellSeq @@ -402,6 +408,8 @@ proc registerCycle(s: Cell; desc: PNimTypeV2) = when logOrc: writeCell("[added root]", s, desc) + orcAssert strstr(desc.name, "TType") == nil, "added a TType as a root!" + proc GC_runOrc* = ## Forces a cycle collection pass. collectCycles() @@ -436,10 +444,15 @@ proc GC_disableMarkAndSweep*() = ## For `--gc:orc` an alias for `GC_disableOrc`. GC_disableOrc() +const + acyclicFlag = 1 # see also cggtypes.nim, proc genTypeInfoV2Impl + when optimizedOrc: - template markedAsCyclic(s: Cell): bool = (s.rc and maybeCycle) != 0 + template markedAsCyclic(s: Cell; desc: PNimTypeV2): bool = + (desc.flags and acyclicFlag) == 0 and (s.rc and maybeCycle) != 0 else: - template markedAsCyclic(s: Cell): bool = true + template markedAsCyclic(s: Cell; desc: PNimTypeV2): bool = + (desc.flags and acyclicFlag) == 0 proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} = if isDestroyAction: @@ -448,7 +461,7 @@ proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline. else: # do not call 'rememberCycle' again unless this cell # got an 'incRef' event: - if s.rootIdx == 0 and markedAsCyclic(s): + if s.rootIdx == 0 and markedAsCyclic(s, desc): s.setColor colBlack registerCycle(s, desc) |