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

arigo at codespeak.net arigo at codespeak.net
Sat May 6 09:54:02 CEST 2006


Author: arigo
Date: Sat May  6 09:53:59 2006
New Revision: 26843

Modified:
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/annotation/description.py
   pypy/dist/pypy/annotation/test/test_annrpython.py
   pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py
   pypy/dist/pypy/rpython/lltypesystem/rtagged.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py
   pypy/dist/pypy/rpython/objectmodel.py
   pypy/dist/pypy/rpython/test/test_objectmodel.py
Log:
* fix for buggy __slots__ support
* enhanced UnboxedValue to allow the value to also show up
  as an attribute, with a name chosen by the user


Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Sat May  6 09:53:59 2006
@@ -314,9 +314,6 @@
 def robjmodel_hint(s, **kwds_s):
     return s
 
-def robjmodel_getvalue_from_unboxed(s):
-    return SomeInteger()
-
 def llmemory_cast_ptr_to_adr(s):
     return SomeAddress()
 
@@ -373,8 +370,6 @@
 BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hlinvoke] = robjmodel_hlinvoke
 BUILTIN_ANALYZERS[pypy.rpython.objectmodel.keepalive_until_here] = robjmodel_keepalive_until_here
 BUILTIN_ANALYZERS[pypy.rpython.objectmodel.hint] = robjmodel_hint
-BUILTIN_ANALYZERS[pypy.rpython.objectmodel.getvalue_from_unboxed] = \
-                                               robjmodel_getvalue_from_unboxed
 BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_ptr_to_adr] = llmemory_cast_ptr_to_adr
 BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_ptr] = llmemory_cast_adr_to_ptr
 BUILTIN_ANALYZERS[pypy.rpython.lltypesystem.llmemory.cast_adr_to_int] = llmemory_cast_adr_to_int

Modified: pypy/dist/pypy/annotation/description.py
==============================================================================
--- pypy/dist/pypy/annotation/description.py	(original)
+++ pypy/dist/pypy/annotation/description.py	Sat May  6 09:53:59 2006
@@ -365,41 +365,41 @@
             if base is not object:
                 self.basedesc = bookkeeper.getdesc(base)
 
+    def add_source_attribute(self, name, value, mixin=False):
+        if isinstance(value, types.FunctionType):
+            # for debugging
+            if not hasattr(value, 'class_'):
+                value.class_ = self.pyobj # remember that this is really a method
+            if self.specialize:
+                # make a custom funcdesc that specializes on its first
+                # argument (i.e. 'self').
+                from pypy.annotation.specialize import specialize_argtype
+                def argtype0(funcdesc, args_s):
+                    return specialize_argtype(funcdesc, args_s, 0)
+                funcdesc = FunctionDesc(self.bookkeeper, value,
+                                        specializer=argtype0)
+                self.classdict[name] = funcdesc
+                return
+            if mixin:
+                # make a new copy of the FunctionDesc for this class,
+                # but don't specialize further for all subclasses
+                funcdesc = FunctionDesc(self.bookkeeper, value)
+                self.classdict[name] = funcdesc
+                return
+            # NB. if value is, say, AssertionError.__init__, then we
+            # should not use getdesc() on it.  Never.  The problem is
+            # that the py lib has its own AssertionError.__init__ which
+            # is of type FunctionType.  But bookkeeper.immutablevalue()
+            # will do the right thing in s_get_value().
+
+        if type(value) is MemberDescriptorType:
+            # skip __slots__, showing up in the class as 'member' objects
+            return
+        self.classdict[name] = Constant(value)
+
     def add_sources_for_class(self, cls, mixin=False):
         for name, value in cls.__dict__.items():
-            ## -- useless? -- ignore some special attributes
-            ##if name.startswith('_') and not isinstance(value, types.FunctionType):
-            ##    continue
-            if isinstance(value, types.FunctionType):
-                # for debugging
-                if not hasattr(value, 'class_'):
-                    value.class_ = self.pyobj # remember that this is really a method
-                if self.specialize:
-                    # make a custom funcdesc that specializes on its first
-                    # argument (i.e. 'self').
-                    from pypy.annotation.specialize import specialize_argtype
-                    def argtype0(funcdesc, args_s):
-                        return specialize_argtype(funcdesc, args_s, 0)
-                    funcdesc = FunctionDesc(self.bookkeeper, value,
-                                            specializer=argtype0)
-                    self.classdict[name] = funcdesc
-                    continue
-                if mixin:
-                    # make a new copy of the FunctionDesc for this class,
-                    # but don't specialize further for all subclasses
-                    funcdesc = FunctionDesc(self.bookkeeper, value)
-                    self.classdict[name] = funcdesc
-                    continue
-                # NB. if value is, say, AssertionError.__init__, then we
-                # should not use getdesc() on it.  Never.  The problem is
-                # that the py lib has its own AssertionError.__init__ which
-                # is of type FunctionType.  But bookkeeper.immutablevalue()
-                # will do the right thing in s_get_value().
-
-            if type(value) is MemberDescriptorType:
-                # skip __slots__, showing up in the class as 'member' objects
-                continue
-            self.classdict[name] = Constant(value)
+            self.add_source_attribute(name, value, mixin)
 
     def getclassdef(self, key):
         try:
@@ -531,8 +531,9 @@
             # there is a new attribute
             cls = self.pyobj
             if name in cls.__dict__:
-                self.classdict[name] = Constant(cls.__dict__[name])
-                return self
+                self.add_source_attribute(name, cls.__dict__[name])
+                if name in self.classdict:
+                    return self
         return None
 
     def consider_call_site(bookkeeper, family, descs, args, s_result):

Modified: pypy/dist/pypy/annotation/test/test_annrpython.py
==============================================================================
--- pypy/dist/pypy/annotation/test/test_annrpython.py	(original)
+++ pypy/dist/pypy/annotation/test/test_annrpython.py	Sat May  6 09:53:59 2006
@@ -2074,6 +2074,18 @@
         s = a.build_types(f, [int])
         assert s.knowntype == int
 
+    def test_unboxed_value(self):
+        class A(object):
+            pass
+        class C(A, objectmodel.UnboxedValue):
+            __slots__ = 'smallint'
+        def f(n):
+            return C(n).smallint
+
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [int])
+        assert s.knowntype == int
+
 
 def g(n):
     return [0,1,2,n]

Modified: pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rbuiltin.py	Sat May  6 09:53:59 2006
@@ -59,13 +59,8 @@
     c = hop.inputconst(pyobj_repr, __import__)
     return hop.genop('simple_call', [c] + args_v, resulttype = pyobj_repr)
 
-def rtype_getvalue_from_unboxed(hop):
-    from pypy.rpython.lltypesystem.rtagged import rtype_getvalue_from_unboxed
-    return rtype_getvalue_from_unboxed(hop)
-
 BUILTIN_TYPER = {}
 BUILTIN_TYPER[objectmodel.instantiate] = rtype_instantiate
-BUILTIN_TYPER[objectmodel.getvalue_from_unboxed] = rtype_getvalue_from_unboxed
 BUILTIN_TYPER[isinstance] = rtype_builtin_isinstance
 BUILTIN_TYPER[hasattr] = rtype_builtin_hasattr
 BUILTIN_TYPER[__import__] = rtype_builtin___import__

Modified: pypy/dist/pypy/rpython/lltypesystem/rtagged.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rtagged.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rtagged.py	Sat May  6 09:53:59 2006
@@ -16,9 +16,18 @@
 
     def _setup_repr(self):
         InstanceRepr._setup_repr(self)
-        if len(self.allinstancefields) != 1:
-            raise TyperError("%r cannot have fields besides __class__: %r" % (
-                self.classdef, self.allinstancefields.keys()))
+        flds = self.allinstancefields.keys()
+        flds.remove('__class__')
+        if self.is_parent:
+            if flds:
+                raise TyperError("%r is a base class of an UnboxedValue,"
+                                 "so it cannot have fields: %r" % (
+                    self.classdef, flds))
+        else:
+            if len(flds) != 1:
+                raise TyperError("%r must have exactly one field: %r" % (
+                    self.classdef, flds))
+            self.specialfieldname = flds[0]
 
     def new_instance(self, llops, classcallhop=None):
         if self.is_parent:
@@ -49,9 +58,13 @@
             number = value.getvalue()
             return ll_int_to_unboxed(self.lowleveltype, number)
 
-    def getfield(self, vinst, attr, llops, force_cast=False):
-        if attr != '__class__':
-            raise MissingRTypeAttribute(attr)
+    def getvalue_from_unboxed(self, llops, vinst):
+        assert not self.is_parent
+        v2 = llops.genop('cast_ptr_to_int', [vinst],  resulttype=lltype.Signed)
+        c_one = inputconst(lltype.Signed, 1)
+        return llops.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed)
+
+    def gettype_from_unboxed(self, llops, vinst):
         unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef)
         cunboxedcls = inputconst(CLASSTYPE, unboxedclass_repr.getvtable())
         if self.is_parent:
@@ -61,12 +74,21 @@
         else:
             return cunboxedcls
 
+    def getfield(self, vinst, attr, llops, force_cast=False):
+        if not self.is_parent and attr == self.specialfieldname:
+            return self.getvalue_from_unboxed(llops, vinst)
+        elif attr == '__class__':
+            return self.gettype_from_unboxed(llops, vinst)
+        else:
+            raise MissingRTypeAttribute(attr)
+
     def rtype_type(self, hop):
         [vinst] = hop.inputargs(self)
-        return self.getfield(vinst, '__class__', hop.llops)
+        return self.gettype_from_unboxed(hop.llops, vinst)
 
     def rtype_setattr(self, hop):
-        raise TyperError("cannot set attributes on %r" % (self,))
+        # only for UnboxedValue.__init__(), which is not actually called
+        hop.genop('UnboxedValue_setattr', [])
 
     def ll_str(self, i):
         if lltype.cast_ptr_to_int(i) & 1:
@@ -116,12 +138,3 @@
         return answer_if_unboxed
     else:
         return ll_issubclass_const(obj.typeptr, minid, maxid)
-
-def rtype_getvalue_from_unboxed(hop):
-    assert isinstance(hop.args_r[0], TaggedInstanceRepr)
-    assert not hop.args_r[0].is_parent
-    [v_instance] = hop.inputargs(hop.args_r[0])
-    v2 = hop.genop('cast_ptr_to_int', [v_instance], resulttype = lltype.Signed)
-    c_one = hop.inputconst(lltype.Signed, 1)
-    return hop.genop('int_rshift',    [v2, c_one],  resulttype = lltype.Signed)
-

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_rtagged.py	Sat May  6 09:53:59 2006
@@ -15,15 +15,12 @@
         return self.normalint + x + 2
 
 class C(A, UnboxedValue):
+    __slots__ = 'smallint'
     def meth(self, x):
-        return self.getvalue() + x + 3
+        return self.smallint + x + 3
 
 # ____________________________________________________________
 
-def test_on_top_of_cpython():
-    assert C(17).getvalue() == 17
-    assert C(20).meth(10) == 33
-
 def test_instantiate():
     def fn1(n):
         return C(n)
@@ -31,6 +28,12 @@
     value = lltype.cast_ptr_to_int(res)
     assert value == 42 * 2 + 1    # for now
 
+def test_attribute():
+    def fn1(n):
+        return C(n).smallint
+    res = interpret(fn1, [42])
+    assert res == 42
+
 def test_getvalue():
     def fn1(n):
         return C(n).getvalue()
@@ -49,7 +52,7 @@
         if isinstance(x, B):
             return 'B', x.normalint
         elif isinstance(x, C):
-            return 'C', x.getvalue()
+            return 'C', x.smallint
         else:
             return 'A', 0
 
@@ -68,7 +71,7 @@
             x = c
         else:
             x = C(n)
-        return x.getvalue()
+        return x.smallint
 
     res = interpret(fn, [12])
     assert res == 12
@@ -80,7 +83,7 @@
         if x is None:
             return sys.maxint
         else:
-            return x.getvalue()
+            return x.smallint
     def fn(n):
         if n < 0:
             x = None

Modified: pypy/dist/pypy/rpython/objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/objectmodel.py	(original)
+++ pypy/dist/pypy/rpython/objectmodel.py	Sat May  6 09:53:59 2006
@@ -117,25 +117,28 @@
 
     def __new__(cls, value):
         assert '__init__' not in cls.__dict__  # won't be called anyway
+        assert isinstance(cls.__slots__, str) or len(cls.__slots__) == 1
+        return super(UnboxedValue, cls).__new__(cls)
+
+    def __init__(self, value):
+        # this funtion is annotated but not included in the translated program
         int_as_pointer = value * 2 + 1   # XXX for now
         if -sys.maxint-1 <= int_as_pointer <= sys.maxint:
-            result = super(UnboxedValue, cls).__new__(cls)
-            result._value_ = value
-            return result
+            if isinstance(self.__slots__, str):
+                setattr(self, self.__slots__, value)
+            else:
+                setattr(self, self.__slots__[0], value)
         else:
             raise OverflowError("UnboxedValue: argument out of range")
 
-    def __init__(self, value):
-        pass
-
     def __repr__(self):
         return '<unboxed %d>' % (self.getvalue(),)
 
-    def getvalue(self):
-        return getvalue_from_unboxed(self)
-
-def getvalue_from_unboxed(obj):
-    return obj._value_     # this function is special-cased by the annotator
+    def getvalue(self):   # helper, equivalent to reading the custom field
+        if isinstance(self.__slots__, str):
+            return getattr(self, self.__slots__)
+        else:
+            return getattr(self, self.__slots__[0])
 
 # ____________________________________________________________
 

Modified: pypy/dist/pypy/rpython/test/test_objectmodel.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_objectmodel.py	(original)
+++ pypy/dist/pypy/rpython/test/test_objectmodel.py	Sat May  6 09:53:59 2006
@@ -251,3 +251,18 @@
         return d[2]
     res = interpret(g, [3])
     assert res == 77
+
+def test_unboxed_value():
+    class Base(object):
+        pass
+    class C(Base, UnboxedValue):
+        __slots__ = 'smallint'
+
+    assert C(17).smallint == 17
+    assert C(17).getvalue() == 17
+
+    class A(UnboxedValue):
+        __slots__ = ['value']
+
+    assert A(12098).value == 12098
+    assert A(12098).getvalue() == 12098



More information about the Pypy-commit mailing list