[pypy-commit] pypy gc-del: in-progress
arigo
noreply at buildbot.pypy.org
Mon Mar 4 10:04:46 CET 2013
Author: Armin Rigo <arigo at tunes.org>
Branch: gc-del
Changeset: r61993:ac5c5480c694
Date: 2013-03-04 10:04 +0100
http://bitbucket.org/pypy/pypy/changeset/ac5c5480c694/
Log: in-progress
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
@@ -11,7 +11,7 @@
WEAKREFPTR
from rpython.tool.sourcetools import func_with_new_name
from rpython.translator.backendopt import graphanalyze
-from rpython.translator.backendopt.finalizer import FinalizerAnalyzer
+from rpython.translator.backendopt.destructor import DestructorAnalyzer
from rpython.translator.backendopt.support import var_needsgc
import types
@@ -650,21 +650,15 @@
info = self.layoutbuilder.get_info(type_id)
c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
kind_and_fptr = self.special_funcptr_for_type(TYPE)
- has_finalizer = (kind_and_fptr is not None and
- kind_and_fptr[0] == "finalizer")
- has_light_finalizer = (kind_and_fptr is not None and
- kind_and_fptr[0] == "light_finalizer")
- 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 = (kind_and_fptr is not None and
+ kind_and_fptr[0] == "destructor")
+ c_has_destructor = rmodel.inputconst(lltype.Bool, has_destructor)
if not op.opname.endswith('_varsize') and not flags.get('varsize'):
#malloc_ptr = self.malloc_fixedsize_ptr
zero = flags.get('zero', False)
if (self.malloc_fast_ptr is not None and
- not c_has_finalizer.value and
+ not has_destructor and
(self.malloc_fast_is_clearing or not zero)):
malloc_ptr = self.malloc_fast_ptr
elif zero:
@@ -672,10 +666,9 @@
else:
malloc_ptr = self.malloc_fixedsize_ptr
args = [self.c_const_gc, c_type_id, c_size,
- c_has_finalizer, c_has_light_finalizer,
- rmodel.inputconst(lltype.Bool, False)]
+ c_has_destructor, rmodel.inputconst(lltype.Bool, False)]
else:
- assert not c_has_finalizer.value
+ assert not has_destructor
info_varsize = self.layoutbuilder.get_info_varsize(type_id)
v_length = op.args[-1]
c_ofstolength = rmodel.inputconst(lltype.Signed,
@@ -830,13 +823,12 @@
def gct_do_malloc_fixedsize_clear(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_clear_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)
@@ -1204,6 +1196,9 @@
def pop_roots(self, hop, livevars):
raise NotImplementedError
+ def gct_gc_register_finalizer(self, op):
+ xxx
+
class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
@@ -1218,36 +1213,32 @@
self.translator = translator
super(TransformerLayoutBuilder, self).__init__(GCClass, lltype2vtable)
- def has_finalizer(self, TYPE):
+ def has_destructor(self, TYPE):
rtti = get_rtti(TYPE)
return rtti is not None and getattr(rtti._obj, 'destructor_funcptr',
None)
- def has_light_finalizer(self, TYPE):
- special = self.special_funcptr_for_type(TYPE)
- return special is not None and special[0] == 'light_finalizer'
-
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]
typename = TYPE.__name__
- def ll_finalizer(addr, ignored):
+ def ll_destructor(addr, ignored):
v = llmemory.cast_adr_to_ptr(addr, DESTR_ARG)
ll_call_destructor(destrptr, v, typename)
return llmemory.NULL
- fptr = self.transformer.annotate_finalizer(ll_finalizer,
+ fptr = self.transformer.annotate_finalizer(ll_destructor,
[llmemory.Address, llmemory.Address], llmemory.Address)
g = destrptr._obj.graph
- light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g)
- return fptr, light
+ DestructorAnalyzer(self.translator).check_destructor(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
@@ -377,15 +377,12 @@
def special_funcptr_for_type(self, TYPE):
if TYPE in self._special_funcptrs:
return self._special_funcptrs[TYPE]
- fptr1, is_lightweight = self.make_finalizer_funcptr_for_type(TYPE)
+ fptr1 = self.make_destructor_funcptr_for_type(TYPE)
fptr2 = self.make_custom_trace_funcptr_for_type(TYPE)
assert not (fptr1 and fptr2), (
"type %r needs both a finalizer and a custom tracer" % (TYPE,))
if fptr1:
- if is_lightweight:
- kind_and_fptr = "light_finalizer", fptr1
- else:
- kind_and_fptr = "finalizer", fptr1
+ kind_and_fptr = "destructor", fptr1
elif fptr2:
kind_and_fptr = "custom_trace", fptr2
else:
@@ -393,9 +390,9 @@
self._special_funcptrs[TYPE] = kind_and_fptr
return kind_and_fptr
- def make_finalizer_funcptr_for_type(self, TYPE):
+ def make_destructor_funcptr_for_type(self, TYPE):
# must be overridden for proper finalizer support
- return None, False
+ return None
def make_custom_trace_funcptr_for_type(self, TYPE):
# must be overridden for proper custom tracer support
diff --git a/rpython/memory/gcwrapper.py b/rpython/memory/gcwrapper.py
--- a/rpython/memory/gcwrapper.py
+++ b/rpython/memory/gcwrapper.py
@@ -1,4 +1,4 @@
-from rpython.translator.backendopt.finalizer import FinalizerAnalyzer
+from rpython.translator.backendopt.destructor import DestructorAnalyzer
from rpython.rtyper.lltypesystem import lltype, llmemory, llheap
from rpython.rtyper import llinterp
from rpython.rtyper.annlowlevel import llhelper
@@ -204,7 +204,7 @@
self.llinterp = llinterp
super(DirectRunLayoutBuilder, self).__init__(GCClass, lltype2vtable)
- def make_finalizer_funcptr_for_type(self, TYPE):
+ def make_destructor_funcptr_for_type(self, TYPE):
from rpython.memory.gctransform.support import get_rtti
rtti = get_rtti(TYPE)
if rtti is not None and hasattr(rtti._obj, 'destructor_funcptr'):
@@ -212,10 +212,10 @@
DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
destrgraph = destrptr._obj.graph
else:
- return None, False
+ return None
t = self.llinterp.typer.annotator.translator
- light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph)
+ DestructorAnalyzer(t).check_destructor(destrgraph)
def ll_finalizer(addr, dummy):
assert dummy == llmemory.NULL
try:
@@ -225,7 +225,7 @@
raise RuntimeError(
"a finalizer raised an exception, shouldn't happen")
return llmemory.NULL
- return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light
+ return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer)
def make_custom_trace_funcptr_for_type(self, TYPE):
from rpython.memory.gctransform.support import get_rtti
diff --git a/rpython/memory/test/snippet.py b/rpython/memory/test/snippet.py
--- a/rpython/memory/test/snippet.py
+++ b/rpython/memory/test/snippet.py
@@ -2,6 +2,7 @@
from rpython.tool.udir import udir
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rlib import rgc
class SemiSpaceGCTestDefines:
@@ -51,7 +52,8 @@
def __init__(self, key):
self.key = key
self.refs = []
- def __del__(self):
+ rgc.register_finalizer(self.finalize)
+ def finalize(self):
assert state.age[self.key] == -1
state.age[self.key] = state.time
state.progress = True
@@ -113,8 +115,8 @@
return f
- def test_finalizer_order(self):
- res = self.run('finalizer_order')
+ def test_full_finalizer_order(self):
+ res = self.run('full_finalizer_order')
if res != "ok":
i, summary, msg = res.split('\n')
i = int(i)
diff --git a/rpython/memory/test/test_gc.py b/rpython/memory/test/test_gc.py
--- a/rpython/memory/test/test_gc.py
+++ b/rpython/memory/test/test_gc.py
@@ -129,7 +129,7 @@
assert res == concat(100)
#assert simulator.current_size - curr < 16000 * INT_SIZE / 4
- def test_finalizer(self):
+ def test_destructor(self):
class B(object):
pass
b = B()
@@ -153,88 +153,94 @@
res = self.interpret(f, [5])
assert res == 6
- def test_finalizer_calls_malloc(self):
+ def test_finalizer(self):
class B(object):
pass
b = B()
b.nextid = 0
+ b.num_finalized = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def finalizer(self):
+ b.num_finalized += 1
+ def allocate(x):
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ rgc.register_finalizer(a.finalizer)
+ def f(x):
+ allocate(x)
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_finalized
+ res = self.interpret(f, [6])
+ assert res == 6
+
+ def test_finalizer_and_destructor(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_finalized = 0
b.num_deleted = 0
class A(object):
def __init__(self):
self.id = b.nextid
b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- C()
- class C(A):
+ def finalizer(self):
+ assert n.num_deleted <= b.num_finalized
+ b.num_finalized += 1
def __del__(self):
b.num_deleted += 1
def f(x):
a = A()
+ rgc.register_finalizer(a.finalizer)
i = 0
while i < x:
i += 1
a = A()
llop.gc__collect(lltype.Void)
llop.gc__collect(lltype.Void)
- return b.num_deleted
+ return b.num_finalized * 100 + b.num_deleted
res = self.interpret(f, [5])
- assert res == 12
+ assert res == 606
- def test_finalizer_calls_collect(self):
+ def test_finalize_later(self):
class B(object):
pass
b = B()
b.nextid = 0
- b.num_deleted = 0
+ b.num_finalized = 0
class A(object):
def __init__(self):
self.id = b.nextid
b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- llop.gc__collect(lltype.Void)
+ def finalizer(self):
+ b.num_finalized += 1
+ if (b.num_finalized % 3) == 0:
+ raise rgc.FinalizeLater
def f(x):
a = A()
+ rgc.register_finalizer(a.finalizer)
i = 0
while i < x:
i += 1
a = A()
llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted
+ if b.num_finalized == 0:
+ llop.gc__collect(lltype.Void)
+ assert b.num_finalized == 3
+ rgc.progress_through_finalizer_queue()
+ assert b.num_finalized == 6
+ rgc.progress_through_finalizer_queue()
+ assert b.num_finalized == 8
+ rgc.progress_through_finalizer_queue()
+ assert b.num_finalized == 8
res = self.interpret(f, [5])
- assert res == 6
-
- def test_finalizer_resurrects(self):
- 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
- def __del__(self):
- b.num_deleted += 1
- b.a = self
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- aid = b.a.id
- b.a = None
- # check that __del__ 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)
- res = self.interpret(f, [5])
- assert 160 <= res <= 165
+ assert res == 606
def test_custom_trace(self):
from rpython.rtyper.annlowlevel import llhelper
diff --git a/rpython/translator/backendopt/finalizer.py b/rpython/translator/backendopt/destructor.py
rename from rpython/translator/backendopt/finalizer.py
rename to rpython/translator/backendopt/destructor.py
--- a/rpython/translator/backendopt/finalizer.py
+++ b/rpython/translator/backendopt/destructor.py
@@ -2,15 +2,12 @@
from rpython.translator.backendopt import graphanalyze
from rpython.rtyper.lltypesystem import lltype
-class FinalizerError(Exception):
- """ __del__ marked as lightweight finalizer, but the analyzer did
- not agree
- """
+class DestructorError(Exception):
+ """The __del__() method contains unsupported operations"""
-class FinalizerAnalyzer(graphanalyze.BoolGraphAnalyzer):
- """ Analyzer that determines whether a finalizer is lightweight enough
- so it can be called without all the complicated logic in the garbage
- collector. The set of operations here is restrictive for a good reason
+class DestructorAnalyzer(graphanalyze.BoolGraphAnalyzer):
+ """ Analyzer that checks if a destructor is lightweight enough for
+ RPython. The set of operations here is restrictive for a good reason
- it's better to be safe. Specifically disallowed operations:
* anything that escapes self
@@ -20,12 +17,10 @@
'direct_ptradd', 'force_cast', 'track_alloc_stop',
'raw_free']
- def analyze_light_finalizer(self, graph):
+ def check_destructor(self, graph):
result = self.analyze_direct_call(graph)
- if (result is self.top_result() and
- getattr(graph.func, '_must_be_light_finalizer_', False)):
- raise FinalizerError(FinalizerError.__doc__, graph)
- return result
+ if result is self.top_result():
+ raise DestructorError(DestructorError.__doc__, graph)
def analyze_simple_operation(self, op, graphinfo):
if op.opname in self.ok_operations:
More information about the pypy-commit
mailing list