[pypy-svn] r77296 - in pypy/branch/jit-str/pypy/jit: codewriter codewriter/test metainterp metainterp/optimizeopt

arigo at codespeak.net arigo at codespeak.net
Thu Sep 23 13:42:59 CEST 2010


Author: arigo
Date: Thu Sep 23 13:42:57 2010
New Revision: 77296

Modified:
   pypy/branch/jit-str/pypy/jit/codewriter/effectinfo.py
   pypy/branch/jit-str/pypy/jit/codewriter/jtransform.py
   pypy/branch/jit-str/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/optimizer.py
   pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/virtualize.py
   pypy/branch/jit-str/pypy/jit/metainterp/resume.py
Log:
Work towards making str_concat virtuals.


Modified: pypy/branch/jit-str/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/branch/jit-str/pypy/jit/codewriter/effectinfo.py	Thu Sep 23 13:42:57 2010
@@ -121,3 +121,15 @@
     def analyze_simple_operation(self, op):
         return op.opname in ('jit_force_virtualizable',
                              'jit_force_virtual')
+
+# ____________________________________________________________
+
+_callinfo_for_oopspec = {}
+
+def callinfo_for_oopspec(oopspecindex):
+    """A memo function that returns the calldescr and the function
+    address (as an int) of one of the OS_XYZ functions defined above.
+    Don't use this if there might be several implementations of the same
+    OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
+    return _callinfo_for_oopspec.get(oopspecindex, (None, 0))
+callinfo_for_oopspec._annspecialcase_ = 'specialize:memo'

Modified: pypy/branch/jit-str/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/jit-str/pypy/jit/codewriter/jtransform.py	Thu Sep 23 13:42:57 2010
@@ -1,12 +1,12 @@
 import py, sys
-from pypy.rpython.lltypesystem import lltype, rstr, rclass
+from pypy.rpython.lltypesystem import lltype, llmemory, rstr, rclass
 from pypy.rpython import rlist
 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, IndirectCallTargets
 from pypy.jit.codewriter import support, heaptracker
-from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.effectinfo import EffectInfo, _callinfo_for_oopspec
 from pypy.jit.codewriter.policy import log
 from pypy.jit.metainterp.typesystem import deref, arrayItem
 from pypy.rlib import objectmodel
@@ -1029,6 +1029,8 @@
 
     def _handle_oopspec_call(self, op, args, oopspecindex):
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex)
+        func = heaptracker.adr2int(llmemory.cast_ptr_to_adr(op.args[0].value))
+        _callinfo_for_oopspec[oopspecindex] = calldescr, func
         op1 = self.rewrite_call(op, 'residual_call',
                                 [op.args[0], calldescr],
                                 args=args)

Modified: pypy/branch/jit-str/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/jit-str/pypy/jit/codewriter/test/test_jtransform.py	Thu Sep 23 13:42:57 2010
@@ -718,6 +718,11 @@
     assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_UNI_CONCAT
     assert op1.args[2] == ListOfKind('ref', [v1, v2])
     assert op1.result == v3
+    #
+    # check the callinfo_for_oopspec
+    got = effectinfo.callinfo_for_oopspec(effectinfo.EffectInfo.OS_UNI_CONCAT)
+    assert got[0] == op1.args[1]    # the calldescr
+    assert heaptracker.int2adr(got[1]) == llmemory.cast_ptr_to_adr(func)
 
 def test_str_stringslice_startonly():
     # test that the oopspec is present and correctly transformed

Modified: pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/optimizer.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/optimizer.py	(original)
+++ pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/optimizer.py	Thu Sep 23 13:42:57 2010
@@ -306,6 +306,9 @@
         # accumulate counters
         self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
 
+    def send_extra_operation(self, op):
+        self.first_optimization.propagate_forward(op)
+
     def propagate_forward(self, op):
         self.producer[op.result] = op
         opnum = op.opnum

Modified: pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/virtualize.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/virtualize.py	(original)
+++ pypy/branch/jit-str/pypy/jit/metainterp/optimizeopt/virtualize.py	Thu Sep 23 13:42:57 2010
@@ -7,7 +7,7 @@
 from pypy.jit.metainterp.optimizeutil import _findall
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp.optimizeopt.optimizer import *
-from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
 from pypy.rlib.unroll import unrolling_iterable
 
 
@@ -196,15 +196,23 @@
         return modifier.make_varray(self.arraydescr)
 
 
-class VStringPlainValue(AbstractVirtualValue):
+class VAbstractStringValue(AbstractVirtualValue):
+
+    def getlengthvalue(self):
+        raise NotImplementedError
+
+
+class VStringPlainValue(VAbstractStringValue):
     """A string built with newstr(const)."""
 
-    def __init__(self, optimizer, size, keybox, source_op=None):
-        AbstractVirtualValue.__init__(self, optimizer, keybox, source_op)
+    def setup(self, size):
         self._chars = [CVAL_ZERO] * size
+        self._lengthvalue = None     # cache only
 
-    def getlength(self):
-        return len(self._chars)
+    def getlengthvalue(self):
+        if self._lengthvalue is None:
+            self._lengthvalue = ConstantValue(ConstInt(len(self._chars)))
+        return self._lengthvalue
 
     def getitem(self, index):
         return self._chars[index]
@@ -232,27 +240,40 @@
                 value.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
-        return modifier.make_vstrconcat()
+        return modifier.make_vstrplain()
 
 
-class VStringConcatValue(AbstractVirtualValue):
+class VStringConcatValue(VAbstractStringValue):
     """The concatenation of two other strings."""
 
-    def __init__(self, optimizer, keybox):
-        AbstractVirtualValue.__init__(self, optimizer, keybox)
-        self._left = None
-        self._right = None
+    def setup(self, left, right, length):
+        self.left = left
+        self.right = right
+        self.lengthvalue = length
+
+    def getlengthvalue(self):
+        return self.lengthvalue
 
     def _really_force(self):
-        xxx
+        assert self.source_op is not None
+        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
+        leftbox = self.left.force_box()
+        rightbox = self.right.force_box()
+        self.box = box = self.source_op.result
+        newoperations = self.optimizer.newoperations
+        newoperations.append(ResOperation(rop.CALL,
+                                          [ConstInt(func), leftbox, rightbox],
+                                          box, calldescr))
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
-            leftbox = self._left.get_key_box()
-            rightbox = self._right.get_key_box()
+            # we don't store the lengthvalue in guards, because the
+            # guard-failed code starts with a regular STR_CONCAT again
+            leftbox = self.left.get_key_box()
+            rightbox = self.right.get_key_box()
             modifier.register_virtual_fields(self.keybox, [leftbox, rightbox])
-            self._left.get_args_for_fail(modifier)
-            self._right.get_args_for_fail(modifier)
+            self.left.get_args_for_fail(modifier)
+            self.right.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
         return modifier.make_vstrconcat()
@@ -346,13 +367,13 @@
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def make_vstring_plain(self, length, box, source_op=None):
-        vvalue = VStringPlainValue(self.optimizer, length, box, source_op)
+    def make_vstring_plain(self, box, source_op=None):
+        vvalue = VStringPlainValue(self.optimizer, box, source_op)
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def make_vstring_concat(self, box):
-        vvalue = VStringConcatValue(self.optimizer, box)
+    def make_vstring_concat(self, box, source_op=None):
+        vvalue = VStringConcatValue(self.optimizer, box, source_op)
         self.make_equal_to(box, vvalue)
         return vvalue
 
@@ -398,14 +419,13 @@
         vrefinfo = self.optimizer.metainterp_sd.virtualref_info
         # op.args[1] should really never point to null here
         # - set 'forced' to point to the real object
-        op1 = ResOperation(rop.SETFIELD_GC, op.args, None,
-                          descr = vrefinfo.descr_forced)
-        self.optimize_SETFIELD_GC(op1)
+        seo = self.optimizer.send_extra_operation
+        seo(ResOperation(rop.SETFIELD_GC, op.args, None,
+                         descr = vrefinfo.descr_forced))
         # - set 'virtual_token' to TOKEN_NONE
         args = [op.args[0], ConstInt(vrefinfo.TOKEN_NONE)]
-        op1 = ResOperation(rop.SETFIELD_GC, args, None,
-                      descr = vrefinfo.descr_virtual_token)
-        self.optimize_SETFIELD_GC(op1)
+        seo(ResOperation(rop.SETFIELD_GC, args, None,
+                         descr = vrefinfo.descr_virtual_token))
         # Note that in some cases the virtual in op.args[1] has been forced
         # already.  This is fine.  In that case, and *if* a residual
         # CALL_MAY_FORCE suddenly turns out to access it, then it will
@@ -535,7 +555,8 @@
             # build a new one with the ConstInt argument
             if not isinstance(op.args[0], ConstInt):
                 op = ResOperation(rop.NEWSTR, [length_box], op.result)
-            self.make_vstring_plain(length_box.getint(), op.result, op)
+            vvalue = self.make_vstring_plain(op.result, op)
+            vvalue.setup(length_box.getint())
         else:
             self.emit_operation(op)
 
@@ -563,15 +584,23 @@
     def optimize_STRLEN(self, op):
         value = self.getvalue(op.args[0])
         if isinstance(value, VStringPlainValue):  # even if no longer virtual
-            self.make_constant_int(op.result, value.getlength())
+            self.make_equal_to(op.result, value.getlengthvalue())
         else:
             value.ensure_nonnull()
             self.emit_operation(op)
 
     def opt_call_oopspec_STR_CONCAT(self, op):
-        value = self.make_vstring_concat(op.result)
-        value._left = self.getvalue(op.args[1])
-        value._right = self.getvalue(op.args[2])
+        lengthbox = BoxInt()
+        len1box = BoxInt()
+        len2box = BoxInt()
+        seo = self.optimizer.send_extra_operation
+        seo(ResOperation(rop.STRLEN, [op.args[1]], len1box))
+        seo(ResOperation(rop.STRLEN, [op.args[2]], len2box))
+        seo(ResOperation(rop.INT_ADD, [len1box, len2box], lengthbox))
+        value = self.make_vstring_concat(op.result, op)
+        value.setup(left = self.getvalue(op.args[1]),
+                    right = self.getvalue(op.args[2]),
+                    length = self.getvalue(lengthbox))
         return True
 
     def propagate_forward(self, op):

Modified: pypy/branch/jit-str/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jit-str/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/jit-str/pypy/jit/metainterp/resume.py	Thu Sep 23 13:42:57 2010
@@ -4,6 +4,7 @@
 from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.metainterp import jitprof
+from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rlib import rarithmetic
 from pypy.rlib.objectmodel import we_are_translated, specialize
@@ -253,6 +254,9 @@
     def make_varray(self, arraydescr):
         return VArrayInfo(arraydescr)
 
+    def make_vstrplain(self):
+        return VStrPlainInfo()
+
     def make_vstrconcat(self):
         return VStrConcatInfo()
 
@@ -489,14 +493,8 @@
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
-class VStrConcatInfo(AbstractVirtualInfo):
-    """Stands for the string made out of the concatenation of all
-    fieldnums.  Each fieldnum can be an integer (the ord() of a single
-    character) or a pointer (another string).     XXX only integers implemented
-    """
-    def __init__(self):
-        pass
-        #self.fieldnums = ...
+class VStrPlainInfo(AbstractVirtualInfo):
+    """Stands for the string made out of the characters of all fieldnums."""
 
     @specialize.argtype(1)
     def allocate(self, decoder):
@@ -510,7 +508,29 @@
             decoder.strsetitem(string, i, self.fieldnums[i])
 
     def debug_prints(self):
-        debug_print("\tvstringinfo")
+        debug_print("\tvstrplaininfo length", len(self.fieldnums))
+
+
+class VStrConcatInfo(AbstractVirtualInfo):
+    """Stands for the string made out of the concatenation of two
+    other strings."""
+
+    @specialize.argtype(1)
+    def allocate(self, decoder):
+        # xxx for blackhole resuming, this will build all intermediate
+        # strings and throw them away immediately, which is a bit sub-
+        # efficient.  Not sure we care.
+        left, right = self.fieldnums
+        return decoder.concat_strings(left, right)
+
+    @specialize.argtype(1)
+    def setfields(self, decoder, string):
+        # we do everything in allocate(); no risk of circular data structure
+        # with strings.
+        pass    
+
+    def debug_prints(self):
+        debug_print("\tvstrconcatinfo")
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
@@ -651,7 +671,16 @@
                                                   arraydescr, ConstInt(length))
 
     def allocate_string(self, length):
-        return self.metainterp.execute_and_record(rop.NEWSTR, ConstInt(length))
+        return self.metainterp.execute_and_record(rop.NEWSTR,
+                                                  None, ConstInt(length))
+
+    def concat_strings(self, str1num, str2num):
+        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
+        str1box = self.decode_box(str1num, REF)
+        str2box = self.decode_box(str2num, REF)
+        return self.metainterp.execute_and_record(rop.CALL, calldescr,
+                                                  ConstInt(func),
+                                                  str1box, str2box)
 
     def setfield(self, descr, structbox, fieldnum):
         if descr.is_pointer_field():



More information about the Pypy-commit mailing list