[pypy-commit] pypy lightweight-finalizers: Make rclass aware of lightweight finalizers. Write a test in test_gc and
fijal
noreply at buildbot.pypy.org
Thu Sep 29 22:34:23 CEST 2011
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: lightweight-finalizers
Changeset: r47692:d7d83ce34d5d
Date: 2011-09-29 17:34 -0300
http://bitbucket.org/pypy/pypy/changeset/d7d83ce34d5d/
Log: Make rclass aware of lightweight finalizers. Write a test in test_gc
and make it pass (badly?) on marksweep
diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -363,7 +363,7 @@
Struct._install_extras(self, **kwds)
def _attach_runtime_type_info_funcptr(self, funcptr, destrptr,
- customtraceptr):
+ customtraceptr, raw_mem_attr_name):
if self._runtime_type_info is None:
raise TypeError("attachRuntimeTypeInfo: %r must have been built "
"with the rtti=True argument" % (self,))
@@ -399,6 +399,8 @@
raise TypeError("expected a custom trace function "
"implementation, got: %s" % customtraceptr)
self._runtime_type_info.custom_trace_funcptr = customtraceptr
+ if raw_mem_attr_name is not None:
+ self._runtime_type_info.raw_mem_attr_name = raw_mem_attr_name
class GcStruct(RttiStruct):
_gckind = 'gc'
@@ -2058,11 +2060,12 @@
return _ptr(PTRTYPE, oddint, solid=True)
def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None,
- customtraceptr=None):
+ customtraceptr=None, raw_mem_attr_name=None):
if not isinstance(GCSTRUCT, RttiStruct):
raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT
GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr,
- customtraceptr)
+ customtraceptr,
+ raw_mem_attr_name)
return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info)
def getRuntimeTypeInfo(GCSTRUCT):
diff --git a/pypy/rpython/lltypesystem/rclass.py b/pypy/rpython/lltypesystem/rclass.py
--- a/pypy/rpython/lltypesystem/rclass.py
+++ b/pypy/rpython/lltypesystem/rclass.py
@@ -391,26 +391,39 @@
def _setup_repr_final(self):
AbstractInstanceRepr._setup_repr_final(self)
if self.gcflavor == 'gc':
- if (self.classdef is not None and
- self.classdef.classdesc.lookup('__del__') is not None):
- s_func = self.classdef.classdesc.s_read_attribute('__del__')
- source_desc = self.classdef.classdesc.lookup('__del__')
- source_classdef = source_desc.getclassdef(None)
- source_repr = getinstancerepr(self.rtyper, source_classdef)
- assert len(s_func.descriptions) == 1
- funcdesc, = s_func.descriptions
- graph = funcdesc.getuniquegraph()
- self.check_graph_of_del_does_not_call_too_much(graph)
- FUNCTYPE = FuncType([Ptr(source_repr.object_type)], Void)
- destrptr = functionptr(FUNCTYPE, graph.name,
- graph=graph,
- _callable=graph.func)
- else:
- destrptr = None
+ destrptr = None
+ raw_mem_attr_name = None
+ if self.classdef is not None:
+ classdesc = self.classdef.classdesc
+ if classdesc.lookup('__del__') is not None:
+ s_func = classdesc.s_read_attribute('__del__')
+ if classdesc.lookup('_raw_mem_ptr_name'):
+ # this object has a __del__, but it actually does not
+ # do much
+ assert s_func.const.func_name == 'remove_raw_mem_attr',(
+ "You overloaded __del__ on an object that owns"
+ " a reference to a low level pointer")
+ raw_mem_attr_name = classdesc.s_read_attribute(
+ '_raw_mem_ptr_name').const
+ else:
+ source_desc = classdesc.lookup('__del__')
+ source_classdef = source_desc.getclassdef(None)
+ source_repr = getinstancerepr(self.rtyper,
+ source_classdef)
+ assert len(s_func.descriptions) == 1
+ funcdesc, = s_func.descriptions
+ graph = funcdesc.getuniquegraph()
+ self.check_graph_of_del_does_not_call_too_much(graph)
+ FUNCTYPE = FuncType([Ptr(source_repr.object_type)],
+ Void)
+ destrptr = functionptr(FUNCTYPE, graph.name,
+ graph=graph,
+ _callable=graph.func)
OBJECT = OBJECT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
ll_runtime_type_info,
- OBJECT, destrptr)
+ OBJECT, destrptr,
+ raw_mem_attr_name)
vtable = self.rclass.getvtable()
self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py
--- a/pypy/rpython/memory/gc/base.py
+++ b/pypy/rpython/memory/gc/base.py
@@ -72,7 +72,9 @@
is_rpython_class,
has_custom_trace,
get_custom_trace,
- fast_path_tracing):
+ fast_path_tracing,
+ has_raw_mem_ptr,
+ ofs_to_raw_mem_ptr):
self.getfinalizer = getfinalizer
self.is_varsize = is_varsize
self.has_gcptr_in_varsize = has_gcptr_in_varsize
@@ -89,6 +91,8 @@
self.has_custom_trace = has_custom_trace
self.get_custom_trace = get_custom_trace
self.fast_path_tracing = fast_path_tracing
+ self.has_raw_mem_ptr = has_raw_mem_ptr
+ self.ofs_to_raw_mem_ptr = ofs_to_raw_mem_ptr
def get_member_index(self, type_id):
return self.member_index(type_id)
diff --git a/pypy/rpython/memory/gc/marksweep.py b/pypy/rpython/memory/gc/marksweep.py
--- a/pypy/rpython/memory/gc/marksweep.py
+++ b/pypy/rpython/memory/gc/marksweep.py
@@ -362,6 +362,11 @@
obj = gc_info + size_gc_header
self.write_free_statistics(typeid, obj)
freed_size += estimate
+ if self.has_raw_mem_ptr(typeid):
+ p = (addr + size_gc_header +
+ self.ofs_to_raw_mem_ptr(typeid)).ptr[0]
+ if p:
+ lltype.free(p, flavor='raw')
raw_free(addr)
hdr = next
ppnext.address[0] = llmemory.NULL
diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py
--- a/pypy/rpython/memory/gctypelayout.py
+++ b/pypy/rpython/memory/gctypelayout.py
@@ -34,6 +34,8 @@
("finalizer_or_customtrace", FINALIZER_OR_CT),
("fixedsize", lltype.Signed),
("ofstoptrs", lltype.Ptr(OFFSETS_TO_GC_PTR)),
+ ("ofstorawptr", lltype.Signed),
+ # XXX merge me with finalizer_or_custometrace
hints={'immutable': True},
)
VARSIZE_TYPE_INFO = lltype.Struct("varsize_type_info",
@@ -136,6 +138,12 @@
infobits = self.get(typeid).infobits
return infobits & T_ANY_SLOW_FLAG == 0
+ def q_has_raw_mem_ptr(self, typeid):
+ return self.get(typeid).infobits & T_HAS_RAW_MEM_PTR != 0
+
+ def q_ofs_to_raw_mem_ptr(self, typeid):
+ return self.get(typeid).ofstorawptr
+
def set_query_functions(self, gc):
gc.set_query_functions(
self.q_is_varsize,
@@ -153,7 +161,9 @@
self.q_is_rpython_class,
self.q_has_custom_trace,
self.q_get_custom_trace,
- self.q_fast_path_tracing)
+ self.q_fast_path_tracing,
+ self.q_has_raw_mem_ptr,
+ self.q_ofs_to_raw_mem_ptr)
# the lowest 16bits are used to store group member index
@@ -165,6 +175,7 @@
T_IS_RPYTHON_INSTANCE = 0x100000 # the type is a subclass of OBJECT
T_HAS_FINALIZER = 0x200000
T_HAS_CUSTOM_TRACE = 0x400000
+T_HAS_RAW_MEM_PTR = 0x800000
T_KEY_MASK = intmask(0xFF000000)
T_KEY_VALUE = intmask(0x5A000000) # bug detection only
@@ -236,6 +247,10 @@
infobits |= T_IS_WEAKREF
if is_subclass_of_object(TYPE):
infobits |= T_IS_RPYTHON_INSTANCE
+ if getattr(TYPE._runtime_type_info, 'raw_mem_attr_name', None):
+ name = TYPE._runtime_type_info.raw_mem_attr_name
+ infobits |= T_HAS_RAW_MEM_PTR
+ info.ofstorawptr = llmemory.offsetof(TYPE, 'inst_' + name)
info.infobits = infobits | T_KEY_VALUE
# ____________________________________________________________
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -129,6 +129,27 @@
res = self.interpret(concat, [100])
assert res == concat(100)
#assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+
+ def test_lightweight_finalizer(self):
+ T = lltype.Struct('T', ('x', lltype.Signed))
+
+ @rgc.owns_raw_memory('p')
+ class AClass(object):
+ p = lltype.nullptr(T)
+
+ def __init__(self, arg):
+ if arg:
+ self.p = lltype.malloc(T, flavor='raw')
+
+ def f():
+ for i in range(3):
+ AClass(3)
+ AClass(0)
+ llop.gc__collect(lltype.Void)
+ # assert did not crash with malloc mismatch, ie those things
+ # has been freed
+
+ self.interpret(f, [])
def test_finalizer(self):
class B(object):
diff --git a/pypy/rpython/rtyper.py b/pypy/rpython/rtyper.py
--- a/pypy/rpython/rtyper.py
+++ b/pypy/rpython/rtyper.py
@@ -705,7 +705,7 @@
return self.getcallable(graph)
def attachRuntimeTypeInfoFunc(self, GCSTRUCT, func, ARG_GCSTRUCT=None,
- destrptr=None):
+ destrptr=None, raw_mem_attr_name=None):
self.call_all_setups() # compute ForwardReferences now
if ARG_GCSTRUCT is None:
ARG_GCSTRUCT = GCSTRUCT
@@ -717,7 +717,8 @@
raise TyperError("runtime type info function %r returns %r, "
"excepted Ptr(RuntimeTypeInfo)" % (func, s))
funcptr = self.getcallable(graph)
- attachRuntimeTypeInfo(GCSTRUCT, funcptr, destrptr)
+ attachRuntimeTypeInfo(GCSTRUCT, funcptr, destrptr, None,
+ raw_mem_attr_name)
# register operations from annotation model
RPythonTyper._registeroperations(annmodel)
diff --git a/pypy/rpython/test/test_rclass.py b/pypy/rpython/test/test_rclass.py
--- a/pypy/rpython/test/test_rclass.py
+++ b/pypy/rpython/test/test_rclass.py
@@ -4,6 +4,7 @@
from pypy.rpython.lltypesystem.lltype import *
from pypy.rpython.ootypesystem import ootype
from pypy.rlib.rarithmetic import intmask, r_longlong
+from pypy.rlib import rgc
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
from pypy.rpython.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY
from pypy.rpython.rclass import IR_QUASIIMMUTABLE, IR_QUASIIMMUTABLE_ARRAY
@@ -972,9 +973,31 @@
graph = graphof(t, f)
TYPE = graph.startblock.operations[0].args[0].value
RTTI = getRuntimeTypeInfo(TYPE)
- queryptr = RTTI._obj.query_funcptr # should not raise
+ RTTI._obj.query_funcptr # should not raise
destrptr = RTTI._obj.destructor_funcptr
assert destrptr is not None
+
+ def test_lightweight_del(self):
+ T = Struct('T', ('x', Signed))
+
+ @rgc.owns_raw_memory('p')
+ class A(object):
+ p = nullptr(T)
+
+ def __init__(self, arg):
+ self.p = malloc(T, flavor='raw')
+
+ def f():
+ A(3)
+
+ t = TranslationContext()
+ t.buildannotator().build_types(f, [])
+ t.buildrtyper().specialize()
+ graph = graphof(t, f)
+ TYPE = graph.startblock.operations[0].args[0].value
+ RTTI = getRuntimeTypeInfo(TYPE)
+ RTTI._obj.query_funcptr # should not raise
+ assert RTTI._obj.raw_mem_attr_name == 'p'
def test_del_inheritance(self):
from pypy.rlib import rgc
More information about the pypy-commit
mailing list