[pypy-svn] r77780 - in pypy/branch/jit-str-unicode/pypy/jit: backend/test backend/x86 backend/x86/test codewriter codewriter/test metainterp metainterp/optimizeopt metainterp/test

arigo at codespeak.net arigo at codespeak.net
Mon Oct 11 14:26:23 CEST 2010


Author: arigo
Date: Mon Oct 11 14:26:19 2010
New Revision: 77780

Modified:
   pypy/branch/jit-str-unicode/pypy/jit/backend/test/runner_test.py
   pypy/branch/jit-str-unicode/pypy/jit/backend/test/test_ll_random.py
   pypy/branch/jit-str-unicode/pypy/jit/backend/x86/regalloc.py
   pypy/branch/jit-str-unicode/pypy/jit/backend/x86/test/test_string.py
   pypy/branch/jit-str-unicode/pypy/jit/codewriter/effectinfo.py
   pypy/branch/jit-str-unicode/pypy/jit/codewriter/jtransform.py
   pypy/branch/jit-str-unicode/pypy/jit/codewriter/test/test_jtransform.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/history.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/intbounds.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/rewrite.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/string.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/resume.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/oparser.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizefindnode.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizeopt.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_resume.py
   pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_string.py
Log:
Check-in.  Should be done.


Modified: pypy/branch/jit-str-unicode/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/backend/test/runner_test.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/backend/test/runner_test.py	Mon Oct 11 14:26:19 2010
@@ -833,6 +833,23 @@
                                                         length_box], 'void')
                                 assert self.look_string(r_box) == "!??cdef?!"
 
+    def test_copyunicodecontent(self):
+        s_box = self.alloc_unicode(u"abcdef")
+        for s_box in [s_box, s_box.constbox()]:
+            for srcstart_box in [BoxInt(2), ConstInt(2)]:
+                for dststart_box in [BoxInt(3), ConstInt(3)]:
+                    for length_box in [BoxInt(4), ConstInt(4)]:
+                        for r_box_is_const in [False, True]:
+                            r_box = self.alloc_unicode(u"!???????!")
+                            if r_box_is_const:
+                                r_box = r_box.constbox()
+                                self.execute_operation(rop.COPYUNICODECONTENT,
+                                                       [s_box, r_box,
+                                                        srcstart_box,
+                                                        dststart_box,
+                                                        length_box], 'void')
+                                assert self.look_unicode(r_box) == u"!??cdef?!"
+
     def test_do_unicode_basic(self):
         u = self.cpu.bh_newunicode(5)
         self.cpu.bh_unicodesetitem(u, 4, 123)
@@ -1227,6 +1244,10 @@
         u_box = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, u))
         return u_box
 
+    def look_unicode(self, unicode_box):
+        u = unicode_box.getref(lltype.Ptr(rstr.UNICODE))
+        return u''.join(u.chars)
+
 
     def test_casts(self):
         py.test.skip("xxx fix or kill")

Modified: pypy/branch/jit-str-unicode/pypy/jit/backend/test/test_ll_random.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/backend/test/test_ll_random.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/backend/test/test_ll_random.py	Mon Oct 11 14:26:19 2010
@@ -599,7 +599,7 @@
     OPERATIONS.append(StrLenOperation(rop.STRLEN))
     OPERATIONS.append(UnicodeLenOperation(rop.UNICODELEN))
     OPERATIONS.append(CopyStrContentOperation(rop.COPYSTRCONTENT))
-    #OPERATIONS.append(CopyUnicodeContentOperation(rop.COPYUNICODECONTENT))
+    OPERATIONS.append(CopyUnicodeContentOperation(rop.COPYUNICODECONTENT))
 
 for i in range(2):
     OPERATIONS.append(GuardClassOperation(rop.GUARD_CLASS))

Modified: pypy/branch/jit-str-unicode/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/backend/x86/regalloc.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/backend/x86/regalloc.py	Mon Oct 11 14:26:19 2010
@@ -778,15 +778,11 @@
             loc = self.loc(op.getarg(0))
             return self._call(op, [loc])
         # boehm GC (XXX kill the following code at some point)
-        ofs_items, itemsize, ofs = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code)
-        if itemsize == 4:
-            return self._malloc_varsize(ofs_items, ofs, 2, op.getarg(0),
-                                        op.result)
-        elif itemsize == 2:
-            return self._malloc_varsize(ofs_items, ofs, 1, op.getarg(0),
-                                        op.result)
-        else:
-            assert False, itemsize
+        ofs_items, _, ofs = symbolic.get_array_token(rstr.UNICODE,
+                                                   self.translate_support_code)
+        scale = self._get_unicode_item_scale()
+        return self._malloc_varsize(ofs_items, ofs, scale, op.getarg(0),
+                                    op.result)
 
     def _malloc_varsize(self, ofs_items, ofs_length, scale, v, res_v):
         # XXX kill this function at some point
@@ -959,6 +955,12 @@
     consider_unicodegetitem = consider_strgetitem
 
     def consider_copystrcontent(self, op):
+        self._consider_copystrcontent(op, is_unicode=False)
+
+    def consider_copyunicodecontent(self, op):
+        self._consider_copystrcontent(op, is_unicode=True)
+
+    def _consider_copystrcontent(self, op, is_unicode):
         # compute the source address
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(args[0], args)
@@ -970,7 +972,8 @@
         srcaddr_box = TempBox()
         forbidden_vars = [args[1], args[3], args[4], srcaddr_box]
         srcaddr_loc = self.rm.force_allocate_reg(srcaddr_box, forbidden_vars)
-        self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc)
+        self._gen_address_inside_string(base_loc, ofs_loc, srcaddr_loc,
+                                        is_unicode=is_unicode)
         # compute the destination address
         base_loc = self.rm.make_sure_var_in_reg(args[1], forbidden_vars)
         ofs_loc = self.rm.make_sure_var_in_reg(args[3], forbidden_vars)
@@ -980,25 +983,57 @@
         forbidden_vars = [args[4], srcaddr_box]
         dstaddr_box = TempBox()
         dstaddr_loc = self.rm.force_allocate_reg(dstaddr_box, forbidden_vars)
-        self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc)
+        self._gen_address_inside_string(base_loc, ofs_loc, dstaddr_loc,
+                                        is_unicode=is_unicode)
+        # compute the length in bytes
+        length_box = args[4]
+        length_loc = self.loc(length_box)
+        if is_unicode:
+            self.rm.possibly_free_var(length_box)
+            forbidden_vars = [srcaddr_box, dstaddr_box]
+            bytes_box = TempBox()
+            bytes_loc = self.rm.force_allocate_reg(bytes_box, forbidden_vars)
+            scale = self._get_unicode_item_scale()
+            if not (isinstance(length_loc, ImmedLoc) or
+                    isinstance(length_loc, RegLoc)):
+                self.assembler.mov(length_loc, bytes_loc)
+                length_loc = bytes_loc
+            self.assembler.load_effective_addr(length_loc, 0, scale, bytes_loc)
+            length_box = bytes_box
+            length_loc = bytes_loc
         # call memcpy()
-        length_loc = self.loc(args[4])
         self.rm.before_call()
         self.xrm.before_call()
         self.assembler._emit_call(imm(self.assembler.memcpy_addr),
                                   [dstaddr_loc, srcaddr_loc, length_loc])
-        self.rm.possibly_free_var(args[4])
+        self.rm.possibly_free_var(length_box)
         self.rm.possibly_free_var(dstaddr_box)
         self.rm.possibly_free_var(srcaddr_box)
 
-    def _gen_address_inside_string(self, baseloc, ofsloc, resloc):
+    def _gen_address_inside_string(self, baseloc, ofsloc, resloc, is_unicode):
         cpu = self.assembler.cpu
-        ofs_items, itemsize, _ = symbolic.get_array_token(rstr.STR,
+        if is_unicode:
+            ofs_items, _, _ = symbolic.get_array_token(rstr.UNICODE,
+                                                  self.translate_support_code)
+            scale = self._get_unicode_item_scale()
+        else:
+            ofs_items, itemsize, _ = symbolic.get_array_token(rstr.STR,
                                                   self.translate_support_code)
-        assert itemsize == 1
-        self.assembler.load_effective_addr(ofsloc, ofs_items, 0,
+            assert itemsize == 1
+            scale = 0
+        self.assembler.load_effective_addr(ofsloc, ofs_items, scale,
                                            resloc, baseloc)
 
+    def _get_unicode_item_scale(self):
+        _, itemsize, _ = symbolic.get_array_token(rstr.UNICODE,
+                                                  self.translate_support_code)
+        if itemsize == 4:
+            return 2
+        elif itemsize == 2:
+            return 1
+        else:
+            raise AssertionError("bad unicode item size")
+
     def consider_jump(self, op):
         assembler = self.assembler
         assert self.jump_target_descr is None

Modified: pypy/branch/jit-str-unicode/pypy/jit/backend/x86/test/test_string.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/backend/x86/test/test_string.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/backend/x86/test/test_string.py	Mon Oct 11 14:26:19 2010
@@ -2,8 +2,12 @@
 from pypy.jit.metainterp.test import test_string
 from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
 
-class TestString(Jit386Mixin, test_string.StringTests):
+class TestString(Jit386Mixin, test_string.TestLLtype):
     # for the individual tests see
     # ====> ../../../metainterp/test/test_string.py
-    CALL = 'call'
-    CALL_PURE = 'call_pure'
+    pass
+
+class TestUnicode(Jit386Mixin, test_string.TestLLtypeUnicode):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_string.py
+    pass

Modified: pypy/branch/jit-str-unicode/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/codewriter/effectinfo.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/codewriter/effectinfo.py	Mon Oct 11 14:26:19 2010
@@ -18,19 +18,30 @@
     # the 'oopspecindex' field is one of the following values:
     OS_NONE                     = 0    # normal case, no oopspec
     OS_ARRAYCOPY                = 1    # "list.ll_arraycopy"
-    OS_STR_CONCAT               = 2    # "stroruni.concat"
-    OS_UNI_CONCAT               = 3    # "stroruni.concat"
-    OS_STR_SLICE                = 4    # "stroruni.slice"
-    OS_UNI_SLICE                = 5    # "stroruni.slice"
-    OS_STR_EQUAL                = 6    # "stroruni.equal"
-    OS_UNI_EQUAL                = 7    # "stroruni.equal"
-    OS_STREQ_SLICE_CHECKNULL    = 8    # s2!=NULL and s1[x:x+length]==s2
-    OS_STREQ_SLICE_NONNULL      = 9    # s1[x:x+length]==s2   (assert s2!=NULL)
-    OS_STREQ_SLICE_CHAR         = 10   # s1[x:x+length]==char
-    OS_STREQ_NONNULL            = 11   # s1 == s2    (assert s1!=NULL,s2!=NULL)
-    OS_STREQ_NONNULL_CHAR       = 12   # s1 == char  (assert s1!=NULL)
-    OS_STREQ_CHECKNULL_CHAR     = 13   # s1!=NULL and s1==char
-    OS_STREQ_LENGTHOK           = 14   # s1 == s2    (assert len(s1)==len(s2))
+    OS_STR2UNICODE              = 2    # "str.str2unicode"
+
+    OS_STR_CONCAT               = 22   # "stroruni.concat"
+    OS_STR_SLICE                = 23   # "stroruni.slice"
+    OS_STR_EQUAL                = 24   # "stroruni.equal"
+    OS_STREQ_SLICE_CHECKNULL    = 25   # s2!=NULL and s1[x:x+length]==s2
+    OS_STREQ_SLICE_NONNULL      = 26   # s1[x:x+length]==s2   (assert s2!=NULL)
+    OS_STREQ_SLICE_CHAR         = 27   # s1[x:x+length]==char
+    OS_STREQ_NONNULL            = 28   # s1 == s2    (assert s1!=NULL,s2!=NULL)
+    OS_STREQ_NONNULL_CHAR       = 29   # s1 == char  (assert s1!=NULL)
+    OS_STREQ_CHECKNULL_CHAR     = 30   # s1!=NULL and s1==char
+    OS_STREQ_LENGTHOK           = 31   # s1 == s2    (assert len(s1)==len(s2))
+
+    OS_UNI_CONCAT               = 42   #
+    OS_UNI_SLICE                = 43   #
+    OS_UNI_EQUAL                = 44   #
+    OS_UNIEQ_SLICE_CHECKNULL    = 45   #
+    OS_UNIEQ_SLICE_NONNULL      = 46   #
+    OS_UNIEQ_SLICE_CHAR         = 47   #
+    OS_UNIEQ_NONNULL            = 48   #   the same for unicode
+    OS_UNIEQ_NONNULL_CHAR       = 49   #   (must be the same amount as for
+    OS_UNIEQ_CHECKNULL_CHAR     = 50   #   STR, in the same order)
+    OS_UNIEQ_LENGTHOK           = 51   #
+    _OS_offset_uni              = OS_UNI_CONCAT - OS_STR_CONCAT
 
     def __new__(cls, readonly_descrs_fields,
                 write_descrs_fields, write_descrs_arrays,

Modified: pypy/branch/jit-str-unicode/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/codewriter/jtransform.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/codewriter/jtransform.py	Mon Oct 11 14:26:19 2010
@@ -316,6 +316,8 @@
             prepare = self._handle_list_call
         elif oopspec_name.startswith('stroruni.'):
             prepare = self._handle_stroruni_call
+        elif oopspec_name == 'str.str2unicode':
+            prepare = self._handle_str2unicode_call
         elif oopspec_name.startswith('virtual_ref'):
             prepare = self._handle_virtual_ref_call
         else:
@@ -1106,11 +1108,16 @@
                      [SoU, SoU],
                      lltype.Signed),
                 ]:
+                if args[0].concretetype.TO == rstr.UNICODE:
+                    otherindex += EffectInfo._OS_offset_uni
                 self._register_extra_helper(otherindex, othername,
                                             argtypes, resulttype)
         #
         return self._handle_oopspec_call(op, args, dict[oopspec_name])
 
+    def _handle_str2unicode_call(self, op, oopspec_name, args):
+        return self._handle_oopspec_call(op, args, EffectInfo.OS_STR2UNICODE)
+
     # ----------
     # VirtualRefs.
 

Modified: pypy/branch/jit-str-unicode/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/codewriter/test/test_jtransform.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/codewriter/test/test_jtransform.py	Mon Oct 11 14:26:19 2010
@@ -77,7 +77,8 @@
 class FakeBuiltinCallControl:
     def guess_call_kind(self, op):
         return 'builtin'
-    def getcalldescr(self, op, oopspecindex):
+    def getcalldescr(self, op, oopspecindex=None):
+        assert oopspecindex is not None    # in this test
         return 'calldescr-%d' % oopspecindex
     def calldescr_canraise(self, calldescr):
         return False
@@ -766,6 +767,24 @@
     assert op1.args[3] == ListOfKind('ref', [v1])
     assert op1.result == v4
 
+def test_str2unicode():
+    # test that the oopspec is present and correctly transformed
+    PSTR = lltype.Ptr(rstr.STR)
+    PUNICODE = lltype.Ptr(rstr.UNICODE)
+    FUNC = lltype.FuncType([PSTR], PUNICODE)
+    func = lltype.functionptr(FUNC, 'll_str2unicode',
+                            _callable=rstr.LLHelpers.ll_str2unicode)
+    v1 = varoftype(PSTR)
+    v2 = varoftype(PUNICODE)
+    op = SpaceOperation('direct_call', [const(func), v1], v2)
+    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+    op1 = tr.rewrite_operation(op)
+    assert op1.opname == 'residual_call_r_r'
+    assert op1.args[0].value == func
+    assert op1.args[1] == 'calldescr-%d' % effectinfo.EffectInfo.OS_STR2UNICODE
+    assert op1.args[2] == ListOfKind('ref', [v1])
+    assert op1.result == v2
+
 def test_list_ll_arraycopy():
     from pypy.rlib.rgc import ll_arraycopy
     LIST = lltype.GcArray(lltype.Signed)

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/history.py	Mon Oct 11 14:26:19 2010
@@ -698,6 +698,21 @@
     return result
 _const_ptr_for_string = {}
 
+def get_const_ptr_for_unicode(s):
+    from pypy.rpython.annlowlevel import llunicode
+    if not we_are_translated():
+        try:
+            return _const_ptr_for_unicode[s]
+        except KeyError:
+            pass
+    if isinstance(s, str):
+        s = unicode(s)
+    result = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, llunicode(s)))
+    if not we_are_translated():
+        _const_ptr_for_unicode[s] = result
+    return result
+_const_ptr_for_unicode = {}
+
 # ____________________________________________________________
 
 # The TreeLoop class contains a loop or a generalized loop, i.e. a tree

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/intbounds.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/intbounds.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/intbounds.py	Mon Oct 11 14:26:19 2010
@@ -191,6 +191,7 @@
         v1.intbound.make_ge(IntLowerBound(0))
 
     optimize_STRLEN = optimize_ARRAYLEN_GC
