Author: Antonio Cuni <[email protected]>
Branch: faster-rstruct-2
Changeset: r91306:67ba2f0639a7
Date: 2017-05-16 11:39 +0200
http://bitbucket.org/pypy/pypy/changeset/67ba2f0639a7/
Log: rewrite buffer.GCBuffer as a class decorator instead of a base
class, because we need to provide different, specialized versions of
typed_{read,write} in which base_ofs is a constant to make the
codewriter happy
diff --git a/pypy/objspace/std/bytearrayobject.py
b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -8,7 +8,8 @@
from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
nonmoving_raw_ptr_for_resizable_list)
from rpython.rlib import jit
-from rpython.rlib.buffer import (GCBuffer, get_gc_data_for_list_of_chars,
+from rpython.rlib.buffer import (Buffer, GCBuffer,
+ get_gc_data_for_list_of_chars,
get_gc_data_offset_for_list_of_chars)
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
@@ -1257,7 +1258,8 @@
start += step
-class BytearrayBuffer(GCBuffer):
+@GCBuffer
+class BytearrayBuffer(Buffer):
_immutable_ = True
def __init__(self, ba, readonly=False):
@@ -1302,12 +1304,13 @@
p = rffi.ptradd(p, ba._offset)
return p
+ @staticmethod
+ def _get_gc_data_offset():
+ return get_gc_data_offset_for_list_of_chars()
+
def _get_gc_data(self):
return get_gc_data_for_list_of_chars(self.ba._data)
- def _get_gc_data_offset(self):
- return get_gc_data_offset_for_list_of_chars()
-
@specialize.argtype(1)
def _memcmp(selfvalue, buffer, length):
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -31,9 +31,10 @@
"""
Base class for buffers of bytes.
- Most probably, you do NOT want to use this as a base class, but either
- GCBuffer or RawBuffer, so that you automatically get the proper
- implementation of typed_read and typed_write.
+ Most probably, you do NOT want to use this as a lone base class, but
+ either inherit from RawBuffer or use the GCBuffer class decorator, so that
+ you automatically get the proper implementation of typed_read and
+ typed_write.
"""
_attrs_ = ['readonly']
_immutable_ = True
@@ -126,52 +127,46 @@
return llop.raw_store(lltype.Void, ptr, byte_offset, value)
-class GCBuffer(Buffer):
+def GCBuffer(buffercls):
"""
- A buffer which is baked by a GC-managed memory area. It implements
- typed_read and typed_write in terms of llop.gc_load_indexed and
- llop.gc_store_indexed.
+ class decorator for a buffer which is baked by a GC-managed memory
+ area. It implements typed_read and typed_write in terms of
+ llop.gc_load_indexed and llop.gc_store_indexed.
- Subclasses MUST override the _get_gc_* methods.
- """
- _immutable_ = True
- _attrs_ = ['readonly']
+ The target class MUST provide the following methods:
+
+ @staticmethod
+ def _get_gc_data_offset(self):
+ raise NotImplementedError
def _get_gc_data(self):
raise NotImplementedError
-
- def _get_gc_data_offset(self):
- """
- Return the offset to use with _get_gc_data() for calling
- llop.gc_{load,store}_indexed.
- """
- raise NotImplementedError
+ """
+ # We had to write this as a class decorator instead of a base class
+ # because we need to produce specialized versions of typed_{read,write} in
+ # which base_ofs is an RPython constant.
+ base_ofs = buffercls._get_gc_data_offset()
+ scale_factor = llmemory.sizeof(lltype.Char)
@specialize.ll_and_arg(1)
def typed_read(self, TP, byte_offset):
- """
- Read the value of type TP starting at byte_offset. No bounds checks
- """
lldata = self._get_gc_data()
- base_ofs = self._get_gc_data_offset()
- scale_factor = llmemory.sizeof(lltype.Char)
return llop.gc_load_indexed(TP, lldata, byte_offset,
scale_factor, base_ofs)
@specialize.ll_and_arg(1)
def typed_write(self, TP, byte_offset, value):
- """
- Write the value of type TP at byte_offset. No bounds checks
- """
if self.readonly:
raise CannotWrite
lldata = self._get_gc_data()
- base_ofs = self._get_gc_data_offset()
- scale_factor = llmemory.sizeof(lltype.Char)
value = lltype.cast_primitive(TP, value)
return llop.gc_store_indexed(lltype.Void, lldata, byte_offset, value,
scale_factor, base_ofs)
+ buffercls.typed_read = typed_read
+ buffercls.typed_write = typed_write
+ return buffercls
+
def get_gc_data_for_list_of_chars(data):
ll_data = ll_for_resizable_list(data)
@@ -183,7 +178,8 @@
return llmemory.itemoffsetof(LIST.items.TO, 0)
-class ByteBuffer(GCBuffer):
+@GCBuffer
+class ByteBuffer(Buffer):
_immutable_ = True
def __init__(self, n):
@@ -205,11 +201,13 @@
def _get_gc_data(self):
return get_gc_data_for_list_of_chars(self.data)
- def _get_gc_data_offset(self):
+ @staticmethod
+ def _get_gc_data_offset():
return get_gc_data_offset_for_list_of_chars()
-class StringBuffer(GCBuffer):
+@GCBuffer
+class StringBuffer(Buffer):
_attrs_ = ['readonly', 'value']
_immutable_ = True
@@ -242,7 +240,8 @@
# may still raise ValueError on some GCs
return rffi.get_raw_address_of_string(self.value)
- def _get_gc_data_offset(self):
+ @staticmethod
+ def _get_gc_data_offset():
return (llmemory.offsetof(STR, 'chars') +
llmemory.itemoffsetof(STR.chars, 0))
diff --git a/rpython/rlib/test/test_buffer.py b/rpython/rlib/test/test_buffer.py
--- a/rpython/rlib/test/test_buffer.py
+++ b/rpython/rlib/test/test_buffer.py
@@ -6,6 +6,8 @@
from rpython.annotator.annrpython import RPythonAnnotator
from rpython.annotator.model import SomeInteger
from rpython.rtyper.test.tool import BaseRtypingTest
+from rpython.jit.metainterp.test.support import LLJitMixin
+
class MyRawBuffer(RawBuffer):
@@ -182,3 +184,33 @@
buf.setslice(0, data)
assert buf.typed_read(rffi.USHORT, 0) == 0x1234
assert buf.typed_read(rffi.USHORT, 2) == 0x5678
+
+
+class TestJIT(LLJitMixin):
+
+ def test_GCBuffer_typed_read(self):
+ from rpython.rlib import jit
+ DATA = struct.pack('i', 0x12345678)
+
+ @jit.dont_look_inside
+ def make_buffer(flag):
+ if flag:
+ buf = ByteBuffer(len(DATA))
+ buf.setslice(0, DATA)
+ else:
+ buf = StringBuffer(DATA)
+ return buf
+
+ def f(flag):
+ buf = make_buffer(flag)
+ return buf.typed_read(rffi.INT, 0)
+
+ for flag in (0, 1):
+ res = self.interp_operations(f, [0], supports_singlefloats=True)
+ #
+ self.check_operations_history({'call_r': 1,
+ 'guard_no_exception': 1,
+ 'guard_class': 1,
+ 'gc_load_indexed_i': 1,
+ 'finish': 1})
+ assert res == 0x12345678
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit