Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Created June 4, 2015 17:27
Show Gist options
  • Save fowlmouth/94ee8e79e06b22b28959 to your computer and use it in GitHub Desktop.
Save fowlmouth/94ee8e79e06b22b28959 to your computer and use it in GitHub Desktop.
discard """
a generic gc test?
what operations are required
- an expression that saves a ref must increment its reference
- an expression that replaces a ref must decrement the ref it held previously
- a gc-safe type decrements held references upon destruction (manual or automatic)
"""
template gcTest* (body: untyped): stmt {. dirty, immediate } =
template exprIncsRef (rf, xpr: untyped): stmt =
{.line: instantiationInfo() }:
block:
let rc = getRefCount(rf)
block: xpr
GC_fullCollect()
do_assert(
not rf.isNil and getRefCount(rf) == rc+1,
"expression did not incref: "& astToStr(xpr) )
template exprDecsRef (rf, xpr: untyped): stmt =
{.line: instantiationInfo() }:
block:
do_assert(not rf.isNil, "reference is not valid! "& $instantiationInfo())
let old_rf = rf
let old_rc = getRefCount(rf)
block: xpr
GC_fullCollect()
do_assert(
getRefCount(old_rf) == old_rc-1,
"expression did not dec ref "& astToStr(xpr)
)
template exprReplacesRef (newRf, oldRf, xpr: untyped): stmt =
{.line: instantiationInfo() }:
exprIncsRef(newRf):
exprDecsRef(oldRf):
xpr
template exprDoesntRef (oldRf, xpr: untyped): stmt =
{.line: instantiationInfo() }:
let old_rc = getRefCount(oldRf)
xpr
GC_fullCollect()
do_assert getRefCount(oldRf) == old_rc, "expression did not keep ref "& astToStr(xpr)
try:
body
except:
echo("Unhandled exception: " & getCurrentExceptionMsg())
echo getCurrentException().getStackTrace()
## gc test for ref object components
import cmodel, std_test, gctester
type GC1 = ref object
defPrimitiveComponent(GC1, GC1)
var global_o: GC1
gcTest:
proc x =
var my = aggxGC1.instantiate
block:
var my_o: GC1
new(my_o) do (some:GC1): echo"Freeing GC1"
exprIncsRef(my_o):
my.findData(GC1)[] = my_o
exprDecsRef(my_o):
my.findDataM(GC1) = nil.GC1
assert getRefCount(my_o) == 0
exprIncsRef(my_o):
global_o = my_o
exprIncsRef(my_o):
my.findData(GC1)[] = my_o
assert getRefCount(my_o) == 2
assert global_o.isNil
x()
GCfullCollect()
## after freeing, the only reference should be global_o
assert getRefCount(global_o) == 1, "invalid ref count for global_o:"& $getRefCount(global_o)
## test that storing Objects in slots of components is gc safe
import cmodel, std_test, gctester
gcTest:
let my_comp = dynaComponent("my_comp", "child1", "child2")
let aggx = aggregate(my_comp)
let my1 = aggx.instantiate()
let my2 = aggx.instantiate()
exprIncsRef(my1):
discard my2.send("child1:", my1)
exprReplacesRef(my2, my1):
discard my2.send("child1:", my2)
exprDecsRef(my2):
discard my2.send("child1:", nil.Object)
assert getRefCount(my1) == 0
assert getRefCount(my2) == 0
# objects stored in closures are destroyed with the closure
import cmodel, std_test, gctester
type GC1 = ref object
defPrimitiveComponent(GC1, GC1)
gcTest:
let my_o = instantiate aggregate(typeComponent(GC1))
proc mkClosure(o:Object): proc(): Object =
return proc(): Object =
return o
var p: proc(): Object
exprIncsRef(my_o):
p = mkClosure(my_o)
assert getRefCount(my_o) == 1
assert p() == my_o
exprDecsRef(my_o):
p = nil
assert getRefCount(my_o) == 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment