[pypy-svn] r74494 - in pypy/branch/blackhole-improvement/pypy/jit: backend/llgraph codewriter codewriter/test metainterp metainterp/test

arigo at codespeak.net arigo at codespeak.net
Wed May 12 09:18:31 CEST 2010


Author: arigo
Date: Wed May 12 09:18:28 2010
New Revision: 74494

Added:
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/effectinfo.py
      - copied, changed from r74456, pypy/branch/blackhole-improvement/pypy/jit/metainterp/effectinfo.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_effectinfo.py
      - copied, changed from r74456, pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_effectinfo.py
Removed:
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/effectinfo.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_effectinfo.py
Modified:
   pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/llimpl.py
   pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/runner.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/assembler.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/jitcode.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_assembler.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_codewriter.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_regalloc.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/history.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/blackhole-improvement/pypy/jit/metainterp/typesystem.py
Log:
General progress.


Modified: pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/llimpl.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/llimpl.py	Wed May 12 09:18:28 2010
@@ -1185,19 +1185,19 @@
     array = array._obj.container
     return array.getlength()
 
-def do_strlen(_, string):
+def do_strlen(string):
     str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string)
     return len(str.chars)
 
-def do_strgetitem(_, string, index):
+def do_strgetitem(string, index):
     str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string)
     return ord(str.chars[index])
 
-def do_unicodelen(_, string):
+def do_unicodelen(string):
     uni = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), string)
     return len(uni.chars)
 
-def do_unicodegetitem(_, string, index):
+def do_unicodegetitem(string, index):
     uni = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), string)
     return ord(uni.chars[index])
 
@@ -1311,18 +1311,18 @@
     newvalue = cast_from_ptr(FIELDTYPE, newvalue)
     setattr(ptr, fieldname, newvalue)
 
-def do_newstr(_, length):
+def do_newstr(length):
     x = rstr.mallocstr(length)
     return cast_to_ptr(x)
 
-def do_newunicode(_, length):
+def do_newunicode(length):
     return cast_to_ptr(rstr.mallocunicode(length))
 
-def do_strsetitem(_, string, index, newvalue):
+def do_strsetitem(string, index, newvalue):
     str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string)
     str.chars[index] = chr(newvalue)
 
-def do_unicodesetitem(_, string, index, newvalue):
+def do_unicodesetitem(string, index, newvalue):
     uni = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), string)
     uni.chars[index] = unichr(newvalue)
 

Modified: pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/runner.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/backend/llgraph/runner.py	Wed May 12 09:18:28 2010
@@ -315,23 +315,17 @@
 ##        array = arraybox.getref_base()
 ##        return history.BoxInt(llimpl.do_arraylen_gc(arraydescr, array))
 
-##    def do_strlen(self, stringbox):
-##        string = stringbox.getref_base()
-##        return history.BoxInt(llimpl.do_strlen(0, string))
+    def bh_strlen(self, string):
+        return llimpl.do_strlen(string)
 
-##    def do_strgetitem(self, stringbox, indexbox):
-##        string = stringbox.getref_base()
-##        index = indexbox.getint()
-##        return history.BoxInt(llimpl.do_strgetitem(0, string, index))
+    def bh_strgetitem(self, string, index):
+        return llimpl.do_strgetitem(string, index)
 
-##    def do_unicodelen(self, stringbox):
-##        string = stringbox.getref_base()
-##        return history.BoxInt(llimpl.do_unicodelen(0, string))
+    def bh_unicodelen(self, string):
+        return llimpl.do_unicodelen(string)
 
-##    def do_unicodegetitem(self, stringbox, indexbox):
-##        string = stringbox.getref_base()
-##        index = indexbox.getint()
-##        return history.BoxInt(llimpl.do_unicodegetitem(0, string, index))
+    def bh_unicodegetitem(self, string, index):
+        return llimpl.do_unicodegetitem(string, index)
 
 ##    def do_getarrayitem_gc(self, arraybox, indexbox, arraydescr):
 ##        assert isinstance(arraydescr, Descr)
@@ -509,25 +503,17 @@
 ##    def do_same_as(self, box1):
 ##        return box1.clonebox()
 
-##    def do_newstr(self, lengthbox):
-##        length = lengthbox.getint()
-##        return history.BoxPtr(llimpl.do_newstr(0, length))
-
-##    def do_newunicode(self, lengthbox):
-##        length = lengthbox.getint()
-##        return history.BoxPtr(llimpl.do_newunicode(0, length))
+    def bh_newstr(self, length):
+        return llimpl.do_newstr(length)
 
-##    def do_strsetitem(self, stringbox, indexbox, newvaluebox):
-##        string = stringbox.getref_base()
-##        index = indexbox.getint()
-##        newvalue = newvaluebox.getint()
-##        llimpl.do_strsetitem(0, string, index, newvalue)
+    def bh_newunicode(self, length):
+        return llimpl.do_newunicode(length)
 
-##    def do_unicodesetitem(self, stringbox, indexbox, newvaluebox):
-##        string = stringbox.getref_base()
-##        index = indexbox.getint()
-##        newvalue = newvaluebox.getint()
-##        llimpl.do_unicodesetitem(0, string, index, newvalue)
+    def bh_strsetitem(self, string, index, newvalue):
+        llimpl.do_strsetitem(string, index, newvalue)
+
+    def bh_unicodesetitem(self, string, index, newvalue):
+        llimpl.do_unicodesetitem(string, index, newvalue)
 
     def bh_call_i(self, func, calldescr, args_i, args_r, args_f):
         self._prepare_call(INT, calldescr, args_i, args_r, args_f)

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/assembler.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/assembler.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/assembler.py	Wed May 12 09:18:28 2010
@@ -1,6 +1,6 @@
 from pypy.jit.metainterp.history import AbstractDescr, getkind
 from pypy.jit.codewriter.flatten import Register, Label, TLabel, KINDS
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
 from pypy.jit.codewriter.format import format_assembler
 from pypy.jit.codewriter.jitcode import SwitchDictDescr, JitCode
 from pypy.objspace.flow.model import Constant
@@ -12,6 +12,7 @@
     def __init__(self):
         self.insns = {}
         self.descrs = []
+        self.indirectcalltargets = set()    # set of JitCodes
         self._descr_dict = {}
         self._count_jitcodes = 0
 
@@ -26,6 +27,7 @@
         self.check_result()
         if jitcode is None:
             jitcode = JitCode(ssarepr.name)
+        jitcode._ssarepr = ssarepr
         self.make_jitcode(jitcode)
         if self._count_jitcodes < 20:    # stop if we have a lot of them
             jitcode._dump = format_assembler(ssarepr)
