[pypy-svn] r37966 - in pypy/branch/jit-virtual-world/pypy: jit/timeshifter jit/timeshifter/test rpython translator/c

arigo at codespeak.net arigo at codespeak.net
Mon Feb 5 15:24:03 CET 2007


Author: arigo
Date: Mon Feb  5 15:23:58 2007
New Revision: 37966

Added:
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/exception.py   (contents, props changed)
Modified:
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/oop.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_portal.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
   pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
   pypy/branch/jit-virtual-world/pypy/rpython/llinterp.py
   pypy/branch/jit-virtual-world/pypy/translator/c/exceptiontransform.py
Log:
(pedronis, arre, arigo)

* simplify exceptiontransform to use a Struct instead of an RPyhton
  instance to store the current exception.

* after residual calls, if possible, we check for exceptions using
  promotion.  This allows the JIT compiler to only produce code
  for the branch that is actually taken (i.e. the non-exceptional
  branch, usually).


Added: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/exception.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/exception.py	Mon Feb  5 15:23:58 2007
@@ -0,0 +1,76 @@
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.jit.timeshifter import rvalue, rtimeshift
+
+
+class ExceptionDesc:
+
+    def __init__(self, hrtyper, lazy_exception_path):
+        RGenOp = hrtyper.RGenOp
+        self.etrafo = hrtyper.annotator.exceptiontransformer
+        self.cexcdata = self.etrafo.cexcdata
+        self.exc_data_ptr = self.cexcdata.value
+        self.gv_excdata = RGenOp.constPrebuiltGlobal(self.exc_data_ptr)
+
+        EXCDATA = self.etrafo.EXCDATA
+        self.exc_type_token  = RGenOp.fieldToken(EXCDATA, 'exc_type')
+        self.exc_value_token = RGenOp.fieldToken(EXCDATA, 'exc_value')
+        self.exc_type_kind   = RGenOp.kindToken(EXCDATA.exc_type)
+        self.exc_value_kind  = RGenOp.kindToken(EXCDATA.exc_value)
+
+        LL_EXC_TYPE  = EXCDATA.exc_type
+        LL_EXC_VALUE = EXCDATA.exc_value
+
+        self.gv_null_exc_type = RGenOp.constPrebuiltGlobal(
+                                         lltype.nullptr(LL_EXC_TYPE.TO))
+        self.gv_null_exc_value = RGenOp.constPrebuiltGlobal(
+                                         lltype.nullptr(LL_EXC_VALUE.TO))
+        self.null_exc_type_box = rvalue.PtrRedBox(self.exc_type_kind,
+                                                  self.gv_null_exc_type)
+        self.null_exc_value_box = rvalue.PtrRedBox(self.exc_value_kind,
+                                                   self.gv_null_exc_value)
+        self.lazy_exception_path = lazy_exception_path
+
+    def _freeze_(self):
+        return True
+
+    def genop_get_exc_type(self, builder):
+        return builder.genop_getfield(self.exc_type_token, self.gv_excdata)
+
+    def genop_get_exc_value(self, builder):
+        return builder.genop_getfield(self.exc_value_token, self.gv_excdata)
+
+    def genop_set_exc_type(self, builder, gv_value):
+        builder.genop_setfield(self.exc_type_token, self.gv_excdata, gv_value)
+
+    def genop_set_exc_value(self, builder, gv_value):
+        builder.genop_setfield(self.exc_value_token, self.gv_excdata, gv_value)
+
+    def fetch_global_excdata(self, jitstate, known_occurred=False):
+        builder = jitstate.curbuilder
+        gv_etype  = self.genop_get_exc_type (builder)
+        gv_evalue = self.genop_get_exc_value(builder)
+        self.genop_set_exc_type (builder, self.gv_null_exc_type )
+        self.genop_set_exc_value(builder, self.gv_null_exc_value)
+        etypebox  = rvalue.PtrRedBox(self.exc_type_kind,  gv_etype )
+        evaluebox = rvalue.PtrRedBox(self.exc_value_kind, gv_evalue)
+        etypebox .known_nonzero = known_occurred
+        evaluebox.known_nonzero = known_occurred
+        rtimeshift.setexctypebox (jitstate, etypebox)
+        rtimeshift.setexcvaluebox(jitstate, evaluebox)
+
+    def store_global_excdata(self, jitstate):
+        builder = jitstate.curbuilder
+        etypebox = jitstate.exc_type_box
+        if etypebox.is_constant():
+            ll_etype = rvalue.ll_getvalue(etypebox, llmemory.Address)
+            if not ll_etype:
+                return       # we know there is no exception set
+        evaluebox = jitstate.exc_value_box
+        gv_etype  = etypebox .getgenvar(jitstate)
+        gv_evalue = evaluebox.getgenvar(jitstate)
+        self.genop_set_exc_type (builder, gv_etype )
+        self.genop_set_exc_value(builder, gv_evalue)
+
+    def gen_exc_occurred(self, builder):
+        gv_etype = self.genop_get_exc_type(builder)
+        return builder.genop_ptr_nonzero(self.exc_type_kind, gv_etype)

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/hrtyper.py	Mon Feb  5 15:23:58 2007
@@ -22,6 +22,7 @@
 from pypy.jit.hintannotator.model import originalconcretetype
 from pypy.jit.timeshifter import rtimeshift, rvalue, rcontainer, oop
 from pypy.jit.timeshifter.transform import HintGraphTransformer
