diff options
-rw-r--r-- | compiler/ccgexprs.nim | 2 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/commands.nim | 21 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 3 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 77 | ||||
-rw-r--r-- | compiler/options.nim | 1 | ||||
-rw-r--r-- | lib/core/runtime_v2.nim | 22 | ||||
-rw-r--r-- | lib/system.nim | 18 | ||||
-rw-r--r-- | lib/system/hti.nim | 4 | ||||
-rw-r--r-- | lib/system/mmdisp.nim | 4 | ||||
-rw-r--r-- | lib/system/repr.nim | 2 | ||||
-rw-r--r-- | lib/system/threads.nim | 2 |
12 files changed, 123 insertions, 35 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index cc4e8de42..f6cf799bd 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1206,7 +1206,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = if sizeExpr.isNil: sizeExpr = "sizeof($1)" % [getTypeDesc(p.module, bt)] - if optOwnedRefs in p.config.globalOptions: + if optTinyRtti in p.config.globalOptions: b.r = ropecg(p.module, "($1) #nimNewObj($2)", [getTypeDesc(p.module, typ), sizeExpr]) genAssignment(p, a, b, {}) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index fcef4a0ff..a3d807e26 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -16,7 +16,7 @@ const # above X strings a hash-switch for strings is generated proc getTraverseProc(p: BProc, v: PSym): Rope = - if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and + if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcV2, gcRefc} and optOwnedRefs notin p.config.globalOptions and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage diff --git a/compiler/commands.nim b/compiler/commands.nim index a3ab6e522..249312f50 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -230,6 +230,7 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo of "markandsweep": result = conf.selectedGC == gcMarkAndSweep of "generational": result = false of "destructors": result = conf.selectedGC == gcDestructors + of "hooks": result = conf.selectedGC == gcHooks of "go": result = conf.selectedGC == gcGo of "none": result = conf.selectedGC == gcNone of "stack", "regions": result = conf.selectedGC == gcRegions @@ -453,6 +454,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.selectedGC = gcDestructors defineSymbol(conf.symbols, "gcdestructors") incl conf.globalOptions, optSeqDestructors + incl conf.globalOptions, optTinyRtti + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimV2") + of "hooks": + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") + incl conf.globalOptions, optSeqDestructors + processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) + if pass in {passCmd2, passPP}: + defineSymbol(conf.symbols, "nimSeqsV2") of "go": conf.selectedGC = gcGo defineSymbol(conf.symbols, "gogc") @@ -460,7 +472,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; conf.selectedGC = gcNone defineSymbol(conf.symbols, "nogc") of "stack", "regions": - conf.selectedGC= gcRegions + conf.selectedGC = gcRegions defineSymbol(conf.symbols, "gcregions") else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "warnings", "w": @@ -509,7 +521,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; undefSymbol(conf.symbols, "useNimRtl") of "oldnewlines": case arg.normalize - of "","on": + of "", "on": conf.oldNewlines = true defineSymbol(conf.symbols, "nimOldNewlines") of "off": @@ -763,9 +775,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; incl(conf.globalOptions, optOwnedRefs) incl(conf.globalOptions, optSeqDestructors) defineSymbol(conf.symbols, "nimV2") - conf.selectedGC = gcDestructors - defineSymbol(conf.symbols, "gcdestructors") + conf.selectedGC = gcHooks + defineSymbol(conf.symbols, "gchooks") defineSymbol(conf.symbols, "nimSeqsV2") + defineSymbol(conf.symbols, "nimOwnedEnabled") of "seqsv2": processOnOffSwitchG(conf, {optSeqDestructors}, arg, pass, info) if pass in {passCmd2, passPP}: diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index e99c7bc12..4a2d40ec7 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -344,7 +344,8 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) = # with cycles properly, so it's better to produce a weak ref (=ptr) here. # This seems to be generally correct but since it's a bit risky it's disabled # for now. - let fieldType = if isDefined(c.graph.config, "nimCycleBreaker"): + let fieldType = if isDefined(c.graph.config, "nimCycleBreaker") or + c.graph.config.selectedGC == gcDestructors: c.getEnvTypeForOwnerUp(dep, info) #getHiddenParam(dep).typ else: c.getEnvTypeForOwner(dep, info) diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim index ffdf3e16e..4b69a9e9a 100644 --- a/compiler/liftdestructors.nim +++ b/compiler/liftdestructors.nim @@ -359,6 +359,58 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedDestructor: body.add genBuiltin(c.g, mDestroy, "destroy", x) +proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + var actions = newNodeI(nkStmtList, c.info) + let elemType = t.lastSon + + if isFinal(elemType): + addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr)) + actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x) + else: + addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr)) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x) + + let cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x) + cond.typ = getSysType(c.g, x.info, tyBool) + + case c.kind + of attachedSink: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) + of attachedAsgn: + body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) + of attachedDestructor: + body.add genIf(c, cond, actions) + of attachedDeepCopy: assert(false, "cannot happen") + +proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = + ## Closures are really like refs except they always use a virtual destructor + ## and we need to do the refcounting only on the ref field which we call 'xenv': + let xenv = genBuiltin(c.g, mAccessEnv, "accessEnv", x) + xenv.typ = getSysType(c.g, c.info, tyPointer) + + var actions = newNodeI(nkStmtList, c.info) + actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xenv) + + let cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, xenv) + cond.typ = getSysType(c.g, x.info, tyBool) + + case c.kind + of attachedSink: + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) + of attachedAsgn: + let yenv = genBuiltin(c.g, mAccessEnv, "accessEnv", y) + yenv.typ = getSysType(c.g, c.info, tyPointer) + body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv)) + body.add genIf(c, cond, actions) + body.add newAsgnStmt(x, y) + of attachedDestructor: + body.add genIf(c, cond, actions) + of attachedDeepCopy: assert(false, "cannot happen") + proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = case c.kind of attachedSink: @@ -367,7 +419,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x)) body.add newAsgnStmt(x, y) of attachedAsgn: - body.add genIf(c, y, callCodegenProc(c.g, "nimIncWeakRef", c.info, y)) + body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y)) body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x)) body.add newAsgnStmt(x, y) of attachedDestructor: @@ -411,8 +463,8 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = call.sons[0] = newSymNode(createMagic(c.g, "deepCopy", mDeepCopy)) call.sons[1] = y body.add newAsgnStmt(x, call) - elif optOwnedRefs in c.g.config.globalOptions and - optRefCheck in c.g.config.options: + elif (optOwnedRefs in c.g.config.globalOptions and + optRefCheck in c.g.config.options) or c.g.config.selectedGC == gcDestructors: let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) case c.kind @@ -424,7 +476,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = of attachedAsgn: let yy = genBuiltin(c.g, mAccessEnv, "accessEnv", y) yy.typ = getSysType(c.g, c.info, tyPointer) - body.add genIf(c, yy, callCodegenProc(c.g, "nimIncWeakRef", c.info, yy)) + body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy)) body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx)) body.add newAsgnStmt(x, y) of attachedDestructor: @@ -439,7 +491,6 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) = let xx = genBuiltin(c.g, mAccessEnv, "accessEnv", x) xx.typ = getSysType(c.g, c.info, tyPointer) var actions = newNodeI(nkStmtList, c.info) - let elemType = t.lastSon #discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx)) actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx) case c.kind @@ -457,14 +508,19 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyPtr, tyOpt, tyUncheckedArray: defaultOp(c, t, body, x, y) of tyRef: - if optOwnedRefs in c.g.config.globalOptions and - optRefCheck in c.g.config.options: + if c.g.config.selectedGC == gcDestructors: + atomicRefOp(c, t, body, x, y) + elif (optOwnedRefs in c.g.config.globalOptions and + optRefCheck in c.g.config.options): 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) + if c.g.config.selectedGC == gcDestructors: + atomicClosureOp(c, t, body, x, y) + else: + closureOp(c, t, body, x, y) else: defaultOp(c, t, body, x, y) of tyOwned: @@ -532,7 +588,8 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) = tyGenericInst, tyStatic, tyAlias, tySink: fillBody(c, lastSon(t), body, x, y) -proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; info: TLineInfo): PSym = +proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType; + kind: TTypeAttachedOp; info: TLineInfo): PSym = assert typ.kind == tyDistinct let baseType = typ[0] if baseType.attachedOps[kind] == nil: @@ -571,7 +628,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp; typ.attachedOps[kind] = result var tk: TTypeKind - if g.config.selectedGC == gcDestructors: + if g.config.selectedGC in {gcDestructors, gcHooks}: tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind else: tk = tyNone # no special casing for strings and seqs diff --git a/compiler/options.nim b/compiler/options.nim index 286ca8fcf..d3918363e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -116,6 +116,7 @@ type TStringSeq* = seq[string] TGCMode* = enum # the selected GC gcUnselected, gcNone, gcBoehm, gcRegions, gcMarkAndSweep, gcDestructors, + 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/runtime_v2.nim b/lib/core/runtime_v2.nim index 5c9554ad8..fe4bf37bf 100644 --- a/lib/core/runtime_v2.nim +++ b/lib/core/runtime_v2.nim @@ -57,13 +57,13 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} = else: inc allocs -proc nimDecWeakRef(p: pointer) {.compilerRtl.} = +proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = when hasThreadSupport: atomicDec head(p).rc else: dec head(p).rc -proc nimIncWeakRef(p: pointer) {.compilerRtl.} = +proc nimIncRef(p: pointer) {.compilerRtl, inl.} = when hasThreadSupport: atomicInc head(p).rc else: @@ -106,11 +106,25 @@ proc nimDestroyAndDispose(p: pointer) {.compilerRtl.} = cstderr.rawWrite "has destructor!\n" nimRawDispose(p) -proc isObj(obj: PNimType, subclass: cstring): bool {.compilerproc.} = +proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} = + if p != nil: + when hasThreadSupport: + if atomicLoadN(addr head(p).rc, ATOMIC_RELAXED) == 0: + result = true + else: + if atomicDec(head(p).rc) <= 0: + result = true + else: + if head(p).rc == 0: + result = true + else: + dec head(p).rc + +proc isObj(obj: PNimType, 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) {.compilerproc.} = +proc chckObj(obj: PNimType, subclass: cstring) {.compilerRtl.} = # checks if obj is of type subclass: if not isObj(obj, subclass): sysFatal(ObjectConversionError, "invalid object conversion") diff --git a/lib/system.nim b/lib/system.nim index 54ced6c7c..1485e4f6a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1722,12 +1722,12 @@ template `isnot`*(x, y: untyped): untyped = not (x is y) ## assert 42 isnot float ## assert @[1, 2] isnot enum -when (defined(nimV2) and not defined(nimscript)) or defined(nimFixedOwned): +when (defined(nimOwnedEnabled) and not defined(nimscript)) or defined(nimFixedOwned): type owned*[T]{.magic: "BuiltinType".} ## type constructor to mark a ref/ptr or a closure as `owned`. else: template owned*(t: typedesc): typedesc = t -when defined(nimV2) and not defined(nimscript): +when defined(nimOwnedEnabled) and not defined(nimscript): proc new*[T](a: var owned(ref T)) {.magic: "New", noSideEffect.} ## Creates a new object of type ``T`` and returns a safe (traced) ## reference to it in ``a``. @@ -3237,6 +3237,8 @@ proc `<`*[T: tuple](x, y: T): bool = # ----------------- GC interface --------------------------------------------- +const + usesDestructors = defined(gcDestructors) or defined(gcHooks) when not defined(nimscript) and hasAlloc: type @@ -3246,7 +3248,7 @@ when not defined(nimscript) and hasAlloc: gcOptimizeTime, ## optimize for speed gcOptimizeSpace ## optimize for memory footprint - when not defined(JS) and not defined(gcDestructors): + when not defined(JS) and not usesDestructors: proc GC_disable*() {.rtl, inl, benign.} ## Disables the GC. If called `n` times, `n` calls to `GC_enable` ## are needed to reactivate the GC. @@ -3602,7 +3604,7 @@ when not defined(JS): #and not defined(nimscript): {.push stack_trace: off, profiler:off.} when hasAlloc: - when not defined(gcRegions) and not defined(gcDestructors): + when not defined(gcRegions) and not usesDestructors: proc initGC() {.gcsafe.} proc initStackBottom() {.inline, compilerproc.} = @@ -3620,7 +3622,7 @@ when not defined(JS): #and not defined(nimscript): when declared(nimGC_setStackBottom): nimGC_setStackBottom(locals) - when not defined(gcDestructors): + when not usesDestructors: {.push profiler: off.} var strDesc = TNimType(size: sizeof(string), kind: tyString, flags: {ntfAcyclic}) @@ -3792,10 +3794,10 @@ when not defined(JS): #and not defined(nimscript): when hasAlloc: include "system/strmantle" when hasThreadSupport: - when hostOS != "standalone" and not defined(gcDestructors): include "system/channels" + when hostOS != "standalone" and not usesDestructors: include "system/channels" when not defined(nimscript) and hasAlloc: - when not defined(gcDestructors): + when not usesDestructors: include "system/assign" when not defined(nimV2): include "system/repr" @@ -4396,7 +4398,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = discard when hasAlloc and not defined(nimscript) and not defined(JS) and - not defined(gcDestructors): + not usesDestructors: # 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/hti.nim b/lib/system/hti.nim index b2e90211d..c20f132fb 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -87,7 +87,7 @@ type ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow # version TNimType {.compilerproc.} = object - when defined(gcDestructors): + when defined(gcHooks): head*: pointer size*: int kind: TNimKind @@ -103,7 +103,7 @@ type instances: int # count the number of instances sizes: int # sizes of all instances in bytes -when defined(gcDestructors): +when defined(gcHooks): type PNimType* = ptr TNimType else: diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index de89acd33..330c551c5 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -507,10 +507,10 @@ else: elif defined(gcRegions): # XXX due to bootstrapping reasons, we cannot use compileOption("gc", "stack") here include "system/gc_regions" - elif defined(nimV2) or defined(gcDestructors): + elif defined(nimV2) or usesDestructors: var allocator {.rtlThreadVar.}: MemRegion instantiateForRegion(allocator) - when defined(gcDestructors): + when defined(gcHooks): include "system/gc_hooks" elif defined(gcMarkAndSweep): # XXX use 'compileOption' here diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 0c7848c75..43bbc8bb6 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -226,7 +226,7 @@ when not defined(useNimRtl): cl: var ReprClosure) = # we know that p is not nil here: when declared(CellSet): - when defined(boehmGC) or defined(gogc) or defined(nogc) or defined(gcDestructors): + when defined(boehmGC) or defined(gogc) or defined(nogc) or usesDestructors: var cell = cast[PCell](p) else: var cell = usrToCell(p) diff --git a/lib/system/threads.nim b/lib/system/threads.nim index ad1d82be2..b09ed0c6f 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -148,7 +148,7 @@ else: proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) = when defined(boehmgc): boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd) - elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not defined(gcDestructors): + elif not defined(nogc) and not defined(gogc) and not defined(gcRegions) and not usesDestructors: var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall, gcsafe.} = threadProcWrapDispatch[TArg] # init the GC for refc/markandsweep |