[pypy-svn] r79936 - in pypy/branch/out-of-line-guards/pypy: jit/backend/llgraph jit/codewriter jit/codewriter/test jit/metainterp jit/metainterp/test rpython/lltypesystem

fijal at codespeak.net fijal at codespeak.net
Thu Dec 9 17:07:15 CET 2010


Author: fijal
Date: Thu Dec  9 17:07:12 2010
New Revision: 79936

Modified:
   pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py
   pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py
   pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py
   pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py
   pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py
   pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py
Log:
Try to merge my changes up-to-date. I'm not completely sure, since SVN
screwed me up massively on this one


Modified: pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/llimpl.py	Thu Dec  9 17:07:12 2010
@@ -157,6 +157,7 @@
     'force_token'     : ((), 'int'),
     'call_may_force'  : (('int', 'varargs'), 'intorptr'),
     'guard_not_forced': ((), None),
+    'guard_not_invariant': ((), None),
 }
 
 # ____________________________________________________________
@@ -925,6 +926,8 @@
         if forced:
             raise GuardFailed
 
+    def op_guard_not_invariant(self, descr):
+        pass
 
 class OOFrame(Frame):
 

Modified: pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/backend/llgraph/runner.py	Thu Dec  9 17:07:12 2010
@@ -488,6 +488,10 @@
         self.latest_frame = frame
         return self.get_fail_descr_from_number(fail_index)
 
+    def get_invalidate_asm(self, TP, fieldname):
+        def invalidate_asm(arg, fieldname):
+            XXX # write me
+        return invalidate_asm
 
 class OOtypeCPU_xxx_disabled(BaseCPU):
     is_oo = True

Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/call.py	Thu Dec  9 17:07:12 2010
@@ -6,6 +6,7 @@
 from pypy.jit.codewriter import support
 from pypy.jit.codewriter.jitcode import JitCode
 from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
+from pypy.jit.codewriter.effectinfo import JitInvariantAnalyzer
 from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
 from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
 from pypy.translator.simplify import get_funcobj, get_functype
@@ -30,6 +31,7 @@
             self.raise_analyzer = RaiseAnalyzer(translator)
             self.readwrite_analyzer = ReadWriteAnalyzer(translator)
             self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
+            self.jit_invariant_analyzer = JitInvariantAnalyzer(translator)
         #
         for index, jd in enumerate(jitdrivers_sd):
             jd.index = index
@@ -216,7 +218,9 @@
                 assert not NON_VOID_ARGS, ("arguments not supported for "
                                            "loop-invariant function!")
         # build the extraeffect
-        if self.virtualizable_analyzer.analyze(op):
+        if self.jit_invariant_analyzer.analyze(op):
+            extraeffect = EffectInfo.EF_FORCES_JIT_INVARIANT
+        elif self.virtualizable_analyzer.analyze(op):
             extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
         elif loopinvariant:
             extraeffect = EffectInfo.EF_LOOPINVARIANT
@@ -234,7 +238,7 @@
         #
         if pure or loopinvariant:
             assert effectinfo is not None
-            assert extraeffect != EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+            assert extraeffect < EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
         #
         return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT,
                                     effectinfo)

Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/effectinfo.py	Thu Dec  9 17:07:12 2010
@@ -14,6 +14,7 @@
     EF_CAN_RAISE                       = 2 #normal function (can raise)
     EF_LOOPINVARIANT                   = 3 #special: call it only once per loop
     EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 4 #can raise and force virtualizables
+    EF_FORCES_JIT_INVARIANT            = 5 #can force jit invariant
 
     # the 'oopspecindex' field is one of the following values:
     OS_NONE                     = 0    # normal case, no oopspec
@@ -142,6 +143,10 @@
         return op.opname in ('jit_force_virtualizable',
                              'jit_force_virtual')
 
+class JitInvariantAnalyzer(BoolGraphAnalyzer):
+    def analyze_simple_operation(self, op):
+        return op.opname == 'jit_invariant_setfield'
+
 # ____________________________________________________________
 
 class CallInfoCollection(object):

Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/jtransform.py	Thu Dec  9 17:07:12 2010
@@ -32,6 +32,7 @@
         self.cpu = cpu
         self.callcontrol = callcontrol
         self.portal_jd = portal_jd   # non-None only for the portal graph(s)
