[pypy-svn] r16175 - in pypy/dist/pypy: annotation rpython rpython/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Aug 19 19:34:00 CEST 2005


Author: pedronis
Date: Fri Aug 19 19:33:57 2005
New Revision: 16175

Modified:
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/rpython/lltype.py
   pypy/dist/pypy/rpython/normalizecalls.py
   pypy/dist/pypy/rpython/objectmodel.py
   pypy/dist/pypy/rpython/rbuiltin.py
   pypy/dist/pypy/rpython/rclass.py
   pypy/dist/pypy/rpython/rmodel.py
   pypy/dist/pypy/rpython/test/test_lltype.py
   pypy/dist/pypy/rpython/test/test_nongc.py
   pypy/dist/pypy/rpython/test/test_rtyper.py
Log:
support for _alloc_flavor_ in class definitions to allow non-gc allocation strategies for classes.

introduced a flavor (defaults to 'gc') argument to malloc, and flavor_malloc free_non_gc_object
ops

non-gc is assumed if the flavor string doesn't start with 'gc'. In that case a Struct and not a GcStruct
will be used for the instances. There's a common base instance object for such non-gc classes, using
the rclass.NONGCOBJECT Struct.




Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Fri Aug 19 19:33:57 2005
@@ -337,6 +337,15 @@
 BUILTIN_ANALYZERS[lltype.getRuntimeTypeInfo] = getRuntimeTypeInfo
 BUILTIN_ANALYZERS[lltype.runtime_type_info] = runtime_type_info
 
+#________________________________
+# non-gc objects
+
+def robjmodel_free_non_gc_object(obj):
+    pass
+
+BUILTIN_ANALYZERS[pypy.rpython.objectmodel.free_non_gc_object] = (
+    robjmodel_free_non_gc_object)
+
 #_________________________________
 # memory address
 

Modified: pypy/dist/pypy/rpython/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltype.py	Fri Aug 19 19:33:57 2005
@@ -348,7 +348,7 @@
 
     def _example(self):
         o = self.TO._container_example()
-        return _ptr(self, o, immortal=True)
+        return _ptr(self, o, solid=True)
 
 
 # ____________________________________________________________
@@ -462,7 +462,7 @@
 
 class _ptr(object):
     __slots__ = ('_TYPE', '_T', 
-                 '_weak', '_immortal',
+                 '_weak', '_solid',
                  '_obj0', '__weakref__')
 
     def _set_TYPE(self, TYPE):
@@ -474,8 +474,8 @@
     def _set_weak(self, weak):
         _ptr._weak.__set__(self, weak)
 
-    def _set_immortal(self, immortal):
-        _ptr._immortal.__set__(self, immortal)
+    def _set_solid(self, solid):
+        _ptr._solid.__set__(self, solid)
 
     def _set_obj0(self, obj):
         _ptr._obj0.__set__(self, obj)
@@ -483,11 +483,11 @@
     def _needsgc(self):
         return self._TYPE._needsgc() # xxx other rules?
 
-    def __init__(self, TYPE, pointing_to, immortal=False):
+    def __init__(self, TYPE, pointing_to, solid=False):
         self._set_TYPE(TYPE)
         self._set_T(TYPE.TO)
         self._set_weak(False)
-        self._setobj(pointing_to, immortal)
+        self._setobj(pointing_to, solid)
 
     def __eq__(self, other):
         if not isinstance(other, _ptr):
@@ -508,15 +508,15 @@
 
     # _setobj, _getobj and _obj0 are really _internal_ implementations details of _ptr,
     # use _obj if necessary instead !
-    def _setobj(self, pointing_to, immortal=False):        
+    def _setobj(self, pointing_to, solid=False):        
         if pointing_to is None:
             obj0 = None
-        elif immortal or isinstance(self._T, (GC_CONTAINER, FuncType)):
+        elif solid or isinstance(self._T, (GC_CONTAINER, FuncType)):
             obj0 = pointing_to
         else:
             self._set_weak(True)
             obj0 = weakref.ref(pointing_to)
-        self._set_immortal(immortal)
+        self._set_solid(solid)
         self._set_obj0(obj0)
         
     def _getobj(self):
