[pypy-svn] r48198 - in pypy/dist/pypy/jit: codegen/i386 codegen/llgraph codegen/test hintannotator hintannotator/test timeshifter timeshifter/test

arigo at codespeak.net arigo at codespeak.net
Tue Oct 30 14:46:51 CET 2007


Author: arigo
Date: Tue Oct 30 14:46:50 2007
New Revision: 48198

Modified:
   pypy/dist/pypy/jit/codegen/i386/operation.py
   pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
   pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
   pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
   pypy/dist/pypy/jit/hintannotator/model.py
   pypy/dist/pypy/jit/hintannotator/test/test_annotator.py
   pypy/dist/pypy/jit/timeshifter/hrtyper.py
   pypy/dist/pypy/jit/timeshifter/rcontainer.py
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/test/test_portal.py
   pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
Log:
Attempt to fix the JIT.  This adds support for the new interior pointer
operations (and for int_add_nonneg_ovf).


Modified: pypy/dist/pypy/jit/codegen/i386/operation.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/i386/operation.py	(original)
+++ pypy/dist/pypy/jit/codegen/i386/operation.py	Tue Oct 30 14:46:50 2007
@@ -198,7 +198,7 @@
         self.emit(allocator.mc, dstop, op2)
 
 class OpIntAdd(BinaryOp):
-    opname = 'int_add', 'uint_add', 'int_add_ovf'
+    opname = 'int_add', 'uint_add', 'int_add_ovf', 'int_add_nonneg_ovf'
     emit = staticmethod(I386CodeBuilder.ADD)
     commutative = True
     ccexcflag = Conditions['O']

Modified: pypy/dist/pypy/jit/codegen/llgraph/llimpl.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/llimpl.py	Tue Oct 30 14:46:50 2007
@@ -244,6 +244,114 @@
     return isinstance(c, flowmodel.Constant)
 
 
