[pypy-svn] r25299 - in pypy/dist/pypy/rpython/rctypes: . test
arigo at codespeak.net
arigo at codespeak.net
Tue Apr 4 16:44:48 CEST 2006
Author: arigo
Date: Tue Apr 4 16:44:47 2006
New Revision: 25299
Modified:
pypy/dist/pypy/rpython/rctypes/rmodel.py
pypy/dist/pypy/rpython/rctypes/rpointer.py
pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py
Log:
(arre, arigo)
Keepalives for pointers and for non-memory-owning boxes.
Seems to be right, but not obvious.
Modified: pypy/dist/pypy/rpython/rctypes/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rmodel.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rmodel.py Tue Apr 4 16:44:47 2006
@@ -25,6 +25,9 @@
# variables. It's a Ptr to a GcStruct. This is a box
# traked by our GC around the raw 'c_data_type'-shaped
# data.
+ #
+ # * 'owner_lowleveltype' is the lowleveltype of the repr for the same
+ # ctype but for ownsmemory=True.
def __init__(self, rtyper, s_ctypesobject, ll_type):
# s_ctypesobject: the annotation to represent
@@ -44,22 +47,30 @@
raise TyperError("unsupported ctypes memorystate %r" % memorystate)
self.c_data_type = self.get_c_data_type(ll_type)
+ content_keepalives = self.get_content_keepalives()
- if self.ownsmemory:
- self.lowleveltype = lltype.Ptr(
+ self.owner_lowleveltype = lltype.Ptr(
lltype.GcStruct( "CtypesBox_%s" % (ctype.__name__,),
- ( "c_data", self.c_data_type )
+ ( "c_data", self.c_data_type ),
+ *content_keepalives
)
)
+ if self.ownsmemory:
+ self.lowleveltype = self.owner_lowleveltype
else:
self.lowleveltype = lltype.Ptr(
lltype.GcStruct( "CtypesBox_%s" % (ctype.__name__,),
- ( "c_data_ref", lltype.Ptr(self.c_data_type) )
+ ( "c_data_ref", lltype.Ptr(self.c_data_type) ),
+ ( "c_data_owner_keepalive", self.owner_lowleveltype ),
+ *content_keepalives
)
)
- # XXX keepalives...
self.const_cache = {} # store generated const values+original value
+ def get_content_keepalives(self):
+ "Return extra keepalive fields used for the content of this object."
+ return []
+
def get_c_data(self, llops, v_box):
if self.ownsmemory:
inputargs = [v_box, inputconst(lltype.Void, "c_data")]
@@ -70,11 +81,20 @@
return llops.genop('getfield', inputargs,
lltype.Ptr(self.c_data_type) )
+ def get_c_data_owner(self, llops, v_box):
+ if self.ownsmemory:
+ return v_box
+ else:
+ inputargs = [v_box, inputconst(lltype.Void,
+ "c_data_owner_keepalive")]
+ return llops.genop('getfield', inputargs,
+ self.owner_lowleveltype)
+
def allocate_instance(self, llops):
c1 = inputconst(lltype.Void, self.lowleveltype.TO)
return llops.genop("malloc", [c1], resulttype=self.lowleveltype)
- def allocate_instance_ref(self, llops, v_c_data):
+ def allocate_instance_ref(self, llops, v_c_data, v_c_data_owner=None):
"""Only if self.ownsmemory is false. This allocates a new instance
and initialize its c_data_ref field."""
if self.ownsmemory:
@@ -83,6 +103,12 @@
v_box = self.allocate_instance(llops)
inputargs = [v_box, inputconst(lltype.Void, "c_data_ref"), v_c_data]
llops.genop('setfield', inputargs)
+ if v_c_data_owner is not None:
+ assert v_c_data_owner.concretetype == self.owner_lowleveltype
+ inputargs = [v_box,
+ inputconst(lltype.Void, "c_data_owner_keepalive"),
+ v_c_data_owner]
+ llops.genop('setfield', inputargs)
return v_box
@@ -94,7 +120,7 @@
if (r_from.ctype == r_to.ctype and
r_from.ownsmemory and not r_to.ownsmemory):
v_c_data = r_from.get_c_data(llops, v)
- return r_to.allocate_instance_ref(llops, v_c_data)
+ return r_to.allocate_instance_ref(llops, v_c_data, v)
else:
return NotImplemented
Modified: pypy/dist/pypy/rpython/rctypes/rpointer.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rpointer.py (original)
+++ pypy/dist/pypy/rpython/rctypes/rpointer.py Tue Apr 4 16:44:47 2006
@@ -1,4 +1,4 @@
-from pypy.rpython.rmodel import Repr
+from pypy.rpython.rmodel import Repr, inputconst
from pypy.rpython import extregistry
from pypy.rpython.lltypesystem import lltype
from pypy.annotation import model as annmodel
@@ -16,6 +16,15 @@
super(PointerRepr, self).__init__(rtyper, s_pointer, ll_contents)
+ def get_content_keepalives(self):
+ "Return an extra keepalive field used for the pointer's contents."
+ return [('keepalive_contents', self.r_contents.owner_lowleveltype)]
+
+ def setkeepalive(self, llops, v_box, v_owner):
+ inputargs = [v_box, inputconst(lltype.Void, 'keepalive_contents'),
+ v_owner]
+ llops.genop('setfield', inputargs)
+
def rtype_getattr(self, hop):
s_attr = hop.args_s[1]
assert s_attr.is_constant()
@@ -113,7 +122,9 @@
if len(hop.args_s):
v_contentsbox, = hop.inputargs(r_ptr.r_contents)
v_c_data = r_ptr.r_contents.get_c_data(hop.llops, v_contentsbox)
+ v_owner = r_ptr.r_contents.get_c_data_owner(hop.llops, v_contentsbox)
r_ptr.setvalue(hop.llops, v_result, v_c_data)
+ r_ptr.setkeepalive(hop.llops, v_result, v_owner)
return v_result
def pointerinstance_compute_annotation(type, instance):
Modified: pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py (original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rpointer.py Tue Apr 4 16:44:47 2006
@@ -71,3 +71,20 @@
res = interpret(func, [])
assert res == 42
+
+ def test_keepalive(self):
+ ptrtype = POINTER(c_int)
+ def func(n):
+ if n == 1:
+ x = c_int(6)
+ p1 = ptrtype(x)
+ else:
+ y = c_int(7)
+ p1 = ptrtype(y)
+ # x or y risk being deallocated by the time we get there,
+ # unless p1 correctly keeps them alive. The llinterpreter
+ # detects this error exactly.
+ return p1.contents.value
+
+ res = interpret(func, [3])
+ assert res == 7
More information about the Pypy-commit
mailing list