+        self.asmcodes_appenders = {}
 
     def transform(self, graph):
         self.graph = graph
@@ -554,6 +555,7 @@
                                                 arrayfielddescr,
                                                 arraydescr)
             return []
+        extrargs = []
         # check for _immutable_fields_ hints
         if v_inst.concretetype.TO._immutable_field(c_fieldname.value):
             if (self.callcontrol is not None and
@@ -565,7 +567,10 @@
         else:
             jit_inv = v_inst.concretetype.TO._hints.get('jit_invariant_fields')
             if jit_inv and op.args[1].value in jit_inv.fields:
-                pure = '_pure'
+                pure = '_invariant'
+                c_func = self._get_appender_for_asmcode(
+                    v_inst.concretetype.TO, c_fieldname.value)
+                extrargs.append(c_func)
             else:
                 pure = ''
         argname = getattr(v_inst.concretetype.TO, '_gckind', 'gc')
@@ -573,7 +578,40 @@
                                       c_fieldname.value)
         kind = getkind(RESULT)[0]
         return SpaceOperation('getfield_%s_%s%s' % (argname, kind, pure),
-                              [v_inst, descr], op.result)
+                              [v_inst, descr] + extrargs, op.result)
+
+    def _get_appender_for_asmcode(self, TP, fieldname):
+        from pypy.rpython.lltypesystem.rclass import ASMCODE
+        from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
+        from pypy.annotation.model import lltype_to_annotation
+
+        key = (TP, fieldname)
+        try:
+            return self.asmcodes_appenders[key]
+        except KeyError:
+            name = 'asmcodes_' + fieldname[len('inst_'):]
+            
+            def appender(inst, v):
+                inst = lltype.cast_opaque_ptr(lltype.Ptr(TP), inst)
+                new_asmcode = lltype.malloc(ASMCODE)
+                new_asmcode.address = v
+                next = getattr(inst, name)
+                if not next:
+                    setattr(inst, name, new_asmcode)
+                else:
+                    prev = next
+                    while next:
+                        prev = next
+                        next = next.next
+                    prev.next = new_asmcode
+
+            args_s = [lltype_to_annotation(llmemory.GCREF)] * 2
+            s_result = lltype_to_annotation(lltype.Void)
+            mixlevelann = MixLevelHelperAnnotator(self.cpu.rtyper)
+            c_appender = mixlevelann.constfunc(appender, args_s, s_result)
+            mixlevelann.finish()
+            self.asmcodes_appenders[key] = c_appender
+            return c_appender
 
     def rewrite_op_setfield(self, op):
         if self.is_typeptr_getset(op):

Modified: pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/codewriter/test/test_jtransform.py	Thu Dec  9 17:07:12 2010
@@ -956,7 +956,8 @@
                         Constant('inst_x', lltype.Void)], v2)
     tr = Transformer(FakeCPU())
     op1 = tr.rewrite_operation(op)
-    assert op1.opname == 'getfield_gc_i_pure'
+    assert op1.opname == 'getfield_gc_i_invariant'
+    assert len(op1.args) == 3
 
 def test_jit_invariant_setfield():
     from pypy.rpython.rclass import FieldListAccessor

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/blackhole.py	Thu Dec  9 17:07:12 2010
@@ -1087,6 +1087,10 @@
     bhimpl_getfield_gc_r_pure = bhimpl_getfield_gc_r
     bhimpl_getfield_gc_f_pure = bhimpl_getfield_gc_f
 
+    bhimpl_getfield_gc_i_invariant = bhimpl_getfield_gc_i
+    bhimpl_getfield_gc_r_invariant = bhimpl_getfield_gc_r
+    bhimpl_getfield_gc_f_invariant = bhimpl_getfield_gc_f
+
     bhimpl_getfield_vable_i = bhimpl_getfield_gc_i
     bhimpl_getfield_vable_r = bhimpl_getfield_gc_r
     bhimpl_getfield_vable_f = bhimpl_getfield_gc_f

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/compile.py	Thu Dec  9 17:07:12 2010
@@ -101,6 +101,7 @@
     if old_loop_token is not None:
         metainterp.staticdata.log("reusing old loop")
         return old_loop_token
+    metainterp.remember_jit_invariants(loop)
     send_loop_to_backend(metainterp_sd, loop, "loop")
     insert_loop_token(old_loop_tokens, loop_token)
     record_loop_or_bridge(loop)
@@ -563,6 +564,7 @@
         # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
         prepare_last_operation(new_loop, target_loop_token)
         resumekey.compile_and_attach(metainterp, new_loop)
+        metainterp.remember_jit_invariants(target_loop_token)
         record_loop_or_bridge(new_loop)
     return target_loop_token
 

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/pyjitpl.py	Thu Dec  9 17:07:12 2010
@@ -1,5 +1,6 @@
 import py, os, sys
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
+from pypy.rpython.lltypesystem.rclass import ASMCODE
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -509,6 +510,14 @@
     opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
     opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
 
+    @arguments("box", "descr", "box")
+    def _opimpl_getfield_gc_invariant_any(self, box, fielddescr, c_func):
+        self.metainterp.invariant_structs.append((box, c_func))
+        return self.execute_with_descr(rop.GETFIELD_GC_PURE, fielddescr, box)
+    opimpl_getfield_gc_i_invariant = _opimpl_getfield_gc_invariant_any
+    opimpl_getfield_gc_r_invariant = _opimpl_getfield_gc_invariant_any
+    opimpl_getfield_gc_f_invariant = _opimpl_getfield_gc_invariant_any
+
     @arguments("orgpc", "box", "descr")
     def _opimpl_getfield_gc_greenfield_any(self, pc, box, fielddescr):
         ginfo = self.metainterp.jitdriver_sd.greenfield_info
@@ -1163,10 +1172,9 @@
         assert i == len(allboxes)
         #
         effectinfo = descr.get_extra_info()
-        if (effectinfo is None or
-                effectinfo.extraeffect ==
-                             effectinfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE or
-                assembler_call):
+        force_vir = effectinfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE 
+        if (effectinfo is None or effectinfo.extraeffect >= force_vir or
+            assembler_call):
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.clear_exception()
             self.metainterp.vable_and_vrefs_before_residual_call()
@@ -1178,6 +1186,8 @@
             if resbox is not None:
                 self.make_result_of_lastop(resbox)
             self.metainterp.vable_after_residual_call()
+            if effectinfo.extraeffect >= effectinfo.EF_FORCES_JIT_INVARIANT:
+                self.generate_guard(rop.GUARD_NOT_INVARIANT, None)
             self.generate_guard(rop.GUARD_NOT_FORCED, None)
             self.metainterp.handle_possible_exception()
             return resbox
@@ -1393,6 +1403,7 @@
         self.portal_trace_positions = []
         self.free_frames_list = []
         self.last_exc_value_box = None
+        self.invariant_structs = []
 
     def perform_call(self, jitcode, boxes, greenkey=None):
         # causes the metainterp to enter the given subfunction
@@ -2227,6 +2238,14 @@
         op = op.copy_and_change(rop.CALL_ASSEMBLER, args=args, descr=token)
         self.history.operations.append(op)
 
+    def remember_jit_invariants(self, token):
+        lltoken = lltype.cast_opaque_ptr(llmemory.GCREF, token)
+        seen = {}
+        for b_struct, c_appender in self.invariant_structs:
+            if (b_struct, c_appender) not in seen:
+                heaptracker.int2adr(c_func.value).ptr(b_struct.value, lltoken)
+                seend[(b_struct, c_appender)] = None
+
 # ____________________________________________________________
 
 class GenerateMergePoint(JitException):

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/resoperation.py	Thu Dec  9 17:07:12 2010
@@ -379,7 +379,8 @@
     'GUARD_EXCEPTION/1d',
     'GUARD_NO_OVERFLOW/0d',
     'GUARD_OVERFLOW/0d',
-    'GUARD_NOT_FORCED/0d',
+    'GUARD_NOT_FORCED/0d', # forcing virtualrefs/virtualizables
+    'GUARD_NOT_INVARIANT/0d', # forcing jit invariant fields
     '_GUARD_LAST', # ----- end of guard operations -----
 
     '_NOSIDEEFFECT_FIRST', # ----- start of no_side_effect operations -----

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/test/test_basic.py	Thu Dec  9 17:07:12 2010
@@ -723,7 +723,7 @@
 
     def test_getfield_jit_invariant(self):
         class A(object):
-            _jit_invariant_fields_ = 'x'
+            _jit_invariant_fields_ = ['x']
 
         a1 = A()
         a1.x = 5
@@ -739,6 +739,31 @@
         res = self.interp_operations(f, [-3])
         self.check_operations_history(getfield_gc = 0)
 
+    def test_setfield_jit_invariant(self):
+        class A(object):
+            _jit_invariant_fields_ = ['x']
+
+        a = A()
+        a.x = 1
+
+        myjitdriver = JitDriver(greens = [], reds = ['i'])
+
+        @dont_look_inside
+        def g(i):
+            if i == 5:
+                a.x = 5
+
+        def f():
+            i = 0
+            while i < 10:
+                myjitdriver.can_enter_jit(i=i)
+                myjitdriver.jit_merge_point(i=i)
+                g(i)
+                i += a.x
+
+        self.meta_interp(f, [])
+        self.check_loop_count(2)
+
     def test_setfield_bool(self):
         class A:
             def __init__(self):

Modified: pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/jit/metainterp/warmspot.py	Thu Dec  9 17:07:12 2010
@@ -820,10 +820,19 @@
             op.opname = 'direct_call'
             op.args[:3] = [closures[key]]
 
+    def replace_jit_invariant_with_direct_call(self, op):
+        op.opname = 'direct_call'
+        ARG = op.args[0].concretetype
+        FUNC = lltype.Ptr(lltype.FuncType([ARG, lltype.Void], lltype.Void))
+        llptr = self.helper_func(FUNC, self.cpu.get_invalidate_asm(FUNC,
+                                                             op.args[1].value))
+        cptr = Constant(llptr, lltype.Void)
+        op.args = [cptr, op.args[0], op.args[1]]
+
     def rewrite_jit_invariant_setfield(self):
         graphs = self.translator.graphs
         for graph, block, i in find_jit_invariant_setfield(graphs):
-            del block.operations[i] # for now
+            self.replace_jit_invariant_with_direct_call(block.operations[i])
 
     def rewrite_force_virtual(self, vrefinfo):
         if self.cpu.ts.name != 'lltype':

Modified: pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/lloperation.py	Thu Dec  9 17:07:12 2010
@@ -433,6 +433,7 @@
     'jit_marker':           LLOp(),
     'jit_force_virtualizable':LLOp(canrun=True),
     'jit_force_virtual':    LLOp(canrun=True),
+    'jit_invariant_setfield': LLOp(canrun=True),
     'get_exception_addr':   LLOp(),
     'get_exc_value_addr':   LLOp(),
     'do_malloc_fixedsize_clear':LLOp(canraise=(MemoryError,),canunwindgc=True),

Modified: pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py	(original)
+++ pypy/branch/out-of-line-guards/pypy/rpython/lltypesystem/rclass.py	Thu Dec  9 17:07:12 2010
@@ -87,7 +87,7 @@
 # a linked-list of assembler codes to invalidate in case jit_invariant_fields
 # are modified
 ASMCODE = lltype.GcForwardReference()
-ASMCODE.become(GcStruct('asmcode', ('address', llmemory.Address),
+ASMCODE.become(GcStruct('asmcode', ('address', llmemory.GCREF),
                         ('next', lltype.Ptr(ASMCODE))))
 
 def cast_vtable_to_typeptr(vtable):
@@ -148,6 +148,9 @@
             #
             self.rbase = getclassrepr(self.rtyper, self.classdef.basedef)
             self.rbase.setup()
+            # jit_invariant_fields
+            jit_inv_fields = self.classdef.classdesc.classdict.get(
+                '_jit_invariant_fields_')
             kwds = {'hints': {'immutable': True}}
             vtable_type = Struct('%s_vtable' % self.classdef.name,
                                  ('super', self.rbase.vtable_type),
@@ -517,7 +520,9 @@
         # for virtualizables; see rvirtualizable2.py
         if (op == 'setfield' and cname.value.startswith('inst_') and
             cname.value[len('inst_'):] in self.jit_invariant_fields):
-            llops.genop('jit_invariant_setfield', [])
+            name = cname.value
+            cname = Constant('asmcodes_' + name[len('inst_'):], lltype.Void)
+            llops.genop('jit_invariant_setfield', [vinst, cname])
 
     def new_instance(self, llops, classcallhop=None):
         """Build a new instance, without calling __init__."""



More information about the Pypy-commit mailing list