Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r81509:c46508226ad9
Date: 2015-12-31 10:46 +0000
http://bitbucket.org/pypy/pypy/changeset/c46508226ad9/

Log:    Remove the hacks in optimizeopt introduced by 'faster-rstruct' and
        instead add a 'llop.gc_load_indexed' operation that turns into a
        regular GC_LOAD_INDEXED resop.

diff --git a/pypy/module/pypyjit/test_pypy_c/test_struct.py 
b/pypy/module/pypyjit/test_pypy_c/test_struct.py
--- a/pypy/module/pypyjit/test_pypy_c/test_struct.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_struct.py
@@ -45,7 +45,7 @@
 
         # the newstr and the strsetitems are because the string is forced,
         # which is in turn because the optimizer doesn't know how to handle a
-        # getarrayitem_gc_i on a virtual string. It could be improved, but it
+        # gc_load_indexed_i on a virtual string. It could be improved, but it
         # is also true that in real life cases struct.unpack is called on
         # strings which come from the outside, so it's a minor issue.
         assert loop.match_by_id("unpack", """
@@ -55,17 +55,17 @@
             strsetitem(p88, 1, i14)
             strsetitem(p88, 2, i17)
             strsetitem(p88, 3, i20)
-            i91 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+            i91 = gc_load_indexed_i(p88, 0, 1, _, -4)
         """)
 
     def test_struct_object(self):
         def main(n):
             import struct
-            s = struct.Struct("i")
+            s = struct.Struct("ii")
             i = 1
             while i < n:
-                buf = s.pack(i)       # ID: pack
-                x = s.unpack(buf)[0]  # ID: unpack
+                buf = s.pack(-1, i)     # ID: pack
+                x = s.unpack(buf)[1]    # ID: unpack
                 i += x / i
             return i
 
@@ -88,10 +88,15 @@
 
         assert loop.match_by_id('unpack', """
             # struct.unpack
-            p88 = newstr(4)
-            strsetitem(p88, 0, i11)
-            strsetitem(p88, 1, i14)
-            strsetitem(p88, 2, i17)
-            strsetitem(p88, 3, i20)
-            i91 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+            p88 = newstr(8)
+            strsetitem(p88, 0, 255)
+            strsetitem(p88, 1, 255)
+            strsetitem(p88, 2, 255)
+            strsetitem(p88, 3, 255)
+            strsetitem(p88, 4, i11)
+            strsetitem(p88, 5, i14)
+            strsetitem(p88, 6, i17)
+            strsetitem(p88, 7, i20)
+            i90 = gc_load_indexed_i(p88, 0, 1, _, -4)
+            i91 = gc_load_indexed_i(p88, 4, 1, _, -4)
         """)
diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -13,6 +13,7 @@
 
 from rpython.rtyper.llinterp import LLInterpreter, LLException
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
+from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper import rclass
 
 from rpython.rlib.clibffi import FFI_DEFAULT_ABI
@@ -638,18 +639,9 @@
         return array.getlength()
 
     def bh_getarrayitem_gc(self, a, index, descr):
+        a = support.cast_arg(lltype.Ptr(descr.A), a)
+        array = a._obj
         assert index >= 0
-        if descr.A is descr.OUTERA:
-            a = support.cast_arg(lltype.Ptr(descr.A), a)
-        else:
-            # we use rffi.cast instead of support.cast_arg because the types
-            # might not be "compatible" enough from the lltype point of
-            # view. In particular, this happens when we use
-            # str_storage_getitem, in which an rpy_string is casted to
-            # rpy_string_as_Signed (or similar)
-            a = rffi.cast(lltype.Ptr(descr.OUTERA), a)
-            a = getattr(a, descr.OUTERA._arrayfld)
-        array = a._obj
         return support.cast_result(descr.A.OF, array.getitem(index))
 
     bh_getarrayitem_gc_pure_i = bh_getarrayitem_gc
@@ -714,6 +706,24 @@
         else:
             return self.bh_raw_load_i(struct, offset, descr)
 
+    def bh_gc_load_indexed_i(self, struct, index, scale, base_ofs, bytes):
+        if   bytes == 1: T = rffi.UCHAR
+        elif bytes == 2: T = rffi.USHORT
+        elif bytes == 4: T = rffi.UINT
+        elif bytes == 8: T = rffi.ULONGLONG
+        elif bytes == -1: T = rffi.SIGNEDCHAR
+        elif bytes == -2: T = rffi.SHORT
+        elif bytes == -4: T = rffi.INT
+        elif bytes == -8: T = rffi.LONGLONG
+        else: raise NotImplementedError(bytes)
+        x = llop.gc_load_indexed(T, struct, index, scale, base_ofs)
+        return lltype.cast_primitive(lltype.Signed, x)
+
+    def bh_gc_load_indexed_f(self, struct, index, scale, base_ofs, bytes):
+        if bytes != 8:
+            raise Exception("gc_load_indexed_f is only for 'double'!")
+        return llop.gc_load_indexed(rffi.DOUBLE, struct, index, scale, 
base_ofs)
+
     def bh_increment_debug_counter(self, addr):
         p = rffi.cast(rffi.CArrayPtr(lltype.Signed), addr)
         p[0] += 1
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -725,6 +725,16 @@
     def bh_raw_load_f(self, addr, offset, descr):
         return self.read_float_at_mem(addr, offset)
 
+    def bh_gc_load_indexed_i(self, addr, index, scale, base_ofs, bytes):
+        offset = base_ofs + scale * index
+        return self.read_int_at_mem(addr, offset, abs(bytes), bytes < 0)
+
+    def bh_gc_load_indexed_f(self, addr, index, scale, base_ofs, bytes):
+        # only for 'double'!
+        assert bytes == rffi.sizeof(lltype.Float)
+        offset = base_ofs + scale * index
+        return self.read_float_at_mem(addr, offset)
+
     def bh_new(self, sizedescr):
         return self.gc_ll_descr.gc_malloc(sizedescr)
 
diff --git a/rpython/jit/codewriter/jtransform.py 
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1021,18 +1021,20 @@
             kind = getkind(op.result.concretetype)[0]
             return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
                                   op.result)
-        elif isinstance(op.args[0].concretetype.TO, lltype.GcStruct):
-            # special-case 2: GcStruct with Array field
-            v_inst, c_field, v_index = op.args
-            STRUCT = v_inst.concretetype.TO
-            ARRAY = getattr(STRUCT, c_field.value)
-            assert isinstance(ARRAY, lltype.Array)
-            arraydescr = self.cpu.arraydescrof(STRUCT)
-            kind = getkind(op.result.concretetype)[0]
-            assert kind in ('i', 'f')
-            return SpaceOperation('getarrayitem_gc_%s' % kind,
-                                  [op.args[0], v_index, arraydescr],
-                                  op.result)
+        #elif isinstance(op.args[0].concretetype.TO, lltype.GcStruct):
+        #    # special-case 2: GcStruct with Array field
+        #    ---was added in the faster-rstruct branch,---
+        #    ---no longer directly supported---
+        #    v_inst, c_field, v_index = op.args
+        #    STRUCT = v_inst.concretetype.TO
+        #    ARRAY = getattr(STRUCT, c_field.value)
+        #    assert isinstance(ARRAY, lltype.Array)
+        #    arraydescr = self.cpu.arraydescrof(STRUCT)
+        #    kind = getkind(op.result.concretetype)[0]
+        #    assert kind in ('i', 'f')
+        #    return SpaceOperation('getarrayitem_gc_%s' % kind,
+        #                          [op.args[0], v_index, arraydescr],
+        #                          op.result)
         else:
             assert False, 'not supported'
 
@@ -1084,6 +1086,25 @@
         return SpaceOperation('raw_load_%s' % kind,
                               [op.args[0], op.args[1], descr], op.result)
 
