Author: Armin Rigo <ar...@tunes.org> Branch: gc-del-3 Changeset: r84179:979bc16d2cc9 Date: 2016-05-03 22:48 +0200 http://bitbucket.org/pypy/pypy/changeset/979bc16d2cc9/
Log: in-progress diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py --- a/rpython/memory/gc/base.py +++ b/rpython/memory/gc/base.py @@ -6,6 +6,9 @@ from rpython.memory.support import DEFAULT_CHUNK_SIZE from rpython.memory.support import get_address_stack, get_address_deque from rpython.memory.support import AddressDict, null_address_dict +from rpython.memory.support import make_list_of_nongc_instances +from rpython.memory.support import list_set_nongc_instance +from rpython.memory.support import list_get_nongc_instance from rpython.rtyper.lltypesystem.llmemory import NULL, raw_malloc_usage TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed), @@ -33,7 +36,7 @@ self.config = config assert isinstance(translated_to_c, bool) self.translated_to_c = translated_to_c - self._finalizer_queue_objects = [] + self.run_finalizer_queues = make_list_of_nongc_instances(0) def setup(self): # all runtime mutable values' setup should happen here @@ -42,17 +45,23 @@ def register_finalizer_index(self, fq, index): "NOT_RPYTHON" - while len(self._finalizer_queue_objects) <= index: - self._finalizer_queue_objects.append(None) - if self._finalizer_queue_objects[index] is None: - fq._reset() - fq._gc_deque = self.AddressDeque() - self._finalizer_queue_objects[index] = fq - else: - assert self._finalizer_queue_objects[index] is fq + if len(self.run_finalizer_queues) <= index: + array = make_list_of_nongc_instances(index + 1) + for i in range(len(self.run_finalizer_queues)): + array[i] = self.run_finalizer_queues[i] + self.run_finalizer_queues = array + # + fdold = list_get_nongc_instance(self.AddressDeque, + self.run_finalizer_queues, index) + list_set_nongc_instance(self.run_finalizer_queues, index, + self.AddressDeque()) + if fdold is not None: + fdold.delete() def mark_finalizer_to_run(self, fq_index, obj): - self._finalizer_queue_objects[fq_index]._gc_deque.append(obj) + fdeque = list_get_nongc_instance(self.AddressDeque, + self.run_finalizer_queues, fq_index) + fdeque.append(obj) def post_setup(self): # More stuff that needs to be initialized when the GC is already @@ -61,7 +70,7 @@ self.DEBUG = env.read_from_env('PYPY_GC_DEBUG') def _teardown(self): - self._finalizer_queue_objects = [] # for tests + pass def can_optimize_clean_setarrayitems(self): return True # False in case of card marking @@ -342,10 +351,11 @@ def enum_pending_finalizers(self, callback, arg): i = 0 - while i < len(self._finalizer_queue_objects): - fq = self._finalizer_queue_objects[i] - if fq is not None: - fq._gc_deque.foreach(callback, arg) + while i < len(self.run_finalizer_queues): + fdeque = list_get_nongc_instance(self.AddressDeque, + self.run_finalizer_queues, i) + if fdeque is not None: + fdeque.foreach(callback, arg) i += 1 enum_pending_finalizers._annspecialcase_ = 'specialize:arg(1)' @@ -393,14 +403,24 @@ self.finalizer_lock = True try: i = 0 - while i < len(self._finalizer_queue_objects): - fq = self._finalizer_queue_objects[i] - if fq is not None and fq._gc_deque.non_empty(): + while i < len(self.run_finalizer_queues): + fdeque = list_get_nongc_instance(self.AddressDeque, + self.run_finalizer_queues, i) + if fdeque is not None and fdeque.non_empty(): self.finalizer_trigger(i) i += 1 finally: self.finalizer_lock = False + def finalizer_next_dead(self, fq_index): + fdeque = list_get_nongc_instance(self.AddressDeque, + self.run_finalizer_queues, fq_index) + if fdeque.non_empty(): + obj = fdeque.popleft() + else: + obj = llmemory.NULL + return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF) + class MovingGCBase(GCBase): moving_gc = True diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -255,6 +255,7 @@ self.layoutbuilder.encode_type_shapes_now() self.create_custom_trace_funcs(gcdata.gc, translator.rtyper) + self.create_finalizer_trigger(gcdata) annhelper.finish() # at this point, annotate all mix-level helpers annhelper.backend_optimize() @@ -301,7 +302,6 @@ [s_gc, s_typeid16, annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), - annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) self.malloc_varsize_ptr = getfn( @@ -316,7 +316,6 @@ [s_gc, s_typeid16, annmodel.SomeInteger(nonneg=True), annmodel.SomeBool(), - annmodel.SomeBool(), annmodel.SomeBool()], s_gcref, inline = False) self.malloc_varsize_ptr = getfn( @@ -379,7 +378,7 @@ malloc_fast, [s_gc, s_typeid16, annmodel.SomeInteger(nonneg=True), - s_False, s_False, s_False], s_gcref, + s_False, s_False], s_gcref, inline = True) else: self.malloc_fast_ptr = None @@ -597,6 +596,11 @@ "the custom trace hook %r for %r can cause " "the GC to be called!" % (func, TP)) + def create_finalizer_trigger(self, gcdata): + def ll_finalizer_trigger(fq_index): + pass #xxxxxxxxxxxxx + gcdata.init_finalizer_trigger(ll_finalizer_trigger) + def consider_constant(self, TYPE, value): self.layoutbuilder.consider_constant(TYPE, value, self.gcdata.gc) @@ -772,13 +776,10 @@ info = self.layoutbuilder.get_info(type_id) c_size = rmodel.inputconst(lltype.Signed, info.fixedsize) fptrs = self.special_funcptr_for_type(TYPE) - has_finalizer = "finalizer" in fptrs - has_light_finalizer = "light_finalizer" in fptrs - if has_light_finalizer: - has_finalizer = True - c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer) - c_has_light_finalizer = rmodel.inputconst(lltype.Bool, - has_light_finalizer) + has_destructor = "destructor" in fptrs + assert "finalizer" not in fptrs # removed + assert "light_finalizer" not in fptrs # removed + c_has_destructor = rmodel.inputconst(lltype.Bool, has_destructor) if flags.get('nonmovable'): assert op.opname == 'malloc' @@ -788,16 +789,16 @@ elif not op.opname.endswith('_varsize') and not flags.get('varsize'): zero = flags.get('zero', False) if (self.malloc_fast_ptr is not None and - not c_has_finalizer.value and + not c_has_destructor.value and (self.malloc_fast_is_clearing or not zero)): malloc_ptr = self.malloc_fast_ptr else: malloc_ptr = self.malloc_fixedsize_ptr args = [self.c_const_gc, c_type_id, c_size, - c_has_finalizer, c_has_light_finalizer, + c_has_destructor, rmodel.inputconst(lltype.Bool, False)] else: - assert not c_has_finalizer.value + assert not c_has_destructor.value info_varsize = self.layoutbuilder.get_info_varsize(type_id) v_length = op.args[-1] c_ofstolength = rmodel.inputconst(lltype.Signed, @@ -933,13 +934,12 @@ def gct_do_malloc_fixedsize(self, hop): # used by the JIT (see rpython.jit.backend.llsupport.gc) op = hop.spaceop - [v_typeid, v_size, - v_has_finalizer, v_has_light_finalizer, v_contains_weakptr] = op.args + [v_typeid, v_size, v_has_destructor, v_contains_weakptr] = op.args livevars = self.push_roots(hop) hop.genop("direct_call", [self.malloc_fixedsize_ptr, self.c_const_gc, v_typeid, v_size, - v_has_finalizer, v_has_light_finalizer, + v_has_destructor, v_contains_weakptr], resultvar=op.result) self.pop_roots(hop, livevars) @@ -1047,7 +1047,7 @@ c_false = rmodel.inputconst(lltype.Bool, False) c_has_weakptr = rmodel.inputconst(lltype.Bool, True) args = [self.c_const_gc, c_type_id, c_size, - c_false, c_false, c_has_weakptr] + c_false, c_has_weakptr] # push and pop the current live variables *including* the argument # to the weakref_create operation, which must be kept alive and @@ -1518,18 +1518,14 @@ return rtti is not None and getattr(rtti._obj, 'destructor_funcptr', None) - def has_light_finalizer(self, TYPE): - fptrs = self.special_funcptr_for_type(TYPE) - return "light_finalizer" in fptrs - def has_custom_trace(self, TYPE): rtti = get_rtti(TYPE) return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr', None) - def make_finalizer_funcptr_for_type(self, TYPE): - if not self.has_finalizer(TYPE): - return None, False + def make_destructor_funcptr_for_type(self, TYPE): + if not self.has_destructor(TYPE): + return None rtti = get_rtti(TYPE) destrptr = rtti._obj.destructor_funcptr DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0] @@ -1539,12 +1535,9 @@ ll_call_destructor(destrptr, v, typename) fptr = self.transformer.annotate_finalizer(ll_finalizer, [llmemory.Address], lltype.Void) - try: - g = destrptr._obj.graph - light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g) - except lltype.DelayedPointer: - light = False # XXX bah, too bad - return fptr, light + g = destrptr._obj.graph + FinalizerAnalyzer(self.translator).check_light_finalizer(g) + return fptr def make_custom_trace_funcptr_for_type(self, TYPE): if not self.has_custom_trace(TYPE): diff --git a/rpython/memory/gctypelayout.py b/rpython/memory/gctypelayout.py --- a/rpython/memory/gctypelayout.py +++ b/rpython/memory/gctypelayout.py @@ -84,10 +84,10 @@ return (typeinfo.infobits & ANY) != 0 or bool(typeinfo.customfunc) def init_finalizer_trigger(self, finalizer_trigger): - self.finalizer_trigger = finalizer_trigger + self._finalizer_trigger = finalizer_trigger def q_finalizer_trigger(self, fq_index): - self.finalizer_trigger(fq_index) + self._finalizer_trigger(fq_index) def q_destructor_or_custom_trace(self, typeid): return self.get(typeid).customfunc diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py --- a/rpython/memory/gcwrapper.py +++ b/rpython/memory/gcwrapper.py @@ -214,12 +214,9 @@ return (fq, index) def gc_fq_next_dead(self, fq_tag): - fq, _ = self.get_finalizer_queue_index(fq_tag) - if fq._gc_deque.non_empty(): - addr = fq._gc_deque.popleft() - else: - addr = llmemory.NULL - return llmemory.cast_adr_to_ptr(addr, rclass.OBJECTPTR) + fq, index = self.get_finalizer_queue_index(fq_tag) + return lltype.cast_opaque_ptr(rclass.OBJECTPTR, + self.gc.finalizer_next_dead(index)) def gc_fq_register(self, fq_tag, ptr): fq, index = self.get_finalizer_queue_index(fq_tag) diff --git a/rpython/memory/support.py b/rpython/memory/support.py --- a/rpython/memory/support.py +++ b/rpython/memory/support.py @@ -2,6 +2,9 @@ from rpython.rlib.objectmodel import free_non_gc_object, we_are_translated from rpython.rlib.debug import ll_assert from rpython.tool.identity_dict import identity_dict +from rpython.rtyper.rclass import NONGCOBJECTPTR +from rpython.rtyper.annlowlevel import cast_nongc_instance_to_base_ptr +from rpython.rtyper.annlowlevel import cast_base_ptr_to_nongc_instance def mangle_hash(i): @@ -393,3 +396,17 @@ def _null_value_checker(key, value, arg): if value: arg.setitem(key, value) + +# ____________________________________________________________ + +NONGCARRAY = lltype.Array(NONGCOBJECTPTR) + +def make_list_of_nongc_instances(count): + return lltype.malloc(NONGCARRAY, count, flavor='raw', zero=True, + track_allocation=False) + +def list_get_nongc_instance(Class, array, index): + return cast_base_ptr_to_nongc_instance(Class, array[index]) + +def list_set_nongc_instance(array, index, instance): + array[index] = cast_nongc_instance_to_base_ptr(instance) diff --git a/rpython/memory/test/test_transformed_gc.py b/rpython/memory/test/test_transformed_gc.py --- a/rpython/memory/test/test_transformed_gc.py +++ b/rpython/memory/test/test_transformed_gc.py @@ -293,7 +293,7 @@ res = run([]) assert res == 42 - def define_finalizer(cls): + def define_destructor(cls): class B(object): pass b = B() @@ -316,6 +316,39 @@ return b.num_deleted return f + def test_destructor(self): + run = self.runner("destructor") + res = run([5, 42]) #XXX pure lazyness here too + assert res == 6 + + def define_finalizer(cls): + class B(object): + pass + b = B() + b.nextid = 0 + b.num_deleted = 0 + class A(object): + def __init__(self): + self.id = b.nextid + b.nextid += 1 + fq.register_finalizer(self) + class FQ(rgc.FinalizerQueue): + Class = A + def finalizer_trigger(self): + while self.next_dead() is not None: + b.num_deleted += 1 + fq = FQ() + def f(x, y): + a = A() + i = 0 + while i < x: + i += 1 + a = A() + llop.gc__collect(lltype.Void) + llop.gc__collect(lltype.Void) + return b.num_deleted + return f + def test_finalizer(self): run = self.runner("finalizer") res = run([5, 42]) #XXX pure lazyness here too @@ -331,12 +364,20 @@ def __init__(self): self.id = b.nextid b.nextid += 1 - def __del__(self): - b.num_deleted += 1 - C() + fq.register_finalizer(self) class C(AAA): - def __del__(self): - b.num_deleted += 1 + pass + class FQ(rgc.FinalizerQueue): + Class = AAA + def finalizer_trigger(self): + while True: + a = self.next_dead() + if a is None: + break + b.num_deleted += 1 + if not isinstance(a, C): + C() + fq = FQ() def f(x, y): a = AAA() i = 0 @@ -363,9 +404,17 @@ def __init__(self): self.id = b.nextid b.nextid += 1 - def __del__(self): - b.num_deleted += 1 - b.a = self + fq.register_finalizer(self) + class FQ(rgc.FinalizerQueue): + Class = A + def finalizer_trigger(self): + while True: + a = self.next_dead() + if a is None: + break + b.num_deleted += 1 + b.a = a + fq = FQ() def f(x, y): a = A() i = 0 @@ -376,7 +425,7 @@ llop.gc__collect(lltype.Void) aid = b.a.id b.a = None - # check that __del__ is not called again + # check that finalizer_trigger() is not called again llop.gc__collect(lltype.Void) llop.gc__collect(lltype.Void) return b.num_deleted * 10 + aid + 100 * (b.a is None) @@ -440,7 +489,7 @@ res = run([]) assert res - def define_weakref_to_object_with_finalizer(cls): + def define_weakref_to_object_with_destructor(cls): import weakref, gc class A(object): count = 0 @@ -459,6 +508,36 @@ return result return f + def test_weakref_to_object_with_destructor(self): + run = self.runner("weakref_to_object_with_destructor") + res = run([]) + assert res + + def define_weakref_to_object_with_finalizer(cls): + import weakref, gc + class A(object): + count = 0 + a = A() + class B(object): + pass + class FQ(rgc.FinalizerQueue): + Class = B + def finalizer_trigger(self): + while self.next_dead() is not None: + a.count += 1 + fq = FQ() + def g(): + b = B() + fq.register_finalizer(b) + return weakref.ref(b) + def f(): + ref = g() + llop.gc__collect(lltype.Void) + llop.gc__collect(lltype.Void) + result = a.count == 1 and (ref() is None) + return result + return f + def test_weakref_to_object_with_finalizer(self): run = self.runner("weakref_to_object_with_finalizer") res = run([]) @@ -475,15 +554,24 @@ def __init__(self): self.id = b.nextid b.nextid += 1 - def __del__(self): - llop.gc__collect(lltype.Void) - b.num_deleted += 1 - C() - C() + fq.register_finalizer(self) class C(A): - def __del__(self): - b.num_deleted += 1 - b.num_deleted_c += 1 + pass + class FQ(rgc.FinalizerQueue): + Class = A + def finalizer_trigger(self): + while True: + a = self.next_dead() + if a is None: + break + llop.gc__collect(lltype.Void) + b.num_deleted += 1 + if isinstance(a, C): + b.num_deleted_c += 1 + else: + C() + C() + fq = FQ() def f(x, y): persistent_a1 = A() persistent_a2 = A() @@ -756,8 +844,7 @@ if op.opname == 'do_malloc_fixedsize': op.args = [Constant(type_id, llgroup.HALFWORD), Constant(llmemory.sizeof(P), lltype.Signed), - Constant(False, lltype.Bool), # has_finalizer - Constant(False, lltype.Bool), # is_finalizer_light + Constant(False, lltype.Bool), # has_destructor Constant(False, lltype.Bool)] # contains_weakptr break else: @@ -793,8 +880,7 @@ if op.opname == 'do_malloc_fixedsize': op.args = [Constant(type_id, llgroup.HALFWORD), Constant(llmemory.sizeof(P), lltype.Signed), - Constant(False, lltype.Bool), # has_finalizer - Constant(False, lltype.Bool), # is_finalizer_light + Constant(False, lltype.Bool), # has_destructor Constant(False, lltype.Bool)] # contains_weakptr break else: diff --git a/rpython/rtyper/annlowlevel.py b/rpython/rtyper/annlowlevel.py --- a/rpython/rtyper/annlowlevel.py +++ b/rpython/rtyper/annlowlevel.py @@ -471,6 +471,11 @@ return lltype.cast_opaque_ptr(llmemory.GCREF, cast_instance_to_base_ptr(instance)) +@specialize.argtype(0) +def cast_nongc_instance_to_base_ptr(instance): + from rpython.rtyper.rclass import NONGCOBJECTPTR + return cast_object_to_ptr(NONGCOBJECTPTR, instance) + class CastObjectToPtrEntry(extregistry.ExtRegistryEntry): _about_ = cast_object_to_ptr @@ -512,6 +517,8 @@ % (ptr, Class)) return ptr +cast_base_ptr_to_nongc_instance = cast_base_ptr_to_instance + @specialize.arg(0) def cast_gcref_to_instance(Class, ptr): """Reverse the hacking done in cast_instance_to_gcref().""" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit