[pypy-svn] r14566 - in pypy/dist/pypy/rpython: . test

arigo at codespeak.net arigo at codespeak.net
Tue Jul 12 21:47:39 CEST 2005


Author: arigo
Date: Tue Jul 12 21:47:34 2005
New Revision: 14566

Added:
   pypy/dist/pypy/rpython/objectmodel.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/normalizecalls.py
   pypy/dist/pypy/rpython/rbuiltin.py
   pypy/dist/pypy/rpython/rclass.py
   pypy/dist/pypy/rpython/rpbc.py
   pypy/dist/pypy/rpython/rspecialcase.py
   pypy/dist/pypy/rpython/test/test_rbuiltin.py
   pypy/dist/pypy/rpython/test/test_rspecialcase.py
Log:
More strangeness, more progress: test_rbuiltin.test_instantiate_multiple().

instantiate() is now a "built-in" from the point of view of the annotator,
which is progress.

All vtables have an entry 'instantiate' that points to a function that
instantiates the corresponding class.  Building this function is actually "a
bit" messy.  Then instantiate() can just be implemented by calling it.

We are reusing a trick we already used in the previous check-in: here, the
function that instantiate a class are defined (in normalizecalls) as

    def my_instantiate():
        return instantiate(cls)

which means that instantiate() is actually implemented as follows: if the
argument is a known constant class, we instantiate it in the normal way
(rclass.py, rtype_new_instance()).  Otherwise, we load and call the
appropriate version of my_instantiate(), which itself contains again a call to
instantiate() -- but this time with a constant 'cls'...

For reference, the previous check-in used the same trick for calling classes.  
A call to a constant class was already implemented some time ago, so a call to
a non-constant class can be done by calling a helper function __new__() that
is defined as calling a constant class.



Modified: pypy/dist/pypy/rpython/normalizecalls.py
==============================================================================
--- pypy/dist/pypy/rpython/normalizecalls.py	(original)
+++ pypy/dist/pypy/rpython/normalizecalls.py	Tue Jul 12 21:47:34 2005
@@ -5,7 +5,9 @@
 from pypy.objspace.flow.model import SpaceOperation, checkgraph
 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.objectmodel import instantiate
 
 
 def normalize_function_signatures(annotator):
@@ -310,6 +312,24 @@
         new_call_family.patterns = patterns
 
 
+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)
+
+def create_instantiate_function(annotator, cls, classdef):
+    def my_instantiate():
+        return instantiate(cls)
+    my_instantiate = func_with_new_name(my_instantiate,
+                                valid_identifier('instantiate_'+cls.__name__))
+    annotator.build_types(my_instantiate, [])
+    # force the result to be converted to a generic OBJECTPTR
+    generalizedresult = annmodel.SomeInstance(classdef=None)
+    graph = annotator.translator.getflowgraph(my_instantiate)
+    annotator.setbinding(graph.getreturnvar(), generalizedresult)
+    classdef.my_instantiate = my_instantiate
+
+
 def perform_normalizations(rtyper):
     create_class_constructors(rtyper)
     rtyper.annotator.frozen += 1
@@ -319,3 +339,4 @@
         merge_classpbc_getattr_into_classdef(rtyper)
     finally:
         rtyper.annotator.frozen -= 1
+    create_instantiate_functions(rtyper.annotator)

Added: pypy/dist/pypy/rpython/objectmodel.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/objectmodel.py	Tue Jul 12 21:47:34 2005
@@ -0,0 +1,14 @@
+"""
+This file defines utilities for manipulating objects in an
+RPython-compliant way.
+"""
+
+import new
+
+
+def instantiate(cls):
+    "Create an empty instance of 'cls'."
+    if isinstance(cls, type):
+        return object.__new__(cls)
+    else:
+        return new.instance(cls)

Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/rbuiltin.py	Tue Jul 12 21:47:34 2005
@@ -1,7 +1,7 @@
 from pypy.annotation.pairtype import pairtype
 from pypy.annotation import model as annmodel
 from pypy.rpython import lltype
-from pypy.rpython import rarithmetic
+from pypy.rpython import rarithmetic, objectmodel
 from pypy.rpython.rtyper import TyperError
 from pypy.rpython.rrange import rtype_builtin_range, rtype_builtin_xrange 
 from pypy.rpython.rmodel import Repr, TyperError, IntegerRepr, Constant
@@ -180,6 +180,23 @@
     vlist = hop.inputargs(lltype.Float, lltype.Float)
     return hop.genop('float_fmod', vlist, resulttype=lltype.Float)
 
+def ll_instantiate(typeptr, RESULT):
+    my_instantiate = typeptr.instantiate
+    return lltype.cast_pointer(RESULT, my_instantiate())
+
+def rtype_instantiate(hop):
+    s_class = hop.args_s[0]
+    assert isinstance(s_class, annmodel.SomePBC)
+    if len(s_class.prebuiltinstances) != 1:
+        # instantiate() on a variable class
+        vtypeptr, = hop.inputargs(rclass.get_type_repr(hop.rtyper))
+        cresult = hop.inputconst(lltype.Void, hop.r_result.lowleveltype)
+        return hop.gendirectcall(ll_instantiate, vtypeptr, cresult)
+
+    klass = s_class.const
+    return rclass.rtype_new_instance(hop.rtyper, klass, hop.llops)
+
+
 import math
 ##def ll_floor(f1):
 ##    return float(int((f1)
@@ -234,6 +251,7 @@
 BUILTIN_TYPER[lltype.runtime_type_info] = rtype_runtime_type_info
 BUILTIN_TYPER[rarithmetic.intmask] = rtype_intmask
 BUILTIN_TYPER[rarithmetic.r_uint] = rtype_r_uint
+BUILTIN_TYPER[objectmodel.instantiate] = rtype_instantiate
 
 import time
 

Modified: pypy/dist/pypy/rpython/rclass.py
==============================================================================
--- pypy/dist/pypy/rpython/rclass.py	(original)
+++ pypy/dist/pypy/rpython/rclass.py	Tue Jul 12 21:47:34 2005
@@ -8,6 +8,7 @@
 from pypy.rpython.lltype import cast_pointer, castable, nullptr
 from pypy.rpython.lltype import RuntimeTypeInfo, getRuntimeTypeInfo, typeOf
 from pypy.rpython.lltype import Array, Char, Void, attachRuntimeTypeInfo
+from pypy.rpython.lltype import FuncType
 
 #
 #  There is one "vtable" per user class, with the following structure:
@@ -17,6 +18,7 @@
 #          struct object_vtable* parenttypeptr;
 #          RuntimeTypeInfo * rtti;
 #          array { char } * name;
+#          struct object * instantiate();
 #      }
 #
 #  Every other class X, with parent Y, has the structure:
@@ -40,13 +42,13 @@
 
 OBJECT_VTABLE = ForwardReference()
 TYPEPTR = Ptr(OBJECT_VTABLE)
+OBJECT = GcStruct('object', ('typeptr', TYPEPTR))
+OBJECTPTR = Ptr(OBJECT)
 OBJECT_VTABLE.become(Struct('object_vtable',
                             ('parenttypeptr', TYPEPTR),
                             ('rtti', Ptr(RuntimeTypeInfo)),
-                            ('name', Ptr(Array(Char)))))
-
-OBJECT = GcStruct('object', ('typeptr', TYPEPTR))
-OBJECTPTR = Ptr(OBJECT)
+                            ('name', Ptr(Array(Char))),
+                            ('instantiate', Ptr(FuncType([], OBJECTPTR)))))
 
 def getclassrepr(rtyper, classdef):
     try:
@@ -231,6 +233,11 @@
             for i in range(len(name)):
                 vtable.name[i] = name[i]
             vtable.name[len(name)] = '\x00'
+            if hasattr(rsubcls.classdef, 'my_instantiate'):
+                fn = rsubcls.classdef.my_instantiate
+                vtable.instantiate = self.rtyper.getfunctionptr(fn)
+            #else: the classdef was created recently, so no instantiate()
+            #      could reach it
         else:
             # setup class attributes: for each attribute name at the level
             # of 'self', look up its value in the subclass rsubcls

Modified: pypy/dist/pypy/rpython/rpbc.py
==============================================================================
--- pypy/dist/pypy/rpython/rpbc.py	(original)
+++ pypy/dist/pypy/rpython/rpbc.py	Tue Jul 12 21:47:34 2005
@@ -459,37 +459,49 @@
         assert None not in s_pbc.prebuiltinstances, "XXX not implemented"
         if s_pbc.is_constant():
             self.lowleveltype = Void
-            self.class_repr = None
         else:
             self.lowleveltype = rclass.TYPEPTR
-            access_sets = rtyper.annotator.getpbcaccesssets()
-            classes = s_pbc.prebuiltinstances.keys()
+        self._access_set = None
+        self._class_repr = None
+
+    def get_access_set(self):
+        if self._access_set is None:
+            access_sets = self.rtyper.annotator.getpbcaccesssets()
+            classes = self.s_pbc.prebuiltinstances.keys()
             _, _, access = access_sets.find(classes[0])
             for obj in classes[1:]:
                 _, _, access1 = access_sets.find(obj)
                 assert access1 is access       # XXX not implemented
             commonbase = access.commonbase
-            self.class_repr = rclass.getclassrepr(rtyper, commonbase)
-            self.access_set = access
+            self._class_repr = rclass.getclassrepr(self.rtyper, commonbase)
+            self._access_set = access
+        return self._access_set
+
+    def get_class_repr(self):
+        self.get_access_set()
+        return self._class_repr
 
     def convert_const(self, cls):
         if cls not in self.s_pbc.prebuiltinstances:
             raise TyperError("%r not in %r" % (cls, self))
         if self.lowleveltype == Void:
             return cls