+    def rewrite_op_gc_load_indexed(self, op):
+        T = op.result.concretetype
+        kind = getkind(T)[0]
+        assert kind != 'r'
+        descr = self.cpu.arraydescrof(rffi.CArray(T))
+        if (not isinstance(op.args[2], Constant) or
+            not isinstance(op.args[3], Constant)):
+            raise NotImplementedError("gc_load_indexed: 'scale' and 'base_ofs'"
+                                      " should be constants")
+        # xxx hard-code the size in bytes at translation time, which is
+        # probably fine and avoids lots of issues later
+        bytes = descr.get_item_size_in_bytes()
+        if descr.is_item_signed():
+            bytes = -bytes
+        c_bytes = Constant(bytes, lltype.Signed)
+        return SpaceOperation('gc_load_indexed_%s' % kind,
+                              [op.args[0], op.args[1],
+                               op.args[2], op.args[3], c_bytes], op.result)
+
     def _rewrite_equality(self, op, opname):
         arg0, arg1 = op.args
         if isinstance(arg0, Constant) and not arg0.value:
diff --git a/rpython/jit/metainterp/blackhole.py 
b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -1434,6 +1434,13 @@
     def bhimpl_raw_load_f(cpu, addr, offset, arraydescr):
         return cpu.bh_raw_load_f(addr, offset, arraydescr)
 
+    @arguments("cpu", "r", "i", "i", "i", "i", returns="i")
+    def bhimpl_gc_load_indexed_i(cpu, addr, index, scale, base_ofs, bytes):
+        return cpu.bh_gc_load_indexed_i(addr, index,scale,base_ofs, bytes)
+    @arguments("cpu", "r", "i", "i", "i", "i", returns="f")
+    def bhimpl_gc_load_indexed_f(cpu, addr, index, scale, base_ofs, bytes):
+        return cpu.bh_gc_load_indexed_f(addr, index,scale,base_ofs, bytes)
+
     @arguments("r", "d", "d")
     def bhimpl_record_quasiimmut_field(struct, fielddescr, mutatefielddescr):
         pass
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py 
b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -535,16 +535,10 @@
         cf.do_setfield(self, op)
 
     def optimize_GETARRAYITEM_GC_I(self, op):
-        # When using str_storage_getitem it might happen that op.getarg(0) is
-        # a virtual string, NOT an array. In that case, we cannot cache the
-        # getarrayitem as if it were an array, obviously. In theory we could
-        # improve by writing special code to interpter the buffer of the
-        # virtual string as if it were an array, but it looks complicate,
-        # fragile and not worth it.
         arrayinfo = self.ensure_ptr_info_arg0(op)
         indexb = self.getintbound(op.getarg(1))
         cf = None
-        if indexb.is_constant() and not arrayinfo.is_vstring():
+        if indexb.is_constant():
             index = indexb.getint()
             arrayinfo.getlenbound(None).make_gt_const(index)
             # use the cache on (arraydescr, index), which is a constant
@@ -561,7 +555,7 @@
         self.make_nonnull(op.getarg(0))
         self.emit_operation(op)
         # the remember the result of reading the array item
-        if cf is not None and not arrayinfo.is_vstring():
+        if cf is not None:
             arrayinfo.setitem(op.getdescr(), indexb.getint(),
                               self.get_box_replacement(op.getarg(0)),
                               self.get_box_replacement(op), cf,
diff --git a/rpython/jit/metainterp/optimizeopt/info.py 
b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -24,9 +24,6 @@
     def is_virtual(self):
         return False
 
-    def is_vstring(self):
-        return False
-
     def is_precise(self):
         return False
 
diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py 
b/rpython/jit/metainterp/optimizeopt/virtualize.py
--- a/rpython/jit/metainterp/optimizeopt/virtualize.py
+++ b/rpython/jit/metainterp/optimizeopt/virtualize.py
@@ -277,10 +277,8 @@
             self.emit_operation(op)
 
     def optimize_GETARRAYITEM_GC_I(self, op):
-        # When using str_storage_getitem we op.getarg(0) is a string, NOT an
-        # array, hence the check. In that case, it will be forced
         opinfo = self.getptrinfo(op.getarg(0))
-        if opinfo and opinfo.is_virtual() and not opinfo.is_vstring():
+        if opinfo and opinfo.is_virtual():
             indexbox = self.get_constant_box(op.getarg(1))
             if indexbox is not None:
                 item = opinfo.getitem(op.getdescr(), indexbox.getint())
diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py 
b/rpython/jit/metainterp/optimizeopt/vstring.py
--- a/rpython/jit/metainterp/optimizeopt/vstring.py
+++ b/rpython/jit/metainterp/optimizeopt/vstring.py
@@ -62,9 +62,6 @@
         self.mode = mode
         self.length = length
 
-    def is_vstring(self):
-        return True
-
     def getlenbound(self, mode):
         from rpython.jit.metainterp.optimizeopt import intutils
 
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -810,6 +810,27 @@
         return self.execute_with_descr(rop.RAW_LOAD_F, arraydescr,
                                        addrbox, offsetbox)
 
+    def _remove_symbolics(self, c):
+        if not we_are_translated():
+            from rpython.rtyper.lltypesystem import ll2ctypes
+            assert isinstance(c, ConstInt)
+            c = ConstInt(ll2ctypes.lltype2ctypes(c.value))
+        return c
+
+    @arguments("box", "box", "box", "box", "box")
+    def opimpl_gc_load_indexed_i(self, addrbox, indexbox,
+                                 scalebox, baseofsbox, bytesbox):
+        return self.execute(rop.GC_LOAD_INDEXED_I, addrbox, indexbox,
+                            self._remove_symbolics(scalebox),
+                            self._remove_symbolics(baseofsbox), bytesbox)
+
+    @arguments("box", "box", "box", "box", "box")
+    def opimpl_gc_load_indexed_f(self, addrbox, indexbox,
+                                 scalebox, baseofsbox, bytesbox):
+        return self.execute(rop.GC_LOAD_INDEXED_F, addrbox, indexbox,
+                            self._remove_symbolics(scalebox),
+                            self._remove_symbolics(baseofsbox), bytesbox)
+
     @arguments("box")
     def opimpl_hint_force_virtualizable(self, box):
         self.metainterp.gen_store_back_in_vable(box)
diff --git a/rpython/jit/metainterp/test/test_strstorage.py 
b/rpython/jit/metainterp/test/test_strstorage.py
--- a/rpython/jit/metainterp/test/test_strstorage.py
+++ b/rpython/jit/metainterp/test/test_strstorage.py
@@ -19,7 +19,7 @@
         res = self.interp_operations(f, [], supports_singlefloats=True)
         #
         kind = getkind(TYPE)[0] # 'i' or 'f'
-        self.check_operations_history({'getarrayitem_gc_%s' % kind: 1,
+        self.check_operations_history({'gc_load_indexed_%s' % kind: 1,
                                        'finish': 1})
         #
         if TYPE == lltype.SingleFloat:
@@ -29,8 +29,8 @@
             return longlong.int2singlefloat(res)
         return res
 
-    def str_storage_supported(self, TYPE):
-        py.test.skip('this is not a JIT test')
+    #def str_storage_supported(self, TYPE):
+    #    py.test.skip('this is not a JIT test')
 
     def test_force_virtual_str_storage(self):
         byteorder = sys.byteorder
@@ -48,6 +48,6 @@
             'strsetitem': 1,          # str forcing
             'call_pure_r': 1,         # str forcing (copystrcontent)
             'guard_no_exception': 1,  # str forcing
-            'getarrayitem_gc_i': 1,   # str_storage_getitem
+            'gc_load_indexed_i': 1,   # str_storage_getitem
             'finish': 1
             })
diff --git a/rpython/rlib/rstruct/nativefmttable.py 
b/rpython/rlib/rstruct/nativefmttable.py
--- a/rpython/rlib/rstruct/nativefmttable.py
+++ b/rpython/rlib/rstruct/nativefmttable.py
@@ -11,7 +11,6 @@
 from rpython.rlib.rstruct.standardfmttable import native_is_bigendian
 from rpython.rlib.rstruct.error import StructError
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.strstorage import str_storage_getitem
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rtyper.tool import rffi_platform
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
diff --git a/rpython/rlib/rstruct/standardfmttable.py 
b/rpython/rlib/rstruct/standardfmttable.py
--- a/rpython/rlib/rstruct/standardfmttable.py
+++ b/rpython/rlib/rstruct/standardfmttable.py
@@ -12,7 +12,7 @@
 from rpython.rlib.rstruct import ieee
 from rpython.rlib.rstruct.error import StructError, StructOverflowError
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.strstorage import str_storage_getitem, str_storage_supported
+from rpython.rlib.strstorage import str_storage_getitem
 from rpython.rlib import rarithmetic
 from rpython.rtyper.lltypesystem import rffi
 
@@ -185,13 +185,14 @@
             data = fmtiter.read(size)
             fmtiter.appendobj(ieee.unpack_float(data, fmtiter.bigendian))
             return
-        if not str_storage_supported(TYPE):
-            # this happens e.g. on win32 and ARM32: we cannot read the string
-            # content as an array of doubles because it's not properly
-            # aligned. But we can read a longlong and convert to float
-            assert TYPE == rffi.DOUBLE
-            assert rffi.sizeof(TYPE) == 8
-            return unpack_longlong2float(fmtiter)
+        ## XXX check if the following code is still needed
+        ## if not str_storage_supported(TYPE):
+        ##     # this happens e.g. on win32 and ARM32: we cannot read the 
string
+        ##     # content as an array of doubles because it's not properly
+        ##     # aligned. But we can read a longlong and convert to float
+        ##     assert TYPE == rffi.DOUBLE
+        ##     assert rffi.sizeof(TYPE) == 8
+        ##     return unpack_longlong2float(fmtiter)
         try:
             # fast path
             val = unpack_fastpath(TYPE)(fmtiter)
@@ -246,7 +247,7 @@
 
     @specialize.argtype(0)
     def unpack_int_fastpath_maybe(fmtiter):
-        if fmtiter.bigendian != native_is_bigendian or not 
str_storage_supported(TYPE):
+        if fmtiter.bigendian != native_is_bigendian or not native_is_ieee754: 
## or not str_storage_supported(TYPE):
             return False
         try:
             intvalue = unpack_fastpath(TYPE)(fmtiter)
diff --git a/rpython/rlib/strstorage.py b/rpython/rlib/strstorage.py
--- a/rpython/rlib/strstorage.py
+++ b/rpython/rlib/strstorage.py
@@ -9,54 +9,31 @@
 #      rstr.py:copy_string_contents), which has no chance to work during
 #      tracing
 #
-#   2. use llop.raw_load: despite the name, llop.raw_load DOES support reading
-#      from GC pointers. However:
-#
-#        a. we would like to use a CompositeOffset as the offset (using the
-#           same logic as in rstr.py:_get_raw_str_buf), but this is not (yet)
-#           supported before translation: it works only if you pass an actual
-#           integer
-#
-#        b. raw_load from a GC pointer is not (yet) supported by the
-#           JIT. There are plans to introduce a gc_load operation: when it
-#           will be there, we could fix the issue above and actually use it to
-#           implement str_storage_getitem
-#
-#   3. the actual solution: cast rpy_string to a GcStruct which has the very
+#   2. cast rpy_string to a GcStruct which has the very
 #      same layout, with the only difference that its 'chars' field is no
 #      longer an Array(Char) but e.e. an Array(Signed). Then, we just need to
-#      read the appropriate index into the array
+#      read the appropriate index into the array.  To support this solution,
+#      the JIT's optimizer needed a few workarounds.  This was removed.
+#
+#   3. use the newly introduced 'llop.gc_load_indexed'.
+#
 
-from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
-from rpython.rtyper.lltypesystem.rstr import STR, _get_raw_str_buf
+
+from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.lltypesystem.rstr import STR
 from rpython.rtyper.annlowlevel import llstr
-from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.objectmodel import specialize
 
-@specialize.memo()
-def _rpy_string_as_type(TP):
-    # sanity check that STR is actually what we think it is
-    assert STR._flds == {
-        'hash': lltype.Signed,
-        'chars': lltype.Array(lltype.Char, hints={'immutable': True})
-        }
-    STR_AS_TP = lltype.GcStruct('rpy_string_as_%s' % TP,
-                                ('hash',  lltype.Signed),
-                                ('chars', lltype.Array(TP, hints={'immutable': 
True})))
-    return STR_AS_TP
-
-@specialize.arg(0)
-def str_storage_supported(TP):
-    # on some architectures (e.g. win32 and arm32) an array of longlongs needs
-    # to be aligned at 8 bytes boundaries, so we cannot safely cast from STR
-    # to STR_AS_TP. In that case, we str_storage_getitem is simply not
-    # supported
-    return rffi.sizeof(TP) <= rffi.sizeof(lltype.Signed)
 
 @specialize.ll()
-def str_storage_getitem(TP, s, index):
-    assert str_storage_supported(TP) # sanity check
-    STR_AS_TP = _rpy_string_as_type(TP)
+def str_storage_getitem(TP, s, byte_offset):
+    # WARNING: the 'byte_offset' is, as its name says, measured in bytes;
+    # however, it should be aligned for TP, otherwise on some platforms this
+    # code will crash!
     lls = llstr(s)
-    str_as_tp = rffi.cast(lltype.Ptr(STR_AS_TP), lls)
-    index = index / rffi.sizeof(TP)
-    return str_as_tp.chars[index]
+    base_ofs = (llmemory.offsetof(STR, 'chars') +
+                llmemory.itemoffsetof(STR.chars, 0))
+    scale_factor = llmemory.sizeof(lltype.Char)
+    return llop.gc_load_indexed(TP, lls, byte_offset,
+                                scale_factor, base_ofs)
diff --git a/rpython/rlib/test/test_strstorage.py 
b/rpython/rlib/test/test_strstorage.py
--- a/rpython/rlib/test/test_strstorage.py
+++ b/rpython/rlib/test/test_strstorage.py
@@ -2,7 +2,7 @@
 import sys
 import struct
 from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.strstorage import str_storage_getitem, str_storage_supported
+from rpython.rlib.strstorage import str_storage_getitem
 from rpython.rlib.rarithmetic import r_singlefloat
 from rpython.rtyper.test.tool import BaseRtypingTest
 
@@ -10,14 +10,14 @@
 
 class BaseStrStorageTest:
 
-    def test_str_getitem_supported(self):
-        if IS_32BIT:
-            expected = False
-        else:
-            expected = True
-        #
-        assert self.str_storage_supported(rffi.LONGLONG) == expected
-        assert self.str_storage_supported(rffi.DOUBLE) == expected
+    ## def test_str_getitem_supported(self):
+    ##     if IS_32BIT:
+    ##         expected = False
+    ##     else:
+    ##         expected = True
+    ##     #
+    ##     assert self.str_storage_supported(rffi.LONGLONG) == expected
+    ##     assert self.str_storage_supported(rffi.DOUBLE) == expected
 
     def test_signed(self):
         buf = struct.pack('@ll', 42, 43)
@@ -34,8 +34,8 @@
         assert int(x) == 43
 
     def test_float(self):
-        if not str_storage_supported(lltype.Float):
-            py.test.skip('str_storage_getitem(lltype.Float) not supported on 
this machine')
+        ## if not str_storage_supported(lltype.Float):
+        ##     py.test.skip('str_storage_getitem(lltype.Float) not supported 
on this machine')
         buf = struct.pack('@dd', 12.3, 45.6)
         size = struct.calcsize('@d')
         assert self.str_storage_getitem(lltype.Float, buf, 0) == 12.3
@@ -52,20 +52,45 @@
 
 class TestDirect(BaseStrStorageTest):
 
-    def str_storage_supported(self, TYPE):
-        return str_storage_supported(TYPE)
+    ## def str_storage_supported(self, TYPE):
+    ##     return str_storage_supported(TYPE)
 
     def str_storage_getitem(self, TYPE, buf, offset):
         return str_storage_getitem(TYPE, buf, offset)
 
 class TestRTyping(BaseStrStorageTest, BaseRtypingTest):
 
-    def str_storage_supported(self, TYPE):
-        def fn():
-            return str_storage_supported(TYPE)
-        return self.interpret(fn, [])
+    ## def str_storage_supported(self, TYPE):
+    ##     def fn():
+    ##         return str_storage_supported(TYPE)
+    ##     return self.interpret(fn, [])
 
     def str_storage_getitem(self, TYPE, buf, offset):
         def fn(offset):
             return str_storage_getitem(TYPE, buf, offset)
         return self.interpret(fn, [offset])
+
+
+class TestCompiled(BaseStrStorageTest):
+    cache = {}
+
+    def str_storage_getitem(self, TYPE, buf, offset):
+        if TYPE not in self.cache:
+            from rpython.translator.c.test.test_genc import compile
+
+            assert isinstance(TYPE, lltype.Primitive)
+            if TYPE in (lltype.Float, lltype.SingleFloat):
+                TARGET_TYPE = lltype.Float
+            else:
+                TARGET_TYPE = lltype.Signed
+
+            def llf(buf, offset):
+                x = str_storage_getitem(TYPE, buf, offset)
+                return lltype.cast_primitive(TARGET_TYPE, x)
+
+            fn = compile(llf, [str, int])
+            self.cache[TYPE] = fn
+        #
+        fn = self.cache[TYPE]
+        x = fn(buf, offset)
+        return lltype.cast_primitive(TYPE, x)
diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py 
b/rpython/rtyper/lltypesystem/ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/ll2ctypes.py
@@ -902,6 +902,14 @@
                 llobj = ctypes.sizeof(get_ctypes_type(llobj.TYPE)) * 
llobj.repeat
             elif isinstance(llobj, ComputedIntSymbolic):
                 llobj = llobj.compute_fn()
+            elif isinstance(llobj, llmemory.CompositeOffset):
+                llobj = sum([lltype2ctypes(c) for c in llobj.offsets])
+            elif isinstance(llobj, llmemory.FieldOffset):
+                CSTRUCT = get_ctypes_type(llobj.TYPE)
+                llobj = getattr(CSTRUCT, llobj.fldname).offset
+            elif isinstance(llobj, llmemory.ArrayItemsOffset):
+                CARRAY = get_ctypes_type(llobj.TYPE)
+                llobj = CARRAY.items.offset
             else:
                 raise NotImplementedError(llobj)  # don't know about symbolic 
value
 
diff --git a/rpython/rtyper/lltypesystem/lloperation.py 
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -417,6 +417,7 @@
     'raw_load':             LLOp(sideeffects=False, canrun=True),
     'raw_store':            LLOp(canrun=True),
     'bare_raw_store':       LLOp(),
+    'gc_load_indexed':      LLOp(sideeffects=False, canrun=True),
     'stack_malloc':         LLOp(), # mmh
     'track_alloc_start':    LLOp(),
     'track_alloc_stop':     LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py 
b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -702,6 +702,17 @@
     return p[0]
 op_raw_load.need_result_type = True
 
+def op_gc_load_indexed(TVAL, p, index, scale, base_ofs):
+    # 'base_ofs' should be a CompositeOffset(..., ArrayItemsOffset).
+    # 'scale' should be a llmemory.sizeof().
+    from rpython.rtyper.lltypesystem import rffi
+    ofs = base_ofs + scale * index
+    if isinstance(ofs, int):
+        return op_raw_load(TVAL, p, ofs)
+    p = rffi.cast(rffi.CArrayPtr(TVAL), llmemory.cast_ptr_to_adr(p) + ofs)
+    return p[0]
+op_gc_load_indexed.need_result_type = True
+
 def op_likely(x):
     assert isinstance(x, bool)
     return x
diff --git a/rpython/rtyper/lltypesystem/rbytearray.py 
b/rpython/rtyper/lltypesystem/rbytearray.py
--- a/rpython/rtyper/lltypesystem/rbytearray.py
+++ b/rpython/rtyper/lltypesystem/rbytearray.py
@@ -8,10 +8,10 @@
 def mallocbytearray(size):
     return lltype.malloc(BYTEARRAY, size)
 
-_, _, _, copy_bytearray_contents = rstr._new_copy_contents_fun(BYTEARRAY, 
BYTEARRAY,
+_, _, copy_bytearray_contents = rstr._new_copy_contents_fun(BYTEARRAY, 
BYTEARRAY,
                                                          lltype.Char,
                                                          'bytearray')
-_, _, _, copy_bytearray_contents_from_str = 
rstr._new_copy_contents_fun(rstr.STR,
+_, _, copy_bytearray_contents_from_str = rstr._new_copy_contents_fun(rstr.STR,
                                                                   BYTEARRAY,
                                                                   lltype.Char,
                                                                   
'bytearray_from_str')
diff --git a/rpython/rtyper/lltypesystem/rstr.py 
b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -136,15 +136,13 @@
     copy_raw_to_string = func_with_new_name(copy_raw_to_string,
                                               'copy_raw_to_%s' % name)
 
-    return _get_raw_buf, copy_string_to_raw, copy_raw_to_string, 
copy_string_contents
+    return copy_string_to_raw, copy_raw_to_string, copy_string_contents
 
-(_get_raw_str_buf,
- copy_string_to_raw,
+(copy_string_to_raw,
  copy_raw_to_string,
  copy_string_contents) = _new_copy_contents_fun(STR, STR, Char, 'string')
 
-(_get_raw_unicode_buf,
- copy_unicode_to_raw,
+(copy_unicode_to_raw,
  copy_raw_to_unicode,
  copy_unicode_contents) = _new_copy_contents_fun(UNICODE, UNICODE, UniChar, 
'unicode')
 
diff --git a/rpython/translator/c/funcgen.py b/rpython/translator/c/funcgen.py
--- a/rpython/translator/c/funcgen.py
+++ b/rpython/translator/c/funcgen.py
@@ -299,7 +299,7 @@
     def gen_op(self, op):
         macro = 'OP_%s' % op.opname.upper()
         line = None
-        if op.opname.startswith('gc_'):
+        if op.opname.startswith('gc_') and op.opname != 'gc_load_indexed':
             meth = getattr(self.gcpolicy, macro, None)
             if meth:
                 line = meth(self, op)
@@ -709,6 +709,19 @@
           "%(result)s = ((%(typename)s) (((char *)%(addr)s) + %(offset)s))[0];"
           % locals())
 
+    def OP_GC_LOAD_INDEXED(self, op):
+        addr = self.expr(op.args[0])
+        index = self.expr(op.args[1])
+        scale = self.expr(op.args[2])
+        base_ofs = self.expr(op.args[3])
+        result = self.expr(op.result)
+        TYPE = op.result.concretetype
+        typename = cdecl(self.db.gettype(TYPE).replace('@', '*@'), '')
+        return (
+          "%(result)s = ((%(typename)s) (((char *)%(addr)s) + "
+          "%(base_ofs)s + %(scale)s * %(index)s))[0];"
+          % locals())
+
     def OP_CAST_PRIMITIVE(self, op):
         TYPE = self.lltypemap(op.result)
         val =  self.expr(op.args[0])
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to