[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