[pypy-svn] r37151 - in pypy/dist/pypy/rpython/lltypesystem: . test

pedronis at codespeak.net pedronis at codespeak.net
Mon Jan 22 17:28:13 CET 2007


Author: pedronis
Date: Mon Jan 22 17:28:11 2007
New Revision: 37151

Modified:
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
   pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py
Log:
(arre, pedronis): support inheritance for virtualizables.



Modified: pypy/dist/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rclass.py	Mon Jan 22 17:28:11 2007
@@ -314,7 +314,7 @@
         self.lowleveltype = Ptr(self.object_type)
         self.gcflavor = gcflavor
 
-    def _setup_repr(self, llfields=None):
+    def _setup_repr(self, llfields=None, adtmeths=None):
         # NOTE: don't store mutable objects like the dicts below on 'self'
         #       before they are fully built, to avoid strange bugs in case
         #       of recursion where other code would uses these
@@ -353,8 +353,11 @@
                 llfields.append(('wrapper', Ptr(PyObject)))
 
             MkStruct = lltype.STRUCT_BY_FLAVOR[LLFLAVOR[self.gcflavor]]
+            if adtmeths is None:
+                adtmeths = {}
             object_type = MkStruct(self.classdef.name,
                                    ('super', self.rbase.object_type),
+                                   adtmeths=adtmeths,
                                    *llfields)
             self.object_type.become(object_type)
             allinstancefields.update(self.rbase.allinstancefields)

Modified: pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py	Mon Jan 22 17:28:11 2007
@@ -1,3 +1,4 @@
+from pypy.rpython.error import TyperError
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.rmodel import inputconst
 from pypy.rpython.lltypesystem.rclass import InstanceRepr
@@ -8,18 +9,31 @@
     def __init__(self, rtyper, classdef):
         InstanceRepr.__init__(self, rtyper, classdef)
         classdesc = classdef.classdesc
-        assert '_virtualizable_' in classdesc.classdict
-        basedesc = classdesc.basedesc
-        assert basedesc is None or basedesc.lookup('_virtualizable_') is None
-        # xxx check that the parents have no instance field
+        if '_virtualizable_' in classdesc.classdict:
+            basedesc = classdesc.basedesc
+            assert basedesc is None or basedesc.lookup('_virtualizable_') is None
+            self.top_of_virtualizable_hierarchy = True
+        else:
+            self.top_of_virtualizable_hierarchy = False
+
 
     def _setup_repr(self):
         llfields = []
         ACCESS = lltype.ForwardReference()
-        llfields.append(('vable_access', lltype.Ptr(ACCESS)))
-        InstanceRepr._setup_repr(self, llfields)
-        name = self.lowleveltype.TO._name
+        if self.top_of_virtualizable_hierarchy:
+            llfields.append(('vable_access', lltype.Ptr(ACCESS)))
+        InstanceRepr._setup_repr(self, llfields,
+                                 adtmeths={'ACCESS': ACCESS})
+        rbase = self.rbase
         accessors = []
+        if self.top_of_virtualizable_hierarchy:
+            if len(rbase.allinstancefields) != 1:
+                raise TyperError("virtulizable class cannot have"
+                                 " non-virtualizable base class with instance"
+                                 " fields: %r" % self.classdef)
+        else:
+            accessors.append(('parent', rbase.ACCESS))
+        name = self.lowleveltype.TO._name
         SELF = self.lowleveltype
         for name, (mangled_name, r) in self.fields.items():
             T = r.lowleveltype
@@ -28,43 +42,88 @@
             accessors.append(('get_'+mangled_name, GETTER))
             accessors.append(('set_'+mangled_name, SETTER))
         ACCESS.become(lltype.Struct(name+'_access', *accessors))
+                                    
         self.ACCESS = ACCESS
 
