Author: Antonio Cuni <[email protected]>
Branch: faster-rstruct
Changeset: r80736:2294ad1228f5
Date: 2015-11-18 07:21 +0100
http://bitbucket.org/pypy/pypy/changeset/2294ad1228f5/
Log: move str_storage_getitem into its own module, as it's no longer
based on rawstorage. Refactor, and re-implement based on casting.
Add JIT support for force_cast between GC objects and the specific
case of getinteriorfield we need. Add enough support to the llgraph
backend to run the tests
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
@@ -638,9 +638,18 @@
return array.getlength()
def bh_getarrayitem_gc(self, a, index, descr):
- a = support.cast_arg(lltype.Ptr(descr.A), a)
+ 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
- assert index >= 0
return support.cast_result(descr.A.OF, array.getitem(index))
bh_getarrayitem_gc_pure_i = bh_getarrayitem_gc
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
@@ -1008,12 +1008,11 @@
return SpaceOperation('getarrayitem_gc_i',
[op.args[0], v_index, bytearraydescr],
op.result)
- else:
+ elif op.result.concretetype is lltype.Void:
+ return
+ elif isinstance(op.args[0].concretetype.TO, lltype.GcArray):
+ # special-case 1: GcArray of Struct
v_inst, v_index, c_field = op.args
- if op.result.concretetype is lltype.Void:
- return
- # only GcArray of Struct supported
- assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
STRUCT = v_inst.concretetype.TO.OF
assert isinstance(STRUCT, lltype.Struct)
descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
@@ -1022,6 +1021,16 @@
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)
+ return SpaceOperation('getarrayitem_gc_i',
+ [op.args[0], v_index, arraydescr],
+ op.result)
def rewrite_op_setinteriorfield(self, op):
assert len(op.args) == 4
@@ -1130,10 +1139,13 @@
def rewrite_op_force_cast(self, op):
v_arg = op.args[0]
v_result = op.result
- assert not self._is_gc(v_arg)
-
if v_arg.concretetype == v_result.concretetype:
return
+ elif self._is_gc(v_arg) and self._is_gc(v_result):
+ # cast from GC to GC is always fine
+ return
+ else:
+ assert not self._is_gc(v_arg)
float_arg = v_arg.concretetype in [lltype.Float, lltype.SingleFloat]
float_res = v_result.concretetype in [lltype.Float, lltype.SingleFloat]
diff --git a/rpython/jit/metainterp/test/test_rawmem.py
b/rpython/jit/metainterp/test/test_rawmem.py
--- a/rpython/jit/metainterp/test/test_rawmem.py
+++ b/rpython/jit/metainterp/test/test_rawmem.py
@@ -108,18 +108,17 @@
def test_str_storage_int(self):
import struct
- data = struct.pack('q', 42)
+ data = struct.pack('qq', 42, 100)
def f():
- res = str_storage_getitem(lltype.Signed, data, 0)
- return res
+ a = str_storage_getitem(lltype.Signed, data, 0)
+ b = str_storage_getitem(lltype.Signed, data, 8)
+ return a+b
res = self.interp_operations(f, [])
- assert res == 42
- import pdb;pdb.set_trace()
- self.check_operations_history({'call_i': 1, 'guard_no_exception': 1,
- 'call_n': 1,
- 'raw_store': 1, 'raw_load_i': 1,
+ assert res == 142
+ self.check_operations_history({'getarrayitem_gc_i': 2,
+ 'int_add': 1,
'finish': 1})
- self.metainterp.staticdata.stats.check_resops({'finish': 1},
omit_finish=False)
+
class TestRawMem(RawMemTests, LLJitMixin):
diff --git a/rpython/rlib/rawstorage.py b/rpython/rlib/rawstorage.py
--- a/rpython/rlib/rawstorage.py
+++ b/rpython/rlib/rawstorage.py
@@ -6,8 +6,7 @@
from rpython.rlib import rgc
from rpython.rlib.rgc import lltype_is_gc
from rpython.rlib.objectmodel import specialize
-from rpython.rtyper.lltypesystem.rstr import STR, _get_raw_str_buf
-from rpython.rtyper.annlowlevel import llstr
+from rpython.rlib.strstorage import str_storage_getitem
RAW_STORAGE = rffi.CCHARP.TO
RAW_STORAGE_PTR = rffi.CCHARP
@@ -44,30 +43,6 @@
lltype.free(storage, flavor='raw', track_allocation=track_allocation)
[email protected]_collect
[email protected]()
-def str_storage_getitem(TP, s, index):
- lls = llstr(s)
- # from here, no GC operations can happen
- buf = _get_raw_str_buf(STR, lls, 0)
- storage = rffi.cast(RAW_STORAGE_PTR, buf)
- res = raw_storage_getitem(TP, storage, index)
- # end of "no GC" section
- keepalive_until_here(lls)
- return res
-
[email protected]_collect
[email protected]()
-def str_storage_getitem_unaligned(TP, s, index):
- lls = llstr(s)
- # from here, no GC operations can happen
- buf = _get_raw_str_buf(STR, lls, 0)
- storage = rffi.cast(RAW_STORAGE_PTR, buf)
- res = raw_storage_getitem_unaligned(TP, storage, index)
- # end of "no GC" section
- keepalive_until_here(lls)
- return res
-
# ____________________________________________________________
#
# Support for possibly-unaligned accesses
diff --git a/rpython/rlib/strstorage.py b/rpython/rlib/strstorage.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/strstorage.py
@@ -0,0 +1,55 @@
+# Support for str_storage: i.e., reading primitive types out of RPython string
+#
+# There are various possible ways to implement it, however not all of them are
+# easily supported by the JIT:
+#
+# 1. use _get_raw_str_buf and cast the chars buffer to RAW_STORAGE_PTR: this
+# works well without the JIT, but the cast to RAW_STORAGE_PTR needs to
+# happen inside a short "no GC" section (like the one in
+# 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
+# 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
+
+from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
+from rpython.rtyper.lltypesystem.rstr import STR, _get_raw_str_buf
+from rpython.rtyper.annlowlevel import llstr
+from rpython.rlib.objectmodel import specialize
+from rpython.rlib import rgc
+
[email protected]()
+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
+
[email protected]_collect
[email protected]()
+def str_storage_getitem(TP, s, index):
+ STR_AS_TP = rpy_string_as_type(TP)
+ 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]
diff --git a/rpython/rlib/test/test_rawstorage.py
b/rpython/rlib/test/test_rawstorage.py
--- a/rpython/rlib/test/test_rawstorage.py
+++ b/rpython/rlib/test/test_rawstorage.py
@@ -5,7 +5,7 @@
from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage,\
raw_storage_setitem, raw_storage_getitem, AlignmentError,\
raw_storage_setitem_unaligned, raw_storage_getitem_unaligned,\
- str_storage_getitem, str_storage_getitem_unaligned
+ str_storage_getitem
from rpython.rtyper.test.tool import BaseRtypingTest
from rpython.translator.c.test.test_genc import compile
@@ -44,16 +44,6 @@
res = str_storage_getitem(lltype.Float, buf, size*2)
assert res == 123.0
-def test_untranslated_str_storage_unaligned(monkeypatch):
- import struct
- monkeypatch.setattr(rawstorage, 'misaligned_is_fine', False)
- buf = 'foo' + struct.pack('@ll', 42, 43)
- size = struct.calcsize('@l')
- res = str_storage_getitem_unaligned(lltype.Signed, buf, 3)
- assert res == 42
- res = str_storage_getitem_unaligned(lltype.Signed, buf, size+3)
- assert res == 43
-
class TestRawStorage(BaseRtypingTest):
def test_storage_int(self):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit