[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