+# ____________________________________________________________
+# Interior access helpers
+
+class InteriorPtrVariable(object):
+    def __init__(self, base_and_offsets_gv):
+        self.base_and_offsets_gv = base_and_offsets_gv
+
+def gengetsubstruct(block, gv_ptr, gv_PTRTYPE, gv_fieldname):
+    v_ptr = from_opaque_object(gv_ptr)
+    # don't generate any operation for an interior getsubstruct,
+    # but just return a special pseudo-variable
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # a nested getsubstruct
+        v = InteriorPtrVariable(v_ptr.base_and_offsets_gv + [gv_fieldname])
+        return to_opaque_object(v)
+    # in all other cases we need a proper cast
+    gv_ptr = cast(block, gv_PTRTYPE, gv_ptr)
+    PTRTYPE = from_opaque_object(gv_PTRTYPE).value
+    if PTRTYPE.TO._gckind == 'gc':
+        # reading from a GcStruct requires returning an interior pointer
+        # pseudo-variable
+        v = InteriorPtrVariable([gv_ptr, gv_fieldname])
+        return to_opaque_object(v)
+    else:
+        vars_gv = [gv_ptr, gv_fieldname]
+        c_fieldname = from_opaque_object(gv_fieldname)
+        RESULTTYPE = lltype.Ptr(getattr(PTRTYPE.TO, c_fieldname.value))
+        return genop(block, "getsubstruct", vars_gv, RESULTTYPE)
+
+def gengetarraysubstruct(block, gv_ptr, gv_index):
+    v_ptr = from_opaque_object(gv_ptr)
+    # don't generate any operation for an interior getarraysubstruct,
+    # but just return a special pseudo-variable
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # a nested getarraysubstruct
+        v = InteriorPtrVariable(v_ptr.base_and_offsets_gv + [gv_index])
+        return to_opaque_object(v)
+    PTRTYPE = v_ptr.concretetype
+    if PTRTYPE.TO._gckind == 'gc':
+        # reading from a GcArray requires returning an interior pointer
+        # pseudo-variable
+        v = InteriorPtrVariable([gv_ptr, gv_index])
+        return to_opaque_object(v)
+    else:
+        vars_gv = [gv_ptr, gv_index]
+        RESULTTYPE = lltype.Ptr(PTRTYPE.TO.OF)
+        return genop(block, "getarraysubstruct", vars_gv, RESULTTYPE)
+
+def gensetfield(block, gv_ptr, gv_PTRTYPE, gv_fieldname, gv_value):
+    v_ptr = from_opaque_object(gv_ptr)
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # this is really a setinteriorfield
+        vars_gv = v_ptr.base_and_offsets_gv + [gv_fieldname, gv_value]
+        genop(block, "setinteriorfield", vars_gv, lltype.Void)
+    else:
+        # for setfield we need a proper cast (for setinteriorfield, the
+        # top-level cast was already inserted by gengetsubstruct)
+        gv_ptr = cast(block, gv_PTRTYPE, gv_ptr)
+        vars_gv = [gv_ptr, gv_fieldname, gv_value]
+        genop(block, "setfield", vars_gv, lltype.Void)
+
+def gengetfield(block, gv_ptr, gv_PTRTYPE, gv_fieldname):
+    PTRTYPE = from_opaque_object(gv_PTRTYPE).value
+    c_fieldname = from_opaque_object(gv_fieldname)
+    RESULTTYPE = getattr(PTRTYPE.TO, c_fieldname.value)
+    v_ptr = from_opaque_object(gv_ptr)
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # this is really a getinteriorfield
+        vars_gv = v_ptr.base_and_offsets_gv + [gv_fieldname]
+        return genop(block, "getinteriorfield", vars_gv, RESULTTYPE)
+    else:
+        # for getfield we need a proper cast (for getinteriorfield, the
+        # top-level cast was already inserted by gengetsubstruct)
+        gv_ptr = cast(block, gv_PTRTYPE, gv_ptr)
+        vars_gv = [gv_ptr, gv_fieldname]
+        return genop(block, "getfield", vars_gv, RESULTTYPE)
+
+def gensetarrayitem(block, gv_ptr, gv_index, gv_value):
+    v_ptr = from_opaque_object(gv_ptr)
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # this is really a setinteriorfield
+        vars_gv = v_ptr.base_and_offsets_gv + [gv_index, gv_value]
+        genop(block, "setinteriorfield", vars_gv, lltype.Void)
+    else:
+        vars_gv = [gv_ptr, gv_index, gv_value]
+        genop(block, "setarrayitem", vars_gv, lltype.Void)
+
+def gengetarrayitem(block, gv_ITEMTYPE, gv_ptr, gv_index):
+    ITEMTYPE = from_opaque_object(gv_ITEMTYPE).value
+    v_ptr = from_opaque_object(gv_ptr)
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # this is really a getinteriorfield
+        vars_gv = v_ptr.base_and_offsets_gv + [gv_index]
+        return genop(block, "getinteriorfield", vars_gv, ITEMTYPE)
+    else:
+        vars_gv = [gv_ptr, gv_index]
+        return genop(block, "getarrayitem", vars_gv, ITEMTYPE)
+
+def gengetarraysize(block, gv_ptr):
+    v_ptr = from_opaque_object(gv_ptr)
+    if isinstance(v_ptr, InteriorPtrVariable):
+        # this is really a getinteriorarraysize
+        vars_gv = v_ptr.base_and_offsets_gv
+        return genop(block, "getinteriorarraysize", vars_gv, lltype.Signed)
+    else:
+        vars_gv = [gv_ptr]
+        return genop(block, "getarraysize", vars_gv, lltype.Signed)
+
 # XXX
 # temporary interface; it's unclear if genop itself should change to
 # ease dinstinguishing Void special args from the rest. Or there
@@ -503,6 +611,8 @@
 consttypeinfo = declareptrtype(flowmodel.Constant, "ConstOrVar")
 vartypeinfo   = declareptrtype(flowmodel.Variable, "ConstOrVar")
 vartypeinfo.set_lltype(consttypeinfo.get_lltype())   # force same lltype
+interiorptrvartypeinfo = declareptrtype(InteriorPtrVariable, "ConstOrVar")
+interiorptrvartypeinfo.set_lltype(vartypeinfo.get_lltype()) # force same lltype
 linktypeinfo  = declareptrtype(flowmodel.Link, "Link")
 graphtypeinfo = declareptrtype(flowmodel.FunctionGraph, "FunctionGraph")
 
@@ -566,6 +676,13 @@
 setannotation(geninputarg, s_ConstOrVar)
 setannotation(getinputarg, s_ConstOrVar)
 setannotation(genop, s_ConstOrVar)
+setannotation(gengetsubstruct, s_ConstOrVar)
+setannotation(gengetarraysubstruct, s_ConstOrVar)
+setannotation(gensetfield, None)
+setannotation(gengetfield, s_ConstOrVar)
+setannotation(gensetarrayitem, None)
+setannotation(gengetarrayitem, s_ConstOrVar)
+setannotation(gengetarraysize, s_ConstOrVar)
 setannotation(end, None)
 setannotation(genconst, s_ConstOrVar)
 setannotation(genzeroconst, s_ConstOrVar)

Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	Tue Oct 30 14:46:50 2007
@@ -159,53 +159,63 @@
     def genop_getfield(self, (gv_name, gv_PTRTYPE, gv_FIELDTYPE), gv_ptr):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_getfield: bad currently_writing")
-        vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v), gv_name.v]
-        return LLVar(llimpl.genop(self.b, 'getfield', vars_gv,
-                                  gv_FIELDTYPE.v))        
+        return LLVar(llimpl.gengetfield(self.b, gv_ptr.v,
+                                        gv_PTRTYPE.v, gv_name.v))
+        #vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v), gv_name.v]
+        #return LLVar(llimpl.genop(self.b, 'getfield', vars_gv,
+        #                          gv_FIELDTYPE.v))        
     
     def genop_setfield(self, (gv_name, gv_PTRTYPE, gv_FIELDTYPE), gv_ptr,
                                                                   gv_value):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_setfield: bad currently_writing")
-        vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v),
-                   gv_name.v,
-                   llimpl.cast(self.b, gv_FIELDTYPE.v, gv_value.v)]
-        return LLVar(llimpl.genop(self.b, 'setfield', vars_gv,
-                                  gv_Void.v))        
+        v_value = llimpl.cast(self.b, gv_FIELDTYPE.v, gv_value.v)
+        llimpl.gensetfield(self.b, gv_ptr.v, gv_PTRTYPE.v, gv_name.v, v_value)
+        #vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v),
+        #           gv_name.v,
+        #           llimpl.cast(self.b, gv_FIELDTYPE.v, gv_value.v)]
+        #return LLVar(llimpl.genop(self.b, 'setfield', vars_gv,
+        #                          gv_Void.v))        
     
     def genop_getsubstruct(self, (gv_name, gv_PTRTYPE, gv_FIELDTYPE), gv_ptr):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_getsubstruct: bad currently_writing")
-        vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v), gv_name.v]
-        return LLVar(llimpl.genop(self.b, 'getsubstruct', vars_gv,
-                                  gv_FIELDTYPE.v))        
+        return LLVar(llimpl.gengetsubstruct(self.b, gv_ptr.v,
+                                            gv_PTRTYPE.v, gv_name.v))
+        #vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v), gv_name.v]
+        #return LLVar(llimpl.genop(self.b, 'getsubstruct', vars_gv,
+        #                          gv_FIELDTYPE.v))        
 
     def genop_getarrayitem(self, gv_ITEMTYPE, gv_ptr, gv_index):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_getarrayitem: bad currently_writing")
-        vars_gv = [gv_ptr.v, gv_index.v]
-        return LLVar(llimpl.genop(self.b, 'getarrayitem', vars_gv,
-                                  gv_ITEMTYPE.v))
+        return LLVar(llimpl.gengetarrayitem(self.b, gv_ITEMTYPE.v,
+                                            gv_ptr.v, gv_index.v))
+        #vars_gv = [gv_ptr.v, gv_index.v]
+        #return LLVar(llimpl.genop(self.b, 'getarrayitem', vars_gv,
+        #                          gv_ITEMTYPE.v))
 
     def genop_getarraysubstruct(self, gv_ITEMTYPE, gv_ptr, gv_index):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_getarraysubstruct: bad currently_writing")
-        vars_gv = [gv_ptr.v, gv_index.v]
-        return LLVar(llimpl.genop(self.b, 'getarraysubstruct', vars_gv,
-                                  gv_ITEMTYPE.v))
+        return LLVar(llimpl.gengetarraysubstruct(self.b, gv_ptr.v, gv_index.v))
+        #vars_gv = [gv_ptr.v, gv_index.v]
+        #return LLVar(llimpl.genop(self.b, 'getarraysubstruct', vars_gv,
+        #                          gv_ITEMTYPE.v))
 
     def genop_setarrayitem(self, gv_ITEMTYPE, gv_ptr, gv_index, gv_value):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_setarrayitem: bad currently_writing")
-        vars_gv = [gv_ptr.v, gv_index.v, gv_value.v]
-        return LLVar(llimpl.genop(self.b, 'setarrayitem', vars_gv,
-                                  gv_Void.v))
+        llimpl.gensetarrayitem(self.b, gv_ptr.v, gv_index.v, gv_value.v)
+        #vars_gv = [gv_ptr.v, gv_index.v, gv_value.v]
+        #llimpl.genop(self.b, 'setarrayitem', vars_gv, gv_Void.v)
 
     def genop_getarraysize(self, gv_ITEMTYPE, gv_ptr):
         debug_assert(self.rgenop.currently_writing is self,
                      "genop_getarraysize: bad currently_writing")
-        return LLVar(llimpl.genop(self.b, 'getarraysize', [gv_ptr.v],
-                                  gv_Signed.v))
+        return LLVar(llimpl.gengetarraysize(self.b, gv_ptr.v))
+        #return LLVar(llimpl.genop(self.b, 'getarraysize', [gv_ptr.v],
+        #                          gv_Signed.v))
 
     def genop_malloc_fixedsize(self, (gv_TYPE, gv_PTRTYPE)):
         debug_assert(self.rgenop.currently_writing is self,

Modified: pypy/dist/pypy/jit/codegen/test/rgenop_tests.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/test/rgenop_tests.py	(original)
+++ pypy/dist/pypy/jit/codegen/test/rgenop_tests.py	Tue Oct 30 14:46:50 2007
@@ -2075,3 +2075,40 @@
                 x |= 1
             result = fnptr(x)
             assert result == expected(x)
+
+    def test_interior_access(self):
+        # for assembler backends, the 'interior' lloperations can be
+        # simply expressed as a sequence of genop_getsubstruct and
+        # genop_getarraysubstruct.  So we put magic in the llgraph
+        # backend to recognize and rebuild the expected 'interior'
+        # lloperation in the llgraphs.
+        T = lltype.Struct('T', ('x', lltype.Signed))
+        A = lltype.Array(T)
+        S = lltype.GcStruct('S', ('a', A))
+        rgenop = self.RGenOp()
+        sigtoken = rgenop.sigToken(FUNC)
+        builder, gv_fn, [gv_x] = rgenop.newgraph(sigtoken, "interior_access")
+        builder.start_writing()
+        gv_s = builder.genop_malloc_varsize(rgenop.varsizeAllocToken(S),
+                                            rgenop.genconst(5))
+        # generate an expanded 'setinteriorfield'
+        gv_a1 = builder.genop_getsubstruct(rgenop.fieldToken(S, 'a'), gv_s)
+        gv_t1 = builder.genop_getarraysubstruct(rgenop.arrayToken(A),
+                                                gv_a1, rgenop.genconst(3))
+        builder.genop_setfield(rgenop.fieldToken(T, 'x'), gv_t1, gv_x)
+        # generate an expanded 'getinteriorfield'
+        gv_a1 = builder.genop_getsubstruct(rgenop.fieldToken(S, 'a'), gv_s)
+        gv_t1 = builder.genop_getarraysubstruct(rgenop.arrayToken(A),
+                                                gv_a1, rgenop.genconst(3))
+        gv_y = builder.genop_getfield(rgenop.fieldToken(T, 'x'), gv_t1)
+        # generate an expanded 'getinteriorarraysize'
+        gv_a1 = builder.genop_getsubstruct(rgenop.fieldToken(S, 'a'), gv_s)
+        gv_z = builder.genop_getarraysize(rgenop.arrayToken(A), gv_a1)
+        # return
+        gv_result = builder.genop2("int_add", gv_y, gv_z)
+        builder.finish_and_return(sigtoken, gv_result)
+        builder.end()
+
+        fnptr = self.cast(gv_fn, 1)
+        result = fnptr(42)
+        assert result == 47

Modified: pypy/dist/pypy/jit/hintannotator/model.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/model.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/model.py	Tue Oct 30 14:46:50 2007
@@ -4,6 +4,7 @@
 from pypy.rpython.lltypesystem import lltype, lloperation
 
 UNARY_OPERATIONS = """same_as hint getfield setfield getsubstruct getarraysize
+                      getinteriorfield getinteriorarraysize setinteriorfield
                       cast_pointer
                       direct_call
                       indirect_call
@@ -24,7 +25,7 @@
 BINARY_OPERATIONS = """int_add int_sub int_mul int_mod int_and int_rshift
                        int_lshift int_floordiv int_xor int_or
                        int_add_ovf int_sub_ovf int_mul_ovf int_mod_ovf
-                       int_floordiv_ovf int_lshift_ovf
+                       int_floordiv_ovf int_lshift_ovf int_add_nonneg_ovf
                        uint_add uint_sub uint_mul uint_mod uint_and
                        uint_lshift uint_rshift uint_floordiv
                        char_gt char_lt char_le char_ge char_eq char_ne
@@ -346,6 +347,35 @@
         FIELD_TYPE = getattr(S, hs_fieldname.const)
         return SomeLLAbstractVariable(lltype.Ptr(FIELD_TYPE), hs_v1.deepfrozen)
 
+    def _getinterior(hs_v1, *offsets_hs):
+        hs_container = hs_v1
+        for hs_offset in offsets_hs:
+            if hs_offset.concretetype is lltype.Signed:
+                hs_container = pair(hs_container,hs_offset).getarraysubstruct()
+            else:
+                hs_container = hs_container.getsubstruct(hs_offset)
+        return hs_container
+
+    def getinteriorfield(hs_v1, *offsets_hs):
+        hs_container = hs_v1._getinterior(*offsets_hs[:-1])
+        hs_lastofs   = offsets_hs[-1]
+        if hs_lastofs.concretetype is lltype.Signed:
+            return pair(hs_container, hs_lastofs).getarrayitem()
+        else:
+            return hs_container.getfield(hs_lastofs)
+
+    def getinteriorarraysize(hs_v1, *offsets_hs):
+        return hs_v1._getinterior(*offsets_hs).getarraysize()
+
+    def setinteriorfield(hs_v1, *offsets_and_val_hs):
+        hs_inner   = hs_v1._getinterior(*offsets_and_val_hs[:-2])
+        hs_lastofs = offsets_and_val_hs[-2]
+        hs_value   = offsets_and_val_hs[-1]
+        if hs_lastofs.concretetype is lltype.Signed:
+            pair(hs_inner, hs_lastofs).setarrayitem(hs_value)
+        else:
+            hs_inner.setfield(hs_lastofs, hs_value)
+
     def cast_pointer(hs_v1):
         RESTYPE = getbookkeeper().current_op_concretetype()
         return SomeLLAbstractVariable(RESTYPE, hs_v1.deepfrozen)

Modified: pypy/dist/pypy/jit/hintannotator/test/test_annotator.py
==============================================================================
--- pypy/dist/pypy/jit/hintannotator/test/test_annotator.py	(original)
+++ pypy/dist/pypy/jit/hintannotator/test/test_annotator.py	Tue Oct 30 14:46:50 2007
@@ -144,7 +144,9 @@
         res = hint(res, variable=True)
         return res
 
-    hs = hannotate(ll_function, [int, int], policy=P_NOVIRTUAL)
+    # must backendoptimize to remove the mallocs related to the interior ptrs
+    hs = hannotate(ll_function, [int, int], policy=P_NOVIRTUAL,
+                   backendoptimize=True)
     assert hs.concretetype == lltype.Signed
 
 
@@ -428,6 +430,7 @@
     assert hs1.contentdef.degenerated
 
 def test_degenerated_merge_cross_substructure():
+    py.test.skip("no longer a valid test")
     from pypy.rlib import objectmodel
     S = lltype.Struct('S', ('n', lltype.Signed))
     T = lltype.GcStruct('T', ('s', S), ('s1', S), ('n', lltype.Float))

Modified: pypy/dist/pypy/jit/timeshifter/hrtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/hrtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/hrtyper.py	Tue Oct 30 14:46:50 2007
@@ -880,6 +880,100 @@
             ts.s_RedBox)
 
 
+    def _getinteriordesc(self, hop, PTRTYPE, nb_offsets):
+        path = []
+        CONTAINER = PTRTYPE.TO
+        indices_v = []
+        for i in range(1, 1 + nb_offsets):
+            T = originalconcretetype(hop.args_s[i])
+            if T is lltype.Void:
+                fieldname = hop.args_v[i].value
+                CONTAINER = getattr(CONTAINER, fieldname)
+                path.append(fieldname)
+            else:
+                assert T is lltype.Signed
+                CONTAINER = CONTAINER.OF
+                path.append(None)    # placeholder for 'array index'
+                v_index = hop.inputarg(self.getredrepr(lltype.Signed), arg=i)
+                indices_v.append(v_index)
+        if CONTAINER is lltype.Void:     # Void field
+            return None, None
+        else:
+            return (rcontainer.InteriorDesc(self, PTRTYPE.TO, tuple(path)),
+                    indices_v)
+
+    def translate_op_getinteriorfield(self, hop):
+        ts = self
+        # no virtualizable access read here
+        PTRTYPE = originalconcretetype(hop.args_s[0])
+        assert not PTRTYPE.TO._hints.get('virtualizable', False)
+
+        # non virtual case
+        interiordesc, indices_v = self._getinteriordesc(hop, PTRTYPE,
+                                                        hop.nb_args - 1)
+        if interiordesc is None:     # Void field
+            return None
+        v_argbox = hop.inputarg(self.getredrepr(PTRTYPE), arg=0)
+        v_argbox = hop.llops.as_ptrredbox(v_argbox)
+        c_deepfrozen = inputconst(lltype.Bool, hop.args_s[0].deepfrozen)
+        c_interiordesc = inputconst(lltype.Void, interiordesc)
+        s_interiordesc = ts.rtyper.annotator.bookkeeper.immutablevalue(
+            interiordesc)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(
+            rtimeshift.ll_gengetinteriorfield,
+            [ts.s_JITState, annmodel.s_Bool, s_interiordesc, ts.s_PtrRedBox]
+                                               + [ts.s_RedBox]*len(indices_v),
+            [v_jitstate   , c_deepfrozen   , c_interiordesc, v_argbox      ]
+                                               + indices_v,
+            ts.s_RedBox)
+
+    def translate_op_setinteriorfield(self, hop):
+        ts = self
+        PTRTYPE = originalconcretetype(hop.args_s[0])
+        # non virtual case
+        interiordesc, indices_v = self._getinteriordesc(hop, PTRTYPE,
+                                                        hop.nb_args - 2)
+        if interiordesc is None:     # Void field
+            return None
+        v_destbox = hop.inputarg(self.getredrepr(PTRTYPE), arg=0)
+        v_valuebox = hop.inputarg(self.getredrepr(interiordesc.VALUETYPE),
+                                  arg = hop.nb_args - 1)
+        v_destbox = hop.llops.as_ptrredbox(v_destbox)
+        c_interiordesc = inputconst(lltype.Void, interiordesc)
+        s_interiordesc = ts.rtyper.annotator.bookkeeper.immutablevalue(
+            interiordesc)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(
+            rtimeshift.ll_gensetinteriorfield,
+            [ts.s_JITState, s_interiordesc, ts.s_PtrRedBox, ts.s_RedBox]
+                                               + [ts.s_RedBox]*len(indices_v),
+            [v_jitstate,    c_interiordesc, v_destbox,      v_valuebox]
+                                               + indices_v,
+            annmodel.s_None)
+
+    def translate_op_getinteriorarraysize(self, hop):
+        ts = self
+        PTRTYPE = originalconcretetype(hop.args_s[0])
+        # non virtual case
+        interiordesc, indices_v = self._getinteriordesc(hop, PTRTYPE,
+                                                        hop.nb_args - 1)
+        assert interiordesc is not None
+        v_argbox = hop.inputarg(self.getredrepr(PTRTYPE), arg=0)
+        v_argbox = hop.llops.as_ptrredbox(v_argbox)
+        c_interiordesc = inputconst(lltype.Void, interiordesc)
+        s_interiordesc = ts.rtyper.annotator.bookkeeper.immutablevalue(
+            interiordesc)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(
+            rtimeshift.ll_gengetinteriorarraysize,
+            [ts.s_JITState, s_interiordesc, ts.s_PtrRedBox]
+                                               + [ts.s_RedBox]*len(indices_v),
+            [v_jitstate,    c_interiordesc, v_argbox      ]
+                                               + indices_v,
+            ts.s_RedBox)
+
+
     def translate_op_cast_pointer(self, hop):
         FROM_TYPE = originalconcretetype(hop.args_s[0])
         [v_argbox] = hop.inputargs(self.getredrepr(FROM_TYPE))

Modified: pypy/dist/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rcontainer.py	Tue Oct 30 14:46:50 2007
@@ -349,6 +349,147 @@
         content.content_boxes.append(outsidebox)             
         return vstructbox
 
+
+class InteriorDesc(object):
+    __metaclass__ = cachedtype
+
+    def __init__(self, hrtyper, TOPCONTAINER, path):
+        self.TOPCONTAINER = TOPCONTAINER
+        self.path = path
+        PTRTYPE = lltype.Ptr(TOPCONTAINER)
+        TYPE = TOPCONTAINER
+        fielddescs = []
+        for offset in path:
+            LASTCONTAINER = TYPE
+            if offset is None:           # array substruct
+                fielddescs.append(ArrayFieldDesc(hrtyper, TYPE))
+                TYPE = TYPE.OF
+            else:
+                fielddescs.append(NamedFieldDesc(hrtyper, lltype.Ptr(TYPE),
+                                                 offset))
+                TYPE = getattr(TYPE, offset)
+        unroll_path = unrolling_iterable(path)
+        self.VALUETYPE = TYPE
+
+        if not isinstance(TYPE, lltype.ContainerType):
+            lastoffset = path[-1]
+            lastfielddesc = fielddescs[-1]
+            immutable = LASTCONTAINER._hints.get('immutable', False)
+            getinterior_initial = make_interior_getter(fielddescs[:-1])
+
+            def gengetinteriorfield(jitstate, deepfrozen, argbox, *indexboxes):
+                if (immutable or deepfrozen) and argbox.is_constant():
+                    ptr = rvalue.ll_getvalue(argbox, PTRTYPE)
+                    if ptr:    # else don't constant-fold the segfault...
+                        i = 0
+                        for offset in unroll_path:
+                            if offset is None:        # array substruct
+                                indexbox = indexboxes[i]
+                                i += 1
+                                if not indexbox.is_constant():
+                                    break    # non-constant array index
+                                index = rvalue.ll_getvalue(indexbox,
+                                                           lltype.Signed)
+                                ptr = ptr[index]
+                            else:
+                                ptr = getattr(ptr, offset)
+                        else:
+                            # constant-folding: success
+                            assert i == len(indexboxes)
+                            return rvalue.ll_fromvalue(jitstate, ptr)
+                argbox = getinterior_initial(jitstate, argbox, *indexboxes)
+                if lastoffset is None:      # getarrayitem
+                    indexbox = indexboxes[-1]
+                    genvar = jitstate.curbuilder.genop_getarrayitem(
+                        lastfielddesc.arraytoken,
+                        argbox.getgenvar(jitstate),
+                        indexbox.getgenvar(jitstate))
+                    return lastfielddesc.makebox(jitstate, genvar)
+                else:  # getfield
+                    return argbox.op_getfield(jitstate, lastfielddesc)
+
+            def gensetinteriorfield(jitstate, destbox, valuebox, *indexboxes):
+                destbox = getinterior_initial(jitstate, destbox, *indexboxes)
+                if lastoffset is None:      # setarrayitem
+                    indexbox = indexboxes[-1]
+                    genvar = jitstate.curbuilder.genop_setarrayitem(
+                        lastfielddesc.arraytoken,
+                        destbox.getgenvar(jitstate),
+                        indexbox.getgenvar(jitstate),
+                        valuebox.getgenvar(jitstate)
+                        )
+                else:  # setfield
+                    destbox.op_setfield(jitstate, lastfielddesc, valuebox)
+
+            self.gengetinteriorfield = gengetinteriorfield
+            self.gensetinteriorfield = gensetinteriorfield
+
+        else:
+            assert isinstance(TYPE, lltype.Array)
+            arrayfielddesc = ArrayFieldDesc(hrtyper, TYPE)
+            getinterior_all = make_interior_getter(fielddescs)
+
+            def gengetinteriorarraysize(jitstate, argbox, *indexboxes):
+                if argbox.is_constant():
+                    ptr = rvalue.ll_getvalue(argbox, PTRTYPE)
+                    if ptr:    # else don't constant-fold the segfault...
+                        i = 0
+                        for offset in unroll_path:
+                            if offset is None:        # array substruct
+                                indexbox = indexboxes[i]
+                                i += 1
+                                if not indexbox.is_constant():
+                                    break    # non-constant array index
+                                index = rvalue.ll_getvalue(indexbox,
+                                                           lltype.Signed)
+                                ptr = ptr[index]
+                            else:
+                                ptr = getattr(ptr, offset)
+                        else:
+                            # constant-folding: success
+                            assert i == len(indexboxes)
+                            return rvalue.ll_fromvalue(jitstate, len(ptr))
+                argbox = getinterior_all(jitstate, argbox, *indexboxes)
+                genvar = jitstate.curbuilder.genop_getarraysize(
+                    arrayfielddesc.arraytoken,
+                    argbox.getgenvar(jitstate))
+                return rvalue.IntRedBox(arrayfielddesc.indexkind, genvar)
+
+            self.gengetinteriorarraysize = gengetinteriorarraysize
+
+    def _freeze_(self):
+        return True
+
+
+def make_interior_getter(fielddescs, _cache={}):
+    # returns a 'getinterior(jitstate, argbox, *indexboxes)' function
+    key = tuple(fielddescs)
+    try:
+        return _cache[key]
+    except KeyError:
+        unroll_fielddescs = unrolling_iterable([
+            (fielddesc, isinstance(fielddesc, ArrayFieldDesc))
+            for fielddesc in fielddescs])
+
+        def getinterior(jitstate, argbox, *indexboxes):
+            i = 0
+            for fielddesc, is_array in unroll_fielddescs:
+                if is_array:    # array substruct
+                    indexbox = indexboxes[i]
+                    i += 1
+                    genvar = jitstate.curbuilder.genop_getarraysubstruct(
+                        fielddesc.arraytoken,
+                        argbox.getgenvar(jitstate),
+                        indexbox.getgenvar(jitstate))
+                    argbox = fielddesc.makebox(jitstate, genvar)
+                else:   # getsubstruct
+                    argbox = argbox.op_getsubstruct(jitstate, fielddesc)
+                assert isinstance(argbox, rvalue.PtrRedBox)
+            return argbox
+
+        _cache[key] = getinterior
+        return getinterior
+
 # ____________________________________________________________
 
 # XXX basic field descs for now

Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Tue Oct 30 14:46:50 2007
@@ -11,6 +11,7 @@
 FOLDABLE_GREEN_OPS = dict.fromkeys(lloperation.enum_foldable_ops())
 FOLDABLE_GREEN_OPS['getfield'] = None
 FOLDABLE_GREEN_OPS['getarrayitem'] = None
