[pypy-svn] r51600 - in pypy/branch/unified-rtti/pypy/rpython/lltypesystem: . test
arigo at codespeak.net
arigo at codespeak.net
Mon Feb 18 18:16:46 CET 2008
Author: arigo
Date: Mon Feb 18 18:16:45 2008
New Revision: 51600
Modified:
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py
pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_lltype.py
Log:
Tests and implementation for the new interface.
(Nothing else fixed yet, of course)
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/lltype.py Mon Feb 18 18:16:45 2008
@@ -147,9 +147,11 @@
def _inline_is_varsize(self, last):
raise TypeError, "%r cannot be inlined in structure" % self
- def _install_extras(self, adtmeths={}, hints={}):
+ def _install_extras(self, adtmeths={}, hints={}, runtime_type_info=None):
self._adtmeths = frozendict(adtmeths)
self._hints = frozendict(hints)
+ if runtime_type_info is not None:
+ _install_rtti(self, runtime_type_info)
def __getattr__(self, name):
adtmeth = self._adtmeths.get(name, NFOUND)
@@ -207,7 +209,7 @@
if self._names:
first = self._names[0]
FIRSTTYPE = self._flds[first]
- if (isinstance(FIRSTTYPE, (Struct, PyObjectType)) and
+ if (isinstance(FIRSTTYPE, FirstStructTypes) and
self._gckind == FIRSTTYPE._gckind):
return first, FIRSTTYPE
return None, None
@@ -281,34 +283,7 @@
n = 1
return _struct(self, n, initialization='example')
-class RttiStruct(Struct):
- _runtime_type_info = None
-
- def _attach_runtime_type_info_funcptr(self, funcptr, destrptr):
- if self._runtime_type_info is None:
- self._runtime_type_info = opaqueptr(RuntimeTypeInfo, name=self._name, about=self)._obj
- if funcptr is not None:
- T = typeOf(funcptr)
- if (not isinstance(T, Ptr) or
- not isinstance(T.TO, FuncType) or
- len(T.TO.ARGS) != 1 or
- T.TO.RESULT != Ptr(RuntimeTypeInfo) or
- castable(T.TO.ARGS[0], Ptr(self)) < 0):
- raise TypeError("expected a runtime type info function "
- "implementation, got: %s" % funcptr)
- self._runtime_type_info.query_funcptr = funcptr
- if destrptr is not None :
- T = typeOf(destrptr)
- if (not isinstance(T, Ptr) or
- not isinstance(T.TO, FuncType) or
- len(T.TO.ARGS) != 1 or
- T.TO.RESULT != Void or
- castable(T.TO.ARGS[0], Ptr(self)) < 0):
- raise TypeError("expected a destructor function "
- "implementation, got: %s" % destrptr)
- self._runtime_type_info.destructor_funcptr = destrptr
-
-class GcStruct(RttiStruct):
+class GcStruct(Struct):
_gckind = 'gc'
STRUCT_BY_FLAVOR = {'raw': Struct,
@@ -441,6 +416,19 @@
return [arg for arg in self.ARGS if arg is not Void]
+class RuntimeTypeInfoType(ContainerType):
+ _gckind = 'raw'
+
+ def _inline_is_varsize(self, last):
+ return False
+
+ def _allocate(self, initialization, parent=None, parentindex=None):
+ return _rtti(initialization=initialization,
+ parent=parent, parentindex=parentindex)
+
+RuntimeTypeInfo = RuntimeTypeInfoType()
+
+
class OpaqueType(ContainerType):
_gckind = 'raw'
@@ -466,8 +454,6 @@
def _allocate(self, initialization, parent=None, parentindex=None):
return self._defl(parent=parent, parentindex=parentindex)
-RuntimeTypeInfo = OpaqueType("RuntimeTypeInfo")
-
class GcOpaqueType(OpaqueType):
_gckind = 'gc'
@@ -491,6 +477,8 @@
PyObject = PyObjectType()
+FirstStructTypes = (Struct, PyObjectType, RuntimeTypeInfoType)
+
class ForwardReference(ContainerType):
_gckind = 'raw'
def become(self, realcontainertype):
@@ -768,8 +756,8 @@
% (CURTYPE, PTRTYPE))
if CURTYPE == PTRTYPE:
return 0
- if (not isinstance(CURTYPE.TO, (Struct, PyObjectType)) or
- not isinstance(PTRTYPE.TO, (Struct, PyObjectType))):
+ if (not isinstance(CURTYPE.TO, FirstStructTypes) or
+ not isinstance(PTRTYPE.TO, FirstStructTypes)):
raise InvalidCast(CURTYPE, PTRTYPE)
CURSTRUC = CURTYPE.TO
PTRSTRUC = PTRTYPE.TO
@@ -1653,6 +1641,24 @@
def __setattr__(self, attr, value):
raise AttributeError("cannot change the attributes of %r" % (self,))
+
+class _rtti(_parentable):
+ _kind = "rtti"
+
+ def __init__(self, initialization=None, parent=None, parentindex=None):
+ _parentable.__init__(self, RuntimeTypeInfo)
+ if parent is not None:
+ self._setparentstructure(parent, parentindex)
+
+ def _set_gctype(self, GCTYPE):
+ if hasattr(self, 'GCTYPE'):
+ raise TypeError("cannot use the same _rtti for several GC types")
+ if GCTYPE._gckind != 'gc':
+ raise TypeError("non-GC type %r cannot have an rtti" % (GCTYPE,))
+ self._GCTYPE = GCTYPE
+ self.destructor_funcptr = nullptr(FuncType([Ptr(GCTYPE)], Void))
+
+
class _opaque(_parentable):
def __init__(self, TYPE, parent=None, parentindex=None, **attrs):
_parentable.__init__(self, TYPE)
@@ -1726,6 +1732,8 @@
elif isinstance(T, OpaqueType):
assert n is None
o = _opaque(T, initialization=initialization)
+ elif T == RuntimeTypeInfo:
+ o = _rtti(initialization=initialization)
else:
raise TypeError, "malloc for Structs and Arrays only"
if T._gckind != 'gc' and not immortal and flavor.startswith('gc'):
@@ -1773,37 +1781,58 @@
assert oddint & 1, "only odd integers can be cast back to ptr"
return _ptr(PTRTYPE, oddint, solid=True)
-def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None):
- if not isinstance(GCSTRUCT, RttiStruct):
- raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT
- GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr)
- return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info)
-
-def getRuntimeTypeInfo(GCSTRUCT):
- if not isinstance(GCSTRUCT, RttiStruct):
- raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT
- if GCSTRUCT._runtime_type_info is None:
- raise ValueError, ("no attached runtime type info for GcStruct %s" %
- GCSTRUCT._name)
- return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info)
+def getRuntimeTypeInfo(TYPE, cache=None):
+ """Return the runtime_type_info attached to the GcStruct TYPE.
+ This is typically of type != Ptr(RuntimeTypeInfo) but castable
+ to Ptr(RuntimeTypeInfo). This raises TypeError if the TYPE has
+ no runtime_type_info, unless 'cache' is specified; in that case,
+ TYPE can be any GC type and a runtime_type_info is created for
+ it if it has none and stored in the cache to avoid mutating
+ the TYPE.
+ """
+ if isinstance(TYPE, GcStruct) and hasattr(TYPE, '_rtti'):
+ return top_container(TYPE._rtti)._as_ptr()
+ if cache is None:
+ raise TypeError("%r has no runtime_type_info" % (TYPE,))
+ try:
+ return cache[TYPE]
+ except KeyError:
+ rttiptr = malloc(RuntimeTypeInfo, immortal=True)
+ rttiptr._obj._set_gctype(TYPE)
+ cache[TYPE] = rttiptr
+ return rttiptr
+
+def _install_rtti(STRUCT, runtime_type_info):
+ if not isinstance(STRUCT, GcStruct):
+ raise TypeError("can only attach a runtime_type_info to a GcStruct")
+ if runtime_type_info is None:
+ runtime_type_info = malloc(RuntimeTypeInfo, immortal=True)
+ rttiptr = cast_pointer(Ptr(RuntimeTypeInfo), runtime_type_info)
+ # check that the attached info is compatible with the inlined parent
+ # structure type's attached info
+ name, SUBSTRUCT = STRUCT._first_struct()
+ if SUBSTRUCT is not None:
+ if not hasattr(SUBSTRUCT, '_rtti'):
+ raise TypeError("first inlined GcStruct has no runtime_type_info")
+ PARENT = typeOf(top_container(SUBSTRUCT._rtti))
+ cast_pointer(Ptr(PARENT), runtime_type_info) # for checking
+ # ready
+ assert not hasattr(STRUCT, '_rtti')
+ STRUCT._rtti = rttiptr._obj
+ rttiptr._obj._set_gctype(STRUCT)
def runtime_type_info(p):
- T = typeOf(p)
- if not isinstance(T, Ptr) or not isinstance(T.TO, RttiStruct):
- raise TypeError, "runtime_type_info on non-RttiStruct pointer: %s" % p
- struct = p._obj
- top_parent = top_container(struct)
- result = getRuntimeTypeInfo(top_parent._TYPE)
- static_info = getRuntimeTypeInfo(T.TO)
- query_funcptr = getattr(static_info._obj, 'query_funcptr', None)
- if query_funcptr is not None:
- T = typeOf(query_funcptr).TO.ARGS[0]
- result2 = query_funcptr(cast_pointer(T, p))
- if result != result2:
- raise RuntimeError, ("runtime type-info function for %s:\n"
- " returned: %s,\n"
- "should have been: %s" % (p, result2, result))
- return result
+ """This is a run-time operation that returns the exact type of 'p',
+ as a Ptr(RuntimeTypeInfo).
+ """
+ # This might assume that 'p' points to a GcStruct with an explicitly
+ # specified runtime_type_info; it is unclear for now if all GCs will
+ # support this operation for other kinds of GC types.
+ GCTYPE = typeOf(p).TO
+ assert isinstance(GCTYPE, GcStruct), "XXX for now"
+ assert hasattr(GCTYPE, '_rtti'), "XXX for now"
+ EXACTTYPE = typeOf(top_container(p._obj))
+ return EXACTTYPE._rtti._as_ptr()
def isCompatibleType(TYPE1, TYPE2):
return TYPE1._is_compatible(TYPE2)
Modified: pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_lltype.py
==============================================================================
--- pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_lltype.py (original)
+++ pypy/branch/unified-rtti/pypy/rpython/lltypesystem/test/test_lltype.py Mon Feb 18 18:16:45 2008
@@ -357,76 +357,55 @@
p = cast_pointer(Ptr(S), p1)
assert p.s1.x == 5
-def test_getRuntimeTypeInfo():
- S = GcStruct('s', ('x', Signed))
- py.test.raises(ValueError, "getRuntimeTypeInfo(S)")
- pinf0 = attachRuntimeTypeInfo(S)
- assert pinf0._obj.about == S
- pinf = getRuntimeTypeInfo(S)
- assert pinf == pinf0
- pinf1 = getRuntimeTypeInfo(S)
- assert pinf == pinf1
- Z = GcStruct('z', ('x', Unsigned))
- attachRuntimeTypeInfo(Z)
- assert getRuntimeTypeInfo(Z) != pinf0
- Sbis = GcStruct('s', ('x', Signed))
- attachRuntimeTypeInfo(Sbis)
- assert getRuntimeTypeInfo(Sbis) != pinf0
- assert Sbis != S # the attached runtime type info distinguishes them
+def test_runtime_type_info():
+ T1 = Struct('T1', ('base', RuntimeTypeInfo), ('u', Signed))
+ t1 = malloc(T1, immortal=True)
+ t1.u = 21
+ S1 = GcStruct('S1', ('x', Signed), runtime_type_info=t1)
+
+ T2bogus = Struct('T2bogus', ('foobar', Signed))
+ t2bogus = malloc(T2bogus, immortal=True)
+ py.test.raises(TypeError, "GcStruct('S2', runtime_type_info=t2bogus)")
+
+ T2 = Struct('T2', ('base', T1), ('v', Signed))
+ t2 = malloc(T2, immortal=True)
+ t2.base.u = 22
+ t2.v = 33
+ S2 = GcStruct('S2', ('parent', S1), ('y', Signed), runtime_type_info=t2)
+
+ assert getRuntimeTypeInfo(S1) == t1
+ assert getRuntimeTypeInfo(S2) == t2
+
+ x1 = malloc(S1)
+ x2 = malloc(S2)
+ p2 = x2.parent
+ assert runtime_type_info(x1) == t1.base
+ assert runtime_type_info(x2) == t2.base.base
+ assert runtime_type_info(p2) == t2.base.base
+
+ S1bis = GcStruct('S1', ('x', Signed))
+ assert S1bis != S1 # attached runtime type info distinguishes them
+ py.test.raises(TypeError, getRuntimeTypeInfo, S1bis)
+
+ cache = {}
+ assert getRuntimeTypeInfo(S1, cache=cache) == t1
+ t1bis = getRuntimeTypeInfo(S1bis, cache=cache)
+ assert t1bis != t1.base
+ assert getRuntimeTypeInfo(S1bis, cache=cache) == t1bis
def test_getRuntimeTypeInfo_destrpointer():
- S = GcStruct('s', ('x', Signed))
+ S = GcStruct('s', ('x', Signed),
+ runtime_type_info=malloc(RuntimeTypeInfo, immortal=True))
def f(s):
s.x = 1
- def type_info_S(p):
- return getRuntimeTypeInfo(S)
- qp = functionptr(FuncType([Ptr(S)], Ptr(RuntimeTypeInfo)),
- "type_info_S",
- _callable=type_info_S)
dp = functionptr(FuncType([Ptr(S)], Void),
"destructor_funcptr",
_callable=f)
- pinf0 = attachRuntimeTypeInfo(S, qp, destrptr=dp)
- assert pinf0._obj.about == S
pinf = getRuntimeTypeInfo(S)
- assert pinf == pinf0
- pinf1 = getRuntimeTypeInfo(S)
- assert pinf == pinf1
+ assert pinf._obj.destructor_funcptr == nullptr(FuncType([Ptr(S)], Void))
+ pinf._obj.destructor_funcptr = dp
assert pinf._obj.destructor_funcptr == dp
- assert pinf._obj.query_funcptr == qp
-def test_runtime_type_info():
- S = GcStruct('s', ('x', Signed))
- attachRuntimeTypeInfo(S)
- s = malloc(S)
- s.x = 0
- assert runtime_type_info(s) == getRuntimeTypeInfo(S)
- S1 = GcStruct('s1', ('sub', S), ('x', Signed))
- attachRuntimeTypeInfo(S1)
- s1 = malloc(S1)
- s1.sub.x = 0
- s1.x = 0
- assert runtime_type_info(s1) == getRuntimeTypeInfo(S1)
- assert runtime_type_info(s1.sub) == getRuntimeTypeInfo(S1)
- assert runtime_type_info(cast_pointer(Ptr(S), s1)) == getRuntimeTypeInfo(S1)
- def dynamic_type_info_S(p):
- if p.x == 0:
- return getRuntimeTypeInfo(S)
- else:
- return getRuntimeTypeInfo(S1)
- fp = functionptr(FuncType([Ptr(S)], Ptr(RuntimeTypeInfo)),
- "dynamic_type_info_S",
- _callable=dynamic_type_info_S)
- attachRuntimeTypeInfo(S, fp)
- assert s.x == 0
- assert runtime_type_info(s) == getRuntimeTypeInfo(S)
- s.x = 1
- py.test.raises(RuntimeError, "runtime_type_info(s)")
- assert s1.sub.x == 0
- py.test.raises(RuntimeError, "runtime_type_info(s1.sub)")
- s1.sub.x = 1
- assert runtime_type_info(s1.sub) == getRuntimeTypeInfo(S1)
-
def test_flavor_malloc():
def isweak(p, T):
return p._weak and typeOf(p).TO == T
More information about the Pypy-commit
mailing list