-    def set_vable(self, llops, vinst, name, llvalue):
-        cname = inputconst(lltype.Void, 'vable_'+name)
-        vvalue = inputconst(lltype.typeOf(llvalue), llvalue)
-        llops.genop('setfield', [vinst, cname, vvalue])
+    def get_top_virtualizable_type(self):
+        if self.top_of_virtualizable_hierarchy:
+            return self.lowleveltype
+        else:
+            return self.rbase.get_top_virtualizable_type()
+
+    def set_vable(self, llops, vinst, force_cast=False):
+        if self.top_of_virtualizable_hierarchy:
+            if force_cast:
+                vinst = llops.genop('cast_pointer', [vinst], resulttype=self)
+            for name, llvalue in (('access', lltype.nullptr(self.ACCESS)),):
+                cname = inputconst(lltype.Void, 'vable_'+name)
+                vvalue = inputconst(lltype.typeOf(llvalue), llvalue)
+                llops.genop('setfield', [vinst, cname, vvalue])
+        else:
+            self.rbase.set_vable(llops, vinst, force_cast=True)
 
     def new_instance(self, llops, classcallhop=None, v_cpytype=None):
         vptr = InstanceRepr.new_instance(self, llops, classcallhop, v_cpytype)
-        self.set_vable(llops, vptr, 'access', lltype.nullptr(self.ACCESS))
+        self.set_vable(llops, vptr)
         return vptr
 
+    def get_namedesc(self, mangled_name):
+        TOPPTR = self.get_top_virtualizable_type()
+        namedesc = NameDesc(mangled_name, TOPPTR, lltype.Ptr(self.ACCESS))
+        return inputconst(lltype.Void, namedesc)
+        
+
     def getfield(self, vinst, attr, llops, force_cast=False):
         """Read the given attribute (or __class__ for the type) of 'vinst'."""
         if attr in self.fields:
             mangled_name, r = self.fields[attr]
             if force_cast:
                 vinst = llops.genop('cast_pointer', [vinst], resulttype=self)
-            cname = inputconst(lltype.Void, NameDesc(mangled_name))
+            cname = self.get_namedesc(mangled_name)
             return llops.gendirectcall(ll_access_get, vinst, cname)
         else:
-            return InstanceRepr.getfield(vinst, attr, llops, force_cast)
+            return InstanceRepr.getfield(self, vinst, attr, llops, force_cast)
 
+    def setfield(self, vinst, attr, vvalue, llops, force_cast=False, opname='setfield'):
+        """Write the given attribute (or __class__ for the type) of 'vinst'."""
+        if attr in self.fields:
+            mangled_name, r = self.fields[attr]
+            if force_cast:
+                vinst = llops.genop('cast_pointer', [vinst], resulttype=self)
+            cname = self.get_namedesc(mangled_name)                
+            llops.gendirectcall(ll_access_set, vinst, cname, vvalue)
+        else:
+            InstanceRepr.setfield(self, vinst, attr, vvalue, llops, force_cast,
+                                  opname)
+            
 class NameDesc(object):
     __metaclass__ = cachedtype
     
-    def __init__(self, name):
+    def __init__(self, name, TOPPTR, ACCESSPTR):
         self.name = name
+        self.TOPPTR = TOPPTR
+        self.ACCESSPTR = ACCESSPTR
 
     def _freeze_(self):
         return True
 
 
 def ll_access_get(vinst, namedesc):
-    access = vinst.vable_access
     name = namedesc.name
+    top = lltype.cast_pointer(namedesc.TOPPTR, vinst)
+    access = top.vable_access
     if access:
-        return getattr(access, 'get_'+name)(vinst)
+        return getattr(lltype.cast_pointer(namedesc.ACCESSPTR, access),
+                       'get_'+name)(vinst)
     else:
         return getattr(vinst, name)
