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

Reply via email to