+FOLDABLE_GREEN_OPS['getinteriorfield'] = None
 
 NULL_OBJECT = base_ptr_lltype()._defl()
 
@@ -211,6 +212,20 @@
         argbox.getgenvar(jitstate))
     return rvalue.IntRedBox(fielddesc.indexkind, genvar)
 
+
+def ll_gengetinteriorfield(jitstate, deepfrozen, interiordesc,
+                           argbox, *indexboxes):
+    return interiordesc.gengetinteriorfield(jitstate, deepfrozen,
+                                            argbox, *indexboxes)
+
+def ll_gensetinteriorfield(jitstate, interiordesc, destbox,
+                           valuebox, *indexboxes):
+    interiordesc.gensetinteriorfield(jitstate, destbox, valuebox, *indexboxes)
+
+def ll_gengetinteriorarraysize(jitstate, interiordesc, argbox, *indexboxes):
+    return interiordesc.gengetinteriorarraysize(jitstate, argbox, *indexboxes)
+
+
 def ll_genptrnonzero(jitstate, argbox, reverse):
     if argbox.is_constant():
         addr = rvalue.ll_getvalue(argbox, llmemory.Address)

Modified: pypy/dist/pypy/jit/timeshifter/test/test_portal.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_portal.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_portal.py	Tue Oct 30 14:46:50 2007
@@ -196,10 +196,16 @@
             s = ["aaaaaaaaaab", "aaaa"][gets]
             return recognizetable(dfatable, s, final_states)
 
-        res = self.timeshift_from_portal(main, recognizetable, [0], policy=P_NOVIRTUAL)
+        # must backendoptimize to remove the mallocs related
+        # to the interior ptrs
+        res = self.timeshift_from_portal(main, recognizetable, [0],
+                                         policy=P_NOVIRTUAL,
+                                         backendoptimize=True)
         assert res
 
-        res = self.timeshift_from_portal(main, recognizetable, [1], policy=P_NOVIRTUAL)
+        res = self.timeshift_from_portal(main, recognizetable, [1],
+                                         policy=P_NOVIRTUAL,
+                                         backendoptimize=True)
         assert not res
 
     def test_dfa_compile2(self):
@@ -210,11 +216,17 @@
             s = ["aaaaaaaaaab", "aaaa"][gets]
             return recognizeparts(alltrans, final_states, s)
 
-        res = self.timeshift_from_portal(main, recognizeparts, [0, 0], policy=P_NOVIRTUAL)
+        # must backendoptimize to remove the mallocs related
+        # to the interior ptrs
+        res = self.timeshift_from_portal(main, recognizeparts, [0, 0],
+                                         policy=P_NOVIRTUAL,
+                                         backendoptimize=True)
         assert res
 
         # XXX unfortunately we have to create a new version each time - because of pbc
-        res = self.timeshift_from_portal(main, recognizeparts, [1, 0], policy=P_NOVIRTUAL)
+        res = self.timeshift_from_portal(main, recognizeparts, [1, 0],
+                                         policy=P_NOVIRTUAL,
+                                         backendoptimize=True)
         assert not res
 
     def test_dfa_compile3(self):

Modified: pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_timeshift.py	Tue Oct 30 14:46:50 2007
@@ -59,8 +59,7 @@
         auto_inlining(t, threshold=inline)
     if backendoptimize:
         from pypy.translator.backendopt.all import backend_optimizations
-        if inline is not None:
-            backend_optimizations(t, inline_threshold=inline)
+        backend_optimizations(t, inline_threshold=inline or 0)
     if portal is None:
         portal = func
     if hasattr(policy, "seetranslator"):
@@ -809,16 +808,14 @@
                               policy=P_NOVIRTUAL)
          assert res == 42
          self.check_insns({'malloc_varsize': 1,
-                           'getarraysubstruct': 3,
-                           'setfield': 2, 'getfield': 1,
+                           'setinteriorfield': 2, 'getinteriorfield': 1,
                            'getarraysize': 1, 'int_mul': 1})
 
          res = self.timeshift(ll_function, [21, -21, 1], [],
                               policy=P_NOVIRTUAL)
          assert res == -42
          self.check_insns({'malloc_varsize': 1,
-                           'getarraysubstruct': 3,
-                           'setfield': 2, 'getfield': 1,
+                           'setinteriorfield': 2, 'getinteriorfield': 1,
                            'getarraysize': 1, 'int_mul': 1})
 
 
@@ -835,12 +832,14 @@
          res = self.timeshift(ll_function, [21, -21, 0], [],
                               policy=P_NOVIRTUAL)
          assert res == 42
-         self.check_insns(malloc_varsize=1)
+         self.check_insns(malloc_varsize=1,
+                          getinteriorarraysize=1)
 
          res = self.timeshift(ll_function, [21, -21, 1], [],
                               policy=P_NOVIRTUAL)
          assert res == -42
-         self.check_insns(malloc_varsize=1)
+         self.check_insns(malloc_varsize=1,
+                          getinteriorarraysize=1)
 
     def test_array_of_voids(self):
         A = lltype.GcArray(lltype.Void)



More information about the Pypy-commit mailing list