+from pypy.jit.timeshifter.exception import ExceptionDesc
 from pypy.jit.codegen import model as cgmodel
 
 class HintTypeSystem(LowLevelTypeSystem):
@@ -77,69 +78,13 @@
         (self.s_Queue,
          self.r_Queue)       = self.s_r_instanceof(rtimeshift.BaseDispatchQueue)
 
-        self.etrafo = hannotator.exceptiontransformer
-        self.cexcdata = self.etrafo.cexcdata
-        self.exc_data_ptr = self.cexcdata.value
-        gv_excdata = RGenOp.constPrebuiltGlobal(self.exc_data_ptr)
-        LL_EXC_TYPE  = rtyper.exceptiondata.lltype_of_exception_type
-        LL_EXC_VALUE = rtyper.exceptiondata.lltype_of_exception_value
-        null_exc_type_box = rvalue.redbox_from_prebuilt_value(RGenOp,
-                                         lltype.nullptr(LL_EXC_TYPE.TO))
-        null_exc_value_box = rvalue.redbox_from_prebuilt_value(RGenOp,
-                                         lltype.nullptr(LL_EXC_VALUE.TO))
-
-        p = self.etrafo.rpyexc_fetch_type_ptr.value
-        gv_rpyexc_fetch_type = RGenOp.constPrebuiltGlobal(p)
-        tok_fetch_type = RGenOp.sigToken(lltype.typeOf(p).TO)
-        kind_etype = RGenOp.kindToken(LL_EXC_TYPE)
-
-        p = self.etrafo.rpyexc_fetch_value_ptr.value
-        gv_rpyexc_fetch_value = RGenOp.constPrebuiltGlobal(p)
-        tok_fetch_value = RGenOp.sigToken(lltype.typeOf(p).TO)
-        kind_evalue = RGenOp.kindToken(LL_EXC_VALUE)
-
-        p = self.etrafo.rpyexc_clear_ptr.value
-        gv_rpyexc_clear = RGenOp.constPrebuiltGlobal(p)
-        tok_clear = RGenOp.sigToken(lltype.typeOf(p).TO)
-
-        p = self.etrafo.rpyexc_raise_ptr.value
-        gv_rpyexc_raise = RGenOp.constPrebuiltGlobal(p)
-        tok_raise = RGenOp.sigToken(lltype.typeOf(p).TO)
-
-        def fetch_global_excdata(jitstate):
-            builder = jitstate.curbuilder
-            gv_etype = builder.genop_call(tok_fetch_type,
-                                          gv_rpyexc_fetch_type, [])
-            gv_evalue = builder.genop_call(tok_fetch_value,
-                                           gv_rpyexc_fetch_value, [])
-            builder.genop_call(tok_clear, gv_rpyexc_clear, [])
-            etypebox  = rvalue.PtrRedBox(kind_etype,  gv_etype)
-            evaluebox = rvalue.PtrRedBox(kind_evalue, gv_evalue)
-            rtimeshift.setexctypebox (jitstate, etypebox)
-            rtimeshift.setexcvaluebox(jitstate, evaluebox)
-        self.fetch_global_excdata = fetch_global_excdata
-
-        def store_global_excdata(jitstate):
-            builder = jitstate.curbuilder
-            etypebox = jitstate.exc_type_box
-            if etypebox.is_constant():
-                ll_etype = rvalue.ll_getvalue(etypebox, llmemory.Address)
-                if not ll_etype:
-                    return       # we known there is no exception set
-            evaluebox = jitstate.exc_value_box
-            gv_etype  = etypebox .getgenvar(jitstate)
-            gv_evalue = evaluebox.getgenvar(jitstate)
-            builder.genop_call(tok_raise,
-                               gv_rpyexc_raise, [gv_etype, gv_evalue])
-        self.store_global_excdata = store_global_excdata
-
-        def ll_fresh_jitstate(builder):
+        def ll_fresh_jitstate(builder, exceptiondesc):
             return rtimeshift.JITState(builder, None,
-                                       null_exc_type_box,
-                                       null_exc_value_box)
+                                       exceptiondesc.null_exc_type_box,
+                                       exceptiondesc.null_exc_value_box)
         self.ll_fresh_jitstate = ll_fresh_jitstate
 
-        def ll_finish_jitstate(jitstate, graphsigtoken):
+        def ll_finish_jitstate(jitstate, exceptiondesc, graphsigtoken):
             assert jitstate.resuming is None
             returnbox = rtimeshift.getreturnbox(jitstate)
             gv_ret = returnbox.getgenvar(jitstate)
@@ -149,7 +94,7 @@
                 content = virtualizable_box.content
                 assert isinstance(content, rcontainer.VirtualizableStruct)
                 content.store_back(jitstate)        
-            store_global_excdata(jitstate)
+            exceptiondesc.store_global_excdata(jitstate)
             jitstate.curbuilder.finish_and_return(graphsigtoken, gv_ret)
         self.ll_finish_jitstate = ll_finish_jitstate
 
@@ -200,6 +145,9 @@
                 "Forgot 'hint(None, global_merge_point=True)'?")
         self.log.event("Timeshifted control flow of %d graphs." % (len(seen),))
 
+        self.exceptiondesc = ExceptionDesc(self,
+                                           self.portal_contains_global_mp)
+
         #import pdb; pdb.set_trace()
         # only keep the hint-annotated graphs that are really useful
         self.annotator.translator.graphs = [graph
@@ -277,6 +225,7 @@
         args_specification = unrolling_iterable(args_specification)
         fresh_jitstate = self.ll_fresh_jitstate
         finish_jitstate = self.ll_finish_jitstate
+        exceptiondesc = self.exceptiondesc
         sigtoken = rgenop.sigToken(FUNC)
 
         # debug helper
@@ -323,7 +272,7 @@
                 builder, gv_generated, inputargs_gv = rgenop.newgraph(sigtoken,
                                                              "generated")
                 cache[key] = gv_generated
-                top_jitstate = fresh_jitstate(builder)
+                top_jitstate = fresh_jitstate(builder, exceptiondesc)
                 i = 0
                 for color, _, make_arg_redbox in args_specification:
                     if color == "green":
@@ -350,7 +299,7 @@
                 builder.start_writing()
                 top_jitstate = portal_fn(top_jitstate, *portal_ts_args)
                 if top_jitstate is not None:
-                    finish_jitstate(top_jitstate, sigtoken)
+                    finish_jitstate(top_jitstate, exceptiondesc, sigtoken)
                 builder.end()
                 builder.show_incremental_progress()
 
@@ -379,7 +328,7 @@
         TYPES = [v.concretetype for v in origportalgraph.getargs()]
         argspecandtypes = unrolling_iterable(zip(args_specification,
                                                   TYPES))
-        fetch_global_excdata = self.fetch_global_excdata
+        fetch_global_excdata = self.exceptiondesc.fetch_global_excdata
 
         def portalreentry(jitstate, *args): # xxx virtualizables?
             i = 0
@@ -419,7 +368,7 @@
                         i += 1
                         portal_ts_args += (box,)
 
-                top_jitstate = fresh_jitstate(builder)
+                top_jitstate = fresh_jitstate(builder, exceptiondesc)
                 state.graph_compilation_queue.append((top_jitstate, portal_ts_args))
 
             gv_res = curbuilder.genop_call(sigtoken, gv_generated, args_gv)
@@ -713,12 +662,12 @@
         if isinstance(hop.args_r[0], BlueRepr):
             return hop.args_r[0].timeshift_getfield(hop)
         ts = self
-        if hop.args_v[0] == ts.cexcdata:
+        if hop.args_v[0] == ts.exceptiondesc.cexcdata:
             # reading one of the exception boxes (exc_type or exc_value)
             fieldname = hop.args_v[1].value
-            if fieldname.endswith('exc_type'):
+            if fieldname == 'exc_type':
                 reader = rtimeshift.getexctypebox
-            elif fieldname.endswith('exc_value'):
+            elif fieldname == 'exc_value':
                 reader = rtimeshift.getexcvaluebox
             else:
                 raise Exception("getfield(exc_data, %r)" % (fieldname,))
@@ -793,12 +742,12 @@
         VALUETYPE = originalconcretetype(hop.args_s[2])
         if VALUETYPE is lltype.Void:
             return
-        if hop.args_v[0] == ts.cexcdata:
+        if hop.args_v[0] == ts.exceptiondesc.cexcdata:
             # reading one of the exception boxes (exc_type or exc_value)
             fieldname = hop.args_v[1].value
-            if fieldname.endswith('exc_type'):
+            if fieldname == 'exc_type':
                 writer = rtimeshift.setexctypebox
-            elif fieldname.endswith('exc_value'):
+            elif fieldname == 'exc_value':
                 writer = rtimeshift.setexcvaluebox
             else:
                 raise Exception("setfield(exc_data, %r)" % (fieldname,))
@@ -1207,6 +1156,7 @@
         RESIDUAL_FUNCTYPE = self.get_residual_functype(tsgraph)
         residualSigToken = self.RGenOp.sigToken(RESIDUAL_FUNCTYPE)
         ll_finish_jitstate = self.ll_finish_jitstate
+        exceptiondesc = self.exceptiondesc
 
         args_s = [self.s_JITState] + [annmodel.lltype_to_annotation(ARG)
                                       for ARG in TS_FUNC.TO.ARGS[1:]]
@@ -1220,7 +1170,8 @@
             jitstate.resumepoint = N
             finaljitstate = tsfn(jitstate, *dummy_args)
             if finaljitstate is not None:
-                ll_finish_jitstate(finaljitstate, residualSigToken)
+                ll_finish_jitstate(finaljitstate, exceptiondesc,
+                                   residualSigToken)
 
         return self.translate_op_merge_point(hop,
                         global_resumer = call_for_global_resuming)
@@ -1277,15 +1228,19 @@
     # handling of the various kinds of calls
 
     def translate_op_oopspec_was_residual(self, hop):
-        return hop.inputconst(lltype.Bool, False)
+        v_jitstate = hop.llops.getjitstate()
+        return hop.llops.genmixlevelhelpercall(rtimeshift.oopspec_was_residual,
+                                               [self.s_JITState],
+                                               [v_jitstate     ],
+                                               annmodel.s_Bool)
 
-    def translate_op_oopspec_call(self, hop):
+    def translate_op_oopspec_call(self, hop, can_raise=True):
         # special-cased call, for things like list methods
         from pypy.jit.timeshifter.oop import OopSpecDesc, Index
 
         c_func = hop.args_v[0]
         fnobj = c_func.value._obj
-        oopspecdesc = OopSpecDesc(self, fnobj)
+        oopspecdesc = OopSpecDesc(self, fnobj, can_raise)
         hop.r_s_popfirstarg()
 
         args_v = []
@@ -1343,6 +1298,9 @@
                                       [v_jitstate,    c_oopspecdesc] + args_v,
                                       s_result)
 
+    def translate_op_oopspec_call_noexc(self, hop):
+        return self.translate_op_oopspec_call(hop, False)
+
     def translate_op_green_call(self, hop):
         for r_arg in hop.args_r:
             assert isinstance(r_arg, GreenRepr)
@@ -1427,27 +1385,32 @@
         oop = dopts['oop']
         v_jitstate = hop.llops.getjitstate()
         if withexc:
-            hop.llops.genmixlevelhelpercall(self.fetch_global_excdata,
-                                            [self.s_JITState], [v_jitstate],
-                                            annmodel.s_None)
-        if not oop:
-            v_after = hop.llops.genmixlevelhelpercall(
-                            rtimeshift.after_residual_call,
-                            [self.s_JITState],
-                            [v_jitstate],
-                            self.s_RedBox)
-        else: # xxx
-            v_after = hop.inputconst(self.getredrepr(lltype.Signed), 0)
-
+            c_exception_desc = hop.inputconst(lltype.Void, self.exceptiondesc)
+        else:
+            c_exception_desc = hop.inputconst(lltype.Void, None)
+        bk = self.rtyper.annotator.bookkeeper
+        s_exception_desc = bk.immutablevalue(c_exception_desc.value)
+        c_check_forced = hop.inputconst(lltype.Bool, not oop)
+        v_after = hop.llops.genmixlevelhelpercall(
+            rtimeshift.ll_after_residual_call,
+            [self.s_JITState, s_exception_desc, annmodel.s_Bool],
+            [v_jitstate     , c_exception_desc, c_check_forced ],
+            self.s_RedBox)
         return v_after
-        
-    def translate_op_reshape(self, hop):
-        v_jitstate = hop.llops.getjitstate()                
-        v_shape, = hop.inputargs(self.getredrepr(lltype.Signed))
-        return hop.llops.genmixlevelhelpercall(rtimeshift.reshape,
-                                               [self.s_JITState, self.s_RedBox],
-                                               [v_jitstate     , v_shape      ],
-                                               annmodel.s_None)        
+
+    def translate_op_residual_fetch(self, hop):
+        dopts = hop.args_v[1].value
+        oop = dopts['oop']
+        v_jitstate = hop.llops.getjitstate()
+        v_flags = hop.inputarg(self.getredrepr(lltype.Signed), arg=0)
+        bk = self.rtyper.annotator.bookkeeper
+        c_exception_desc = hop.inputconst(lltype.Void, self.exceptiondesc)
+        s_exception_desc = bk.immutablevalue(c_exception_desc.value)
+        c_check_forced = hop.inputconst(lltype.Bool, not oop)
+        return hop.llops.genmixlevelhelpercall(rtimeshift.residual_fetch,
+           [self.s_JITState, s_exception_desc, annmodel.s_Bool, self.s_RedBox],
+           [v_jitstate     , c_exception_desc, c_check_forced , v_flags      ],
+           annmodel.s_None)
 
     def translate_op_reverse_split_queue(self, hop):
         hop.llops.genmixlevelhelpercall(rtimeshift.reverse_split_queue,

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/oop.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/oop.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/oop.py	Mon Feb  5 15:23:58 2007
@@ -16,11 +16,13 @@
 
     do_call = None
 
-    def __init__(self, hrtyper, fnobj):
+    def __init__(self, hrtyper, fnobj, can_raise):
         ll_func = fnobj._callable
         FUNCTYPE = lltype.typeOf(fnobj)
         nb_args = len(FUNCTYPE.ARGS)
 
+        self.can_raise = can_raise
+
         # parse the oopspec and fill in the arguments
         operation_name, args = ll_func.oopspec.split('(', 1)
         assert args.endswith(')')
@@ -79,12 +81,6 @@
         self.ll_handler = getattr(vmodule, method)
         self.couldfold = getattr(self.ll_handler, 'couldfold', False)
 
-        # exception handling
-        graph = fnobj.graph
-        etrafo = hrtyper.etrafo
-        self.can_raise = etrafo.raise_analyzer.analyze_direct_call(graph)
-        self.fetch_global_excdata = hrtyper.fetch_global_excdata
-
         if self.couldfold:
             ARGS = FUNCTYPE.ARGS
             residualargsources = self.residualargsources
@@ -129,7 +125,7 @@
                 return self.errorbox
         gv_result = builder.genop_call(self.sigtoken, self.gv_fnptr, args_gv)
         if self.can_raise:
-            self.fetch_global_excdata(jitstate)
+            jitstate.generated_oop_residual_can_raise = True
         return self.redboxbuilder(self.result_kind, gv_result)
 
     def residual_exception(self, jitstate, ExcCls):

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rcontainer.py	Mon Feb  5 15:23:58 2007
@@ -759,7 +759,7 @@
         access_token = typedesc.access_desc.fieldtoken
         builder.genop_setfield(access_token, gv_outside, typedesc.gv_access)
 
-    def after_residual_call(self, jitstate):
+    def check_forced_after_residual_call(self, jitstate):
         typedesc = self.typedesc
         builder = jitstate.curbuilder
         gv_outside = self.content_boxes[-1].genvar

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/rtimeshift.py	Mon Feb  5 15:23:58 2007
@@ -518,12 +518,38 @@
     gv_result = builder.genop_call(calldesc.sigtoken, gv_funcbox, args_gv)
     return calldesc.redboxbuilder(calldesc.result_kind, gv_result)
 
-def after_residual_call(jitstate):
-    return jitstate.after_residual_call()
-
-def reshape(jitstate, shapebox):
-    shapemask = rvalue.ll_getvalue(shapebox, lltype.Signed)
-    jitstate.reshape(shapemask)
+def ll_after_residual_call(jitstate, exceptiondesc, check_forced):
+    builder = jitstate.curbuilder
+    if check_forced:
+        gv_flags = jitstate.check_forced_after_residual_call()
+    else:
+        gv_flags = None
+    if exceptiondesc:
+        if exceptiondesc.lazy_exception_path:
+            gv_occurred = exceptiondesc.gen_exc_occurred(builder)
+            gv_flag = builder.genop1("cast_bool_to_int", gv_occurred)
+            if gv_flags is None:
+                gv_flags = gv_flag
+            else:
+                gv_flags = builder.genop2("int_or", gv_flags, gv_flag)
+        else:
+            exceptiondesc.fetch_global_excdata(jitstate)
+    if gv_flags is None:
+        gv_flags = builder.rgenop.constPrebuiltGlobal(0)
+    return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Signed), gv_flags)
+
+def residual_fetch(jitstate, exceptiondesc, check_forced, flagsbox):
+    flags = rvalue.ll_getvalue(flagsbox, lltype.Signed)
+    if flags & 1:   # an exception occurred
+        exceptiondesc.fetch_global_excdata(jitstate, known_occurred=True)
+    if check_forced:
+        shapemask = flags & ~ 1
+        jitstate.reshape(shapemask)
+
+def oopspec_was_residual(jitstate):
+    res = jitstate.generated_oop_residual_can_raise
+    jitstate.generated_oop_residual_can_raise = False
+    return res
 
 
 class ResumingInfo(object):
@@ -898,11 +924,13 @@
                  next
                  virtualizables
                  shape_place
+                 generated_oop_residual_can_raise
               """.split()
 
     returnbox = None
     next      = None   # for linked lists
     promotion_path = None
+    generated_oop_residual_can_raise = False
 
     def __init__(self, builder, frame, exc_type_box, exc_value_box,
                  resumepoint=-1, newgreens=[], resuming=None,
@@ -972,7 +1000,7 @@
         if virtualizables:
             builder = self.curbuilder
             memo = rvalue.make_vrti_memo()
-            memo.bitcount = 0
+            memo.bitcount = 1
             memo.frameindex = 0
             memo.framevars_gv = []
             shape_kind = builder.rgenop.kindToken(lltype.Signed)
@@ -998,29 +1026,28 @@
                 assert isinstance(content, rcontainer.VirtualizableStruct)
                 content.prepare_for_residual_call(self, gv_base, vable_rti)
                 
-    def after_residual_call(self):
+    def check_forced_after_residual_call(self):
         virtualizables = self.virtualizables
         builder = self.curbuilder
         if virtualizables:
             for virtualizable_box in virtualizables:
                 content = virtualizable_box.content
                 assert isinstance(content, rcontainer.VirtualizableStruct)
-                content.after_residual_call(self)
+                content.check_forced_after_residual_call(self)
             shape_kind = builder.rgenop.kindToken(lltype.Signed)
             gv_shape = builder.genop_absorb_place(shape_kind,
                                                   self.shape_place)
             self.shape_place = None
+            return gv_shape
         else:
-            gv_shape = builder.rgenop.genconst(0)
-        return rvalue.IntRedBox(builder.rgenop.kindToken(lltype.Signed),
-                                gv_shape)
+            return None
 
     def reshape(self, shapemask):
         virtualizables = self.virtualizables
         builder = self.curbuilder
         if virtualizables:
             memo = rvalue.make_vrti_memo()
-            memo.bitcount = 0
+            memo.bitcount = 1
             if shapemask:
                 memo.forced = []
             else:

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_portal.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_portal.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_portal.py	Mon Feb  5 15:23:58 2007
@@ -64,8 +64,8 @@
         self.hrtyper.specialize(origportalgraph=origportalgraph,
                            view = conftest.option.view and self.small)
 
-        if conftest.option.view and self.small:
-            t.view()
+        #if conftest.option.view and self.small:
+        #    t.view()
         self.postprocess_timeshifting()
         self.readportalgraph = self.hrtyper.readportalgraph
 
@@ -86,12 +86,14 @@
                                                 backendoptimize=backendoptimize)
         self.main_args = main_args
         self.main_is_portal = main is portal
-        llinterp = LLInterpreter(self.rtyper)
+        exc_data_ptr = self.hrtyper.exceptiondesc.exc_data_ptr
+        llinterp = LLInterpreter(self.rtyper, exc_data_ptr=exc_data_ptr)
         res = llinterp.eval_graph(self.maingraph, main_args)
         return res
 
     def get_residual_graph(self):
-        llinterp = LLInterpreter(self.rtyper)
+        exc_data_ptr = self.hrtyper.exceptiondesc.exc_data_ptr
+        llinterp = LLInterpreter(self.rtyper, exc_data_ptr=exc_data_ptr)
         if self.main_is_portal:
             residual_graph = llinterp.eval_graph(self.readportalgraph,
                                                  self.main_args)._obj.graph
@@ -469,3 +471,49 @@
         res = self.timeshift_from_portal(ll_main, ll_function, [5], policy=P_NOVIRTUAL)
         assert res == 123
         self.check_insns(indirect_call=1)
+
+    def test_residual_red_call_with_promoted_exc(self):
+        def h(x):
+            if x > 0:
+                return x+1
+            else:
+                raise ValueError
+
+        def g(x):
+            return 2*h(x)
+
+        def f(x):
+            hint(None, global_merge_point=True)
+            try:
+                return g(x)
+            except ValueError:
+                return 7
+
+        stop_at_h = StopAtXPolicy(h)
+        res = self.timeshift_from_portal(f, f, [20], policy=stop_at_h)
+        assert res == 42
+        self.check_insns(int_add=0)
+
+        res = self.timeshift_from_portal(f, f, [-20], policy=stop_at_h)
+        assert res == 7
+        self.check_insns(int_add=0)
+
+    def test_residual_oop_raising(self):
+        def g(x):
+            lst = []
+            if x > 10:
+                lst.append(x)
+            return lst
+        def f(x):
+            hint(None, global_merge_point=True)
+            lst = g(x)
+            try:
+                return lst[0]
+            except IndexError:
+                return -42
+
+        res = self.timeshift_from_portal(f, f, [5], policy=P_OOPSPEC)
+        assert res == -42
+
+        res = self.timeshift_from_portal(f, f, [15], policy=P_OOPSPEC)
+        assert res == 15

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/test/test_timeshift.py	Mon Feb  5 15:23:58 2007
@@ -106,6 +106,7 @@
         hrtyper.specialize(view = conftest.option.view and self.small)
         fresh_jitstate = hrtyper.ll_fresh_jitstate
         finish_jitstate = hrtyper.ll_finish_jitstate
+        exceptiondesc = hrtyper.exceptiondesc
         t = rtyper.annotator.translator
 
         # make an interface to the timeshifted graphs:
@@ -180,11 +181,11 @@
                     i += 1
                     timeshifted_entrypoint_args += (box,)
 
-            top_jitstate = fresh_jitstate(builder)
+            top_jitstate = fresh_jitstate(builder, exceptiondesc)
             top_jitstate = timeshifted_entrypoint(top_jitstate,
                                                   *timeshifted_entrypoint_args)
             if top_jitstate is not None:
-                finish_jitstate(top_jitstate, sigtoken)
+                finish_jitstate(top_jitstate, exceptiondesc, sigtoken)
 
             builder.end()
             generated = gv_generated.revealconst(lltype.Ptr(FUNC))
@@ -220,9 +221,9 @@
         self.rtyper = rtyper
         self.hrtyper = hrtyper
         self.annotate_interface_functions()
-        if conftest.option.view and self.small:
-            from pypy.translator.tool.graphpage import FlowGraphPage
-            FlowGraphPage(t, ha.translator.graphs).display()
+        #if conftest.option.view and self.small:
+        #    from pypy.translator.tool.graphpage import FlowGraphPage
+        #    FlowGraphPage(t, ha.translator.graphs).display()
 
         cache = self.__dict__.copy()
         self._cache[key] = cache, getargtypes(rtyper.annotator, values)
@@ -267,12 +268,12 @@
                 residualargs.append(llvalue)
 
         # run the graph generator
-        llinterp = LLInterpreter(self.rtyper)
+        exc_data_ptr = self.hrtyper.exceptiondesc.exc_data_ptr
+        llinterp = LLInterpreter(self.rtyper, exc_data_ptr=exc_data_ptr)
         ll_generated = llinterp.eval_graph(self.maingraph, mainargs)
 
         # now try to run the residual graph generated by the builder
         residual_graph = ll_generated._obj.graph
-        residual_graph.exceptiontransformed = self.hrtyper.exc_data_ptr
         self.ll_generated = ll_generated
         self.residual_graph = residual_graph
         if conftest.option.view:

Modified: pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/jit/timeshifter/transform.py	Mon Feb  5 15:23:58 2007
@@ -672,7 +672,10 @@
     def handle_oopspec_call(self, block, pos, withexc):
         op = block.operations[pos]
         assert op.opname == 'direct_call'
-        op.opname = 'oopspec_call'
+        if withexc:
+            op.opname = 'oopspec_call'            
+        else:
+            op.opname = 'oopspec_call_noexc'            
         if withexc:
             link = split_block(self.hannotator, block, pos+1)
             nextblock = link.target
@@ -765,19 +768,19 @@
                                            oop = False):
         dopts = {'withexc': withexc, 'oop': oop }
         copts = Constant(dopts, lltype.Void)
-        v_shape = self.genop(newops, 'after_residual_call', [copts],
+        v_flags = self.genop(newops, 'after_residual_call', [copts],
                              resulttype=lltype.Signed, red=True)
-        reshape_index = len(newops)
-        self.genop(newops, 'reshape', [v_shape])
-        reshape_pos = pos+reshape_index
+        residual_fetch_index = len(newops)
+        self.genop(newops, 'residual_fetch', [v_flags, copts])
+        residual_fetch_pos = pos+residual_fetch_index
         block.operations[pos:pos+1] = newops
 
-        link = split_block(self.hannotator, block, reshape_pos)
+        link = split_block(self.hannotator, block, residual_fetch_pos)
         nextblock = link.target
 
         reds, greens = self.sort_by_color(link.args)
         self.genop(block, 'save_locals', reds)
-        v_finished_flag = self.genop(block, 'promote', [v_shape],
+        v_finished_flag = self.genop(block, 'promote', [v_flags],
                                      resulttype = lltype.Bool)
         self.go_to_dispatcher_if(block, v_finished_flag)
 

Modified: pypy/branch/jit-virtual-world/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/rpython/llinterp.py	Mon Feb  5 15:23:58 2007
@@ -42,10 +42,11 @@
 class LLInterpreter(object):
     """ low level interpreter working with concrete values. """
 
-    def __init__(self, typer, heap=llheap, tracing=True):
+    def __init__(self, typer, heap=llheap, tracing=True, exc_data_ptr=None):
         self.bindings = {}
         self.typer = typer
         self.heap = heap  #module that provides malloc, etc for lltypes
+        self.exc_data_ptr = exc_data_ptr
         self.active_frame = None
         # XXX hack: set gc to None because
         # prepare_graphs_and_create_gc might already use the llinterpreter!
@@ -150,6 +151,13 @@
             self.active_frame = old_active_frame
         raise ValueError, "couldn't match exception"
 
+    def get_transformed_exc_data(self, graph):
+        if hasattr(graph, 'exceptiontransformed'):
+            return graph.exceptiontransformed
+        if getattr(graph, 'rgenop', False):
+            return self.exc_data_ptr
+        return None
+
 
 def checkptr(ptr):
     assert isinstance(lltype.typeOf(ptr), lltype.Ptr)
@@ -284,18 +292,16 @@
                 raise LLException(etype, evalue)
             resultvar, = block.getvariables()
             result = self.getval(resultvar)
-            if hasattr(self.graph, 'exceptiontransformed'):
+            exc_data = self.llinterpreter.get_transformed_exc_data(self.graph)
+            if exc_data:
                 # re-raise the exception set by this graph, if any
-                exc_data = self.graph.exceptiontransformed
-                etype = rclass.fishllattr(exc_data, 'exc_type')
+                etype = exc_data.exc_type
                 if etype:
-                    evalue = rclass.fishllattr(exc_data, 'exc_value')
+                    evalue = exc_data.exc_value
                     if tracer:
                         tracer.dump('raise')
-                    rclass.feedllattr(exc_data, 'exc_type',
-                                      lltype.typeOf(etype)._defl())
-                    rclass.feedllattr(exc_data, 'exc_value',
-                                      lltype.typeOf(evalue)._defl())
+                    exc_data.exc_type  = lltype.typeOf(etype )._defl()
+                    exc_data.exc_value = lltype.typeOf(evalue)._defl()
                     from pypy.translator.c import exceptiontransform
                     T = resultvar.concretetype
                     errvalue = exceptiontransform.error_value(T)
@@ -554,13 +560,13 @@
         try:
             return self.perform_call(f, FTYPE.ARGS, args)
         except LLException, e:
-            if hasattr(self.graph, 'exceptiontransformed'):
+            exc_data = self.llinterpreter.get_transformed_exc_data(self.graph)
+            if exc_data:
                 # store the LLException into the exc_data used by this graph
-                exc_data = self.graph.exceptiontransformed
                 etype = e.args[0]
                 evalue = e.args[1]
-                rclass.feedllattr(exc_data, 'exc_type', etype)
-                rclass.feedllattr(exc_data, 'exc_value', evalue)
+                exc_data.exc_type  = etype
+                exc_data.exc_value = evalue
                 from pypy.translator.c import exceptiontransform
                 return exceptiontransform.error_value(FTYPE.RESULT)
             raise

Modified: pypy/branch/jit-virtual-world/pypy/translator/c/exceptiontransform.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/translator/c/exceptiontransform.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/translator/c/exceptiontransform.py	Mon Feb  5 15:23:58 2007
@@ -9,6 +9,7 @@
 from pypy.rpython.memory.lladdress import NULL
 from pypy.rpython import rtyper
 from pypy.rpython import rclass
+from pypy.rpython.rmodel import inputconst
 from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
 from pypy.annotation import model as annmodel
 from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
@@ -45,25 +46,25 @@
         mixlevelannotator = MixLevelHelperAnnotator(translator.rtyper)
         l2a = annmodel.lltype_to_annotation
 
-        class ExcData(object):
-            pass
-            #exc_type = lltype.nullptr(self.exc_data.lltype_of_exception_type.TO)
-            #exc_value = lltype.nullptr(self.exc_data.lltype_of_exception_value.TO)
+        EXCDATA = lltype.Struct('ExcData',
+            ('exc_type',  self.lltype_of_exception_type),
+            ('exc_value', self.lltype_of_exception_value))
+        self.EXCDATA = EXCDATA
 
-        exc_data = ExcData()
+        exc_data = lltype.malloc(EXCDATA, immortal=True)
         null_type = lltype.nullptr(self.lltype_of_exception_type.TO)
         null_value = lltype.nullptr(self.lltype_of_exception_value.TO)
         
         def rpyexc_occured():
             exc_type = exc_data.exc_type
-            return exc_type is not null_type
+            return bool(exc_type)
 
         # XXX tmp HACK for genllvm
         # llvm is strongly typed between bools and ints, which means we have no way of
         # calling rpyexc_occured() from c code with lltype.Bool
         def _rpyexc_occured():
             exc_type = exc_data.exc_type
-            return exc_type is not null_type
+            return bool(exc_type)
 
         def rpyexc_fetch_type():
             return exc_data.exc_type
@@ -145,11 +146,8 @@
 
         mixlevelannotator.finish()
 
-        ExcDataDef = translator.annotator.bookkeeper.getuniqueclassdef(ExcData)
-        self.ExcData_repr = rclass.getinstancerepr(translator.rtyper, ExcDataDef)
-        self.exc_data_ptr = self.ExcData_repr.convert_const(exc_data)
-        self.cexcdata = Constant(self.exc_data_ptr,
-                                 self.ExcData_repr.lowleveltype)
+        self.exc_data_ptr = exc_data
+        self.cexcdata = Constant(exc_data, lltype.Ptr(EXCDATA))
         
         self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
         p = lltype.nullptr(self.lltype_of_exception_type.TO)
@@ -157,6 +155,15 @@
         p = lltype.nullptr(self.lltype_of_exception_value.TO)
         self.c_null_evalue = Constant(p, self.lltype_of_exception_value)
 
+    def gen_getfield(self, name, llops):
+        c_name = inputconst(lltype.Void, name)
+        return llops.genop('getfield', [self.cexcdata, c_name],
+                           resulttype = getattr(self.EXCDATA, name))
+
+    def gen_setfield(self, name, v_value, llops):
+        c_name = inputconst(lltype.Void, name)
+        llops.genop('setfield', [self.cexcdata, c_name, v_value])
+
     def transform_completely(self):
         for graph in self.translator.graphs:
             self.create_exception_handling(graph)
@@ -290,11 +297,10 @@
         excblock = Block([])
 
         llops = rtyper.LowLevelOpList(None)
-        r = self.ExcData_repr
-        var_value = r.getfield(self.cexcdata, 'exc_value', llops)
-        var_type  = r.getfield(self.cexcdata, 'exc_type',  llops)
-        r.setfield(self.cexcdata, 'exc_value', self.c_null_evalue, llops)
-        r.setfield(self.cexcdata, 'exc_type',  self.c_null_etype,  llops)
+        var_value = self.gen_getfield('exc_value', llops)
+        var_type  = self.gen_getfield('exc_type' , llops)
+        self.gen_setfield('exc_value', self.c_null_evalue, llops)
+        self.gen_setfield('exc_type',  self.c_null_etype,  llops)
         excblock.operations[:] = llops
         newgraph.exceptblock.inputargs[0].concretetype = self.lltype_of_exception_type
         newgraph.exceptblock.inputargs[1].concretetype = self.lltype_of_exception_value
@@ -329,7 +335,7 @@
             var_exc_occured = llops.genop('ptr_iszero', [spaceop.result],
                                           lltype.Bool)            
         else:
-            v_exc_type = self.ExcData_repr.getfield(self.cexcdata, 'exc_type', llops)
+            v_exc_type = self.gen_getfield('exc_type', llops)
             var_exc_occured = llops.genop('ptr_nonzero', [v_exc_type],
                                           lltype.Bool)
 
@@ -376,7 +382,6 @@
             if normalafterblock is None:
                 normalafterblock = insert_empty_block(None, l0)
             llops = rtyper.LowLevelOpList(None)
-            r = self.ExcData_repr
-            r.setfield(self.cexcdata, 'exc_value', self.c_null_evalue, llops)
-            r.setfield(self.cexcdata, 'exc_type',  self.c_null_etype,  llops)
+            self.gen_setfield('exc_value', self.c_null_evalue, llops)
+            self.gen_setfield('exc_type',  self.c_null_etype,  llops)
             normalafterblock.operations[:0] = llops



More information about the Pypy-commit mailing list