+
+def ll_access_set(vinst, namedesc, value):
+    name = namedesc.name
+    top = lltype.cast_pointer(namedesc.TOPPTR, vinst)
+    access = top.vable_access    
+    if access:
+        getattr(lltype.cast_pointer(namedesc.ACCESSPTR, access),
+                'set_'+name)(vinst, value)
+    else:
+        setattr(vinst, name, value)

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py	Mon Jan 22 17:28:11 2007
@@ -1,6 +1,8 @@
+import py
 from pypy.rpython.lltypesystem import lltype, rclass
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+from pypy.rpython.error import TyperError
 
 class V(object):
     _virtualizable_ = True
@@ -24,7 +26,7 @@
     assert ACCESS.set_inst_v == lltype.Ptr(lltype.FuncType([LLV, lltype.Signed],
                                                            lltype.Void))    
 
-def test_accessors():
+def test_get_accessor():
 
     G = lltype.FuncType([rclass.OBJECTPTR], lltype.Void)
 
@@ -56,3 +58,112 @@
     assert res == 42
 
     assert witness == [42]
+
+def test_set_accessor():
+
+    G = lltype.FuncType([rclass.OBJECTPTR], lltype.Void)
+
+    witness = []
+    
+    def setv(vinst, val):
+        witness.append(val)
+        vinst.inst_v = val
+
+    def g(vobj):
+        vobj = lltype.normalizeptr(vobj)
+        LLV = lltype.typeOf(vobj).TO
+        ACCESS = LLV.vable_access.TO
+        access = lltype.malloc(ACCESS, immortal=True)
+        access.set_inst_v = lltype.functionptr(ACCESS.set_inst_v.TO,
+                                               'setv', _callable=setv)
+        vobj.vable_access = access
+        
+    gptr = lltype.functionptr(G, 'g', _callable=g)
+    
+    def f(v):
+        vinst = V(v)
+        vobj = cast_instance_to_base_ptr(vinst)
+        gptr(vobj)
+        vinst.v = 33
+    res = interpret(f, [42])
+
+    assert witness == [33]
+
+class B(object):
+    _virtualizable_ = True
+
+    x = "XX"
+    
+    def __init__(self, v0):
+        self.v0 = v0
+
+class C(B):
+
+    x = "XXX"
+    
+    def __init__(self, v0, v1):
+        B.__init__(self, v0)
+        self.v1 = v1
+
+
+def test_get_accessor_inheritance():
+
+    G = lltype.FuncType([rclass.OBJECTPTR], lltype.Void)
+
+    witness = []
+    
+    def getv0(vinst):
+        value = vinst.inst_v0
+        witness.append(value)
+        return value
+
+    def getv1(vinst):
+        value = vinst.inst_v1
+        witness.append(value)
+        return value    
+
+    def g(vobj):
+        vobj = lltype.normalizeptr(vobj)
+        LLV = lltype.typeOf(vobj).TO
+        ACCESS = LLV.ACCESS
+        access = lltype.malloc(ACCESS, immortal=True)
+        fp = lltype.functionptr(ACCESS.parent.get_inst_v0.TO, 'getv0',
+                                _callable=getv0)        
+        access.parent.get_inst_v0= fp
+                                     
+        access.get_inst_v1 = lltype.functionptr(ACCESS.get_inst_v1.TO,
+                                               'getv1', _callable=getv1)
+        vobj.super.vable_access = access.parent
+        
+    gptr = lltype.functionptr(G, 'g', _callable=g)
+    
+    def f(v0, v1):
+        B(0)
+        vinst = C(v0, v1)
+        vobj = cast_instance_to_base_ptr(vinst)
+        gptr(vobj)
+        x = vinst.v0
+        y = vinst.v1
+        vinst.x
+        return x+y+len(vinst.x)
+    res = interpret(f, [18, 21])
+    assert res == 42
+
+    assert witness == [18, 21]
+
+class A(object):
+    def __init__(self, v):
+        self.v = v
+
+class AA(A):
+    _virtualizable_ = True
+
+    def __init__(self, vv):
+        self.vv = vv
+
+def test_parent_has_attrs_failure():
+    def f():
+        A(1)
+        AA(3)
+
+    py.test.raises(TyperError, interpret, f, [])



More information about the Pypy-commit mailing list