diff --git a/de.churl.simple/garbagecollection.py b/de.churl.simple/garbagecollection.py index 010bd88..2cc494d 100644 --- a/de.churl.simple/garbagecollection.py +++ b/de.churl.simple/garbagecollection.py @@ -1,12 +1,14 @@ def mark(w_context): + if w_context.mark: # skip cycles + return + w_context.mark = True if not hasattr(w_context, "slots"): # skip primitive objects return for name, obj in w_context.slots.items(): - if name != "__parent__": # only descent - mark(obj) + mark(obj) def sweep(objects): diff --git a/de.churl.simple/objspace.py b/de.churl.simple/objspace.py index 5c4015c..a931d00 100644 --- a/de.churl.simple/objspace.py +++ b/de.churl.simple/objspace.py @@ -44,7 +44,8 @@ class ObjectSpace(object): else: slots = {'__parent__': self.getbuiltins()} - return W_NormalObject(name=name, slots=slots) # lobby isn't collected + self.objects.append(W_NormalObject(name=name, slots=slots)) # needed, otherwise marking skips the root + return self.objects[-1] def newobject(self, name, slots, parentnames): self.objects.append(W_NormalObject(space=self, name=name, diff --git a/mytests/test_gc.py b/mytests/test_gc.py index 48fe235..580f831 100644 --- a/mytests/test_gc.py +++ b/mytests/test_gc.py @@ -4,7 +4,6 @@ from interpreter import Interpreter def test_reassignment_gc(): ast = parse(""" -true x = 2 y = 3 """) @@ -66,6 +65,45 @@ z = y assert x not in interpreter.space.objects +def test_cycle_gc(): + ast = parse(""" +object a: + x = 1 + +object b: + x = a + +a x = b +""") + interpreter = Interpreter() + w_model = interpreter.make_module() + interpreter.eval(ast, w_model) + interpreter.space.gc(w_model) + + a = w_model.getvalue("a") + b = w_model.getvalue("b") + assert a in interpreter.space.objects + assert b in interpreter.space.objects + + ast = parse(""" +a = 0 +""") + interpreter.eval(ast, w_model) + interpreter.space.gc(w_model) + + assert a in interpreter.space.objects + assert b in interpreter.space.objects + + ast = parse(""" +b = 0 +""") + interpreter.eval(ast, w_model) + interpreter.space.gc(w_model) + + assert a not in interpreter.space.objects + assert b not in interpreter.space.objects + + def test_object_gc(): ast = parse(""" object x: