[pypy-commit] pypy virtual-raw-mallocs: implement a "raw virtual buffer": the idea is that we can write values to the

antocuni noreply at buildbot.pypy.org
Tue Dec 18 13:55:00 CET 2012


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: virtual-raw-mallocs
Changeset: r59483:ef4527d0eb9f
Date: 2012-12-18 13:35 +0100
http://bitbucket.org/pypy/pypy/changeset/ef4527d0eb9f/

Log:	implement a "raw virtual buffer": the idea is that we can write
	values to the buffer at arbitrary positions in the buffer: as long
	as we write and read to non-overlapping pices of memory, it's all
	fine, but we need to detect the case in which a write might
	partially overwrite the memory already stored earlier: in that case,
	we raise an exception and abort the optimization

diff --git a/pypy/jit/metainterp/optimizeopt/rawbuffer.py b/pypy/jit/metainterp/optimizeopt/rawbuffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/optimizeopt/rawbuffer.py
@@ -0,0 +1,63 @@
+class InvalidRawOperation(Exception):
+    pass
+
+class InvalidRawWrite(InvalidRawOperation):
+    pass
+
+class InvalidRawRead(InvalidRawOperation):
+    pass
+
+class RawBuffer(object):
+    def __init__(self):
+        # the following lists represents the writes in the buffer: values[i]
+        # is the value of length lengths[i] stored at offset[i].
+        #
+        # the invariant is that they are ordered by offset, and that
+        # offset[i]+length[i] <= offset[i+1], i.e. that the writes never
+        # overlaps
+        self.offsets = []
+        self.lengths = []
+        self.values = []
+
+    def _get_memory(self):
+        """
+        NOT_RPYTHON
+        for testing only
+        """
+        return zip(self.offsets, self.lengths, self.values)
+
+    def write_value(self, offset, length, value):
+        i = 0
+        N = len(self.offsets)
+        while i < N:
+            if self.offsets[i] == offset:
+                if length != self.lengths[i]:
+                    raise InvalidRawWrite
+                # update the value at this offset
+                self.offsets[i] = offset
+                self.lengths[i] = length
+                self.values[i] = value
+                return
+            elif self.offsets[i] > offset:
+                break
+            i += 1
+        #
+        if i < len(self.offsets) and offset+length > self.offsets[i]:
+            raise InvalidRawWrite
+        # insert a new value at offset
+        self.offsets.insert(i, offset)
+        self.lengths.insert(i, length)
+        self.values.insert(i, value)
+
+    def read_value(self, offset, length):
+        i = 0
+        N = len(self.offsets)
+        while i < N:
+            if self.offsets[i] == offset:
+                if length != self.lengths[i]:
+                    raise InvalidRawRead
+                return self.values[i]
+            i += 1
+        # memory location not found: this means we are reading from
+        # uninitialized memory, give up the optimization
+        raise InvalidRawRead
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_rawbuffer.py b/pypy/jit/metainterp/optimizeopt/test/test_rawbuffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/optimizeopt/test/test_rawbuffer.py
@@ -0,0 +1,51 @@
+import py
+from pypy.jit.metainterp.optimizeopt.rawbuffer import (InvalidRawWrite,
+                                                       InvalidRawRead, RawBuffer)
+
+def test_write_value():
+    buf = RawBuffer()
+    buf.write_value(8, 4, 'three')
+    buf.write_value(0, 4, 'one')
+    buf.write_value(4, 2, 'two')
+    buf.write_value(12, 2, 'four')
+    assert buf._get_memory() == [
+        ( 0, 4, 'one'),
+        ( 4, 2, 'two'),
+        ( 8, 4, 'three'),
+        (12, 2, 'four'),
+        ]
+    #
+
+def test_write_value_update():
+    buf = RawBuffer()
+    buf.write_value(0, 4, 'one')
+    buf.write_value(4, 2, 'two')
+    buf.write_value(0, 4, 'ONE')
+    assert buf._get_memory() == [
+        ( 0, 4, 'ONE'),
+        ( 4, 2, 'two'),
+        ]
+
+def test_write_value_invalid_length():
+    buf = RawBuffer()
+    buf.write_value(0, 4, 'one')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(0, 5, 'two')
+    
+def test_write_value_overlapping():
+    buf = RawBuffer()
+    buf.write_value(0, 4, 'one')
+    buf.write_value(6, 4, 'two')
+    with py.test.raises(InvalidRawWrite):
+        buf.write_value(4, 4, 'three')
+
+def test_read_value():
+    buf = RawBuffer()
+    buf.write_value(0, 4, 'one')
+    buf.write_value(4, 4, 'two')
+    assert buf.read_value(0, 4) == 'one'
+    assert buf.read_value(4, 4) == 'two'
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(0, 2)
+    with py.test.raises(InvalidRawRead):
+        buf.read_value(8, 2)


More information about the pypy-commit mailing list