[pypy-svn] r70010 - in pypy/branch/sepcomp/pypy/rpython: . lltypesystem lltypesystem/test test
xoraxax at codespeak.net
xoraxax at codespeak.net
Wed Dec 9 12:48:20 CET 2009
Author: xoraxax
Date: Wed Dec 9 12:48:20 2009
New Revision: 70010
Modified:
pypy/branch/sepcomp/pypy/rpython/lltypesystem/lltype.py
pypy/branch/sepcomp/pypy/rpython/lltypesystem/rclass.py
pypy/branch/sepcomp/pypy/rpython/lltypesystem/rtagged.py
pypy/branch/sepcomp/pypy/rpython/lltypesystem/test/test_lltype.py
pypy/branch/sepcomp/pypy/rpython/normalizecalls.py
pypy/branch/sepcomp/pypy/rpython/rclass.py
pypy/branch/sepcomp/pypy/rpython/rpbc.py
pypy/branch/sepcomp/pypy/rpython/rtyper.py
pypy/branch/sepcomp/pypy/rpython/test/test_rpbc.py
Log:
Add HOp repr.
Modified: pypy/branch/sepcomp/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/lltypesystem/lltype.py Wed Dec 9 12:48:20 2009
@@ -76,6 +76,12 @@
_is_compatible = __eq__
+ def __getstate__(self):
+ return self.__dict__
+
+ def __setstate__(self, val):
+ self.__dict__.update(val)
+
def _enforce(self, value):
if typeOf(value) != self:
raise TypeError
@@ -106,11 +112,6 @@
self.__cached_hash = result
return result
- # due to this dynamic hash value, we should forbid
- # pickling, until we have an algorithm for that.
- # but we just provide a tag for external help.
- __hash_is_not_constant__ = True
-
def __repr__(self):
return '<%s>' % (self,)
@@ -1260,6 +1261,7 @@
class _container(object):
__slots__ = ()
+ _exported = False
def _parentstructure(self, check=True):
return None
def _check(self):
@@ -1280,7 +1282,7 @@
__slots__ = ('_TYPE',
'_parent_type', '_parent_index', '_keepparent',
- '_wrparent',
+ '_wrparent',"_exported",
'__weakref__',
'_storage')
@@ -1651,7 +1653,9 @@
return id(self)
def __setattr__(self, attr, value):
- raise AttributeError("cannot change the attributes of %r" % (self,))
+ if attr != "_exported":
+ raise AttributeError("cannot change the attributes of %r" % (self,))
+ _container.__setattr__(self, attr, value)
class _opaque(_parentable):
def __init__(self, TYPE, parent=None, parentindex=None, **attrs):
@@ -1696,8 +1700,18 @@
return _parentable._normalizedcontainer(self)
+class _external_reference(_container):
+ def __init__(self, TYPE, name, component=None):
+ self._TYPE = TYPE
+ self.name = name
+ self.component = component
+ self.iddata = str(component) + name
+
+ def _getid(self):
+ return id(self.iddata)
+
+
class _pyobject(Hashable, _container):
- __slots__ = [] # or we get in trouble with pickling
_TYPE = PyObject
@@ -1764,6 +1778,10 @@
o = _pyobject(obj)
return _ptr(Ptr(PyObject), o)
+def externalptr(TYPE, name, component=None):
+ o = _external_reference(TYPE, name, component)
+ return _ptr(Ptr(TYPE), o, solid=True)
+
def cast_ptr_to_int(ptr):
return ptr._cast_to_int()
Modified: pypy/branch/sepcomp/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/lltypesystem/rclass.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/lltypesystem/rclass.py Wed Dec 9 12:48:20 2009
@@ -14,7 +14,8 @@
cast_pointer, cast_ptr_to_int, castable, nullptr, \
RuntimeTypeInfo, getRuntimeTypeInfo, typeOf, \
Array, Char, Void, attachRuntimeTypeInfo, \
- FuncType, Bool, Signed, functionptr, FuncType, PyObject
+ FuncType, Bool, Signed, functionptr, FuncType, PyObject, \
+ normalizeptr
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.robject import PyObjRepr, pyobj_repr
from pypy.rpython.extregistry import ExtRegistryEntry
@@ -62,8 +63,8 @@
OBJECTPTR = Ptr(OBJECT)
OBJECT_VTABLE.become(Struct('object_vtable',
#('parenttypeptr', CLASSTYPE),
- ('subclassrange_min', Signed),
- ('subclassrange_max', Signed),
+ ('level', Signed),
+ ('classrow', Ptr(Array(CLASSTYPE))),
('rtti', Ptr(RuntimeTypeInfo)),
('name', Ptr(Array(Char))),
('instantiate', Ptr(FuncType([], OBJECTPTR))),
@@ -86,6 +87,50 @@
return vtable
+
+def weave_llfields(llfields, classinfo, types_only=False):
+ llfields_iter = iter(llfields)
+ result = []
+ for mangled_name, name, value in classinfo:
+ if name is not None:
+ curfield = llfields_iter.next()
+ while curfield is not None and curfield[0] != mangled_name: # XXX does this make sense?
+ result.append((mangled_name, value.get_func()))
+ try:
+ curfield = llfields_iter.next()
+ except StopIteration:
+ curfield = None
+ if curfield is not None:
+ result.append(curfield)
+ else:
+ if not types_only:
+ value = typeOf(value)
+ result.append((mangled_name, value))
+ try:
+ llfields_iter.next()
+ except StopIteration:
+ pass
+ else:
+ raise TyperError("Incorrect set of llfields")
+ return result
+
+def extend_exportinfo(exportinfo, mangled_name, name, r, classdesc=None):
+ T = r.lowleveltype
+ if classdesc is None:
+ llvalue = T
+ var = None
+ else:
+ var = classdesc.read_attribute(name, None)
+ llvalue = r.convert_desc_or_const(var)
+ #import pdb; pdb.set_trace()
+ if var is None or not getattr(var.value, '_export_', None):
+ name = None # hide
+ val = llvalue
+ else:
+ val = var.value
+ exportinfo.append((mangled_name, name, val))
+
+
class ClassRepr(AbstractClassRepr):
def __init__(self, rtyper, classdef):
AbstractClassRepr.__init__(self, rtyper, classdef)
@@ -97,6 +142,7 @@
self.lowleveltype = Ptr(self.vtable_type)
def _setup_repr(self):
+ exportinfo = 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
@@ -105,6 +151,9 @@
pbcfields = {}
allmethods = {}
if self.classdef is not None:
+ if self.classdef.is_exported():
+ exportinfo = []
+ importinfo = self.classdef.get_import_data()
# class attributes
llfields = []
attrs = self.classdef.attrs.items()
@@ -117,9 +166,13 @@
allmethods[name] = True
s_value = s_unboundmethod
r = self.rtyper.getrepr(s_value)
+ #if "Multi" in repr(r) or ("Void" in repr(r.lowleveltype) and name in ("foo", "bar") and "foovoid" not in repr(self)):
+ # import pdb; pdb.set_trace()
mangled_name = 'cls_' + name
clsfields[name] = mangled_name, r
llfields.append((mangled_name, r.lowleveltype))
+ if exportinfo is not None and r.lowleveltype is not Void:
+ extend_exportinfo(exportinfo, mangled_name, name, r, self.classdef.classdesc)
# attributes showing up in getattrs done on the class as a PBC
extra_access_sets = self.rtyper.class_pbc_attributes.get(
self.classdef, {})
@@ -128,7 +181,12 @@
mangled_name = mangle('pbc%d' % counter, attr)
pbcfields[access_set, attr] = mangled_name, r
llfields.append((mangled_name, r.lowleveltype))
+ if exportinfo is not None:
+ assert 0, "not yet supported"
#
+ if importinfo:
+ #import pdb; pdb.set_trace()
+ llfields = weave_llfields(llfields, importinfo.cls)
self.rbase = getclassrepr(self.rtyper, self.classdef.basedef)
self.rbase.setup()
kwds = {'hints': {'immutable': True}}
@@ -136,6 +194,8 @@
('super', self.rbase.vtable_type),
*llfields, **kwds)
self.vtable_type.become(vtable_type)
+ if exportinfo is not None:
+ self.classdef.exportinfo_cls = exportinfo
allmethods.update(self.rbase.allmethods)
self.clsfields = clsfields
self.pbcfields = pbcfields
@@ -159,8 +219,20 @@
def getvtable(self, cast_to_typeptr=True):
"""Return a ptr to the vtable of this type."""
if self.vtable is None:
- self.vtable = malloc(self.vtable_type, immortal=True)
- self.setup_vtable(self.vtable, self)
+ if self.classdef and self.classdef.get_import_data():
+ #from pypy.rpython.lltypesystem.rffi import CConstant
+ handle = self.classdef.get_import_data().vtablename
+ component = None
+ if isinstance(handle, tuple):
+ component, handle = handle
+ #T = lltype.Ptr(lltype.OpaqueType(handle, hints=dict(external_void=True)))
+ #val = CConstant("&" + handle, T)
+ self.vtable = lltype.externalptr(OBJECT_VTABLE, handle + "_vtable", component)
+ #self.vtable = val
+ cast_to_typeptr = False
+ else:
+ self.vtable = malloc(self.vtable_type, immortal=True)
+ self.setup_vtable(self.vtable, self)
#
vtable = self.vtable
if cast_to_typeptr:
@@ -175,11 +247,18 @@
# initialize the 'subclassrange_*' and 'name' fields
if rsubcls.classdef is not None:
#vtable.parenttypeptr = rsubcls.rbase.getvtable()
- vtable.subclassrange_min = rsubcls.classdef.minid
- vtable.subclassrange_max = rsubcls.classdef.maxid
+ vtable.level = rsubcls.classdef.level
+ vtable.classrow = malloc(Array(CLASSTYPE), rsubcls.classdef.level + 1, immortal=True)
+ cur_repr = rsubcls
+ for i in xrange(rsubcls.classdef.level, -1, -1):
+ vtable.classrow[i] = cur_repr.getvtable()
+ cur_repr = cur_repr.rbase
+
+ if rsubcls.classdef.is_exported():
+ rsubcls.classdef.exportinfo_vtableval = normalizeptr(vtable)
else: #for the root class
- vtable.subclassrange_min = 0
- vtable.subclassrange_max = sys.maxint
+ vtable.level = -1
+ vtable.classrow = nullptr(Array(CLASSTYPE))
rinstance = getinstancerepr(self.rtyper, rsubcls.classdef)
rinstance.setup()
if rinstance.gcflavor == 'gc':
@@ -198,6 +277,7 @@
#else: the classdef was created recently, so no instantiate()
# could reach it
else:
+ importinfo = self.classdef.get_import_data()
# setup class attributes: for each attribute name at the level
# of 'self', look up its value in the subclass rsubcls
def assign(mangled_name, value):
@@ -206,7 +286,7 @@
llvalue = r.convert_desc_or_const(value)
setattr(vtable, mangled_name, llvalue)
- mro = list(rsubcls.classdef.getmro())
+ mro = list(rsubcls.classdef.getmro()) # XXX not needed?
for fldname in self.clsfields:
mangled_name, r = self.clsfields[fldname]
if r.lowleveltype is Void:
@@ -223,6 +303,10 @@
attrvalue = rsubcls.classdef.classdesc.read_attribute(attr, None)
if attrvalue is not None:
assign(mangled_name, attrvalue)
+ if importinfo:
+ for mangled_name, name, val in importinfo.cls:
+ if not name:
+ setattr(vtable, mangled_name, val)
# then initialize the 'super' portion of the vtable
self.rbase.setup_vtable(vtable.super, rsubcls)
@@ -282,10 +366,8 @@
## # a class with no subclass
## return hop.genop('ptr_eq', [v_cls1, v_cls2], resulttype=Bool)
## else:
- minid = hop.inputconst(Signed, cls2.subclassrange_min)
- maxid = hop.inputconst(Signed, cls2.subclassrange_max)
- return hop.gendirectcall(ll_issubclass_const, v_cls1, minid,
- maxid)
+ level = hop.inputconst(Signed, cls2.level)
+ return hop.gendirectcall(ll_issubclass_const, v_cls1, v_cls2, level)
else:
v_cls1, v_cls2 = hop.inputargs(class_repr, class_repr)
return hop.gendirectcall(ll_issubclass, v_cls1, v_cls2)
@@ -307,6 +389,7 @@
self.gcflavor = gcflavor
def _setup_repr(self, llfields=None, hints=None, adtmeths=None):
+ exportinfo = 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
@@ -317,6 +400,8 @@
if self.classdef is None:
fields['__class__'] = 'typeptr', get_type_repr(self.rtyper)
else:
+ if self.classdef.is_exported():
+ exportinfo = []
# instance attributes
if llfields is None:
llfields = []
@@ -328,12 +413,18 @@
mangled_name = 'inst_' + name
fields[name] = mangled_name, r
llfields.append((mangled_name, r.lowleveltype))
+ if exportinfo is not None:
+ extend_exportinfo(exportinfo, mangled_name, name, r, None)
+
#
# hash() support
if self.rtyper.needs_hash_support(self.classdef):
from pypy.rpython import rint
fields['_hash_cache_'] = 'hash_cache', rint.signed_repr
llfields.append(('hash_cache', Signed))
+ importinfo = self.classdef.get_import_data()
+ if importinfo:
+ llfields = weave_llfields(llfields, importinfo.inst, True)
self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef,
self.gcflavor)
@@ -347,6 +438,11 @@
if '_immutable_' in self.classdef.classdesc.classdict:
hints = hints.copy()
hints['immutable'] = True
+ if self.classdef.is_exported():
+ hints = hints.copy()
+ hints['_exported'] = True
+ if exportinfo is not None:
+ self.classdef.exportinfo_inst = exportinfo
object_type = MkStruct(self.classdef.name,
('super', self.rbase.object_type),
hints=hints,
@@ -584,16 +680,15 @@
instance_repr = self.common_repr()
v_obj, v_cls = hop.inputargs(instance_repr, class_repr)
- if isinstance(v_cls, Constant):
+ if False and isinstance(v_cls, Constant): # XXX
cls = v_cls.value
# XXX re-implement the following optimization
#if cls.subclassrange_max == cls.subclassrange_min:
# # a class with no subclass
# return hop.gendirectcall(rclass.ll_isinstance_exact, v_obj, v_cls)
#else:
- minid = hop.inputconst(Signed, cls.subclassrange_min)
- maxid = hop.inputconst(Signed, cls.subclassrange_max)
- return hop.gendirectcall(ll_isinstance_const, v_obj, minid, maxid)
+ level = hop.inputconst(Signed, cls.level)
+ return hop.gendirectcall(ll_isinstance_const, v_obj, v_cls, level)
else:
return hop.gendirectcall(ll_isinstance, v_obj, v_cls)
@@ -679,11 +774,10 @@
return cast_pointer(OBJECTPTR, obj).typeptr
def ll_issubclass(subcls, cls):
- return cls.subclassrange_min <= subcls.subclassrange_min <= cls.subclassrange_max
-
-def ll_issubclass_const(subcls, minid, maxid):
- return minid <= subcls.subclassrange_min <= maxid
+ return subcls.level >= cls.level and subcls.classrow[cls.level] == cls
+def ll_issubclass_const(subcls, cls, level):
+ return subcls.level >= level and subcls.classrow[level] == cls
def ll_isinstance(obj, cls): # obj should be cast to OBJECT or NONGCOBJECT
if not obj:
@@ -691,12 +785,12 @@
obj_cls = obj.typeptr
return ll_issubclass(obj_cls, cls)
-def ll_isinstance_const(obj, minid, maxid):
+def ll_isinstance_const(obj, cls, level):
if not obj:
return False
- return ll_issubclass_const(obj.typeptr, minid, maxid)
+ return ll_issubclass_const(obj.typeptr, cls, level)
-def ll_isinstance_exact(obj, cls):
+def ll_isinstance_exact(obj, cls): #unused
if not obj:
return False
obj_cls = obj.typeptr
Modified: pypy/branch/sepcomp/pypy/rpython/lltypesystem/rtagged.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/lltypesystem/rtagged.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/lltypesystem/rtagged.py Wed Dec 9 12:48:20 2009
@@ -129,10 +129,9 @@
cls = v_cls.value
answer = self.unboxedclassdef.issubclass(classdef)
c_answer_if_unboxed = hop.inputconst(lltype.Bool, answer)
- minid = hop.inputconst(lltype.Signed, cls.subclassrange_min)
- maxid = hop.inputconst(lltype.Signed, cls.subclassrange_max)
- return hop.gendirectcall(ll_unboxed_isinstance_const, v_obj,
- minid, maxid, c_answer_if_unboxed)
+ level = hop.inputconst(lltype.Signed, cls.level)
+ return hop.gendirectcall(ll_unboxed_isinstance_const, v_obj, v_cls,
+ level, c_answer_if_unboxed)
def ll_int_to_unboxed(PTRTYPE, value):
@@ -147,10 +146,10 @@
else:
return instance.typeptr
-def ll_unboxed_isinstance_const(obj, minid, maxid, answer_if_unboxed):
+def ll_unboxed_isinstance_const(obj, cls, level, answer_if_unboxed):
if not obj:
return False
if lltype.cast_ptr_to_int(obj) & 1:
return answer_if_unboxed
else:
- return ll_issubclass_const(obj.typeptr, minid, maxid)
+ return ll_issubclass_const(obj.typeptr, cls, level)
Modified: pypy/branch/sepcomp/pypy/rpython/lltypesystem/test/test_lltype.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/lltypesystem/test/test_lltype.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/lltypesystem/test/test_lltype.py Wed Dec 9 12:48:20 2009
@@ -326,6 +326,19 @@
assert S == S1
assert hash(S1) == hash(S)
+
+def test_pickle():
+ S = ForwardReference()
+ S.become(Struct('S', ('p', Ptr(S))))
+ assert S == S
+ hash(S)
+ from pickle import dumps, loads
+ S_pickle = dumps(S)
+ S_loaded = loads(S_pickle)
+ assert S_loaded == S
+ assert hash(S_loaded) == hash(S)
+
+
def test_array_with_non_container_elements():
As = GcArray(Signed)
a = malloc(As, 3)
Modified: pypy/branch/sepcomp/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/normalizecalls.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/normalizecalls.py Wed Dec 9 12:48:20 2009
@@ -331,6 +331,14 @@
classdef.minid = TotalOrderSymbolic(witness, lst)
classdef.maxid = TotalOrderSymbolic(witness + [MAX], lst)
+
+def assign_inheritance_levels(annotator):
+ bk = annotator.bookkeeper
+ for classdef in bk.classdefs:
+ if not hasattr(classdef, 'level'):
+ classdef.level = len(tuple(classdef.getmro())) - 1
+
+
MAX = 1E100
_cdef_id_counter = 0
def get_unique_cdef_id(cdef):
@@ -350,7 +358,7 @@
try:
normalize_call_familes(rtyper.annotator)
merge_classpbc_getattr_into_classdef(rtyper)
- assign_inheritance_ids(rtyper.annotator)
+ assign_inheritance_levels(rtyper.annotator)
finally:
rtyper.annotator.frozen -= 1
create_instantiate_functions(rtyper.annotator)
Modified: pypy/branch/sepcomp/pypy/rpython/rclass.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/rclass.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/rclass.py Wed Dec 9 12:48:20 2009
@@ -77,7 +77,7 @@
if not s_value.isNone() and s_value.getKind() == description.MethodDesc:
s_value = self.classdef.lookup_filter(s_value)
funcdescs = [mdesc.funcdesc for mdesc in s_value.descriptions]
- return annmodel.SomePBC(funcdescs)
+ return annmodel.SomePBC(funcdescs, force_virtual_access=any(mdesc.force_virtual_access for mdesc in s_value.descriptions))
return None # not a method
def get_ll_eq_function(self):
Modified: pypy/branch/sepcomp/pypy/rpython/rpbc.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/rpbc.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/rpbc.py Wed Dec 9 12:48:20 2009
@@ -177,12 +177,14 @@
class AbstractFunctionsPBCRepr(CanBeNull, Repr):
"""Representation selected for a PBC of function(s)."""
-
+ force_virtual = False
def __init__(self, rtyper, s_pbc):
self.rtyper = rtyper
self.s_pbc = s_pbc
self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
- if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None:
+
+ if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None and not (
+ s_pbc.force_virtual_access):
# a single function
self.lowleveltype = Void
else:
Modified: pypy/branch/sepcomp/pypy/rpython/rtyper.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/rtyper.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/rtyper.py Wed Dec 9 12:48:20 2009
@@ -689,6 +689,9 @@
self.r_result = rtyper.getrepr(self.s_result)
rtyper.call_all_setups() # compute ForwardReferences now
+ def __repr__(self):
+ return '<HOp %r #llops=%i>' % (self.spaceop, len(self.llops))
+
def copy(self):
result = HighLevelOp(self.rtyper, self.spaceop,
self.exceptionlinks, self.llops)
Modified: pypy/branch/sepcomp/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/branch/sepcomp/pypy/rpython/test/test_rpbc.py (original)
+++ pypy/branch/sepcomp/pypy/rpython/test/test_rpbc.py Wed Dec 9 12:48:20 2009
@@ -1595,7 +1595,33 @@
self.interpret(f, [int])
class TestLLtype(BaseTestRPBC, LLRtypeMixin):
- pass
+ def test_devoid_exported_func(self):
+ from pypy.translator.translator import graphof
+ from pypy.objspace.flow.model import summary
+ class c:
+ _force_virtual_ = True
+ def foo(self):
+ return 42
+ foo._force_virtual_ = True
+ def f():
+ inst = c()
+ inst.foo()
+ return inst
+ def testfunc(x):
+ return x.foo()
+ def h():
+ return testfunc(c())
+
+ t, r, g = self.gengraph(f)
+ bk = t.annotator.bookkeeper
+ getcdef = bk.getuniqueclassdef
+ classdef = getcdef(c)
+ vt = t.rtyper.class_reprs[classdef].getvtable()
+ assert isinstance(typeOf(t.rtyper.class_reprs[classdef].getvtable(False).cls_foo).TO, FuncType)
+ t, r, g2 = self.gengraph(h)
+ assert not summary(g).get('direct_call', 0)
+ assert not summary(graphof(t, testfunc)).get('direct_call', 0)
+
class TestOOtype(BaseTestRPBC, OORtypeMixin):
pass
More information about the Pypy-commit
mailing list