+    optimize_UNICODELEN = optimize_ARRAYLEN_GC
 
     def make_int_lt(self, box1, box2):
         v1 = self.getvalue(box1)

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/rewrite.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/rewrite.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/rewrite.py	Mon Oct 11 14:26:19 2010
@@ -3,6 +3,7 @@
 from pypy.jit.metainterp.history import ConstInt
 from pypy.jit.metainterp.optimizeutil import _findall
 from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.codewriter.effectinfo import EffectInfo
 
 class OptRewrite(Optimization):
     """Rewrite operations into equivalent, cheaper operations.
@@ -326,8 +327,37 @@
 ##            return
 ##        self.emit_operation(op)
 
-optimize_ops = _findall(OptRewrite, 'optimize_')
-        
+    def optimize_CALL(self, op):
+        # dispatch based on 'oopspecindex' to a method that handles
+        # specifically the given oopspec call.  For non-oopspec calls,
+        # oopspecindex is just zero.
+        effectinfo = op.getdescr().get_extra_info()
+        if effectinfo is not None:
+            oopspecindex = effectinfo.oopspecindex
+            if oopspecindex == EffectInfo.OS_ARRAYCOPY:
+                if self._optimize_CALL_ARRAYCOPY(op):
+                    return
+        self.emit_operation(op)
 
+    def _optimize_CALL_ARRAYCOPY(self, op):
+        source_value = self.getvalue(op.getarg(1))
+        dest_value = self.getvalue(op.getarg(2))
+        source_start_box = self.get_constant_box(op.getarg(3))
+        dest_start_box = self.get_constant_box(op.getarg(4))
+        length = self.get_constant_box(op.getarg(5))
+        if (source_value.is_virtual() and source_start_box and dest_start_box
+            and length and dest_value.is_virtual()):
+            # XXX optimize the case where dest value is not virtual,
+            #     but we still can avoid a mess
+            source_start = source_start_box.getint()
+            dest_start = dest_start_box.getint()
+            for index in range(length.getint()):
+                val = source_value.getitem(index + source_start)
+                dest_value.setitem(index + dest_start, val)
+            return True
+        if length and length.getint() == 0:
+            return True # 0-length arraycopy
+        return False
+
+optimize_ops = _findall(OptRewrite, 'optimize_')
 
-        

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/string.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/string.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/optimizeopt/string.py	Mon Oct 11 14:26:19 2010
@@ -3,6 +3,7 @@
 from pypy.jit.metainterp.history import Box, BoxInt, BoxPtr
 from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr
 from pypy.jit.metainterp.history import get_const_ptr_for_string
+from pypy.jit.metainterp.history import get_const_ptr_for_unicode
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.metainterp.optimizeopt import optimizer, virtualize
 from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
@@ -11,56 +12,103 @@
 from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
 from pypy.jit.codewriter import heaptracker
 from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.objectmodel import specialize
+
+
+class StrOrUnicode(object):
+    def __init__(self, LLTYPE, hlstr, emptystr, chr,
+                 NEWSTR, STRLEN, STRGETITEM, STRSETITEM, COPYSTRCONTENT,
+                 OS_offset):
+        self.LLTYPE = LLTYPE
+        self.hlstr = hlstr
+        self.emptystr = emptystr
+        self.chr = chr
+        self.NEWSTR = NEWSTR
+        self.STRLEN = STRLEN
+        self.STRGETITEM = STRGETITEM
+        self.STRSETITEM = STRSETITEM
+        self.COPYSTRCONTENT = COPYSTRCONTENT
+        self.OS_offset = OS_offset
+
+    def _freeze_(self):
+        return True
+
+mode_string = StrOrUnicode(rstr.STR, annlowlevel.hlstr, '', chr,
+                           rop.NEWSTR, rop.STRLEN, rop.STRGETITEM,
+                           rop.STRSETITEM, rop.COPYSTRCONTENT, 0)
+mode_unicode = StrOrUnicode(rstr.UNICODE, annlowlevel.hlunicode, u'', unichr,
+                            rop.NEWUNICODE, rop.UNICODELEN, rop.UNICODEGETITEM,
+                            rop.UNICODESETITEM, rop.COPYUNICODECONTENT,
+                            EffectInfo._OS_offset_uni)
+
+# ____________________________________________________________
 
 
 class __extend__(optimizer.OptValue):
     """New methods added to the base class OptValue for this file."""
 
-    def getstrlen(self, newoperations):
-        s = self.get_constant_string()
-        if s is not None:
-            return ConstInt(len(s))
+    def getstrlen(self, newoperations, mode):
+        if mode is mode_string:
+            s = self.get_constant_string_spec(mode_string)
+            if s is not None:
+                return ConstInt(len(s))
         else:
-            if newoperations is None:
-                return None
-            self.ensure_nonnull()
-            box = self.force_box()
-            lengthbox = BoxInt()
-            newoperations.append(ResOperation(rop.STRLEN, [box], lengthbox))
-            return lengthbox
+            s = self.get_constant_string_spec(mode_unicode)
+            if s is not None:
+                return ConstInt(len(s))
+        if newoperations is None:
+            return None
+        self.ensure_nonnull()
+        box = self.force_box()
+        lengthbox = BoxInt()
+        newoperations.append(ResOperation(mode.STRLEN, [box], lengthbox))
+        return lengthbox
 
-    def get_constant_string(self):
+    @specialize.arg(1)
+    def get_constant_string_spec(self, mode):
         if self.is_constant():
-            s = self.box.getref(lltype.Ptr(rstr.STR))
-            return annlowlevel.hlstr(s)
+            s = self.box.getref(lltype.Ptr(mode.LLTYPE))
+            return mode.hlstr(s)
         else:
             return None
 
-    def string_copy_parts(self, newoperations, targetbox, offsetbox):
+    def string_copy_parts(self, newoperations, targetbox, offsetbox, mode):
         # Copies the pointer-to-string 'self' into the target string
         # given by 'targetbox', at the specified offset.  Returns the offset
         # at the end of the copy.
-        lengthbox = self.getstrlen(newoperations)
+        lengthbox = self.getstrlen(newoperations, mode)
         srcbox = self.force_box()
         return copy_str_content(newoperations, srcbox, targetbox,
-                                CONST_0, offsetbox, lengthbox)
+                                CONST_0, offsetbox, lengthbox, mode)
 
 
 class VAbstractStringValue(virtualize.AbstractVirtualValue):
-    _attrs_ = ()
+    _attrs_ = ('mode',)
+
+    def __init__(self, optimizer, keybox, source_op, mode):
+        virtualize.AbstractVirtualValue.__init__(self, optimizer, keybox,
+                                                 source_op)
+        self.mode = mode
 
     def _really_force(self):
-        s = self.get_constant_string()
-        if s is not None:
-            c_s = get_const_ptr_for_string(s)
-            self.make_constant(c_s)
-            return
+        if self.mode is mode_string:
+            s = self.get_constant_string_spec(mode_string)
+            if s is not None:
+                c_s = get_const_ptr_for_string(s)
+                self.make_constant(c_s)
+                return
+        else:
+            s = self.get_constant_string_spec(mode_unicode)
+            if s is not None:
+                c_s = get_const_ptr_for_unicode(s)
+                self.make_constant(c_s)
+                return
         assert self.source_op is not None
         self.box = box = self.source_op.result
         newoperations = self.optimizer.newoperations
-        lengthbox = self.getstrlen(newoperations)
-        newoperations.append(ResOperation(rop.NEWSTR, [lengthbox], box))
-        self.string_copy_parts(newoperations, box, CONST_0)
+        lengthbox = self.getstrlen(newoperations, self.mode)
+        newoperations.append(ResOperation(self.mode.NEWSTR, [lengthbox], box))
+        self.string_copy_parts(newoperations, box, CONST_0, self.mode)
 
 
 class VStringPlainValue(VAbstractStringValue):
@@ -74,7 +122,7 @@
         assert 0 <= start <= stop <= len(longerlist)
         self._chars = longerlist[start:stop]
 
-    def getstrlen(self, _):
+    def getstrlen(self, _, mode):
         if self._lengthbox is None:
             self._lengthbox = ConstInt(len(self._chars))
         return self._lengthbox
@@ -86,18 +134,21 @@
         assert isinstance(charvalue, optimizer.OptValue)
         self._chars[index] = charvalue
 
-    def get_constant_string(self):
+    @specialize.arg(1)
+    def get_constant_string_spec(self, mode):
         for c in self._chars:
             if c is optimizer.CVAL_UNINITIALIZED_ZERO or not c.is_constant():
                 return None
-        return ''.join([chr(c.box.getint()) for c in self._chars])
+        return mode.emptystr.join([mode.chr(c.box.getint())
+                                   for c in self._chars])
 
-    def string_copy_parts(self, newoperations, targetbox, offsetbox):
+    def string_copy_parts(self, newoperations, targetbox, offsetbox, mode):
         for i in range(len(self._chars)):
             charbox = self._chars[i].force_box()
-            newoperations.append(ResOperation(rop.STRSETITEM, [targetbox,
-                                                               offsetbox,
-                                                               charbox], None))
+            newoperations.append(ResOperation(mode.STRSETITEM, [targetbox,
+                                                                offsetbox,
+                                                                charbox],
+                                              None))
             offsetbox = _int_add(newoperations, offsetbox, CONST_1)
         return offsetbox
 
@@ -109,7 +160,7 @@
                 value.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
-        return modifier.make_vstrplain()
+        return modifier.make_vstrplain(self.mode is mode_unicode)
 
 
 class VStringConcatValue(VAbstractStringValue):
@@ -120,23 +171,24 @@
         self.right = right
         self.lengthbox = lengthbox
 
-    def getstrlen(self, _):
+    def getstrlen(self, _, mode):
         return self.lengthbox
 
-    def get_constant_string(self):
-        s1 = self.left.get_constant_string()
+    @specialize.arg(1)
+    def get_constant_string_spec(self, mode):
+        s1 = self.left.get_constant_string_spec(mode)
         if s1 is None:
             return None
-        s2 = self.right.get_constant_string()
+        s2 = self.right.get_constant_string_spec(mode)
         if s2 is None:
             return None
         return s1 + s2
 
-    def string_copy_parts(self, newoperations, targetbox, offsetbox):
+    def string_copy_parts(self, newoperations, targetbox, offsetbox, mode):
         offsetbox = self.left.string_copy_parts(newoperations, targetbox,
-                                                offsetbox)
+                                                offsetbox, mode)
         offsetbox = self.right.string_copy_parts(newoperations, targetbox,
-                                                 offsetbox)
+                                                 offsetbox, mode)
         return offsetbox
 
     def get_args_for_fail(self, modifier):
@@ -150,7 +202,7 @@
             self.right.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
-        return modifier.make_vstrconcat()
+        return modifier.make_vstrconcat(self.mode is mode_unicode)
 
 
 class VStringSliceValue(VAbstractStringValue):
@@ -162,12 +214,13 @@
         self.vstart = vstart
         self.vlength = vlength
 
-    def getstrlen(self, _):
+    def getstrlen(self, _, mode):
         return self.vlength.force_box()
 
-    def get_constant_string(self):
+    @specialize.arg(1)
+    def get_constant_string_spec(self, mode):
         if self.vstart.is_constant() and self.vlength.is_constant():
-            s1 = self.vstr.get_constant_string()
+            s1 = self.vstr.get_constant_string_spec(mode)
             if s1 is None:
                 return None
             start = self.vstart.box.getint()
@@ -177,12 +230,12 @@
             return s1[start : start + length]
         return None
 
-    def string_copy_parts(self, newoperations, targetbox, offsetbox):
-        lengthbox = self.getstrlen(newoperations)
+    def string_copy_parts(self, newoperations, targetbox, offsetbox, mode):
+        lengthbox = self.getstrlen(newoperations, mode)
         return copy_str_content(newoperations,
                                 self.vstr.force_box(), targetbox,
                                 self.vstart.force_box(), offsetbox,
-                                lengthbox)
+                                lengthbox, mode)
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
@@ -195,11 +248,11 @@
             self.vlength.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
-        return modifier.make_vstrslice()
+        return modifier.make_vstrslice(self.mode is mode_unicode)
 
 
 def copy_str_content(newoperations, srcbox, targetbox,
-                     srcoffsetbox, offsetbox, lengthbox):
+                     srcoffsetbox, offsetbox, lengthbox, mode):
     if isinstance(srcbox, ConstPtr) and isinstance(srcoffsetbox, Const):
         M = 5
     else:
@@ -208,17 +261,18 @@
         # up to M characters are done "inline", i.e. with STRGETITEM/STRSETITEM
         # instead of just a COPYSTRCONTENT.
         for i in range(lengthbox.value):
-            charbox = _strgetitem(newoperations, srcbox, srcoffsetbox)
+            charbox = _strgetitem(newoperations, srcbox, srcoffsetbox, mode)
             srcoffsetbox = _int_add(newoperations, srcoffsetbox, CONST_1)
-            newoperations.append(ResOperation(rop.STRSETITEM, [targetbox,
-                                                               offsetbox,
-                                                               charbox], None))
+            newoperations.append(ResOperation(mode.STRSETITEM, [targetbox,
+                                                                offsetbox,
+                                                                charbox],
+                                              None))
             offsetbox = _int_add(newoperations, offsetbox, CONST_1)
     else:
         nextoffsetbox = _int_add(newoperations, offsetbox, lengthbox)
-        op = ResOperation(rop.COPYSTRCONTENT, [srcbox, targetbox,
-                                               srcoffsetbox, offsetbox,
-                                               lengthbox], None)
+        op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox,
+                                                srcoffsetbox, offsetbox,
+                                                lengthbox], None)
         newoperations.append(op)
         offsetbox = nextoffsetbox
     return offsetbox
@@ -245,12 +299,16 @@
     newoperations.append(ResOperation(rop.INT_SUB, [box1, box2], resbox))
     return resbox
 
-def _strgetitem(newoperations, strbox, indexbox):
+def _strgetitem(newoperations, strbox, indexbox, mode):
     if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt):
-        s = strbox.getref(lltype.Ptr(rstr.STR))
-        return ConstInt(ord(s.chars[indexbox.getint()]))
+        if mode is mode_string:
+            s = strbox.getref(lltype.Ptr(rstr.STR))
+            return ConstInt(ord(s.chars[indexbox.getint()]))
+        else:
+            s = strbox.getref(lltype.Ptr(rstr.UNICODE))
+            return ConstInt(ord(s.chars[indexbox.getint()]))
     resbox = BoxInt()
-    newoperations.append(ResOperation(rop.STRGETITEM, [strbox, indexbox],
+    newoperations.append(ResOperation(mode.STRGETITEM, [strbox, indexbox],
                                       resbox))
     return resbox
 
@@ -258,62 +316,34 @@
 class OptString(optimizer.Optimization):
     "Handling of strings and unicodes."
 
-    def make_vstring_plain(self, box, source_op=None):
-        vvalue = VStringPlainValue(self.optimizer, box, source_op)
+    def make_vstring_plain(self, box, source_op, mode):
+        vvalue = VStringPlainValue(self.optimizer, box, source_op, mode)
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def make_vstring_concat(self, box, source_op=None):
-        vvalue = VStringConcatValue(self.optimizer, box, source_op)
+    def make_vstring_concat(self, box, source_op, mode):
+        vvalue = VStringConcatValue(self.optimizer, box, source_op, mode)
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def make_vstring_slice(self, box, source_op=None):
-        vvalue = VStringSliceValue(self.optimizer, box, source_op)
+    def make_vstring_slice(self, box, source_op, mode):
+        vvalue = VStringSliceValue(self.optimizer, box, source_op, mode)
         self.make_equal_to(box, vvalue)
         return vvalue
 
-    def optimize_CALL(self, op):
-        # dispatch based on 'oopspecindex' to a method that handles
-        # specifically the given oopspec call.  For non-oopspec calls,
-        # oopspecindex is just zero.
-        effectinfo = op.getdescr().get_extra_info()
-        if effectinfo is not None:
-            oopspecindex = effectinfo.oopspecindex
-            for value, meth in opt_call_oopspec_ops:
-                if oopspecindex == value:
-                    if meth(self, op):
-                        return
-        self.emit_operation(op)
-
-    def opt_call_oopspec_ARRAYCOPY(self, op):
-        source_value = self.getvalue(op.getarg(1))
-        dest_value = self.getvalue(op.getarg(2))
-        source_start_box = self.get_constant_box(op.getarg(3))
-        dest_start_box = self.get_constant_box(op.getarg(4))
-        length = self.get_constant_box(op.getarg(5))
-        if (source_value.is_virtual() and source_start_box and dest_start_box
-            and length and dest_value.is_virtual()):
-            # XXX optimize the case where dest value is not virtual,
-            #     but we still can avoid a mess
-            source_start = source_start_box.getint()
-            dest_start = dest_start_box.getint()
-            for index in range(length.getint()):
-                val = source_value.getitem(index + source_start)
-                dest_value.setitem(index + dest_start, val)
-            return True
-        if length and length.getint() == 0:
-            return True # 0-length arraycopy
-        return False
-
     def optimize_NEWSTR(self, op):
+        self._optimize_NEWSTR(op, mode_string)
+    def optimize_NEWUNICODE(self, op):
+        self._optimize_NEWSTR(op, mode_unicode)
+
+    def _optimize_NEWSTR(self, op, mode):
         length_box = self.get_constant_box(op.getarg(0))
         if length_box:
             # if the original 'op' did not have a ConstInt as argument,
             # build a new one with the ConstInt argument
             if not isinstance(op.getarg(0), ConstInt):
-                op = ResOperation(rop.NEWSTR, [length_box], op.result)
-            vvalue = self.make_vstring_plain(op.result, op)
+                op = ResOperation(mode.NEWSTR, [length_box], op.result)
+            vvalue = self.make_vstring_plain(op.result, op, mode)
             vvalue.setup(length_box.getint())
         else:
             self.getvalue(op.result).ensure_nonnull()
@@ -329,13 +359,20 @@
         value.ensure_nonnull()
         self.emit_operation(op)
 
+    optimize_UNICODESETITEM = optimize_STRSETITEM
+
     def optimize_STRGETITEM(self, op):
+        self._optimize_STRGETITEM(op, mode_string)
+    def optimize_UNICODEGETITEM(self, op):
+        self._optimize_STRGETITEM(op, mode_unicode)
+
+    def _optimize_STRGETITEM(self, op, mode):
         value = self.getvalue(op.getarg(0))
         vindex = self.getvalue(op.getarg(1))
-        vresult = self.strgetitem(value, vindex)
+        vresult = self.strgetitem(value, vindex, mode)
         self.make_equal_to(op.result, vresult)
 
-    def strgetitem(self, value, vindex):
+    def strgetitem(self, value, vindex, mode):
         value.ensure_nonnull()
         #
         if value.is_virtual() and isinstance(value, VStringSliceValue):
@@ -350,28 +387,71 @@
                 return value.getitem(vindex.box.getint())
         #
         resbox = _strgetitem(self.optimizer.newoperations,
-                             value.force_box(),vindex.force_box())
+                             value.force_box(),vindex.force_box(), mode)
         return self.getvalue(resbox)
 
     def optimize_STRLEN(self, op):
+        self._optimize_STRLEN(op, mode_string)
+    def optimize_UNICODELEN(self, op):
+        self._optimize_STRLEN(op, mode_unicode)
+
+    def _optimize_STRLEN(self, op, mode):
         value = self.getvalue(op.getarg(0))
-        lengthbox = value.getstrlen(self.optimizer.newoperations)
+        lengthbox = value.getstrlen(self.optimizer.newoperations, mode)
         self.make_equal_to(op.result, self.getvalue(lengthbox))
 
-    def opt_call_oopspec_STR_CONCAT(self, op):
+    def optimize_CALL(self, op):
+        # dispatch based on 'oopspecindex' to a method that handles
+        # specifically the given oopspec call.  For non-oopspec calls,
+        # oopspecindex is just zero.
+        effectinfo = op.getdescr().get_extra_info()
+        if effectinfo is not None:
+            oopspecindex = effectinfo.oopspecindex
+            for value, meth in opt_call_oopspec_ops:
+                if oopspecindex == value:      # a match with the OS_STR_xxx
+                    if meth(self, op, mode_string):
+                        return
+                    break
+                if oopspecindex == value + EffectInfo._OS_offset_uni:
+                    # a match with the OS_UNI_xxx
+                    if meth(self, op, mode_unicode):
+                        return
+                    break
+            if oopspecindex == EffectInfo.OS_STR2UNICODE:
+                if self.opt_call_str_STR2UNICODE(op):
+                    return
+        self.emit_operation(op)
+
+    def opt_call_str_STR2UNICODE(self, op):
+        # Constant-fold unicode("constant string").
+        # More generally, supporting non-constant but virtual cases is
+        # not obvious, because of the exception UnicodeDecodeError that
+        # can be raised by ll_str2unicode()
+        varg = self.getvalue(op.getarg(1))
+        s = varg.get_constant_string_spec(mode_string)
+        if s is None:
+            return False
+        try:
+            u = unicode(s)
+        except UnicodeDecodeError:
+            return False
+        self.make_constant(op.result, get_const_ptr_for_unicode(u))
+        return True
+
+    def opt_call_stroruni_STR_CONCAT(self, op, mode):
         vleft = self.getvalue(op.getarg(1))
         vright = self.getvalue(op.getarg(2))
         vleft.ensure_nonnull()
         vright.ensure_nonnull()
         newoperations = self.optimizer.newoperations
-        len1box = vleft.getstrlen(newoperations)
-        len2box = vright.getstrlen(newoperations)
+        len1box = vleft.getstrlen(newoperations, mode)
+        len2box = vright.getstrlen(newoperations, mode)
         lengthbox = _int_add(newoperations, len1box, len2box)
-        value = self.make_vstring_concat(op.result, op)
+        value = self.make_vstring_concat(op.result, op, mode)
         value.setup(vleft, vright, lengthbox)
         return True
 
-    def opt_call_oopspec_STR_SLICE(self, op):
+    def opt_call_stroruni_STR_SLICE(self, op, mode):
         newoperations = self.optimizer.newoperations
         vstr = self.getvalue(op.getarg(1))
         vstart = self.getvalue(op.getarg(2))
@@ -380,7 +460,7 @@
         if (isinstance(vstr, VStringPlainValue) and vstart.is_constant()
             and vstop.is_constant()):
             # slicing with constant bounds of a VStringPlainValue
-            value = self.make_vstring_plain(op.result, op)
+            value = self.make_vstring_plain(op.result, op, mode)
             value.setup_slice(vstr._chars, vstart.box.getint(),
                                            vstop.box.getint())
             return True
@@ -398,16 +478,16 @@
                                 vstart.force_box())
             vstart = self.getvalue(startbox)
         #
-        value = self.make_vstring_slice(op.result, op)
+        value = self.make_vstring_slice(op.result, op, mode)
         value.setup(vstr, vstart, self.getvalue(lengthbox))
         return True
 
-    def opt_call_oopspec_STR_EQUAL(self, op):
+    def opt_call_stroruni_STR_EQUAL(self, op, mode):
         v1 = self.getvalue(op.getarg(1))
         v2 = self.getvalue(op.getarg(2))
         #
-        l1box = v1.getstrlen(None)
-        l2box = v2.getstrlen(None)
+        l1box = v1.getstrlen(None, mode)
+        l2box = v2.getstrlen(None, mode)
         if (l1box is not None and l2box is not None and
             isinstance(l1box, ConstInt) and
             isinstance(l2box, ConstInt) and
@@ -416,13 +496,13 @@
             self.make_constant(op.result, CONST_0)
             return True
         #
-        if self.handle_str_equal_level1(v1, v2, op.result):
+        if self.handle_str_equal_level1(v1, v2, op.result, mode):
             return True
-        if self.handle_str_equal_level1(v2, v1, op.result):
+        if self.handle_str_equal_level1(v2, v1, op.result, mode):
             return True
-        if self.handle_str_equal_level2(v1, v2, op.result):
+        if self.handle_str_equal_level2(v1, v2, op.result, mode):
             return True
-        if self.handle_str_equal_level2(v2, v1, op.result):
+        if self.handle_str_equal_level2(v2, v1, op.result, mode):
             return True
         #
         if v1.is_nonnull() and v2.is_nonnull():
@@ -434,37 +514,37 @@
             else:
                 do = EffectInfo.OS_STREQ_NONNULL
             self.generate_modified_call(do, [v1.force_box(),
-                                             v2.force_box()], op.result)
+                                             v2.force_box()], op.result, mode)
             return True
         return False
 
-    def handle_str_equal_level1(self, v1, v2, resultbox):
-        l2box = v2.getstrlen(None)
+    def handle_str_equal_level1(self, v1, v2, resultbox, mode):
+        l2box = v2.getstrlen(None, mode)
         if isinstance(l2box, ConstInt):
             if l2box.value == 0:
-                lengthbox = v1.getstrlen(self.optimizer.newoperations)
+                lengthbox = v1.getstrlen(self.optimizer.newoperations, mode)
                 seo = self.optimizer.send_extra_operation
                 seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox))
                 return True
             if l2box.value == 1:
-                l1box = v1.getstrlen(None)
+                l1box = v1.getstrlen(None, mode)
                 if isinstance(l1box, ConstInt) and l1box.value == 1:
                     # comparing two single chars
-                    vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO)
-                    vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO)
+                    vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
+                    vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
                     seo = self.optimizer.send_extra_operation
                     seo(ResOperation(rop.INT_EQ, [vchar1.force_box(),
                                                   vchar2.force_box()],
                                      resultbox))
                     return True
                 if isinstance(v1, VStringSliceValue):
-                    vchar = self.strgetitem(v2, optimizer.CVAL_ZERO)
+                    vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
                     do = EffectInfo.OS_STREQ_SLICE_CHAR
                     self.generate_modified_call(do, [v1.vstr.force_box(),
                                                      v1.vstart.force_box(),
                                                      v1.vlength.force_box(),
                                                      vchar.force_box()],
-                                                resultbox)
+                                                resultbox, mode)
                     return True
         #
         if v2.is_null():
@@ -482,17 +562,18 @@
         #
         return False
 
-    def handle_str_equal_level2(self, v1, v2, resultbox):
-        l2box = v2.getstrlen(None)
+    def handle_str_equal_level2(self, v1, v2, resultbox, mode):
+        l2box = v2.getstrlen(None, mode)
         if isinstance(l2box, ConstInt):
             if l2box.value == 1:
-                vchar = self.strgetitem(v2, optimizer.CVAL_ZERO)
+                vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
                 if v1.is_nonnull():
                     do = EffectInfo.OS_STREQ_NONNULL_CHAR
                 else:
                     do = EffectInfo.OS_STREQ_CHECKNULL_CHAR
                 self.generate_modified_call(do, [v1.force_box(),
-                                                 vchar.force_box()], resultbox)
+                                                 vchar.force_box()], resultbox,
+                                            mode)
                 return True
         #
         if v1.is_virtual() and isinstance(v1, VStringSliceValue):
@@ -503,11 +584,12 @@
             self.generate_modified_call(do, [v1.vstr.force_box(),
                                              v1.vstart.force_box(),
                                              v1.vlength.force_box(),
-                                             v2.force_box()], resultbox)
+                                             v2.force_box()], resultbox, mode)
             return True
         return False
 
-    def generate_modified_call(self, oopspecindex, args, result):
+    def generate_modified_call(self, oopspecindex, args, result, mode):
+        oopspecindex += mode.OS_offset
         calldescr, func = callinfo_for_oopspec(oopspecindex)
         op = ResOperation(rop.CALL, [ConstInt(func)] + args, result,
                           descr=calldescr)
@@ -525,7 +607,7 @@
 optimize_ops = _findall(OptString, 'optimize_')
 
 def _findall_call_oopspec():
-    prefix = 'opt_call_oopspec_'
+    prefix = 'opt_call_stroruni_'
     result = []
     for name in dir(OptString):
         if name.startswith(prefix):

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/resume.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/resume.py	Mon Oct 11 14:26:19 2010
@@ -255,13 +255,19 @@
     def make_varray(self, arraydescr):
         return VArrayInfo(arraydescr)
 
-    def make_vstrplain(self):
+    def make_vstrplain(self, is_unicode=False):
+        if is_unicode:
+            return VUniPlainInfo()
         return VStrPlainInfo()
 
-    def make_vstrconcat(self):
+    def make_vstrconcat(self, is_unicode=False):
+        if is_unicode:
+            return VUniConcatInfo()
         return VStrConcatInfo()
 
-    def make_vstrslice(self):
+    def make_vstrslice(self, is_unicode=False):
+        if is_unicode:
+            return VUniSliceInfo()
         return VStrSliceInfo()
 
     def register_virtual_fields(self, virtualbox, fieldboxes):
@@ -550,6 +556,60 @@
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
+
+class VUniPlainInfo(AbstractVirtualInfo):
+    """Stands for the unicode string made out of the characters of all
+    fieldnums."""
+
+    @specialize.argtype(1)
+    def allocate(self, decoder, index):
+        length = len(self.fieldnums)
+        string = decoder.allocate_unicode(length)
+        decoder.virtuals_cache[index] = string
+        for i in range(length):
+            decoder.unicode_setitem(string, i, self.fieldnums[i])
+        return string
+
+    def debug_prints(self):
+        debug_print("\tvuniplaininfo length", len(self.fieldnums))
+
+
+class VUniConcatInfo(AbstractVirtualInfo):
+    """Stands for the unicode string made out of the concatenation of two
+    other unicode strings."""
+
+    @specialize.argtype(1)
+    def allocate(self, decoder, index):
+        # 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
+        string = decoder.concat_unicodes(left, right)
+        decoder.virtuals_cache[index] = string
+        return string
+
+    def debug_prints(self):
+        debug_print("\tvuniconcatinfo")
+        for i in self.fieldnums:
+            debug_print("\t\t", str(untag(i)))
+
+
+class VUniSliceInfo(AbstractVirtualInfo):
+    """Stands for the unicode string made out of slicing another
+    unicode string."""
+
+    @specialize.argtype(1)
+    def allocate(self, decoder, index):
+        largerstr, start, length = self.fieldnums
+        string = decoder.slice_unicode(largerstr, start, length)
+        decoder.virtuals_cache[index] = string
+        return string
+
+    def debug_prints(self):
+        debug_print("\tvunisliceinfo")
+        for i in self.fieldnums:
+            debug_print("\t\t", str(untag(i)))
+
 # ____________________________________________________________
 
 class AbstractResumeDataReader(object):
@@ -725,6 +785,32 @@
         return self.metainterp.execute_and_record_varargs(
             rop.CALL, [ConstInt(func), strbox, startbox, stopbox], calldescr)
 
+    def allocate_unicode(self, length):
+        return self.metainterp.execute_and_record(rop.NEWUNICODE,
+                                                  None, ConstInt(length))
+
+    def unicode_setitem(self, strbox, index, charnum):
+        charbox = self.decode_box(charnum, INT)
+        self.metainterp.execute_and_record(rop.UNICODESETITEM, None,
+                                           strbox, ConstInt(index), charbox)
+
+    def concat_unicodes(self, str1num, str2num):
+        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+        str1box = self.decode_box(str1num, REF)
+        str2box = self.decode_box(str2num, REF)
+        return self.metainterp.execute_and_record_varargs(
+            rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
+
+    def slice_unicode(self, strnum, startnum, lengthnum):
+        calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
+        strbox = self.decode_box(strnum, REF)
+        startbox = self.decode_box(startnum, INT)
+        lengthbox = self.decode_box(lengthnum, INT)
+        stopbox = self.metainterp.execute_and_record(rop.INT_ADD, None,
+                                                     startbox, lengthbox)
+        return self.metainterp.execute_and_record_varargs(
+            rop.CALL, [ConstInt(func), strbox, startbox, stopbox], calldescr)
+
     def setfield(self, descr, structbox, fieldnum):
         if descr.is_pointer_field():
             kind = REF
@@ -967,6 +1053,31 @@
         result = funcptr(str, start, start + length)
         return lltype.cast_opaque_ptr(llmemory.GCREF, result)
 
+    def allocate_unicode(self, length):
+        return self.cpu.bh_newunicode(length)
+
+    def unicode_setitem(self, str, index, charnum):
+        char = self.decode_int(charnum)
+        self.cpu.bh_unicodesetitem(str, index, char)
+
+    def concat_unicodes(self, str1num, str2num):
+        str1 = self.decode_ref(str1num)
+        str2 = self.decode_ref(str2num)
+        str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str1)
+        str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str2)
+        funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+        result = funcptr(str1, str2)
+        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
+
+    def slice_unicode(self, strnum, startnum, lengthnum):
+        str = self.decode_ref(strnum)
+        start = self.decode_int(startnum)
+        length = self.decode_int(lengthnum)
+        str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str)
+        funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
+        result = funcptr(str, start, start + length)
+        return lltype.cast_opaque_ptr(llmemory.GCREF, result)
+
     def setfield(self, descr, struct, fieldnum):
         if descr.is_pointer_field():
             newvalue = self.decode_ref(fieldnum)

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/oparser.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/oparser.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/oparser.py	Mon Oct 11 14:26:19 2010
@@ -5,7 +5,7 @@
 
 from pypy.jit.metainterp.history import TreeLoop, BoxInt, ConstInt,\
      ConstObj, ConstPtr, Box, BasicFailDescr, BoxFloat, ConstFloat,\
-     LoopToken, get_const_ptr_for_string
+     LoopToken, get_const_ptr_for_string, get_const_ptr_for_unicode
 from pypy.jit.metainterp.resoperation import rop, ResOperation, ResOpWithDescr, N_aryOp
 from pypy.jit.metainterp.typesystem import llhelper
 from pypy.jit.codewriter.heaptracker import adr2int
@@ -158,10 +158,15 @@
         except ValueError:
             if self.is_float(arg):
                 return ConstFloat(float(arg))
-            if arg.startswith('"') or arg.startswith("'"):
+            if (arg.startswith('"') or arg.startswith("'") or
+                arg.startswith('s"')):
                 # XXX ootype
-                info = arg.strip("'\"")
+                info = arg[1:].strip("'\"")
                 return get_const_ptr_for_string(info)
+            if arg.startswith('u"'):
+                # XXX ootype
+                info = arg[1:].strip("'\"")
+                return get_const_ptr_for_unicode(info)
             if arg.startswith('ConstClass('):
                 name = arg[len('ConstClass('):-1]
                 return self.get_const(name, 'class')

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizefindnode.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizefindnode.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizefindnode.py	Mon Oct 11 14:26:19 2010
@@ -117,33 +117,32 @@
                             EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE))
     arraycopydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
                  EffectInfo([], [], [], oopspecindex=EffectInfo.OS_ARRAYCOPY))
-    strconcatdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR_CONCAT))
-    slicedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR_SLICE))
-    strequaldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR_EQUAL))
-    streq_slice_checknull_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_SLICE_CHECKNULL))
-    streq_slice_nonnull_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_SLICE_NONNULL))
-    streq_slice_char_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_SLICE_CHAR))
-    streq_nonnull_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_NONNULL))
-    streq_nonnull_char_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_NONNULL_CHAR))
-    streq_checknull_char_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_CHECKNULL_CHAR))
-    streq_lengthok_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
-                 EffectInfo([], [], [],
-                     oopspecindex=EffectInfo.OS_STREQ_LENGTHOK))
+
+    for _name, _os in [
+        ('strconcatdescr',               'OS_STR_CONCAT'),
+        ('strslicedescr',                'OS_STR_SLICE'),
+        ('strequaldescr',                'OS_STR_EQUAL'),
+        ('streq_slice_checknull_descr',  'OS_STREQ_SLICE_CHECKNULL'),
+        ('streq_slice_nonnull_descr',    'OS_STREQ_SLICE_NONNULL'),
+        ('streq_slice_char_descr',       'OS_STREQ_SLICE_CHAR'),
+        ('streq_nonnull_descr',          'OS_STREQ_NONNULL'),
+        ('streq_nonnull_char_descr',     'OS_STREQ_NONNULL_CHAR'),
+        ('streq_checknull_char_descr',   'OS_STREQ_CHECKNULL_CHAR'),
+        ('streq_lengthok_descr',         'OS_STREQ_LENGTHOK'),
+        ]:
+        _oopspecindex = getattr(EffectInfo, _os)
+        locals()[_name] = \
+            cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                EffectInfo([], [], [], oopspecindex=_oopspecindex))
+        #
+        _oopspecindex = getattr(EffectInfo, _os.replace('STR', 'UNI'))
+        locals()[_name.replace('str', 'unicode')] = \
+            cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                EffectInfo([], [], [], oopspecindex=_oopspecindex))
+
+    s2u_descr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+                EffectInfo([], [], [], oopspecindex=EffectInfo.OS_STR2UNICODE))
+    #
 
     class LoopToken(AbstractDescr):
         pass

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizeopt.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_optimizeopt.py	Mon Oct 11 14:26:19 2010
@@ -3487,7 +3487,7 @@
         i0 = strlen(p0)
         jump(p0)
         """
