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

pedronis at codespeak.net pedronis at codespeak.net
Mon Jan 22 14:58:33 CET 2007


Author: pedronis
Date: Mon Jan 22 14:58:31 2007
New Revision: 37140

Added:
   pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py   (contents, props changed)
   pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/lltypesystem/rclass.py
Log:
(arre, pedronis) first steps at rtyping 'virtualizable' classes.



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 14:58:31 2007
@@ -314,7 +314,7 @@
         self.lowleveltype = Ptr(self.object_type)
         self.gcflavor = gcflavor
 
-    def _setup_repr(self):
+    def _setup_repr(self, llfields=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
@@ -326,7 +326,8 @@
             fields['__class__'] = 'typeptr', get_type_repr(self.rtyper)
         else:
             # instance attributes
-            llfields = []
+            if llfields is None:
+                llfields = []
             attrs = self.classdef.attrs.items()
             attrs.sort()
             for name, attrdef in attrs:
@@ -605,11 +606,19 @@
 def buildinstancerepr(rtyper, classdef, gcflavor='gc'):
     if classdef is None:
         unboxed = []
+        virtualizable = False
     else:
         unboxed = [subdef for subdef in classdef.getallsubdefs()
                           if subdef.classdesc.pyobj is not None and
                              issubclass(subdef.classdesc.pyobj, UnboxedValue)]
-    if len(unboxed) == 0:
+        virtualizable = classdef.classdesc.read_attribute('_virtualizable_',
+                                                          Constant(False)).value
+    if virtualizable:
+        assert len(unboxed) == 0
+        assert gcflavor == 'gc'
+        from pypy.rpython.lltypesystem import rvirtualizable
+        return rvirtualizable.VirtualizableInstanceRepr(rtyper, classdef)
+    elif len(unboxed) == 0:
         return InstanceRepr(rtyper, classdef, gcflavor)
     else:
         # the UnboxedValue class and its parent classes need a

Added: pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/rvirtualizable.py	Mon Jan 22 14:58:31 2007
@@ -0,0 +1,70 @@
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.rmodel import inputconst
+from pypy.rpython.lltypesystem.rclass import InstanceRepr
+from pypy.rpython.annlowlevel import cachedtype
+
+class VirtualizableInstanceRepr(InstanceRepr):
+
+    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
+
+    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
+        accessors = []
+        SELF = self.lowleveltype
+        for name, (mangled_name, r) in self.fields.items():
+            T = r.lowleveltype
+            GETTER = lltype.Ptr(lltype.FuncType([SELF], T))
+            SETTER = lltype.Ptr(lltype.FuncType([SELF, T], lltype.Void))
+            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 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))
+        return vptr
+
+    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))
+            return llops.gendirectcall(ll_access_get, vinst, cname)
+        else:
+            return InstanceRepr.getfield(vinst, attr, llops, force_cast)
+
+class NameDesc(object):
+    __metaclass__ = cachedtype
+    
+    def __init__(self, name):
+        self.name = name
+
+    def _freeze_(self):
+        return True
+
+
+def ll_access_get(vinst, namedesc):
+    access = vinst.vable_access
+    name = namedesc.name
+    if access:
+        return getattr(access, 'get_'+name)(vinst)
+    else:
+        return getattr(vinst, name)

Added: pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rvirtualizable.py	Mon Jan 22 14:58:31 2007
@@ -0,0 +1,58 @@
+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
+
+class V(object):
+    _virtualizable_ = True
+
+    def __init__(self, v):
+        self.v = v
+
+def test_simple():
+    def f(v):
+        vinst = V(v)
+        return vinst, vinst.v
+    res = interpret(f, [42])
+    assert res.item1 == 42
+    res = lltype.normalizeptr(res.item0)
+    assert res.inst_v == 42
+    assert not res.vable_access
+    LLV = lltype.typeOf(res)
+    ACCESS = lltype.typeOf(res.vable_access).TO
+    assert ACCESS.get_inst_v == lltype.Ptr(lltype.FuncType([LLV],
+                                                           lltype.Signed))
+    assert ACCESS.set_inst_v == lltype.Ptr(lltype.FuncType([LLV, lltype.Signed],
+                                                           lltype.Void))    
+
+def test_accessors():
+
+    G = lltype.FuncType([rclass.OBJECTPTR], lltype.Void)
+
+    witness = []
+    
+    def getv(vinst):
+        value = vinst.inst_v
+        witness.append(value)
+        return value
+
+    def g(vobj):
+        vobj = lltype.normalizeptr(vobj)
+        LLV = lltype.typeOf(vobj).TO
+        ACCESS = LLV.vable_access.TO
+        access = lltype.malloc(ACCESS, immortal=True)
+        access.get_inst_v = lltype.functionptr(ACCESS.get_inst_v.TO,
+                                               'getv', _callable=getv)
+        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)
+        x = vinst.v
+        return x
+    res = interpret(f, [42])
+    assert res == 42
+
+    assert witness == [42]



More information about the Pypy-commit mailing list