@@ -142,6 +144,8 @@
                 self.code.append(chr(num & 0xFF))
                 self.code.append(chr(num >> 8))
                 argcodes.append('d')
+            elif isinstance(x, IndirectCallTargets):
+                self.indirectcalltargets.update(x.lst)
             else:
                 raise NotImplementedError(x)
         #

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/call.py	Wed May 12 09:18:28 2010
@@ -5,13 +5,13 @@
 
 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 effectinfo_from_writeanalyze
+from pypy.jit.codewriter import effectinfo as ef
 from pypy.translator.simplify import get_funcobj, get_functype
 from pypy.rpython.lltypesystem import lltype, llmemory
-
 from pypy.translator.backendopt.canraise import RaiseAnalyzer
 from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
-from pypy.jit.metainterp.effectinfo import VirtualizableAnalyzer
-from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
 
 
 class CallControl(object):
@@ -146,6 +146,12 @@
             return jitcode
 
     def get_jitcode_calldescr(self, graph):
+        """Return the calldescr that describes calls to the 'graph'.
+        This returns a calldescr that is appropriate to attach to the
+        jitcode corresponding to 'graph'.  It has no extra effectinfo,
+        because it is not needed there; it is only used by the blackhole
+        interp to really do the call corresponding to 'inline_call' ops.
+        """
         fnptr = self.rtyper.getcallable(graph)
         FUNC = get_functype(lltype.typeOf(fnptr))
         if self.rtyper.type_system.name == 'ootypesystem':
@@ -158,6 +164,13 @@
         return (fnaddr, calldescr)
 
     def getcalldescr(self, op):
+        """Return the calldescr that describes all calls done by 'op'.
+        This returns a calldescr that we can put in the corresponding
+        call operation in the calling jitcode.  It gets an effectinfo
+        describing the effect of the call: which field types it may
+        change, whether it can force virtualizables, whether it can
+        raise, etc.
+        """
         NON_VOID_ARGS = [x.concretetype for x in op.args[1:]
                                         if x.concretetype is not lltype.Void]
         RESULT = op.result.concretetype
@@ -167,15 +180,46 @@
         assert NON_VOID_ARGS == [T for T in ARGS if T is not lltype.Void]
         assert RESULT == FUNC.RESULT
         # ok
+        # get the 'pure' and 'loopinvariant' flags from the function object
+        pure = False
+        loopinvariant = False
+        if op.opname == "direct_call":
+            func = getattr(get_funcobj(op.args[0].value), '_callable', None)
+            pure = getattr(func, "_pure_function_", False)
+            loopinvariant = getattr(func, "_jit_loop_invariant_", False)
+            if loopinvariant:
+                assert not NON_VOID_ARGS, ("arguments not supported for "
+                                           "loop-invariant function!")
+        # build the extraeffect
+        if self.virtualizable_analyzer.analyze(op):
+            extraeffect = ef.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+        elif loopinvariant:
+            extraeffect = ef.EF_LOOPINVARIANT
+        elif pure:
+            # XXX check what to do about exceptions (also MemoryError?)
+            extraeffect = ef.EF_PURE
+        elif self._canraise(op):
+            extraeffect = ef.EF_CAN_RAISE
+        else:
+            extraeffect = ef.EF_CANNOT_RAISE
+        #
         effectinfo = effectinfo_from_writeanalyze(
-            self.readwrite_analyzer.analyze(op),
-            self.cpu,
-            self.virtualizable_analyzer.analyze(op))
-        calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT,
-                                         effectinfo)
+            self.readwrite_analyzer.analyze(op), self.cpu, extraeffect)
+        #
+        if pure or loopinvariant:
+            assert effectinfo is not None
+            assert extraeffect != ef.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+        #
+        return self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT,
+                                    effectinfo)
+
+    def _canraise(self, op):
         try:
-            canraise = self.raise_analyzer.can_raise(op)
+            return self.raise_analyzer.can_raise(op)
         except lltype.DelayedPointer:
-            canraise = True  # if we need to look into the delayed ptr that is
-                             # the portal, then it's certainly going to raise
-        return calldescr, canraise
+            return True  # if we need to look into the delayed ptr that is
+                         # the portal, then it's certainly going to raise
+
+    def calldescr_canraise(self, calldescr):
+        effectinfo = calldescr.get_extra_info()
+        return effectinfo is None or effectinfo.extraeffect >= ef.EF_CAN_RAISE

Copied: pypy/branch/blackhole-improvement/pypy/jit/codewriter/effectinfo.py (from r74456, pypy/branch/blackhole-improvement/pypy/jit/metainterp/effectinfo.py)
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/effectinfo.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/effectinfo.py	Wed May 12 09:18:28 2010
@@ -4,28 +4,35 @@
 from pypy.rpython.ootypesystem import ootype
 from pypy.translator.backendopt.graphanalyze import BoolGraphAnalyzer
 
+# the 'extraeffect' field is one of the following values:
+EF_PURE                            = 0   # pure function (and cannot raise)
+EF_CANNOT_RAISE                    = 1   # a function which cannot raise
+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
+
+
 class EffectInfo(object):
     _cache = {}
 
     def __new__(cls, readonly_descrs_fields,
                 write_descrs_fields, write_descrs_arrays,
-                forces_virtual_or_virtualizable=False):
+                extraeffect=EF_CAN_RAISE):
         key = (frozenset(readonly_descrs_fields),
                frozenset(write_descrs_fields),
                frozenset(write_descrs_arrays),
-               forces_virtual_or_virtualizable)
+               extraeffect)
         if key in cls._cache:
             return cls._cache[key]
         result = object.__new__(cls)
         result.readonly_descrs_fields = readonly_descrs_fields
         result.write_descrs_fields = write_descrs_fields
         result.write_descrs_arrays = write_descrs_arrays
-        result.forces_virtual_or_virtualizable= forces_virtual_or_virtualizable
+        result.extraeffect = extraeffect
         cls._cache[key] = result
         return result
 
-def effectinfo_from_writeanalyze(effects, cpu,
-                                 forces_virtual_or_virtualizable=False):
+def effectinfo_from_writeanalyze(effects, cpu, extraeffect=EF_CAN_RAISE):
     from pypy.translator.backendopt.writeanalyze import top_set
     if effects is top_set:
         return None
@@ -62,7 +69,7 @@
     return EffectInfo(readonly_descrs_fields,
                       write_descrs_fields,
                       write_descrs_arrays,
-                      forces_virtual_or_virtualizable)
+                      extraeffect)
 
 def consider_struct(TYPE, fieldname):
     if fieldType(TYPE, fieldname) is lltype.Void:

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/flatten.py	Wed May 12 09:18:28 2010
@@ -44,6 +44,12 @@
     def __iter__(self):
         return iter(self.content)
 
+class IndirectCallTargets(object):
+    def __init__(self, lst):
+        self.lst = lst       # list of JitCodes
+    def __repr__(self):
+        return '<IndirectCallTargets>'
+
 KINDS = ['int', 'ref', 'float']
 
 # ____________________________________________________________
@@ -194,7 +200,7 @@
                 linkfalse, linktrue = linktrue, linkfalse
             opname = 'goto_if_not'
             if isinstance(block.exitswitch, tuple):
-                # special case produced by jitter.optimize_goto_if_not()
+                # special case produced by jtransform.optimize_goto_if_not()
                 if block.exitswitch[0] != 'int_is_true':
                     opname = 'goto_if_not_' + block.exitswitch[0]
                 opargs = block.exitswitch[1:]
@@ -303,6 +309,8 @@
                 v = ListOfKind(v.kind, lst)
             elif isinstance(v, AbstractDescr):
                 pass
+            elif isinstance(v, IndirectCallTargets):
+                pass
             else:
                 raise NotImplementedError(type(v))
             args.append(v)

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/format.py	Wed May 12 09:18:28 2010
@@ -2,7 +2,7 @@
 from pypy.objspace.flow.model import Constant
 from pypy.rpython.lltypesystem import lltype
 from pypy.jit.codewriter.flatten import SSARepr, Label, TLabel, Register
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
 from pypy.jit.codewriter.jitcode import SwitchDictDescr
 from pypy.jit.metainterp.history import AbstractDescr
 
@@ -28,7 +28,7 @@
             return '<SwitchDictDescr %s>' % (
                 ', '.join(['%s:%s' % (key, getlabelname(lbl))
                            for key, lbl in x._labels]))
-        elif isinstance(x, AbstractDescr):
+        elif isinstance(x, (AbstractDescr, IndirectCallTargets)):
             return '%r' % (x,)
         else:
             return '<unknown object: %r>' % (x,)

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/jitcode.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/jitcode.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/jitcode.py	Wed May 12 09:18:28 2010
@@ -13,6 +13,7 @@
         self.fnaddr = fnaddr
         self.calldescr = calldescr
         self._called_from = called_from   # debugging
+        self._ssarepr     = None          # debugging
 
     def setup(self, code='', constants_i=[], constants_r=[], constants_f=[],
               num_regs_i=256, num_regs_r=256, num_regs_f=256,
@@ -92,11 +93,21 @@
         return ' '.join(lst)
 
     def _missing_liveness(self, pc):
-        raise KeyError("missing liveness[%d]" % (pc,))
+        raise MissingLiveness("missing liveness[%d]\n%s" % (pc, self.dump()))
+
+    def dump(self):
+        if self._ssarepr is None:
+            return '<no dump available>'
+        else:
+            from pypy.jit.codewriter.format import format_assembler
+            return format_assembler(self._ssarepr)
 
     def __repr__(self):
         return '<JitCode %r>' % self.name
 
+class MissingLiveness(Exception):
+    pass
+
 
 class SwitchDictDescr(AbstractDescr):
     "Get a 'dict' attribute mapping integer values to bytecode positions."

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/jtransform.py	Wed May 12 09:18:28 2010
@@ -3,9 +3,8 @@
 from pypy.jit.metainterp.history import getkind
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
 from pypy.objspace.flow.model import Block, Link, c_last_exception
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
 from pypy.jit.codewriter import support, heaptracker
-from pypy.translator.simplify import get_funcobj
 from pypy.rlib import objectmodel
 from pypy.rlib.jit import _we_are_jitted
 
@@ -217,14 +216,14 @@
         args_f = []
         for v in op.args[1:]:
             self.add_in_correct_list(v, args_i, args_r, args_f)
-        if args_f:   kinds = 'irf'
+        reskind = getkind(op.result.concretetype)[0]
+        if args_f or reskind == 'f': kinds = 'irf'
         elif args_i: kinds = 'ir'
         else:        kinds = 'r'
         sublists = []
         if 'i' in kinds: sublists.append(ListOfKind('int', args_i))
         if 'r' in kinds: sublists.append(ListOfKind('ref', args_r))
         if 'f' in kinds: sublists.append(ListOfKind('float', args_f))
-        reskind = getkind(op.result.concretetype)[0]
         return SpaceOperation('%s_%s_%s' % (namebase, kinds, reskind),
                               initialargs + sublists, op.result)
 
@@ -237,35 +236,16 @@
         else: raise AssertionError(kind)
         lst.append(v)
 
-    def handle_residual_call(self, op):
+    def handle_residual_call(self, op, extraargs=[]):
         """A direct_call turns into the operation 'residual_call_xxx' if it
         is calling a function that we don't want to JIT.  The initial args
-        of 'residual_call_xxx' are the constant function to call, and its
-        calldescr."""
-        calldescr, canraise = self.callcontrol.getcalldescr(op)
-        #
-        pure = False
-        loopinvariant = False
-        if op.opname == "direct_call":
-            func = getattr(get_funcobj(op.args[0].value), '_callable', None)
-            pure = getattr(func, "_pure_function_", False)
-            loopinvariant = getattr(func, "_jit_loop_invariant_", False)
-            if pure or loopinvariant:
-                effectinfo = calldescr.get_extra_info()
-                assert (effectinfo is not None and
-                        not effectinfo.forces_virtual_or_virtualizable)
-        if loopinvariant:
-            name = 'G_residual_call_loopinvariant'
-            assert not non_void_args, ("arguments not supported for "
-                                       "loop-invariant function!")
-        elif pure:
-            # XXX check what to do about exceptions (also MemoryError?)
-            name = 'residual_call_pure'
-        elif canraise:
+        of 'residual_call_xxx' are the function to call, and its calldescr."""
+        calldescr = self.callcontrol.getcalldescr(op)
+        if self.callcontrol.calldescr_canraise(calldescr):
             name = 'G_residual_call'
         else:
             name = 'residual_call'
-        return self.rewrite_call(op, name, [op.args[0], calldescr])
+        return self.rewrite_call(op, name, [op.args[0], calldescr] + extraargs)
 
     def handle_regular_call(self, op):
         """A direct_call turns into the operation 'inline_call_xxx' if it
@@ -276,6 +256,17 @@
                                                called_from=self.graph)
         return self.rewrite_call(op, 'G_inline_call', [jitcode])
 
+    handle_residual_indirect_call = handle_residual_call
+
+    def handle_regular_indirect_call(self, op):
+        """An indirect call where at least one target has a JitCode."""
+        lst = []
+        for targetgraph in self.callcontrol.graphs_from(op):
+            jitcode = self.callcontrol.get_jitcode(targetgraph,
+                                                   called_from=self.graph)
+            lst.append(jitcode)
+        return self.handle_residual_call(op, [IndirectCallTargets(lst)])
+
     def _do_builtin_call(self, op, oopspec_name=None, args=None, extra=None):
         if oopspec_name is None: oopspec_name = op.opname
         if args is None: args = op.args

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/liveness.py	Wed May 12 09:18:28 2010
@@ -2,7 +2,7 @@
 
 
 # Some instruction require liveness information (the ones that can end up
-# in generate_guard() in pyjitpl.py); jitter.py prefixes these opnames
+# in generate_guard() in pyjitpl.py); jtransform.py prefixes these opnames
 # with a 'G_'.  Additionally, boolean and general switches in the flow graph
 # will turn in 'goto_if_not_*' operations, which also require liveness info.
 

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_assembler.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_assembler.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_assembler.py	Wed May 12 09:18:28 2010
@@ -1,7 +1,8 @@
 import py, struct
 from pypy.jit.codewriter.assembler import Assembler
 from pypy.jit.codewriter.flatten import SSARepr, Label, TLabel, Register
-from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
+from pypy.jit.codewriter.jitcode import MissingLiveness
 from pypy.jit.metainterp.history import AbstractDescr
 from pypy.objspace.flow.model import Constant
 from pypy.rpython.lltypesystem import lltype, llmemory
@@ -138,6 +139,16 @@
     assert assembler.insns == {'foobar/d': 0}
     assert assembler.descrs == descrs[::-1]
 
+def test_assemble_indirect_call():
+    lst1 = ["somejitcode1", "somejitcode2"]
+    lst2 = ["somejitcode1", "somejitcode3"]
+    ssarepr = SSARepr("test")
+    ssarepr.insns = [('foobar', IndirectCallTargets(lst1)),
+                     ('foobar', IndirectCallTargets(lst2))]
+    assembler = Assembler()
+    assembler.assemble(ssarepr)
+    assert assembler.indirectcalltargets == set(lst1).union(lst2)
+
 def test_num_regs():
     assembler = Assembler()
     ssarepr = SSARepr("test")
@@ -183,10 +194,10 @@
     assert assembler.insns == {'int_add/ici': 0,
                                'int_mul/iii': 1,
                                'int_return/i': 2}
-    py.test.raises(KeyError, jitcode._live_vars, 0)
-    py.test.raises(KeyError, jitcode._live_vars, 3)
-    py.test.raises(KeyError, jitcode._live_vars, 5)
-    py.test.raises(KeyError, jitcode._live_vars, 24)
+    py.test.raises(MissingLiveness, jitcode._live_vars, 0)
+    py.test.raises(MissingLiveness, jitcode._live_vars, 3)
+    py.test.raises(MissingLiveness, jitcode._live_vars, 5)
+    py.test.raises(MissingLiveness, jitcode._live_vars, 24)
     assert jitcode._live_vars(4) == '%i0'
     assert jitcode._live_vars(8) == '%i0 %i1'
     assert jitcode._live_vars(12) == '%i0'

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_codewriter.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_codewriter.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_codewriter.py	Wed May 12 09:18:28 2010
@@ -44,9 +44,11 @@
     assert jitcode.num_regs_r() == 0
     assert jitcode.num_regs_f() == 0
     assert jitcode._live_vars(5) == '%i0 %i1'
+    #
+    from pypy.jit.codewriter.jitcode import MissingLiveness
     for i in range(len(jitcode.code)+1):
         if i != 5:
-            py.test.raises(KeyError, jitcode._live_vars, i)
+            py.test.raises(MissingLiveness, jitcode._live_vars, i)
 
 def test_call():
     def ggg(x):

Copied: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_effectinfo.py (from r74456, pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_effectinfo.py)
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/test/test_effectinfo.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_effectinfo.py	Wed May 12 09:18:28 2010
@@ -1,7 +1,7 @@
 from pypy.rpython.lltypesystem.rclass import OBJECT
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.ootypesystem import ootype
-from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
+from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
 
 class FakeCPU:
     def fielddescrof(self, T, fieldname):

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_flatten.py	Wed May 12 09:18:28 2010
@@ -45,14 +45,18 @@
         return FakeDescr()
 
 class FakeCallControl:
+    _descr_cannot_raise = FakeDescr()
     def guess_call_kind(self, op):
         return 'residual'
     def getcalldescr(self, op):
         try:
-            can_raise = 'cannot_raise' not in op.args[0].value._obj.graph.name
+            if 'cannot_raise' in op.args[0].value._obj.graph.name:
+                return self._descr_cannot_raise
         except AttributeError:
-            can_raise = True
-        return FakeDescr(), can_raise
+            pass
+        return FakeDescr()
+    def calldescr_canraise(self, calldescr):
+        return calldescr is not self._descr_cannot_raise
 
 def fake_regallocs():
     return {'int': FakeRegAlloc(),

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_jtransform.py	Wed May 12 09:18:28 2010
@@ -31,7 +31,9 @@
     def guess_call_kind(self, op):
         return 'residual'
     def getcalldescr(self, op):
-        return 'calldescr', True
+        return 'calldescr'
+    def calldescr_canraise(self, calldescr):
+        return True
 
 class FakeRegularCallControl:
     def guess_call_kind(self, op):
@@ -42,6 +44,19 @@
         assert graph == 'somegraph'
         return 'somejitcode'
 
+class FakeIndirectCallControl:
+    def guess_call_kind(self, op):
+        return 'regular'
+    def graphs_from(self, op):
+        return ['somegraph1', 'somegraph2']
+    def getcalldescr(self, op):
+        return 'calldescr'
+    def get_jitcode(self, graph, called_from=None):
+        assert graph in ('somegraph1', 'somegraph2')
+        return 'somejitcode' + graph[-1]
+    def calldescr_canraise(self, calldescr):
+        return True
+
 
 def test_optimize_goto_if_not():
     v1 = Variable()
@@ -156,11 +171,13 @@
               if with_r: ARGS += [rclass.OBJECTPTR, lltype.Ptr(rstr.STR)]
               if with_f: ARGS += [lltype.Float, lltype.Float]
               random.shuffle(ARGS)
+              if RESTYPE == lltype.Float: with_f = True
               if with_f: expectedkind = 'irf'   # all kinds
               elif with_i: expectedkind = 'ir'  # integers and references
               else: expectedkind = 'r'          # only references
               yield residual_call_test, ARGS, RESTYPE, expectedkind
               yield direct_call_test, ARGS, RESTYPE, expectedkind
+              yield indirect_call_test, ARGS, RESTYPE, expectedkind
 
 def get_direct_call_op(argtypes, restype):
     FUNC = lltype.FuncType(argtypes, restype)
@@ -207,6 +224,29 @@
         kind = getkind(v.concretetype)
         assert kind == 'void' or kind[0] in expectedkind
 
+def indirect_call_test(argtypes, restype, expectedkind):
+    op = get_direct_call_op(argtypes, restype)
+    op.opname = 'indirect_call'
+    op.args[0] = varoftype(op.args[0].concretetype)
+    op.args.append(Constant(['somegraph1', 'somegraph2'], lltype.Void))
+    tr = Transformer(FakeCPU(), FakeIndirectCallControl())
+    tr.graph = 'someinitialgraph'
+    op1 = tr.rewrite_operation(op)
+    reskind = getkind(restype)[0]
+    assert op1.opname == 'G_residual_call_%s_%s' % (expectedkind, reskind)
+    assert op1.result == op.result
+    assert op1.args[0] == op.args[0]
+    assert op1.args[1] == 'calldescr'
+    assert op1.args[2].lst == ['somejitcode1', 'somejitcode2']
+    assert len(op1.args) == 3 + len(expectedkind)
+    for sublist, kind1 in zip(op1.args[3:], expectedkind):
+        assert sublist.kind.startswith(kind1)
+        assert list(sublist) == [v for v in op.args[1:]
+                                 if getkind(v.concretetype) == sublist.kind]
+    for v in op.args[1:]:
+        kind = getkind(v.concretetype)
+        assert kind == 'void' or kind[0] in expectedkind
+
 def test_getfield():
     # XXX a more compact encoding would be possible, something along
     # the lines of  getfield_gc_r %r0, $offset, %r1

Modified: pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_regalloc.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_regalloc.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/codewriter/test/test_regalloc.py	Wed May 12 09:18:28 2010
@@ -18,7 +18,7 @@
 
     def check_assembler(self, graph, expected, transform=False):
         # 'transform' can be False only for simple graphs.  More complex
-        # graphs must first be transformed by jitter.py before they can be
+        # graphs must first be transformed by jtransform.py before they can be
         # subjected to register allocation and flattening.
         if transform:
             from pypy.jit.codewriter.jtransform import transform_graph

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/blackhole.py	Wed May 12 09:18:28 2010
@@ -218,7 +218,7 @@
         # Get the bhimpl_xxx method.  If we get an AttributeError here,
         # it means that either the implementation is missing, or that it
         # should not appear here at all but instead be transformed away
-        # by codewriter/jitter.py.
+        # by codewriter/jtransform.py.
         unboundmethod = getattr(BlackholeInterpreter, 'bhimpl_' + name).im_func
         verbose = self.verbose
         argtypes = unrolling_iterable(unboundmethod.argtypes)
@@ -726,9 +726,6 @@
     @arguments("cpu", "i", "d", "R", returns="r")
     def bhimpl_residual_call_r_r(cpu, func, calldescr, args_r):
         return cpu.bh_call_r(func, calldescr, None, args_r, None)
-    @arguments("cpu", "i", "d", "R", returns="f")
-    def bhimpl_residual_call_r_f(cpu, func, calldescr, args_r):
-        return cpu.bh_call_f(func, calldescr, None, args_r, None)
     @arguments("cpu", "i", "d", "R")
     def bhimpl_residual_call_r_v(cpu, func, calldescr, args_r):
         cpu.bh_call_v(func, calldescr, None, args_r, None)
@@ -739,9 +736,6 @@
     @arguments("cpu", "i", "d", "I", "R", returns="r")
     def bhimpl_residual_call_ir_r(cpu, func, calldescr, args_i, args_r):
         return cpu.bh_call_r(func, calldescr, args_i, args_r, None)
-    @arguments("cpu", "i", "d", "I", "R", returns="f")
-    def bhimpl_residual_call_ir_f(cpu, func, calldescr, args_i, args_r):
-        return cpu.bh_call_f(func, calldescr, args_i, args_r, None)
     @arguments("cpu", "i", "d", "I", "R")
     def bhimpl_residual_call_ir_v(cpu, func, calldescr, args_i, args_r):
         cpu.bh_call_v(func, calldescr, args_i, args_r, None)
@@ -767,10 +761,6 @@
     def bhimpl_inline_call_r_r(cpu, jitcode, args_r):
         return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
                              None, args_r, None)
-    @arguments("cpu", "j", "R", returns="f")
-    def bhimpl_inline_call_r_f(cpu, jitcode, args_r):
-        return cpu.bh_call_f(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
-                             None, args_r, None)
     @arguments("cpu", "j", "R")
     def bhimpl_inline_call_r_v(cpu, jitcode, args_r):
         return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
@@ -784,10 +774,6 @@
     def bhimpl_inline_call_ir_r(cpu, jitcode, args_i, args_r):
         return cpu.bh_call_r(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
                              args_i, args_r, None)
-    @arguments("cpu", "j", "I", "R", returns="f")
-    def bhimpl_inline_call_ir_f(cpu, jitcode, args_i, args_r):
-        return cpu.bh_call_f(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
-                             args_i, args_r, None)
     @arguments("cpu", "j", "I", "R")
     def bhimpl_inline_call_ir_v(cpu, jitcode, args_i, args_r):
         return cpu.bh_call_v(jitcode.get_fnaddr_as_int(), jitcode.calldescr,
@@ -880,3 +866,29 @@
     @arguments("cpu", "r", returns="i")
     def bhimpl_cast_ptr_to_int(cpu, p):
         return cpu.bh_cast_ptr_to_int(p)
+
+    @arguments("cpu", "i", returns="r")
+    def bhimpl_newstr(cpu, length):
+        return cpu.bh_newstr(length)
+    @arguments("cpu", "r", returns="i")
+    def bhimpl_strlen(cpu, string):
+        return cpu.bh_strlen(string)
+    @arguments("cpu", "r", "i", returns="i")
+    def bhimpl_strgetitem(cpu, string, index):
+        return cpu.bh_strgetitem(string, index)
+    @arguments("cpu", "r", "i", "i")
+    def bhimpl_strsetitem(cpu, string, index, newchr):
+        cpu.bh_strsetitem(string, index, newchr)
+
+    @arguments("cpu", "i", returns="r")
+    def bhimpl_newunicode(cpu, length):
+        return cpu.bh_newunicode(length)
+    @arguments("cpu", "r", returns="i")
+    def bhimpl_unicodelen(cpu, unicode):
+        return cpu.bh_unicodelen(unicode)
+    @arguments("cpu", "r", "i", returns="i")
+    def bhimpl_unicodegetitem(cpu, unicode, index):
+        return cpu.bh_unicodegetitem(unicode, index)
+    @arguments("cpu", "r", "i", "i")
+    def bhimpl_unicodesetitem(cpu, unicode, index, newchr):
+        cpu.bh_unicodesetitem(unicode, index, newchr)

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/history.py	Wed May 12 09:18:28 2010
@@ -360,7 +360,11 @@
     def _get_str(self):    # for debugging only
         from pypy.rpython.annlowlevel import hlstr
         from pypy.rpython.lltypesystem import rstr
-        return hlstr(lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), self.value))
+        try:
+            return hlstr(lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR),
+                                                self.value))
+        except lltype.UninitializedMemoryAccess:
+            return '<uninitialized string>'
 
 class ConstObj(Const):
     type = REF

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/pyjitpl.py	Wed May 12 09:18:28 2010
@@ -22,6 +22,7 @@
 from pypy.rlib.jit import DEBUG_OFF, DEBUG_PROFILE, DEBUG_STEPS, DEBUG_DETAILED
 from pypy.jit.metainterp.compile import GiveUp
 from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
+from pypy.jit.codewriter import effectinfo as ef
 
 # ____________________________________________________________
 
@@ -167,10 +168,10 @@
 
     for _opimpl in ['int_add_ovf', 'int_sub_ovf', 'int_mul_ovf']:
         exec py.code.Source('''
-            @arguments("orgpc", "box", "box")
-            def opimpl_%s(self, pc, b1, b2):
+            @arguments("box", "box")
+            def opimpl_%s(self, b1, b2):
                 resbox = self.execute(rop.%s, b1, b2)
-                self.metainterp.handle_possible_overflow_error(pc)
+                self.metainterp.handle_possible_overflow_error()
                 return resbox
         ''' % (_opimpl, _opimpl.upper())).compile()
 
@@ -289,9 +290,9 @@
         self.load_int()       # past the 'box' argument
         self.ignore_varargs() # past the 'livelist' argument
 
-    @arguments("orgpc", "box", "descr")
-    def opimpl_switch(self, pc, valuebox, switchdict):
-        box = self.implement_guard_value(pc, valuebox)
+    @arguments("box", "descr")
+    def opimpl_switch(self, valuebox, switchdict):
+        box = self.implement_guard_value(valuebox)
         switchvalue = box.getint()
         assert isinstance(switchdict, SwitchDictDescr)
         try:
@@ -632,11 +633,9 @@
 
     opimpl_inline_call_r_i = _opimpl_inline_call1
     opimpl_inline_call_r_r = _opimpl_inline_call1
-    opimpl_inline_call_r_f = _opimpl_inline_call1
     opimpl_inline_call_r_v = _opimpl_inline_call1
     opimpl_inline_call_ir_i = _opimpl_inline_call2
     opimpl_inline_call_ir_r = _opimpl_inline_call2
-    opimpl_inline_call_ir_f = _opimpl_inline_call2
     opimpl_inline_call_ir_v = _opimpl_inline_call2
     opimpl_inline_call_irf_i = _opimpl_inline_call3
     opimpl_inline_call_irf_r = _opimpl_inline_call3
@@ -645,21 +644,19 @@
 
     @arguments("box", "descr", "boxes")
     def _opimpl_residual_call1(self, funcbox, calldescr, argboxes):
-        return self.do_residual_call(funcbox, calldescr, argboxes, exc=True)
+        return self.do_residual_or_indirect_call(funcbox, calldescr, argboxes)
     @arguments("box", "descr", "boxes2")
     def _opimpl_residual_call2(self, funcbox, calldescr, argboxes):
-        return self.do_residual_call(funcbox, calldescr, argboxes, exc=True)
+        return self.do_residual_or_indirect_call(funcbox, calldescr, argboxes)
     @arguments("box", "descr", "boxes3")
     def _opimpl_residual_call3(self, funcbox, calldescr, argboxes):
-        return self.do_residual_call(funcbox, calldescr, argboxes, exc=True)
+        return self.do_residual_or_indirect_call(funcbox, calldescr, argboxes)
 
     opimpl_residual_call_r_i = _opimpl_residual_call1
     opimpl_residual_call_r_r = _opimpl_residual_call1
-    opimpl_residual_call_r_f = _opimpl_residual_call1
     opimpl_residual_call_r_v = _opimpl_residual_call1
     opimpl_residual_call_ir_i = _opimpl_residual_call2
     opimpl_residual_call_ir_r = _opimpl_residual_call2
-    opimpl_residual_call_ir_f = _opimpl_residual_call2
     opimpl_residual_call_ir_v = _opimpl_residual_call2
     opimpl_residual_call_irf_i = _opimpl_residual_call3
     opimpl_residual_call_irf_r = _opimpl_residual_call3
@@ -705,28 +702,6 @@
                                                   call_position)
         return res
 
-    @XXX  #arguments("descr", "varargs")
-    def opimpl_residual_call_noexception(self, calldescr, varargs):
-        self.do_residual_call(varargs, descr=calldescr, exc=False)
-
-    @XXX  #arguments("descr", "varargs")
-    def opimpl_residual_call_pure(self, calldescr, varargs):
-        self.execute_varargs(rop.CALL_PURE, varargs, descr=calldescr, exc=False)
-
-    @XXX  #arguments("orgpc", "descr", "box", "varargs")
-    def opimpl_indirect_call(self, pc, calldescr, box, varargs):
-        box = self.implement_guard_value(pc, box)
-        cpu = self.metainterp.cpu
-        key = cpu.ts.getaddr_for_box(cpu, box)
-        jitcode = self.metainterp.staticdata.bytecode_for_address(key)
-        if jitcode is not None:
-            # we should follow calls to this graph
-            return self.perform_call(jitcode, varargs)
-        else:
-            # but we should not follow calls to that graph
-            return self.do_residual_call([box] + varargs,
-                                         descr=calldescr, exc=True)
-
     @XXX  #arguments("orgpc", "methdescr", "varargs")
     def opimpl_oosend(self, pc, methdescr, varargs):
         objbox = varargs[0]
@@ -743,37 +718,37 @@
             return self.execute_varargs(rop.OOSEND, varargs,
                                         descr=methdescr, exc=True)
 
-    @XXX  #arguments("box")
-    def opimpl_strlen(self, str):
-        self.execute(rop.STRLEN, str)
-
-    @XXX  #arguments("box")
-    def opimpl_unicodelen(self, str):
-        self.execute(rop.UNICODELEN, str)
-
-    @XXX  #arguments("box", "box")
-    def opimpl_strgetitem(self, str, index):
-        self.execute(rop.STRGETITEM, str, index)
+    @arguments("box")
+    def opimpl_strlen(self, strbox):
+        return self.execute(rop.STRLEN, strbox)
 
-    @XXX  #arguments("box", "box")
-    def opimpl_unicodegetitem(self, str, index):
-        self.execute(rop.UNICODEGETITEM, str, index)
+    @arguments("box")
+    def opimpl_unicodelen(self, unicodebox):
+        return self.execute(rop.UNICODELEN, unicodebox)
 
-    @XXX  #arguments("box", "box", "box")
-    def opimpl_strsetitem(self, str, index, newchar):
-        self.execute(rop.STRSETITEM, str, index, newchar)
-
-    @XXX  #arguments("box", "box", "box")
-    def opimpl_unicodesetitem(self, str, index, newchar):
-        self.execute(rop.UNICODESETITEM, str, index, newchar)
+    @arguments("box", "box")
+    def opimpl_strgetitem(self, strbox, indexbox):
+        return self.execute(rop.STRGETITEM, strbox, indexbox)
+
+    @arguments("box", "box")
+    def opimpl_unicodegetitem(self, unicodebox, indexbox):
+        return self.execute(rop.UNICODEGETITEM, unicodebox, indexbox)
+
+    @arguments("box", "box", "box")
+    def opimpl_strsetitem(self, strbox, indexbox, newcharbox):
+        return self.execute(rop.STRSETITEM, strbox, indexbox, newcharbox)
+
+    @arguments("box", "box", "box")
+    def opimpl_unicodesetitem(self, unicodebox, indexbox, newcharbox):
+        self.execute(rop.UNICODESETITEM, unicodebox, indexbox, newcharbox)
 
-    @XXX  #arguments("box")
-    def opimpl_newstr(self, length):
-        self.execute(rop.NEWSTR, length)
+    @arguments("box")
+    def opimpl_newstr(self, lengthbox):
+        return self.execute(rop.NEWSTR, lengthbox)
 
-    @XXX  #arguments("box")
-    def opimpl_newunicode(self, length):
-        self.execute(rop.NEWUNICODE, length)
+    @arguments("box")
+    def opimpl_newunicode(self, lengthbox):
+        return self.execute(rop.NEWUNICODE, lengthbox)
 
     @XXX  #arguments("descr", "varargs")
     def opimpl_residual_oosend_canraise(self, methdescr, varargs):
@@ -787,9 +762,9 @@
     def opimpl_residual_oosend_pure(self, methdescr, boxes):
         self.execute_varargs(rop.OOSEND_PURE, boxes, descr=methdescr, exc=False)
 
-    @arguments("orgpc", "box")
-    def opimpl_int_guard_value(self, pc, box):
-        return self.implement_guard_value(pc, box)
+    @arguments("box")
+    def opimpl_int_guard_value(self, box):
+        return self.implement_guard_value(box)
 
     @XXX  #arguments("orgpc", "int")
     def opimpl_guard_green(self, pc, boxindex):
@@ -802,10 +777,10 @@
         constbox = self.implement_guard_value(pc, box)
         self.env[boxindex] = constbox
 
-    @arguments("orgpc", "box")
-    def opimpl_guard_class(self, pc, box):
+    @arguments("box")
+    def opimpl_guard_class(self, box):
         clsbox = self.cls_of_box(box)
-        self.generate_guard(pc, rop.GUARD_CLASS, box, [clsbox])
+        self.generate_guard(rop.GUARD_CLASS, box, [clsbox])
         return clsbox
 
 ##    @XXX  #arguments("orgpc", "box", "builtin")
@@ -1029,7 +1004,7 @@
         metainterp.attach_debug_info(guard_op)
         return guard_op
 
-    def implement_guard_value(self, pc, box):
+    def implement_guard_value(self, box):
         """Promote the given Box into a Const.  Note: be careful, it's a
         bit unclear what occurs if a single opcode needs to generate
         several ones and/or ones not near the beginning."""
@@ -1037,7 +1012,7 @@
             return box     # no promotion needed, already a Const
         else:
             promoted_box = box.constbox()
-            self.generate_guard(pc, rop.GUARD_VALUE, box, [promoted_box])
+            self.generate_guard(rop.GUARD_VALUE, box, [promoted_box])
             self.metainterp.replace_box(box, promoted_box)
             return promoted_box
 
@@ -1057,15 +1032,16 @@
         resbox = self.metainterp.execute_and_record_varargs(opnum, argboxes,
                                                             descr=descr)
         if exc:
-            self.metainterp.handle_possible_exception(self.pc)
+            self.metainterp.handle_possible_exception()
         else:
             self.metainterp.assert_no_exception()
         return resbox
 
-    def do_residual_call(self, funcbox, descr, argboxes, exc):
+    def do_residual_call(self, funcbox, descr, argboxes):
         allboxes = [funcbox] + argboxes
         effectinfo = descr.get_extra_info()
-        if 0:# XXX effectinfo is None or effectinfo.forces_virtual_or_virtualizable:
+        if (effectinfo is None or
+            effectinfo.extraeffect == ef.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE):
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.vable_and_vrefs_before_residual_call()
             # xxx do something about code duplication
@@ -1080,7 +1056,31 @@
             else:
                 return self.metainterp.assert_no_exception()
         else:
-            return self.execute_varargs(rop.CALL, allboxes, descr, exc)
+            effect = effectinfo.extraeffect
+            if effect == ef.EF_CANNOT_RAISE:
+                opnum, exc = rop.CALL, False
+            elif effect == ef.EF_PURE:
+                opnum, exc = rop.CALL_PURE, False
+            elif effect == ef.EF_LOOPINVARIANT:
+                opnum, exc = rop.CALL_LOOPINVARIANT, True
+            else:
+                opnum, exc = rop.CALL, True
+            return self.execute_varargs(opnum, allboxes, descr, exc)
+
+    def do_residual_or_indirect_call(self, funcbox, calldescr, argboxes):
+        """The 'residual_call' operation is emitted in two cases:
+        when we have to generate a residual CALL operation, but also
+        to handle an indirect_call that may need to be inlined."""
+        funcbox = self.implement_guard_value(funcbox)
+        sd = self.metainterp.staticdata
+        key = sd.cpu.ts.getaddr_for_box(funcbox)
+        jitcode = sd.bytecode_for_address(key)
+        if jitcode is not None:
+            # we should follow calls to this graph
+            return self.metainterp.perform_call(jitcode, argboxes)
+        else:
+            # but we should not follow calls to that graph
+            return self.do_residual_call(funcbox, calldescr, argboxes)
 
 # ____________________________________________________________
 
@@ -1100,14 +1100,12 @@
         RESULT = codewriter.portal_graph.getreturnvar().concretetype
         self.result_type = history.getkind(RESULT)
 
-        self.setup_insns(codewriter.assembler.insns)
-        self.setup_descrs(codewriter.assembler.descrs)
+        asm = codewriter.assembler
+        self.setup_insns(asm.insns)
+        self.setup_descrs(asm.descrs)
+        self.setup_indirectcalltargets(asm.indirectcalltargets)
 
         self.profiler = ProfilerClass()
-
-        self.indirectcall_keys = []
-        self.indirectcall_values = []
-
         self.warmrunnerdesc = warmrunnerdesc
 
         backendmodule = self.cpu.__module__
@@ -1140,6 +1138,9 @@
     def setup_descrs(self, descrs):
         self.opcode_descrs = descrs
 
+    def setup_indirectcalltargets(self, indirectcalltargets):
+        self.indirectcalltargets = list(indirectcalltargets)
+
     def finish_setup(self, optimizer=None):
         warmrunnerdesc = self.warmrunnerdesc
         if warmrunnerdesc is not None:
@@ -1192,24 +1193,16 @@
                 # because the keys are function addresses, so they
                 # can change from run to run.
                 d = {}
-                keys = self.indirectcall_keys
-                values = self.indirectcall_values
-                for i in range(len(keys)):
-                    d[keys[i]] = values[i]
+                for jitcode in self.indirectcalltargets:
+                    d[jitcode.fnaddr] = jitcode
                 self.globaldata.indirectcall_dict = d
             return d.get(fnaddress, None)
         else:
-            for i in range(len(self.indirectcall_keys)):
-                if fnaddress == self.indirectcall_keys[i]:
-                    return self.indirectcall_values[i]
+            for jitcode in self.indirectcalltargets:
+                if jitcode.fnaddr == fnaddress:
+                    return jitcode
             return None
 
-    # ---------- construction-time interface ----------
-
-    def _register_indirect_call_target(self, fnaddress, jitcode):
-        self.indirectcall_keys.append(fnaddress)
-        self.indirectcall_values.append(jitcode)
-
     # ---------------- logging ------------------------
 
     def log(self, msg):
@@ -1273,7 +1266,7 @@
         return False       # XXX get rid of this method
 
     def perform_call(self, jitcode, boxes, greenkey=None):
-        # when tracing, this bytecode causes the subfunction to be entered
+        # causes the metainterp to enter the given subfunction
         f = self.newframe(jitcode, greenkey)
         f.setup_call(boxes)
         raise ChangeFrame
@@ -1865,26 +1858,26 @@
         # mark by replacing it with ConstPtr(NULL)
         self.virtualref_boxes[i+1] = self.cpu.ts.CONST_NULL
 
-    def handle_possible_exception(self, pc):
+    def handle_possible_exception(self):
         frame = self.framestack[-1]
         if self.last_exc_value_box:
             exception_box = self.cpu.ts.cls_of_box(self.last_exc_value_box)
-            op = frame.generate_guard(pc, rop.GUARD_EXCEPTION,
+            op = frame.generate_guard(rop.GUARD_EXCEPTION,
                                       None, [exception_box])
             if op:
                 op.result = self.last_exc_value_box
             self.finishframe_exception()
         else:
-            frame.generate_guard(pc, rop.GUARD_NO_EXCEPTION, None, [])
+            frame.generate_guard(rop.GUARD_NO_EXCEPTION, None, [])
 
-    def handle_possible_overflow_error(self, pc):
+    def handle_possible_overflow_error(self):
         frame = self.framestack[-1]
         if self.last_exc_value_box:
-            frame.generate_guard(pc, rop.GUARD_OVERFLOW, None)
+            frame.generate_guard(rop.GUARD_OVERFLOW, None)
             assert isinstance(self.last_exc_value_box, Const)
             self.finishframe_exception()
         else:
-            frame.generate_guard(pc, rop.GUARD_NO_OVERFLOW, None)
+            frame.generate_guard(rop.GUARD_NO_OVERFLOW, None)
 
     def assert_no_exception(self):
         assert not self.last_exc_value_box
@@ -2066,7 +2059,6 @@
         args = ()
         next_argcode = 0
         code = self.bytecode
-        orgpc = position
         position += 1
         for argtype in argtypes:
             if argtype == "box":     # a box, of whatever type
@@ -2129,8 +2121,6 @@
                                            argcodes[next_argcode + 2])
                 next_argcode = next_argcode + 3
                 position = position3 + 1 + length3
-            elif argtype == "orgpc":
-                value = orgpc
             else:
                 raise AssertionError("bad argtype: %r" % (argtype,))
             args += (value,)

Modified: pypy/branch/blackhole-improvement/pypy/jit/metainterp/typesystem.py
==============================================================================
--- pypy/branch/blackhole-improvement/pypy/jit/metainterp/typesystem.py	(original)
+++ pypy/branch/blackhole-improvement/pypy/jit/metainterp/typesystem.py	Wed May 12 09:18:28 2010
@@ -128,8 +128,8 @@
         return lltype.cast_opaque_ptr(llmemory.GCREF, value)
     cast_to_ref._annspecialcase_ = 'specialize:ll'
     
-    def getaddr_for_box(self, cpu, box):
-        return box.getaddr(cpu)
+    def getaddr_for_box(self, box):
+        return box.getaddr()
 
 def rd_eq(ref1, ref2):
     return ref1 == ref2
@@ -230,7 +230,7 @@
         return ootype.cast_to_object(value)
     cast_to_ref._annspecialcase_ = 'specialize:ll'
 
-    def getaddr_for_box(self, cpu, box):
+    def getaddr_for_box(self, box):
         return box.getref_base()
     
 llhelper = LLTypeHelper()



More information about the Pypy-commit mailing list