[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