[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