[pypy-commit] pypy gc-del-3: in-progress
arigo
pypy.commits at gmail.com
Tue May 3 16:53:04 EDT 2016
Author: Armin Rigo <arigo at 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))
+ at 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()."""
More information about the pypy-commit
mailing list