-        return self.class_repr.convert_const(cls)
+        return rclass.get_type_repr(self.rtyper).convert_const(cls)
 
     def rtype_simple_call(self, hop):
-        if self.class_repr is not None:
+        if self.lowleveltype != Void:
+            # instantiating a class from multiple possible classes
             vcls = hop.inputarg(self, arg=0)
-            vnewfn = self.class_repr.getpbcfield(vcls, self.access_set,
-                                                 '__new__', hop.llops)
+            access_set = self.get_access_set()
+            vnewfn = self.get_class_repr().getpbcfield(vcls, access_set,
+                                                       '__new__', hop.llops)
             hop2 = hop.copy()
             hop2.r_s_popfirstarg()   # discard the class pointer argument
-            hop2.v_s_insertfirstarg(vnewfn, self.access_set.attrs['__new__'])
+            hop2.v_s_insertfirstarg(vnewfn, access_set.attrs['__new__'])
             # now hop2 looks like simple_call(klass__new__, args...)
             return hop2.dispatch()
 
+        # instantiating a single class
         klass = self.s_pbc.const
         v_instance = rclass.rtype_new_instance(hop.rtyper, klass, hop.llops)
         try:
@@ -520,7 +532,15 @@
             return self.getfield(vcls, attr, hop.llops)
 
     def getfield(self, vcls, attr, llops):
-        return self.class_repr.getpbcfield(vcls, self.access_set, attr, llops)
+        access_set = self.get_access_set()
+        class_repr = self.get_class_repr()
+        return class_repr.getpbcfield(vcls, access_set, attr, llops)
+
+class __extend__(pairtype(ClassesPBCRepr, rclass.ClassRepr)):
+    def convert_from_to((r_clspbc, r_cls), v, llops):
+        if r_cls.lowleveltype != r_clspbc.lowleveltype:
+            return NotImplemented   # good enough for now
+        return v
 
 # ____________________________________________________________
 

Modified: pypy/dist/pypy/rpython/rspecialcase.py
==============================================================================
--- pypy/dist/pypy/rpython/rspecialcase.py	(original)
+++ pypy/dist/pypy/rpython/rspecialcase.py	Tue Jul 12 21:47:34 2005
@@ -2,6 +2,7 @@
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
 from pypy.rpython import rclass
+from pypy.rpython.rmodel import TyperError
 
 
 def rtype_call_specialcase(hop):
@@ -22,11 +23,4 @@
     return rtype_override_fn(hop2)
 
 
-def rtype_override_instantiate(hop):
-    s_class = hop.args_s[0]
-    assert isinstance(s_class, annmodel.SomePBC)
-    if len(s_class.prebuiltinstances) != 1:
-        raise TyperError("instantiate() on a variable class")
-
-    klass = s_class.const
-    return rclass.rtype_new_instance(hop.rtyper, klass, hop.llops)
+# def rtype_override_XXX to be added later

Modified: pypy/dist/pypy/rpython/test/test_rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rbuiltin.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rbuiltin.py	Tue Jul 12 21:47:34 2005
@@ -1,5 +1,6 @@
 from pypy.rpython.test.test_llinterp import interpret
 from pypy.rpython.test import test_llinterp
+from pypy.rpython.objectmodel import instantiate
 from pypy.objspace.flow import model as flowmodel
 from pypy.tool import udir
 
@@ -132,4 +133,27 @@
         c = None
         return g(c)
     assert not interpret(fn, [True]) 
-    
+
+def test_instantiate():
+    class A:
+        pass
+    def f():
+        return instantiate(A)
+    res = interpret(f, [])
+    assert res.super.typeptr.name[0] == 'A'
+
+def test_instantiate_multiple():
+    class A:
+        pass
+    class B(A):
+        pass
+    def f(i):
+        if i == 1:
+            cls = A
+        else:
+            cls = B
+        return instantiate(cls)
+    res = interpret(f, [1])
+    assert res.super.typeptr.name[0] == 'A'
+    res = interpret(f, [2])
+    assert res.super.typeptr.name[0] == 'B'

Modified: pypy/dist/pypy/rpython/test/test_rspecialcase.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rspecialcase.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rspecialcase.py	Tue Jul 12 21:47:34 2005
@@ -2,13 +2,6 @@
 from pypy.rpython.test.test_llinterp import interpret
 
 from pypy.translator.ann_override import PyPyAnnotatorPolicy
-from pypy.interpreter.typedef import instantiate
 
 
-def test_instantiate():
-    class A:
-        pass
-    def f():
-        return instantiate(A)
-    res = interpret(f, [], policy=PyPyAnnotatorPolicy())
-    assert res.super.typeptr.name[0] == 'A'
+# nothing to test here at the moment



More information about the Pypy-commit mailing list