@@ -811,16 +811,21 @@
         return "pyobject %s" % (super(_pyobject, self).__str__(),)
 
 
-def malloc(T, n=None, immortal=False):
+def malloc(T, n=None, flavor='gc', immortal=False):
     if isinstance(T, Struct):
         o = _struct(T, n)
     elif isinstance(T, Array):
         o = _array(T, n)
     else:
         raise TypeError, "malloc for Structs and Arrays only"
-    if not isinstance(T, GC_CONTAINER) and not immortal:
-        raise TypeError, "malloc of a non-GC non-immortal structure"
-    return _ptr(Ptr(T), o, immortal)
+    if not isinstance(T, GC_CONTAINER) and not immortal and flavor.startswith('gc'):
+        raise TypeError, "gc flavor malloc of a non-GC non-immortal structure"
+    solid = immortal or not flavor.startswith('gc') # immortal or non-gc case
+    return _ptr(Ptr(T), o, solid)
+
+def flavored_malloc(flavor, T, n=None): # avoids keyword argument usage
+    return malloc(T, n, flavor=flavor)
+    
 
 def functionptr(TYPE, name, **attrs):
     if not isinstance(TYPE, FuncType):
@@ -839,7 +844,7 @@
     if not isinstance(TYPE, OpaqueType):
         raise TypeError, "opaqueptr() for OpaqueTypes only"
     o = _opaque(TYPE, _name=name, **attrs)
-    return _ptr(Ptr(TYPE), o, immortal=attrs.get('immortal', True))
+    return _ptr(Ptr(TYPE), o, solid=attrs.get('immortal', True))
 
 def pyobjectptr(obj):
     o = _pyobject(obj)

Modified: pypy/dist/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/dist/pypy/rpython/normalizecalls.py	(original)
+++ pypy/dist/pypy/rpython/normalizecalls.py	Fri Aug 19 19:33:57 2005
@@ -6,7 +6,7 @@
 from pypy.annotation import model as annmodel
 from pypy.tool.sourcetools import has_varargs, valid_identifier
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rpython.rmodel import TyperError
+from pypy.rpython.rmodel import TyperError, needsgc
 from pypy.rpython.objectmodel import instantiate
 
 
@@ -325,7 +325,8 @@
 def create_instantiate_functions(annotator):
     # build the 'instantiate() -> instance of C' functions for the vtables
     for cls, classdef in annotator.getuserclasses().items():
-        create_instantiate_function(annotator, cls, classdef)
+        if needsgc(classdef): # only gc-case
+            create_instantiate_function(annotator, cls, classdef)
 
 def create_instantiate_function(annotator, cls, classdef):
     def my_instantiate():

Modified: pypy/dist/pypy/rpython/objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/objectmodel.py	(original)
+++ pypy/dist/pypy/rpython/objectmodel.py	Fri Aug 19 19:33:57 2005
@@ -26,6 +26,6 @@
 
 
 def free_non_gc_object(obj):
-    assert getattr(obj.__class__, "_alloc_flavor_", False) == "", "trying to free regular object"
+    assert not getattr(obj.__class__, "_alloc_flavor_", 'gc').startswith('gc'), "trying to free gc object"
     obj.__dict__ = {}
     obj.__class__ = FREED_OBJECT

Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/rbuiltin.py	Fri Aug 19 19:33:57 2005
@@ -141,10 +141,11 @@
         vlist = hop.inputarg(rlist, arg=0)
         cnone = hop.inputconst(rlist, None)
         return hop.genop('ptr_ne', [vlist, cnone], resulttype=lltype.Bool)
-    
-    instance_repr = rclass.getinstancerepr(hop.rtyper, None)
+
     class_repr = rclass.get_type_repr(hop.rtyper)
-    
+    assert isinstance(hop.args_r[0], rclass.InstanceRepr)
+    instance_repr = hop.args_r[0].common_repr()
+
     v_obj, v_cls = hop.inputargs(instance_repr, class_repr)
 
     return hop.gendirectcall(rclass.ll_isinstance, v_obj, v_cls)