-        self.optimize_loop(ops, 'Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not', expected)
 
     def test_addsub_const(self):
         ops = """
@@ -3893,6 +3893,15 @@
         """
         self.optimize_loop(ops, 'Not, Not', expected)
 
+    # ----------
+    def optimize_strunicode_loop(self, ops, spectext, optops):
+        # check with the arguments passed in
+        self.optimize_loop(ops, spectext, optops)
+        # check with replacing 'str' with 'unicode' everywhere
+        self.optimize_loop(ops.replace('str','unicode').replace('s"', 'u"'),
+                           spectext,
+                           optops.replace('str','unicode').replace('s"', 'u"'))
+
     def test_newstr_1(self):
         ops = """
         [i0]
@@ -3905,7 +3914,7 @@
         [i0]
         jump(i0)
         """
-        self.optimize_loop(ops, 'Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not', expected)
 
     def test_newstr_2(self):
         ops = """
@@ -3921,7 +3930,7 @@
         [i0, i1]
         jump(i1, i0)
         """
-        self.optimize_loop(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not', expected)
 
     def test_str_concat_1(self):
         ops = """
@@ -3942,7 +3951,7 @@
         copystrcontent(p2, p3, 0, i4, i5)
         jump(p2, p3)
         """
-        self.optimize_loop(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not', expected)
 
     def test_str_concat_vstr2_str(self):
         ops = """
@@ -3965,7 +3974,7 @@
         copystrcontent(p2, p3, 0, 2, i4)
         jump(i1, i0, p3)
         """
-        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
 
     def test_str_concat_str_vstr2(self):
         ops = """
@@ -3989,7 +3998,7 @@
         i6 = int_add(i5, 1)      # will be killed by the backend
         jump(i1, i0, p3)
         """
-        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
 
     def test_str_concat_str_str_str(self):
         ops = """
@@ -4016,12 +4025,12 @@
         copystrcontent(p3, p5, 0, i12b, i3b)
         jump(p2, p3, p5)
         """
-        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
 
     def test_str_concat_str_cstr1(self):
         ops = """
         [p2]
-        p3 = call(0, p2, "x", descr=strconcatdescr)
+        p3 = call(0, p2, s"x", descr=strconcatdescr)
         jump(p3)
         """
         expected = """
@@ -4035,28 +4044,28 @@
         i5 = int_add(i4, 1)      # will be killed by the backend
         jump(p3)
         """
-        self.optimize_loop(ops, 'Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not', expected)
 
     def test_str_concat_consts(self):
         ops = """
         []
-        p1 = same_as("ab")
-        p2 = same_as("cde")
+        p1 = same_as(s"ab")
+        p2 = same_as(s"cde")
         p3 = call(0, p1, p2, descr=strconcatdescr)
         escape(p3)
         jump()
         """
         expected = """
         []
-        escape("abcde")
+        escape(s"abcde")
         jump()
         """
-        self.optimize_loop(ops, '', expected)
+        self.optimize_strunicode_loop(ops, '', expected)
 
     def test_str_slice_1(self):
         ops = """
         [p1, i1, i2]
-        p2 = call(0, p1, i1, i2, descr=slicedescr)
+        p2 = call(0, p1, i1, i2, descr=strslicedescr)
         jump(p2, i1, i2)
         """
         expected = """
@@ -4066,12 +4075,12 @@
         copystrcontent(p1, p2, i1, 0, i3)
         jump(p2, i1, i2)
         """
-        self.optimize_loop(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not', expected)
 
     def test_str_slice_2(self):
         ops = """
         [p1, i2]
-        p2 = call(0, p1, 0, i2, descr=slicedescr)
+        p2 = call(0, p1, 0, i2, descr=strslicedescr)
         jump(p2, i2)
         """
         expected = """
@@ -4080,13 +4089,13 @@
         copystrcontent(p1, p2, 0, 0, i2)
         jump(p2, i2)
         """
-        self.optimize_loop(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not', expected)
 
     def test_str_slice_3(self):
         ops = """
         [p1, i1, i2, i3, i4]
-        p2 = call(0, p1, i1, i2, descr=slicedescr)
-        p3 = call(0, p2, i3, i4, descr=slicedescr)
+        p2 = call(0, p1, i1, i2, descr=strslicedescr)
+        p3 = call(0, p2, i3, i4, descr=strslicedescr)
         jump(p3, i1, i2, i3, i4)
         """
         expected = """
@@ -4098,12 +4107,12 @@
         copystrcontent(p1, p3, i6, 0, i5)
         jump(p3, i1, i2, i3, i4)
         """
-        self.optimize_loop(ops, 'Not, Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not, Not', expected)
 
     def test_str_slice_getitem1(self):
         ops = """
         [p1, i1, i2, i3]
-        p2 = call(0, p1, i1, i2, descr=slicedescr)
+        p2 = call(0, p1, i1, i2, descr=strslicedescr)
         i4 = strgetitem(p2, i3)
         escape(i4)
         jump(p1, i1, i2, i3)
@@ -4116,7 +4125,7 @@
         escape(i4)
         jump(p1, i1, i2, i3)
         """
-        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not', expected)
 
     def test_str_slice_plain(self):
         ops = """
@@ -4124,7 +4133,7 @@
         p1 = newstr(2)
         strsetitem(p1, 0, i3)
         strsetitem(p1, 1, i4)
-        p2 = call(0, p1, 1, 2, descr=slicedescr)
+        p2 = call(0, p1, 1, 2, descr=strslicedescr)
         i5 = strgetitem(p2, 0)
         escape(i5)
         jump(i3, i4)
@@ -4134,12 +4143,12 @@
         escape(i4)
         jump(i3, i4)
         """
-        self.optimize_loop(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not', expected)
 
     def test_str_slice_concat(self):
         ops = """
         [p1, i1, i2, p2]
-        p3 = call(0, p1, i1, i2, descr=slicedescr)
+        p3 = call(0, p1, i1, i2, descr=strslicedescr)
         p4 = call(0, p3, p2, descr=strconcatdescr)
         jump(p4, i1, i2, p2)
         """
@@ -4155,10 +4164,10 @@
         copystrcontent(p2, p4, 0, i3, i4b)
         jump(p4, i1, i2, p2)
         """
-        self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop(ops, 'Not, Not, Not, Not', expected)
 
     # ----------
-    def optimize_loop_extradescrs(self, ops, spectext, optops):
+    def optimize_strunicode_loop_extradescrs(self, ops, spectext, optops):
         from pypy.jit.metainterp.optimizeopt import string
         def my_callinfo_for_oopspec(oopspecindex):
             calldescrtype = type(LLtypeMixin.strequaldescr)
@@ -4173,7 +4182,7 @@
         saved = string.callinfo_for_oopspec
         try:
             string.callinfo_for_oopspec = my_callinfo_for_oopspec
-            self.optimize_loop(ops, spectext, optops)
+            self.optimize_strunicode_loop(ops, spectext, optops)
         finally:
             string.callinfo_for_oopspec = saved
 
@@ -4184,7 +4193,7 @@
         escape(i0)
         jump(p1, p2)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not', ops)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', ops)
 
     def test_str_equal_noop2(self):
         ops = """
@@ -4209,12 +4218,13 @@
         escape(i0)
         jump(p1, p2, p3)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_slice1(self):
         ops = """
         [p1, i1, i2, p3]
-        p4 = call(0, p1, i1, i2, descr=slicedescr)
+        p4 = call(0, p1, i1, i2, descr=strslicedescr)
         i0 = call(0, p4, p3, descr=strequaldescr)
         escape(i0)
         jump(p1, i1, i2, p3)
@@ -4226,12 +4236,13 @@
         escape(i0)
         jump(p1, i1, i2, p3)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_slice2(self):
         ops = """
         [p1, i1, i2, p3]
-        p4 = call(0, p1, i1, i2, descr=slicedescr)
+        p4 = call(0, p1, i1, i2, descr=strslicedescr)
         i0 = call(0, p3, p4, descr=strequaldescr)
         escape(i0)
         jump(p1, i1, i2, p3)
@@ -4243,13 +4254,14 @@
         escape(i0)
         jump(p1, i1, i2, p3)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_slice3(self):
         ops = """
         [p1, i1, i2, p3]
         guard_nonnull(p3) []
-        p4 = call(0, p1, i1, i2, descr=slicedescr)
+        p4 = call(0, p1, i1, i2, descr=strslicedescr)
         i0 = call(0, p3, p4, descr=strequaldescr)
         escape(i0)
         jump(p1, i1, i2, p3)
@@ -4262,13 +4274,14 @@
         escape(i0)
         jump(p1, i1, i2, p3)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_slice4(self):
         ops = """
         [p1, i1, i2]
-        p3 = call(0, p1, i1, i2, descr=slicedescr)
-        i0 = call(0, p3, "x", descr=strequaldescr)
+        p3 = call(0, p1, i1, i2, descr=strslicedescr)
+        i0 = call(0, p3, s"x", descr=strequaldescr)
         escape(i0)
         jump(p1, i1, i2)
         """
@@ -4279,12 +4292,13 @@
         escape(i0)
         jump(p1, i1, i2)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_slice5(self):
         ops = """
         [p1, i1, i2, i3]
-        p4 = call(0, p1, i1, i2, descr=slicedescr)
+        p4 = call(0, p1, i1, i2, descr=strslicedescr)
         p5 = newstr(1)
         strsetitem(p5, 0, i3)
         i0 = call(0, p5, p4, descr=strequaldescr)
@@ -4298,7 +4312,8 @@
         escape(i0)
         jump(p1, i1, i2, i3)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not, Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not, Not, Not',
+                                                  expected)
 
     def test_str_equal_none1(self):
         ops = """
@@ -4313,7 +4328,7 @@
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_none2(self):
         ops = """
@@ -4328,30 +4343,30 @@
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_nonnull1(self):
         ops = """
         [p1]
         guard_nonnull(p1) []
-        i0 = call(0, p1, "hello world", descr=strequaldescr)
+        i0 = call(0, p1, s"hello world", descr=strequaldescr)
         escape(i0)
         jump(p1)
         """
         expected = """
         [p1]
         guard_nonnull(p1) []
-        i0 = call(0, p1, "hello world", descr=streq_nonnull_descr)
+        i0 = call(0, p1, s"hello world", descr=streq_nonnull_descr)
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_nonnull2(self):
         ops = """
         [p1]
         guard_nonnull(p1) []
-        i0 = call(0, p1, "", descr=strequaldescr)
+        i0 = call(0, p1, s"", descr=strequaldescr)
         escape(i0)
         jump(p1)
         """
@@ -4363,13 +4378,13 @@
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_nonnull3(self):
         ops = """
         [p1]
         guard_nonnull(p1) []
-        i0 = call(0, p1, "x", descr=strequaldescr)
+        i0 = call(0, p1, s"x", descr=strequaldescr)
         escape(i0)
         jump(p1)
         """
@@ -4380,13 +4395,13 @@
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_nonnull4(self):
         ops = """
         [p1, p2]
         p4 = call(0, p1, p2, descr=strconcatdescr)
-        i0 = call(0, "hello world", p4, descr=strequaldescr)
+        i0 = call(0, s"hello world", p4, descr=strequaldescr)
         escape(i0)
         jump(p1, p2)
         """
@@ -4401,17 +4416,17 @@
         i5 = strlen(p2)
         i6 = int_add(i4, i5)      # will be killed by the backend
         copystrcontent(p2, p4, 0, i4, i5)
-        i0 = call(0, "hello world", p4, descr=streq_nonnull_descr)
+        i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr)
         escape(i0)
         jump(p1, p2)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', expected)
 
     def test_str_equal_chars0(self):
         ops = """
         [i1]
         p1 = newstr(0)
-        i0 = call(0, p1, "", descr=strequaldescr)
+        i0 = call(0, p1, s"", descr=strequaldescr)
         escape(i0)
         jump(i1)
         """
@@ -4420,14 +4435,14 @@
         escape(1)
         jump(i1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_chars1(self):
         ops = """
         [i1]
         p1 = newstr(1)
         strsetitem(p1, 0, i1)
-        i0 = call(0, p1, "x", descr=strequaldescr)
+        i0 = call(0, p1, s"x", descr=strequaldescr)
         escape(i0)
         jump(i1)
         """
@@ -4437,7 +4452,7 @@
         escape(i0)
         jump(i1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_chars2(self):
         ops = """
@@ -4445,7 +4460,7 @@
         p1 = newstr(2)
         strsetitem(p1, 0, i1)
         strsetitem(p1, 1, i2)
-        i0 = call(0, p1, "xy", descr=strequaldescr)
+        i0 = call(0, p1, s"xy", descr=strequaldescr)
         escape(i0)
         jump(i1, i2)
         """
@@ -4454,16 +4469,16 @@
         p1 = newstr(2)
         strsetitem(p1, 0, i1)
         strsetitem(p1, 1, i2)
-        i0 = call(0, p1, "xy", descr=streq_lengthok_descr)
+        i0 = call(0, p1, s"xy", descr=streq_lengthok_descr)
         escape(i0)
         jump(i1, i2)
         """
-        self.optimize_loop_extradescrs(ops, 'Not, Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not, Not', expected)
 
     def test_str_equal_chars3(self):
         ops = """
         [p1]
-        i0 = call(0, "x", p1, descr=strequaldescr)
+        i0 = call(0, s"x", p1, descr=strequaldescr)
         escape(i0)
         jump(p1)
         """
@@ -4473,14 +4488,14 @@
         escape(i0)
         jump(p1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
     def test_str_equal_lengthmismatch1(self):
         ops = """
         [i1]
         p1 = newstr(1)
         strsetitem(p1, 0, i1)
-        i0 = call(0, "xy", p1, descr=strequaldescr)
+        i0 = call(0, s"xy", p1, descr=strequaldescr)
         escape(i0)
         jump(i1)
         """
@@ -4489,10 +4504,33 @@
         escape(0)
         jump(i1)
         """
-        self.optimize_loop_extradescrs(ops, 'Not', expected)
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', expected)
 
-    # XXX unicode operations
-    # XXX str2unicode
+    def test_str2unicode_constant(self):
+        ops = """
+        []
+        p0 = call(0, "xy", descr=s2u_descr)      # string -> unicode
+        escape(p0)
+        jump()
+        """
+        expected = """
+        []
+        escape(u"xy")
+        jump()
+        """
+        self.optimize_strunicode_loop_extradescrs(ops, '', expected)
+
+    def test_str2unicode_nonconstant(self):
+        ops = """
+        [p0]
+        p1 = call(0, p0, descr=s2u_descr)      # string -> unicode
+        escape(p1)
+        jump(p1)
+        """
+        self.optimize_strunicode_loop_extradescrs(ops, 'Not', ops)
+        # more generally, supporting non-constant but virtual cases is
+        # not obvious, because of the exception UnicodeDecodeError that
+        # can be raised by ll_str2unicode()
 
 
 ##class TestOOtype(BaseTestOptimizeOpt, OOtypeMixin):

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_resume.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_resume.py	Mon Oct 11 14:26:19 2010
@@ -240,6 +240,17 @@
         return FakeBuiltObject(strconcat=[left, right])
     def slice_string(self, str, start, length):
         return FakeBuiltObject(strslice=[str, start, length])
+    def allocate_unicode(self, length):
+        return FakeBuiltObject(unistring=[None]*length)
+    def unicode_setitem(self, unistring, i, fieldnum):
+        value, tag = untag(fieldnum)
+        assert tag == TAGINT
+        assert 0 <= i < len(unistring.unistring)
+        unistring.unistring[i] = value
+    def concat_unicodes(self, left, right):
+        return FakeBuiltObject(uniconcat=[left, right])
+    def slice_unicode(self, str, start, length):
+        return FakeBuiltObject(unislice=[str, start, length])
 
 class FakeBuiltObject(object):
     def __init__(self, **kwds):
@@ -304,6 +315,30 @@
     assert reader.force_all_virtuals() == [
         FakeBuiltObject(strslice=info.fieldnums)]
 
+def test_vuniplaininfo():
+    info = VUniPlainInfo()
+    info.fieldnums = [tag(60, TAGINT)]
+    reader = FakeResumeDataReader()
+    reader._prepare_virtuals([info])
+    assert reader.force_all_virtuals() == [
+        FakeBuiltObject(unistring=[60])]
+
+def test_vuniconcatinfo():
+    info = VUniConcatInfo()
+    info.fieldnums = [tag(10, TAGBOX), tag(20, TAGBOX)]
+    reader = FakeResumeDataReader()
+    reader._prepare_virtuals([info])
+    assert reader.force_all_virtuals() == [
+        FakeBuiltObject(uniconcat=info.fieldnums)]
+
+def test_vunisliceinfo():
+    info = VUniSliceInfo()
+    info.fieldnums = [tag(10, TAGBOX), tag(20, TAGBOX), tag(30, TAGBOX)]
+    reader = FakeResumeDataReader()
+    reader._prepare_virtuals([info])
+    assert reader.force_all_virtuals() == [
+        FakeBuiltObject(unislice=info.fieldnums)]
+
 # ____________________________________________________________
 
 

Modified: pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_string.py
==============================================================================
--- pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_string.py	(original)
+++ pypy/branch/jit-str-unicode/pypy/jit/metainterp/test/test_string.py	Mon Oct 11 14:26:19 2010
@@ -6,14 +6,17 @@
 
 
 class StringTests:
+    _str, _chr = str, chr
+
     def test_eq_residual(self):
+        _str = self._str
         jitdriver = JitDriver(greens = [], reds = ['n', 'i', 's'])
-        global_s = "hello"
+        global_s = _str("hello")
         def f(n, b, s):
             if b:
-                s += "ello"
+                s += _str("ello")
             else:
-                s += "allo"
+                s += _str("allo")
             i = 0
             while n > 0:
                 jitdriver.can_enter_jit(s=s, n=n, i=i)
@@ -21,18 +24,19 @@
                 n -= 1 + (s == global_s)
                 i += 1
             return i
-        res = self.meta_interp(f, [10, True, 'h'], listops=True)
+        res = self.meta_interp(f, [10, True, _str('h')], listops=True)
         assert res == 5
         self.check_loops(**{self.CALL: 1, self.CALL_PURE: 0})
 
     def test_eq_folded(self):
+        _str = self._str
         jitdriver = JitDriver(greens = ['s'], reds = ['n', 'i'])
-        global_s = "hello"
+        global_s = _str("hello")
         def f(n, b, s):
             if b:
-                s += "ello"
+                s += _str("ello")
             else:
-                s += "allo"
+                s += _str("allo")
             i = 0
             while n > 0:
                 jitdriver.can_enter_jit(s=s, n=n, i=i)
@@ -40,31 +44,18 @@
                 n -= 1 + (s == global_s)
                 i += 1
             return i
-        res = self.meta_interp(f, [10, True, 'h'], listops=True)
+        res = self.meta_interp(f, [10, True, _str('h')], listops=True)
         assert res == 5
         self.check_loops(**{self.CALL: 0, self.CALL_PURE: 0})
 
     def test_newstr(self):
+        _str, _chr = self._str, self._chr
         jitdriver = JitDriver(greens = [], reds = ['n', 'm'])
         def f(n, m):
             while True:
                 jitdriver.can_enter_jit(m=m, n=n)
                 jitdriver.jit_merge_point(m=m, n=n)
-                bytecode = 'adlfkj' + chr(n)
-                res = bytecode[n]
-                m -= 1
-                if m < 0:
-                    return ord(res)
-        res = self.meta_interp(f, [6, 10])
-        assert res == 6
-
-    def test_newunicode(self):
-        jitdriver = JitDriver(greens = [], reds = ['n', 'm'])
-        def f(n, m):
-            while True:
-                jitdriver.can_enter_jit(m=m, n=n)
-                jitdriver.jit_merge_point(m=m, n=n)
-                bytecode = u'adlfkj' + unichr(n)
+                bytecode = _str('adlfkj') + _chr(n)
                 res = bytecode[n]
                 m -= 1
                 if m < 0:
@@ -73,95 +64,96 @@
         assert res == 6
 
     def test_char2string_pure(self):
-        for dochr in [chr, ]: #unichr]:
-            jitdriver = JitDriver(greens = [], reds = ['n'])
-            @dont_look_inside
-            def escape(x):
-                pass
-            def f(n):
-                while n > 0:
-                    jitdriver.can_enter_jit(n=n)
-                    jitdriver.jit_merge_point(n=n)
-                    s = dochr(n)
-                    if not we_are_jitted():
-                        s += s     # forces to be a string
-                    if n > 100:
-                        escape(s)
-                    n -= 1
-                return 42
-            self.meta_interp(f, [6])
-            self.check_loops(newstr=0, strsetitem=0, strlen=0,
-                             newunicode=0, unicodesetitem=0, unicodelen=0)
+        _str, _chr = self._str, self._chr
+        jitdriver = JitDriver(greens = [], reds = ['n'])
+        @dont_look_inside
+        def escape(x):
+            pass
+        def f(n):
+            while n > 0:
+                jitdriver.can_enter_jit(n=n)
+                jitdriver.jit_merge_point(n=n)
+                s = _chr(n)
+                if not we_are_jitted():
+                    s += s     # forces to be a string
+                if n > 100:
+                    escape(s)
+                n -= 1
+            return 42
+        self.meta_interp(f, [6])
+        self.check_loops(newstr=0, strsetitem=0, strlen=0,
+                         newunicode=0, unicodesetitem=0, unicodelen=0)
 
     def test_char2string_escape(self):
-        for dochr in [chr, ]: #unichr]:
-            jitdriver = JitDriver(greens = [], reds = ['n', 'total'])
-            @dont_look_inside
-            def escape(x):
-                return ord(x[0])
-            def f(n):
-                total = 0
-                while n > 0:
-                    jitdriver.can_enter_jit(n=n, total=total)
-                    jitdriver.jit_merge_point(n=n, total=total)
-                    s = dochr(n)
-                    if not we_are_jitted():
-                        s += s    # forces to be a string
-                    total += escape(s)
-                    n -= 1
-                return total
-            res = self.meta_interp(f, [6])
-            assert res == 21
+        _str, _chr = self._str, self._chr
+        jitdriver = JitDriver(greens = [], reds = ['n', 'total'])
+        @dont_look_inside
+        def escape(x):
+            return ord(x[0])
+        def f(n):
+            total = 0
+            while n > 0:
+                jitdriver.can_enter_jit(n=n, total=total)
+                jitdriver.jit_merge_point(n=n, total=total)
+                s = _chr(n)
+                if not we_are_jitted():
+                    s += s    # forces to be a string
+                total += escape(s)
+                n -= 1
+            return total
+        res = self.meta_interp(f, [6])
+        assert res == 21
 
     def test_char2string2char(self):
-        for dochr in [chr, ]: #unichr]:
-            jitdriver = JitDriver(greens = [], reds = ['m', 'total'])
-            def f(m):
-                total = 0
-                while m > 0:
-                    jitdriver.can_enter_jit(m=m, total=total)
-                    jitdriver.jit_merge_point(m=m, total=total)
-                    string = dochr(m)
-                    if m > 100:
-                        string += string    # forces to be a string
-                    # read back the character
-                    c = string[0]
-                    total += ord(c)
-                    m -= 1
-                return total
-            res = self.meta_interp(f, [6])
-            assert res == 21
-            self.check_loops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
-                             newunicode=0, unicodegetitem=0, unicodesetitem=0,
-                             unicodelen=0)
+        _str, _chr = self._str, self._chr
+        jitdriver = JitDriver(greens = [], reds = ['m', 'total'])
+        def f(m):
+            total = 0
+            while m > 0:
+                jitdriver.can_enter_jit(m=m, total=total)
+                jitdriver.jit_merge_point(m=m, total=total)
+                string = _chr(m)
+                if m > 100:
+                    string += string    # forces to be a string
+                # read back the character
+                c = string[0]
+                total += ord(c)
+                m -= 1
+            return total
+        res = self.meta_interp(f, [6])
+        assert res == 21
+        self.check_loops(newstr=0, strgetitem=0, strsetitem=0, strlen=0,
+                         newunicode=0, unicodegetitem=0, unicodesetitem=0,
+                         unicodelen=0)
 
     def test_strconcat_pure(self):
-        for somestr in ["abc", ]: #u"def"]:
-            jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
-            @dont_look_inside
-            def escape(x):
-                pass
-            mylist = [somestr+str(i) for i in range(10)]
-            def f(n, m):
-                while m >= 0:
-                    jitdriver.can_enter_jit(m=m, n=n)
-                    jitdriver.jit_merge_point(m=m, n=n)
-                    s = mylist[n] + mylist[m]
-                    if m > 100:
-                        escape(s)
-                    m -= 1
-                return 42
-            self.meta_interp(f, [6, 7])
-            self.check_loops(newstr=0, strsetitem=0,
-                             newunicode=0, unicodesetitem=0,
-                             call=0, call_pure=0)
+        _str = self._str
+        jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
+        @dont_look_inside
+        def escape(x):
+            pass
+        mylist = [_str("abc") + _str(i) for i in range(10)]
+        def f(n, m):
+            while m >= 0:
+                jitdriver.can_enter_jit(m=m, n=n)
+                jitdriver.jit_merge_point(m=m, n=n)
+                s = mylist[n] + mylist[m]
+                if m > 100:
+                    escape(s)
+                m -= 1
+            return 42
+        self.meta_interp(f, [6, 7])
+        self.check_loops(newstr=0, strsetitem=0,
+                         newunicode=0, unicodesetitem=0,
+                         call=0, call_pure=0)
 
     def test_strconcat_escape_str_str(self):
+        _str = self._str
         jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
         @dont_look_inside
         def escape(x):
             pass
-        mylist = ["somestr"+str(i) for i in range(10)]
+        mylist = [_str("somestr") + _str(i) for i in range(10)]
         def f(n, m):
             while m >= 0:
                 jitdriver.can_enter_jit(m=m, n=n)
@@ -171,46 +163,64 @@
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=1, strsetitem=0, copystrcontent=2,
-                         call=1, call_pure=0)   # escape
+        if _str is str:
+            self.check_loops(newstr=1, strsetitem=0, copystrcontent=2,
+                             call=1, call_pure=0)   # escape
+        else:
+            self.check_loops(newunicode=1, unicodesetitem=0,
+                             copyunicodecontent=2,
+                             call=1, call_pure=0)   # escape
 
     def test_strconcat_escape_str_char(self):
+        _str, _chr = self._str, self._chr
         jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
         @dont_look_inside
         def escape(x):
             pass
-        mylist = ["somestr"+str(i) for i in range(10)]
+        mylist = [_str("somestr") + _str(i) for i in range(10)]
         def f(n, m):
             while m >= 0:
                 jitdriver.can_enter_jit(m=m, n=n)
                 jitdriver.jit_merge_point(m=m, n=n)
-                s = mylist[n] + chr(m)
+                s = mylist[n] + _chr(m)
                 escape(s)
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
-                         call=1, call_pure=0)   # escape
+        if _str is str:
+            self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
+                             call=1, call_pure=0)   # escape
+        else:
+            self.check_loops(newunicode=1, unicodesetitem=1,
+                             copyunicodecontent=1,
+                             call=1, call_pure=0)   # escape
 
     def test_strconcat_escape_char_str(self):
+        _str, _chr = self._str, self._chr
         jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
         @dont_look_inside
         def escape(x):
             pass
-        mylist = ["somestr"+str(i) for i in range(10)]
+        mylist = [_str("somestr") + _str(i) for i in range(10)]
         def f(n, m):
             while m >= 0:
                 jitdriver.can_enter_jit(m=m, n=n)
                 jitdriver.jit_merge_point(m=m, n=n)
-                s = chr(n) + mylist[m]
+                s = _chr(n) + mylist[m]
                 escape(s)
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
-                         call=1, call_pure=0)   # escape
+        if _str is str:
+            self.check_loops(newstr=1, strsetitem=1, copystrcontent=1,
+                             call=1, call_pure=0)   # escape
+        else:
+            self.check_loops(newunicode=1, unicodesetitem=1,
+                             copyunicodecontent=1,
+                             call=1, call_pure=0)   # escape
 
     def test_strconcat_escape_char_char(self):
+        _str, _chr = self._str, self._chr
         jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
         @dont_look_inside
         def escape(x):
@@ -219,91 +229,132 @@
             while m >= 0:
                 jitdriver.can_enter_jit(m=m, n=n)
                 jitdriver.jit_merge_point(m=m, n=n)
-                s = chr(n) + chr(m)
+                s = _chr(n) + _chr(m)
                 escape(s)
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=1, strsetitem=2, copystrcontent=0,
-                         call=1, call_pure=0)   # escape
+        if _str is str:
+            self.check_loops(newstr=1, strsetitem=2, copystrcontent=0,
+                             call=1, call_pure=0)   # escape
+        else:
+            self.check_loops(newunicode=1, unicodesetitem=2,
+                             copyunicodecontent=0,
+                             call=1, call_pure=0)   # escape
 
     def test_strconcat_escape_str_char_str(self):
+        _str, _chr = self._str, self._chr
         jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
         @dont_look_inside
         def escape(x):
             pass
-        mylist = ["somestr"+str(i) for i in range(10)]
+        mylist = [_str("somestr") + _str(i) for i in range(10)]
         def f(n, m):
             while m >= 0:
                 jitdriver.can_enter_jit(m=m, n=n)
                 jitdriver.jit_merge_point(m=m, n=n)
-                s = mylist[n] + chr(n) + mylist[m]
+                s = mylist[n] + _chr(n) + mylist[m]
                 escape(s)
                 m -= 1
             return 42
         self.meta_interp(f, [6, 7])
-        self.check_loops(newstr=1, strsetitem=1, copystrcontent=2,
-                         call=1, call_pure=0)   # escape
+        if _str is str:
+            self.check_loops(newstr=1, strsetitem=1, copystrcontent=2,
+                             call=1, call_pure=0)   # escape
+        else:
+            self.check_loops(newunicode=1, unicodesetitem=1,
+                             copyunicodecontent=2,
+                             call=1, call_pure=0)   # escape
 
     def test_strconcat_guard_fail(self):
-        for somestr in ["abc", ]: #u"def"]:
-            jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
-            @dont_look_inside
-            def escape(x):
-                pass
-            mylist = [somestr+str(i) for i in range(12)]
-            def f(n, m):
-                while m >= 0:
-                    jitdriver.can_enter_jit(m=m, n=n)
-                    jitdriver.jit_merge_point(m=m, n=n)
-                    s = mylist[n] + mylist[m]
-                    if m & 1:
-                        escape(s)
-                    m -= 1
-                return 42
-            self.meta_interp(f, [6, 10])
+        _str = self._str
+        jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
+        @dont_look_inside
+        def escape(x):
+            pass
+        mylist = [_str("abc") + _str(i) for i in range(12)]
+        def f(n, m):
+            while m >= 0:
+                jitdriver.can_enter_jit(m=m, n=n)
+                jitdriver.jit_merge_point(m=m, n=n)
+                s = mylist[n] + mylist[m]
+                if m & 1:
+                    escape(s)
+                m -= 1
+            return 42
+        self.meta_interp(f, [6, 10])
 
     def test_strslice(self):
-        for somestr in ["abc", ]: #u"def"]:
-            jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
-            @dont_look_inside
-            def escape(x):
-                pass
-            def f(n, m):
-                assert n >= 0
-                while m >= 0:
-                    jitdriver.can_enter_jit(m=m, n=n)
-                    jitdriver.jit_merge_point(m=m, n=n)
-                    s = "foobarbazetc"[m:n]
-                    if m <= 5:
-                        escape(s)
-                    m -= 1
-                return 42
-            self.meta_interp(f, [10, 10])
+        _str = self._str
+        longstring = _str("foobarbazetc")
+        jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
+        @dont_look_inside
+        def escape(x):
+            pass
+        def f(n, m):
+            assert n >= 0
+            while m >= 0:
+                jitdriver.can_enter_jit(m=m, n=n)
+                jitdriver.jit_merge_point(m=m, n=n)
+                s = longstring[m:n]
+                if m <= 5:
+                    escape(s)
+                m -= 1
+            return 42
+        self.meta_interp(f, [10, 10])
 
     def test_streq_char(self):
-        for somestr in ["?abcdefg", ]: #u"def"]:
-            jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
-            @dont_look_inside
-            def escape(x):
-                pass
-            def f(n, m):
-                assert n >= 0
-                while m >= 0:
-                    jitdriver.can_enter_jit(m=m, n=n)
-                    jitdriver.jit_merge_point(m=m, n=n)
-                    s = somestr[:m]
-                    escape(s == "?")
-                    m -= 1
-                return 42
-            self.meta_interp(f, [6, 7])
-            self.check_loops(newstr=0, newunicode=0)
-
-
-class TestOOtype(StringTests, OOJitMixin):
-    CALL = "oosend"
-    CALL_PURE = "oosend_pure"
+        _str = self._str
+        longstring = _str("?abcdefg")
+        somechar = _str("?")
+        jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
+        @dont_look_inside
+        def escape(x):
+            pass
+        def f(n, m):
+            assert n >= 0
+            while m >= 0:
+                jitdriver.can_enter_jit(m=m, n=n)
+                jitdriver.jit_merge_point(m=m, n=n)
+                s = longstring[:m]
+                escape(s == somechar)
+                m -= 1
+            return 42
+        self.meta_interp(f, [6, 7])
+        self.check_loops(newstr=0, newunicode=0)
+
+
+#class TestOOtype(StringTests, OOJitMixin):
+#    CALL = "oosend"
+#    CALL_PURE = "oosend_pure"
 
 class TestLLtype(StringTests, LLJitMixin):
     CALL = "call"
     CALL_PURE = "call_pure"
+
+class TestLLtypeUnicode(TestLLtype):
+    _str, _chr = unicode, unichr
+
+    def test_str2unicode(self):
+        _str = self._str
+        jitdriver = JitDriver(greens = [], reds = ['m', 'n'])
+        class Foo:
+            pass
+        @dont_look_inside
+        def escape(x):
+            assert x == _str("6y")
+        def f(n, m):
+            while m >= 0:
+                jitdriver.can_enter_jit(m=m, n=n)
+                jitdriver.jit_merge_point(m=m, n=n)
+                foo = Foo()
+                foo.y = chr(m)
+                foo.y = "y"
+                s = _str(str(n)) + _str(foo.y)
+                escape(s)
+                m -= 1
+            return 42
+        self.meta_interp(f, [6, 7])
+        self.check_loops(call=3,    # str(), _str(), escape()
+                         newunicode=1, unicodegetitem=0,
+                         unicodesetitem=1, copyunicodecontent=1)



More information about the Pypy-commit mailing list