Author: Armin Rigo <[email protected]>
Branch:
Changeset: r88736:a42d0357c952
Date: 2016-11-29 14:22 +0100
http://bitbucket.org/pypy/pypy/changeset/a42d0357c952/
Log: Add rgc.may_ignore_finalizer(): an optimization hint that makes the
GC stop tracking the object---its finalizer(s) won't be called,
then.
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -155,7 +155,10 @@
# 'old_objects_pointing_to_pinned' and doesn't have to be added again.
GCFLAG_PINNED_OBJECT_PARENT_KNOWN = GCFLAG_PINNED
-_GCFLAG_FIRST_UNUSED = first_gcflag << 10 # the first unused bit
+# record that ignore_finalizer() has been called
+GCFLAG_IGNORE_FINALIZER = first_gcflag << 10
+
+_GCFLAG_FIRST_UNUSED = first_gcflag << 11 # the first unused bit
# States for the incremental GC
@@ -1672,7 +1675,7 @@
self.rrc_minor_collection_trace()
#
# visit the "probably young" objects with finalizers. They
- # always all survive.
+ # all survive, except if IGNORE_FINALIZER is set.
if self.probably_young_objects_with_finalizers.non_empty():
self.deal_with_young_objects_with_finalizers()
#
@@ -2675,6 +2678,8 @@
while self.probably_young_objects_with_finalizers.non_empty():
obj = self.probably_young_objects_with_finalizers.popleft()
fq_nr = self.probably_young_objects_with_finalizers.popleft()
+ if self.header(obj).tid & GCFLAG_IGNORE_FINALIZER:
+ continue
self.singleaddr.address[0] = obj
self._trace_drag_out1(self.singleaddr)
obj = self.singleaddr.address[0]
@@ -2697,6 +2702,8 @@
fq_nr = self.old_objects_with_finalizers.popleft()
ll_assert(self._finalization_state(x) != 1,
"bad finalization state 1")
+ if self.header(x).tid & GCFLAG_IGNORE_FINALIZER:
+ continue
if self.header(x).tid & GCFLAG_VISITED:
new_with_finalizer.append(x)
new_with_finalizer.append(fq_nr)
@@ -2787,6 +2794,9 @@
self.objects_to_trace.append(obj)
self.visit_all_objects()
+ def ignore_finalizer(self, obj):
+ self.header(obj).tid |= GCFLAG_IGNORE_FINALIZER
+
# ----------
# Weakrefs
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
@@ -545,6 +545,12 @@
s_gcref],
annmodel.s_None)
+ self.ignore_finalizer_ptr = None
+ if hasattr(GCClass, 'ignore_finalizer'):
+ self.ignore_finalizer_ptr = getfn(GCClass.ignore_finalizer,
+ [s_gc, SomeAddress()],
+ annmodel.s_None)
+
def create_custom_trace_funcs(self, gc, rtyper):
custom_trace_funcs = tuple(rtyper.custom_trace_funcs)
rtyper.custom_trace_funcs = custom_trace_funcs
@@ -1572,6 +1578,13 @@
hop.genop("cast_adr_to_ptr", [v_adr],
resultvar = hop.spaceop.result)
+ def gct_gc_ignore_finalizer(self, hop):
+ if self.ignore_finalizer_ptr is not None:
+ v_adr = hop.genop("cast_ptr_to_adr", [hop.spaceop.args[0]],
+ resulttype=llmemory.Address)
+ hop.genop("direct_call", [self.ignore_finalizer_ptr,
+ self.c_const_gc, v_adr])
+
class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -527,6 +527,12 @@
hop.exception_cannot_occur()
return hop.inputconst(lltype.Signed, hop.s_result.const)
+def may_ignore_finalizer(obj):
+ """Optimization hint: says that it is valid for any finalizer
+ for 'obj' to be ignored, depending on the GC."""
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ llop.gc_ignore_finalizer(lltype.Void, obj)
+
# ____________________________________________________________
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -486,6 +486,7 @@
'gc_add_memory_pressure': LLOp(),
'gc_fq_next_dead' : LLOp(),
'gc_fq_register' : LLOp(),
+ 'gc_ignore_finalizer' : LLOp(canrun=True),
'gc_rawrefcount_init': LLOp(),
'gc_rawrefcount_create_link_pypy': LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -736,6 +736,9 @@
assert isinstance(x, bool)
return x
+def op_gc_ignore_finalizer(obj):
+ pass
+
# ____________________________________________________________
def get_op_impl(opname):
diff --git a/rpython/translator/c/src/mem.h b/rpython/translator/c/src/mem.h
--- a/rpython/translator/c/src/mem.h
+++ b/rpython/translator/c/src/mem.h
@@ -152,6 +152,7 @@
#define OP_GC_IS_RPY_INSTANCE(x, r) r = 0
#define OP_GC_DUMP_RPY_HEAP(fd, r) r = 0
#define OP_GC_SET_EXTRA_THRESHOLD(x, r) /* nothing */
+#define OP_GC_IGNORE_FINALIZER(x, r) /* nothing */
/****************************/
/* The "asmgcc" root finder */
diff --git a/rpython/translator/c/test/test_boehm.py
b/rpython/translator/c/test/test_boehm.py
--- a/rpython/translator/c/test/test_boehm.py
+++ b/rpython/translator/c/test/test_boehm.py
@@ -409,7 +409,9 @@
#
def fn():
for i in range(1000):
- fq.register_finalizer(A(i))
+ x = A(i)
+ fq.register_finalizer(x)
+ rgc.may_ignore_finalizer(x) # this is ignored with Boehm
rgc.collect()
rgc.collect()
if glob.triggered == 0:
diff --git a/rpython/translator/c/test/test_newgc.py
b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -1705,6 +1705,38 @@
res = self.run("limited_memory_linux", -1, runner=myrunner)
assert res == 42
+ def define_ignore_finalizer(cls):
+ class X(object):
+ pass
+ class FQ(rgc.FinalizerQueue):
+ Class = X
+ def finalizer_trigger(self):
+ pass
+ queue = FQ()
+ def g():
+ x1 = X()
+ x2 = X()
+ queue.register_finalizer(x1)
+ queue.register_finalizer(x2)
+ rgc.may_ignore_finalizer(x1)
+ g._dont_inline_ = True
+ def f():
+ g()
+ rgc.collect()
+ seen = 0
+ while True:
+ obj = queue.next_dead()
+ if obj is None:
+ break
+ seen += 1
+ return seen
+ assert f() == 2 # untranslated: may_ignore_finalizer() is ignored
+ return f
+
+ def test_ignore_finalizer(self):
+ res = self.run("ignore_finalizer")
+ assert res == 1 # translated: x1 is removed from the list
+
# ____________________________________________________________________
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit