[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