@@ -318,3 +319,15 @@
 BUILTIN_TYPER[lladdress.raw_malloc] = rtype_raw_malloc
 BUILTIN_TYPER[lladdress.raw_free] = rtype_raw_free
 BUILTIN_TYPER[lladdress.raw_memcopy] = rtype_raw_memcopy
+
+# _________________________________________________________________
+# non-gc objects
+
+def rtype_free_non_gc_object(hop):
+    vinst, = hop.inputargs(hop.args_r[0])
+    flavor = hop.args_r[0].getflavor()
+    assert not flavor.startswith('gc')
+    cflavor = hop.inputconst(lltype.Void, flavor)
+    return hop.genop('free_non_gc_object', [cflavor, vinst])
+    
+BUILTIN_TYPER[objectmodel.free_non_gc_object] = rtype_free_non_gc_object

Modified: pypy/dist/pypy/rpython/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/rclass.py	(original)
+++ pypy/dist/pypy/rpython/rclass.py	Fri Aug 19 19:33:57 2005
@@ -2,7 +2,7 @@
 from pypy.annotation.pairtype import pairtype, pair
 from pypy.annotation import model as annmodel
 from pypy.annotation.classdef import isclassdef
-from pypy.rpython.rmodel import Repr, TyperError, inputconst, warning
+from pypy.rpython.rmodel import Repr, TyperError, inputconst, warning, needsgc
 from pypy.rpython.lltype import ForwardReference, GcForwardReference
 from pypy.rpython.lltype import Ptr, Struct, GcStruct, malloc
 from pypy.rpython.lltype import cast_pointer, castable, nullptr
@@ -39,6 +39,7 @@
 #         ...               // extra instance attributes
 #     }
 #
+# there's also a nongcobject 
 
 OBJECT_VTABLE = ForwardReference()
 TYPEPTR = Ptr(OBJECT_VTABLE)
@@ -49,6 +50,9 @@
                             ('rtti', Ptr(RuntimeTypeInfo)),
                             ('name', Ptr(Array(Char))),
                             ('instantiate', Ptr(FuncType([], OBJECTPTR)))))
+# non-gc case
+NONGCOBJECT = Struct('nongcobject', ('typeptr', TYPEPTR))
+NONGCOBJECTPTR = Ptr(OBJECT)
 
 def getclassrepr(rtyper, classdef):
     try:
@@ -69,16 +73,17 @@
         rtyper.add_pendingsetup(result)
     return result
 
-def getinstancerepr(rtyper, classdef):
+def getinstancerepr(rtyper, classdef, nogc=False):
+    does_need_gc = needsgc(classdef, nogc)
     try:
-        result = rtyper.instance_reprs[classdef]
+        result = rtyper.instance_reprs[classdef, does_need_gc]
     except KeyError:
         if classdef and classdef.cls is Exception:
             # see getclassrepr()
-            result = getinstancerepr(rtyper, None)
+            result = getinstancerepr(rtyper, None, nogc=False)
         else:
-            result = InstanceRepr(rtyper,classdef)
-        rtyper.instance_reprs[classdef] = result
+            result = InstanceRepr(rtyper,classdef, does_need_gc=does_need_gc)
+        rtyper.instance_reprs[classdef, does_need_gc] = result
         rtyper.add_pendingsetup(result)
     return result
 
@@ -217,7 +222,8 @@
                 vtable.parenttypeptr = rsubcls.rbase.getvtable()
             rinstance = getinstancerepr(self.rtyper, rsubcls.classdef)
             rinstance.setup()
-            vtable.rtti = getRuntimeTypeInfo(rinstance.object_type)
+            if rinstance.needsgc: # only gc-case
+                vtable.rtti = getRuntimeTypeInfo(rinstance.object_type)
             if rsubcls.classdef is None:
                 name = 'object'
             else:
@@ -338,15 +344,23 @@
 
 
 class InstanceRepr(Repr):
-    def __init__(self, rtyper, classdef):
+    def __init__(self, rtyper, classdef, does_need_gc=True):
         self.rtyper = rtyper
         self.classdef = classdef
         if classdef is None:
-            self.object_type = OBJECT
+            if does_need_gc:
+                self.object_type = OBJECT
+            else:
+                self.object_type = NONGCOBJECT
         else:
