From 72237e2bcfc371d917e4e14b22a3c447289ea39f Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 25 Nov 2019 15:29:41 +0100 Subject: [PATCH] ARC: ported the GC tests over to --gc:arc --- compiler/lowerings.nim | 1 + compiler/sempass2.nim | 1 + compiler/semtypes.nim | 4 ++++ lib/core/runtime_v2.nim | 12 ++++++++++++ lib/system.nim | 25 +++++++++++++------------ lib/system/strmantle.nim | 9 +++++++++ testament/categories.nim | 8 +++++++- tests/destructor/tmisc_destructors.nim | 2 +- tests/gc/closureleak.nim | 22 +++++++++++++++------- tests/gc/cycleleak.nim | 2 +- tests/gc/gcemscripten.nim | 2 +- tests/gc/gcleak4.nim | 8 ++++---- tests/gc/stackrefleak.nim | 3 ++- tests/gc/weakrefs.nim | 9 ++++++++- 14 files changed, 79 insertions(+), 29 deletions(-) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 0922ab088a..96afc48286 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -60,6 +60,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode = var temp = newSym(skTemp, getIdent(g.cache, genPrefix), owner, value.info, g.config.options) temp.typ = skipTypes(value.typ, abstractInst) incl(temp.flags, sfFromGeneric) + incl(temp.flags, sfCursor) var v = newNodeI(nkVarSection, value.info) let tempAsNode = newSymNode(temp) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 411617acdb..36179511c3 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -759,6 +759,7 @@ proc track(tracked: PEffects, n: PNode) = # check required for 'nim check': if n[1].typ.len > 0: createTypeBoundOps(tracked, n[1].typ.lastSon, n.info) + createTypeBoundOps(tracked, n[1].typ, n.info) for i in 0 ..< safeLen(n): track(tracked, n.sons[i]) of nkDotExpr: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 23bcb3cd17..81efb9517a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -886,6 +886,10 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = t.flags.incl tfHasOwned t.rawAddSonNoPropagationOfTypeFlags result result = t + #if result.kind == tyRef and c.config.selectedGC == gcDestructors: + # result.flags.incl tfHasAsgn + # XXX Something like this is a good idea but it should be done + # in sempass2! proc findEnforcedStaticType(t: PType): PType = # This handles types such as `static[T] and Foo`, diff --git a/lib/core/runtime_v2.nim b/lib/core/runtime_v2.nim index 3dd4a77c62..d566a4c696 100644 --- a/lib/core/runtime_v2.nim +++ b/lib/core/runtime_v2.nim @@ -135,6 +135,18 @@ proc GC_ref*[T](x: ref T) = ## New runtime only supports this operation for 'ref T'. if x != nil: nimIncRef(cast[pointer](x)) +template GC_fullCollect* = + ## Forces a full garbage collection pass. With ``--gc:arc`` a nop. + discard + +template setupForeignThreadGc* = + ## With ``--gc:arc`` a nop. + discard + +template tearDownForeignThreadGc* = + ## With ``--gc:arc`` a nop. + discard + proc isObj(obj: PNimType, subclass: cstring): bool {.compilerRtl, inl.} = proc strstr(s, sub: cstring): cstring {.header: "", importc.} diff --git a/lib/system.nim b/lib/system.nim index 19b96d4a14..30277f6292 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -250,18 +250,19 @@ const ThisIsSystem = true proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} ## Leaked implementation detail. Do not use. -proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. - magic: "NewFinalize", noSideEffect.} - ## Creates a new object of type ``T`` and returns a safe (traced) - ## reference to it in ``a``. - ## - ## When the garbage collector frees the object, `finalizer` is called. - ## The `finalizer` may not keep a reference to the - ## object pointed to by `x`. The `finalizer` cannot prevent the GC from - ## freeing the object. - ## - ## **Note**: The `finalizer` refers to the type `T`, not to the object! - ## This means that for each object of type `T` the finalizer will be called! +when not defined(gcDestructors): + proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. + magic: "NewFinalize", noSideEffect.} + ## Creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. + ## + ## When the garbage collector frees the object, `finalizer` is called. + ## The `finalizer` may not keep a reference to the + ## object pointed to by `x`. The `finalizer` cannot prevent the GC from + ## freeing the object. + ## + ## **Note**: The `finalizer` refers to the type `T`, not to the object! + ## This means that for each object of type `T` the finalizer will be called! when defined(nimV2): proc reset*[T](obj: var T) {.magic: "Destroy", noSideEffect.} diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim index dc3a6de58c..a111ec5630 100644 --- a/lib/system/strmantle.nim +++ b/lib/system/strmantle.nim @@ -304,3 +304,12 @@ proc `$`*(x: uint64): string {.noSideEffect, raises: [].} = let half = i div 2 # Reverse for t in 0 .. half-1: swap(result[t], result[i-t-1]) + +when defined(gcDestructors): + proc GC_getStatistics*(): string = + result = "[GC] total memory: " + result.addInt getTotalMem() + result.add "\n[GC] occupied memory: " + result.addInt getOccupiedMem() + result.add '\n' + #"[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" & diff --git a/testament/categories.nim b/testament/categories.nim index 938f88bf55..5ff5da34ed 100644 --- a/testament/categories.nim +++ b/testament/categories.nim @@ -40,7 +40,8 @@ const "coroutines", "osproc", "shouldfail", - "dir with space" + "dir with space", + "destructor" ] proc isTestFile*(file: string): bool = @@ -176,6 +177,11 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " -d:release", cat) testSpec r, makeTest("tests/gc" / filename, options & " -d:release -d:useRealtimeGC", cat) + when filename != "gctest": + testSpec r, makeTest("tests/gc" / filename, options & + " --gc:arc", cat) + testSpec r, makeTest("tests/gc" / filename, options & + " --gc:arc -d:release", cat) template testWithoutBoehm(filename: untyped) = testWithoutMs filename diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim index 3549383925..fdcea074b2 100644 --- a/tests/destructor/tmisc_destructors.nim +++ b/tests/destructor/tmisc_destructors.nim @@ -28,7 +28,7 @@ proc test(): auto = var (a, b, _) = test() doAssert assign_counter == 0 -doAssert sink_counter == 12 # + 3 because of the conservative tuple unpacking transformation +doAssert sink_counter == 9 # XXX this is still silly and needs to be investigated # bug #11510 proc main = diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim index f86a936d81..508004a532 100644 --- a/tests/gc/closureleak.nim +++ b/tests/gc/closureleak.nim @@ -3,20 +3,28 @@ discard """ disabled: "32bit" """ -from strutils import join - type - TFoo * = object + TFoo* = object id: int fn: proc(){.closure.} var foo_counter = 0 var alive_foos = newseq[int](0) -proc free*(some: ref TFoo) = - #echo "Tfoo #", some.id, " freed" - alive_foos.del alive_foos.find(some.id) +when defined(gcDestructors): + proc `=destroy`(some: var TFoo) = + alive_foos.del alive_foos.find(some.id) + `=destroy`(some.fn) + +else: + proc free*(some: ref TFoo) = + #echo "Tfoo #", some.id, " freed" + alive_foos.del alive_foos.find(some.id) + proc newFoo*(): ref TFoo = - new result, free + when defined(gcDestructors): + new result + else: + new result, free result.id = foo_counter alive_foos.add result.id diff --git a/tests/gc/cycleleak.nim b/tests/gc/cycleleak.nim index 9f5c30ebd4..e355abc968 100644 --- a/tests/gc/cycleleak.nim +++ b/tests/gc/cycleleak.nim @@ -10,7 +10,7 @@ type PModule = ref Module Node = object - owner*: PModule + owner* {.cursor.}: PModule data*: array[0..200, char] # some fat to drain memory faster id: int diff --git a/tests/gc/gcemscripten.nim b/tests/gc/gcemscripten.nim index bbef13d98f..cc12b230f1 100644 --- a/tests/gc/gcemscripten.nim +++ b/tests/gc/gcemscripten.nim @@ -15,7 +15,7 @@ when defined(allow_print): else: const print = false -proc myResult3*(i:int):X {.exportc.} = +proc myResult3*(i:int): X {.exportc.} = if print: echo "3" new(result) if print: echo "3-2" diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim index 35b8ce1121..aec0218e80 100644 --- a/tests/gc/gcleak4.nim +++ b/tests/gc/gcleak4.nim @@ -2,11 +2,11 @@ discard """ outputsub: "no leak: " """ -when defined(GC_setMaxPause): +when declared(GC_setMaxPause): GC_setMaxPause 2_000 type - TExpr = object {.inheritable.} ## abstract base class for an expression + TExpr {.inheritable.} = object ## abstract base class for an expression PLiteral = ref TLiteral TLiteral = object of TExpr x: int @@ -15,7 +15,7 @@ type a, b: ref TExpr op2: string -method eval(e: ref TExpr): int = +method eval(e: ref TExpr): int {.base.} = # override this base method quit "to override!" @@ -30,7 +30,7 @@ proc newLit(x: int): ref TLiteral = result.x = x result.op1 = $getOccupiedMem() -proc newPlus(a, b: ref TExpr): ref TPlusExpr = +proc newPlus(a, b: sink(ref TExpr)): ref TPlusExpr = new(result) result.a = a result.b = b diff --git a/tests/gc/stackrefleak.nim b/tests/gc/stackrefleak.nim index 302ef35997..7f3fbff43d 100644 --- a/tests/gc/stackrefleak.nim +++ b/tests/gc/stackrefleak.nim @@ -12,7 +12,8 @@ type proc makePair: PCyclic = new(result) new(result.sibling) - result.sibling.sibling = result + when not defined(gcDestructors): + result.sibling.sibling = result proc loop = for i in 0..10000: diff --git a/tests/gc/weakrefs.nim b/tests/gc/weakrefs.nim index 0a6d4b873a..81c048d746 100644 --- a/tests/gc/weakrefs.nim +++ b/tests/gc/weakrefs.nim @@ -19,8 +19,15 @@ var proc finalizer(x: StrongObject) = valid.excl(x.id) +when defined(gcDestructors): + proc `=destroy`(x: var TMyObject) = + valid.excl(x.id) + proc create: StrongObject = - new(result, finalizer) + when defined(gcDestructors): + new(result) + else: + new(result, finalizer) result.id = gid valid.incl(gid) inc gid