-            self.object_type = GcForwardReference()
+            if does_need_gc:
+                self.object_type = GcForwardReference()
+            else:
+                self.object_type = ForwardReference()
+            
         self.prebuiltinstances = {}   # { id(x): (x, _ptr) }
         self.lowleveltype = Ptr(self.object_type)
+        self.needsgc = does_need_gc
 
     def __repr__(self):
         if self.classdef is None:
@@ -383,9 +397,14 @@
                 fields['_hash_cache_'] = 'hash_cache', rint.signed_repr
                 llfields.append(('hash_cache', Signed))
 
-            self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef)
+            self.rbase = getinstancerepr(self.rtyper, self.classdef.basedef, not self.needsgc)
             self.rbase.setup()
-            object_type = GcStruct(self.classdef.cls.__name__,
+            if self.needsgc:
+                MkStruct = GcStruct
+            else:
+                MkStruct = Struct
+            
+            object_type = MkStruct(self.classdef.cls.__name__,
                                    ('super', self.rbase.object_type),
                                    *llfields)
             self.object_type.become(object_type)
@@ -393,12 +412,19 @@
         allinstancefields.update(fields)
         self.fields = fields
         self.allinstancefields = allinstancefields
-        attachRuntimeTypeInfo(self.object_type)
+        if self.needsgc: # only gc-case
+            attachRuntimeTypeInfo(self.object_type)
 
     def _setup_repr_final(self):
-        self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
-                                              ll_runtime_type_info,
-                                              OBJECT)
+        if self.needsgc: # only gc-case
+            self.rtyper.attachRuntimeTypeInfoFunc(self.object_type,
+                                                  ll_runtime_type_info,
+                                                  OBJECT)
+    def common_repr(self): # -> object or nongcobject reprs
+        return getinstancerepr(self.rtyper, None, nogc=not self.needsgc)
+
+    def getflavor(self):
+        return getattr(self.classdef.cls, '_alloc_flavor_', 'gc')        
 
     def convert_const(self, value):
         if value is None:
@@ -423,7 +449,7 @@
             return self.prebuiltinstances[id(value)][1]
         except KeyError:
             self.setup()
-            result = malloc(self.object_type)
+            result = malloc(self.object_type, flavor=self.getflavor()) # pick flavor
             self.prebuiltinstances[id(value)] = value, result
             self.initialize_prebuilt_instance(value, classdef, result)
             return result
@@ -500,9 +526,16 @@
 
     def new_instance(self, llops):
         """Build a new instance, without calling __init__."""
+        mallocop = 'malloc'
         ctype = inputconst(Void, self.object_type)
-        vptr = llops.genop('malloc', [ctype],
-                           resulttype = Ptr(self.object_type))
+        vlist = [ctype]
+        if self.classdef is not None:
+            flavor = self.getflavor()
+            if flavor != 'gc': # not defalut flavor
+                mallocop = 'flavored_malloc'
+                vlist = [inputconst(Void, flavor)] + vlist
+        vptr = llops.genop(mallocop, vlist,
+                           resulttype = Ptr(self.object_type)) # xxx flavor
         ctypeptr = inputconst(TYPEPTR, self.rclass.getvtable())
         self.setfield(vptr, '__class__', ctypeptr, llops)
         # initialize instance attributes from their defaults from the class
@@ -561,7 +594,7 @@
         vinst, = hop.inputargs(self)
         return hop.genop('ptr_nonzero', [vinst], resulttype=Bool)
 
-    def ll_str(i, r):
+    def ll_str(i, r): # doesn't work for non-gc classes!
         instance = cast_pointer(OBJECTPTR, i)
         from pypy.rpython import rstr
         nameLen = len(instance.typeptr.name)
@@ -601,9 +634,11 @@
     def rtype_is_((r_ins1, r_ins2), hop):
         if r_ins1.classdef is None or r_ins2.classdef is None:
             basedef = None
+            nogc = not (r_ins1.needsgc and r_ins2.needsgc)
         else:
             basedef = r_ins1.classdef.commonbase(r_ins2.classdef)
-        r_ins = getinstancerepr(r_ins1.rtyper, basedef)
+            nogc = False
+        r_ins = getinstancerepr(r_ins1.rtyper, basedef, nogc=nogc)
         return pairtype(Repr, Repr).rtype_is_(pair(r_ins, r_ins), hop)
 
     rtype_eq = rtype_is_
@@ -630,9 +665,11 @@
 #
 #  Low-level implementation of operations on classes and instances
 
+# doesn't work for non-gc stuff!
 def ll_cast_to_object(obj):
     return cast_pointer(OBJECTPTR, obj)
 
+# doesn't work for non-gc stuff!
 def ll_type(obj):
     return cast_pointer(OBJECTPTR, obj).typeptr
 
@@ -643,10 +680,10 @@
         subcls = subcls.parenttypeptr
     return True
 
-def ll_isinstance(obj, cls):
+def ll_isinstance(obj, cls): # obj should be cast to OBJECT or NONGCOBJECT
     if not obj:
         return False
-    obj_cls = ll_type(obj)
+    obj_cls = obj.typeptr
     return ll_issubclass(obj_cls, cls)
 
 def ll_runtime_type_info(obj):

Modified: pypy/dist/pypy/rpython/rmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/rmodel.py	(original)
+++ pypy/dist/pypy/rpython/rmodel.py	Fri Aug 19 19:33:57 2005
@@ -297,3 +297,10 @@
 
 def warning(msg):
     ansi_print("*** WARNING: %s" % (msg,), esc="31") # RED
+
+
+def needsgc(classdef, nogc=False):
+    if classdef is None:
+        return not nogc
+    else:
+        return getattr(classdef.cls, '_alloc_flavor_', 'gc').startswith('gc')

Modified: pypy/dist/pypy/rpython/test/test_lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_lltype.py	(original)
+++ pypy/dist/pypy/rpython/test/test_lltype.py	Fri Aug 19 19:33:57 2005
@@ -389,3 +389,11 @@
     s1.sub.x = 1
     assert runtime_type_info(s1.sub) == getRuntimeTypeInfo(S1)
     
+def test_flavor_malloc():
+    S = Struct('s', ('x', Signed))
+    py.test.raises(TypeError, malloc, S)
+    p = malloc(S, flavor="raw")
+    assert typeOf(p).TO == S
+    assert not isweak(p, S)
+    
+    

Modified: pypy/dist/pypy/rpython/test/test_nongc.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_nongc.py	(original)
+++ pypy/dist/pypy/rpython/test/test_nongc.py	Fri Aug 19 19:33:57 2005
@@ -25,7 +25,129 @@
     py.test.raises(RuntimeError, "t.a")
     py.test.raises(AssertionError, "free_non_gc_object(TestClass2())")
 
-def DONOTtest_rtype_free_non_gc_object():
+def test_alloc_flavor():
+    class A:
+        _alloc_flavor_ = "raw"
+    def f():
+        return A()
+    a = RPythonAnnotator()
+    #does not raise:
+    s = a.build_types(f, [])
+    assert s.knowntype == A
+    rtyper = RPythonTyper(a)
+    rtyper.specialize()
+    Adef = rtyper.annotator.getuserclasses()[A]
+    assert (Adef, False) in rtyper.instance_reprs
+    assert (Adef, True) not in rtyper.instance_reprs    
+    
+def test_alloc_flavor_subclassing():
+    class A:
+        _alloc_flavor_ = "raw"
+    class B(A):
+        def __init__(self, a):
+            self.a = a
+    def f():
+        return B(0)
+    a = RPythonAnnotator()
+    #does not raise:
+    s = a.build_types(f, [])
+    assert s.knowntype == B
+    rtyper = RPythonTyper(a)
+    rtyper.specialize()
+    Adef = rtyper.annotator.getuserclasses()[A]
+    assert (Adef, False) in rtyper.instance_reprs
+    assert (Adef, True) not in rtyper.instance_reprs
+    Bdef = rtyper.annotator.getuserclasses()[B]
+    assert (Bdef, False) in rtyper.instance_reprs
+    assert (Bdef, True) not in rtyper.instance_reprs        
+
+def test_unsupported():
+    class A:
+        _alloc_flavor_ = "raw"
+    def f():
+        return str(A())
+    a = RPythonAnnotator()
+    #does not raise:
+    s = a.build_types(f, [])
+    assert s.knowntype == str
+    rtyper = RPythonTyper(a)
+    py.test.raises(TypeError,rtyper.specialize) # results in an invalid cast
+
+def test_isinstance():
+    class A:
+        _alloc_flavor_ = "raw"
+    class B(A):
+        pass
+    class C(B):
+        pass
+    
+    def f(i):
+        if i == 0:
+            o = None
+        elif i == 1:
+            o = A()
+        elif i == 2:
+            o = B()
+        else:
+            o = C()
+        return 100*isinstance(o, A)+10*isinstance(o, B)+1*isinstance(o ,C)
+
+    a = RPythonAnnotator()
+    #does not raise:
+    s = a.build_types(f, [int])
+    assert s.knowntype == int
+    rtyper = RPythonTyper(a)
+    rtyper.specialize()
+##     res = interpret(f, [1])
+##     assert res == 100
+##     res = interpret(f, [2])
+##     assert res == 110
+##     res = interpret(f, [3])
+##     assert res == 111
+
+##     res = interpret(f, [0])
+##     assert res == 0
+
+
+def test_is():
+    class A:
+        _alloc_flavor_ = "raw"
+        pass
+    class B(A): pass
+    class C: pass
+    def f(i):
+        a = A()
+        b = B()
+        c = C()
+        d = None
+        e = None
+        if i == 0:
+            d = a
+        elif i == 1:
+            d = b
+        elif i == 2:
+            e = c
+        return (0x0001*(a is b) | 0x0002*(a is c) | 0x0004*(a is d) |
+                0x0008*(a is e) | 0x0010*(b is c) | 0x0020*(b is d) |
+                0x0040*(b is e) | 0x0080*(c is d) | 0x0100*(c is e) |
+                0x0200*(d is e))
+    a = RPythonAnnotator()
+    #does not raise:
+    s = a.build_types(f, [int])
+    assert s.knowntype == int
+    rtyper = RPythonTyper(a)
+    rtyper.specialize()
+##     res = interpret(f, [0])
+##     assert res == 0x0004
+##     res = interpret(f, [1])
+##     assert res == 0x0020
+##     res = interpret(f, [2])
+##     assert res == 0x0100
+##     res = interpret(f, [3])
+##     assert res == 0x0200
+
+
+def test_rtype__nongc_object():
     class TestClass(object):
         _alloc_flavor_ = ""
         def __init__(self, a):
@@ -36,7 +158,7 @@
             return 42
     def malloc_and_free(a):
         ci = TestClass(a)
-        b = ci.a
+        b = ci.method1()
         free_non_gc_object(ci)
         return b
     a = RPythonAnnotator()

Modified: pypy/dist/pypy/rpython/test/test_rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rtyper.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rtyper.py	Fri Aug 19 19:33:57 2005
@@ -3,6 +3,7 @@
 from pypy.rpython.lltype import *
 from pypy.rpython.test.test_llinterp import interpret 
 from pypy.rpython.rtyper import RPythonTyper
+from pypy.rpython import rmodel
 import py
 
 def setup_module(mod): 
@@ -107,3 +108,28 @@
     a.translator.specialize()
     assert [vT.concretetype for vT in vTs] == [Void] * 3
     
+
+def test_needsgc():
+    class A:
+        pass
+    class B:
+        _alloc_flavor_ = "gc"
+    class R:
+        _alloc_flavor_ = "nongc"
+    class DummyClsDef:
+        def __init__(self, cls):
+            self.cls = cls
+
+    assert rmodel.needsgc(DummyClsDef(A))
+    assert rmodel.needsgc(DummyClsDef(A), nogc=True)
+    assert rmodel.needsgc(DummyClsDef(B))
+    assert rmodel.needsgc(DummyClsDef(B), nogc=True)
+    assert not rmodel.needsgc(DummyClsDef(R))
+    assert not rmodel.needsgc(DummyClsDef(R), nogc=False)
+    assert rmodel.needsgc(None)
+    assert rmodel.needsgc(None, nogc=False)
+    assert not rmodel.needsgc(None, nogc=True)            
+
+    
+
+        



More information about the Pypy-commit mailing list