Author: Ronan Lamy <[email protected]>
Branch: py3.5
Changeset: r91408:66108bb2353d
Date: 2017-05-24 17:35 +0100
http://bitbucket.org/pypy/pypy/changeset/66108bb2353d/
Log: hg merge default
diff too long, truncating to 2000 out of 4286 lines
diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
--- a/pypy/doc/test/test_whatsnew.py
+++ b/pypy/doc/test/test_whatsnew.py
@@ -102,6 +102,8 @@
assert not not_documented
if branch == 'py3k':
assert not not_merged
+ else:
+ assert branch in documented, 'Please document this branch before
merging: %s' % branch
def test_startrev_on_default():
doc = ROOT.join('pypy', 'doc')
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -56,3 +56,15 @@
Remove faulty fastpath from ctypes
+.. branch: sockopt_zero
+
+Passing a buffersize of 0 to socket.getsockopt
+
+.. branch: better-test-whatsnew
+
+.. branch: faster-rstruct-2
+
+Improve the performance of struct.pack and struct.pack_into by using raw_store
+or gc_store_indexed whenever possible. Moreover, enable the existing
+struct.unpack fast path to all the existing buffer types, whereas previously
+it was enabled only for strings
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -23,7 +23,7 @@
Installing Visual Compiler v9 (for Python 2.7)
----------------------------------------------
-This compiler, while the standard one for Python 2.7, is depricated. Microsoft
has
+This compiler, while the standard one for Python 2.7, is deprecated. Microsoft
has
made it available as the `Microsoft Visual C++ Compiler for Python 2.7`_ (the
link
was checked in Nov 2016). Note that the compiler suite will be installed in
``C:\Users\<user name>\AppData\Local\Programs\Common\Microsoft\Visual C++ for
Python``.
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -1,5 +1,6 @@
from rpython.rlib.rstruct.error import StructError
from rpython.rlib.buffer import StringBuffer, SubBuffer
+from rpython.rlib.mutbuffer import MutableStringBuffer
from pypy.interpreter.error import oefmt
@@ -72,14 +73,15 @@
def bytes_from_value(self, space, w_val):
from pypy.module.struct.formatiterator import PackFormatIterator
itemsize = self.getitemsize()
- fmtiter = PackFormatIterator(space, [w_val], itemsize)
+ buf = MutableStringBuffer(itemsize)
+ fmtiter = PackFormatIterator(space, buf, [w_val])
try:
fmtiter.interpret(self.getformat())
except StructError as e:
raise oefmt(space.w_TypeError,
"memoryview: invalid type for format '%s'",
self.getformat())
- return fmtiter.result.build()
+ return buf.finish()
def _copy_buffer(self):
if self.getndim() == 0:
diff --git a/pypy/module/_cffi_backend/cbuffer.py
b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -6,13 +6,13 @@
from pypy.module._cffi_backend import ctypestruct
from pypy.interpreter.buffer import SimpleView
-from rpython.rlib.buffer import Buffer
+from rpython.rlib.buffer import RawBuffer
from rpython.rtyper.annlowlevel import llstr
from rpython.rtyper.lltypesystem import rffi
from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
-class LLBuffer(Buffer):
+class LLBuffer(RawBuffer):
_immutable_ = True
def __init__(self, raw_cdata, size):
@@ -35,7 +35,7 @@
def getslice(self, start, stop, step, size):
if step == 1:
return rffi.charpsize2str(rffi.ptradd(self.raw_cdata, start), size)
- return Buffer.getslice(self, start, stop, step, size)
+ return RawBuffer.getslice(self, start, stop, step, size)
def setslice(self, start, string):
raw_cdata = rffi.ptradd(self.raw_cdata, start)
diff --git a/pypy/module/_rawffi/buffer.py b/pypy/module/_rawffi/buffer.py
--- a/pypy/module/_rawffi/buffer.py
+++ b/pypy/module/_rawffi/buffer.py
@@ -1,11 +1,10 @@
from rpython.rtyper.lltypesystem import rffi
-
-from rpython.rlib.buffer import Buffer
+from rpython.rlib.buffer import RawBuffer
# XXX not the most efficient implementation
-class RawFFIBuffer(Buffer):
+class RawFFIBuffer(RawBuffer):
_immutable_ = True
def __init__(self, datainstance):
diff --git a/pypy/module/_socket/interp_socket.py
b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -367,20 +367,19 @@
except SocketError as e:
raise converted_error(space, e)
- @unwrap_spec(level=int, optname=int)
- def getsockopt_w(self, space, level, optname, w_buflen=None):
+ @unwrap_spec(level=int, optname=int, buflen=int)
+ def getsockopt_w(self, space, level, optname, buflen=0):
"""getsockopt(level, option[, buffersize]) -> value
Get a socket option. See the Unix manual for level and option.
If a nonzero buffersize argument is given, the return value is a
string of that length; otherwise it is an integer.
"""
- if w_buflen is None:
+ if buflen == 0:
try:
return space.newint(self.sock.getsockopt_int(level, optname))
except SocketError as e:
raise converted_error(space, e)
- buflen = space.int_w(w_buflen)
return space.newbytes(self.sock.getsockopt(level, optname, buflen))
def gettimeout_w(self, space):
diff --git a/pypy/module/_socket/test/test_sock_app.py
b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -514,6 +514,19 @@
(reuse,) = struct.unpack('i', reusestr)
assert reuse != 0
+ def test_getsetsockopt_zero(self):
+ # related to issue #2561: when specifying the buffer size param:
+ # if 0 or None, should return the setted value,
+ # otherwise an empty buffer of the specified size
+ import _socket
+ s = _socket.socket()
+ assert s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 0) == 0
+ assert s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 2) ==
b'\x00\x00'
+ s.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, True)
+ assert s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 0) == 1
+ s.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1)
+ assert s.getsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 0) == 1
+
def test_socket_ioctl(self):
import _socket, sys
if sys.platform != 'win32':
diff --git a/pypy/module/array/interp_array.py
b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -1,11 +1,11 @@
from rpython.rlib import jit, rgc
+from rpython.rlib.buffer import RawBuffer
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rarithmetic import ovfcheck, widen
from rpython.rlib.unroll import unrolling_iterable
from rpython.rtyper.annlowlevel import llstr
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
-from rpython.rlib.buffer import Buffer
from pypy.interpreter.buffer import BufferView
from pypy.interpreter.baseobjspace import W_Root
@@ -848,7 +848,7 @@
v.typecode = k
unroll_typecodes = unrolling_iterable(types.keys())
-class ArrayData(Buffer):
+class ArrayData(RawBuffer):
_immutable_ = True
readonly = False
def __init__(self, w_array):
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -324,6 +324,7 @@
to compress, call the flush() method to finish the compression process,
and return what is left in the internal buffers."""
+ assert data is not None
try:
self.lock()
datasize = len(data)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -22,8 +22,7 @@
from pypy.interpreter.buffer import BufferView
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.argument import Arguments
-
-from rpython.rlib.buffer import Buffer
+from rpython.rlib.buffer import RawBuffer
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib.objectmodel import specialize, not_rpython
from rpython.tool.sourcetools import func_renamer
@@ -428,7 +427,7 @@
fq = FQ()
-class CBuffer(Buffer):
+class CBuffer(RawBuffer):
_immutable_ = True
def __init__(self, view):
self.view = view
diff --git a/pypy/module/micronumpy/concrete.py
b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -3,7 +3,7 @@
from rpython.rlib import jit, rgc
from rpython.rlib.rarithmetic import ovfcheck
from rpython.rlib.listsort import make_timsort_class
-from rpython.rlib.buffer import Buffer
+from rpython.rlib.buffer import RawBuffer
from rpython.rlib.debug import make_sure_not_resized
from rpython.rlib.rstring import StringBuilder
from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \
@@ -702,7 +702,8 @@
def __del__(self):
free_raw_storage(self.storage)
-class ArrayData(Buffer):
+
+class ArrayData(RawBuffer):
_immutable_ = True
def __init__(self, impl, readonly):
self.impl = impl
diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py
--- a/pypy/module/mmap/interp_mmap.py
+++ b/pypy/module/mmap/interp_mmap.py
@@ -4,8 +4,8 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
from pypy.interpreter.buffer import SimpleView
-from rpython.rlib.buffer import Buffer
from rpython.rlib import rmmap, rarithmetic, objectmodel
+from rpython.rlib.buffer import RawBuffer
from rpython.rlib.rmmap import RValueError, RTypeError, RMMapError
from rpython.rlib.rstring import StringBuilder
@@ -309,7 +309,7 @@
return OperationError(space.w_SystemError, space.newtext('%s' % e))
-class MMapBuffer(Buffer):
+class MMapBuffer(RawBuffer):
_immutable_ = True
def __init__(self, space, mmap, readonly):
@@ -329,7 +329,7 @@
if step == 1:
return self.mmap.getslice(start, size)
else:
- return Buffer.getslice(self, start, stop, step, size)
+ return RawBuffer.getslice(self, start, stop, step, size)
def setitem(self, index, char):
self.check_valid_writeable()
diff --git a/pypy/module/pypyjit/test_pypy_c/test_buffers.py
b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_buffers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
@@ -34,29 +34,13 @@
i = 0
while i < n:
i += 1
- struct.unpack('<i', a) # ID: unpack
+ struct.unpack('i', a) # ID: unpack
return i
log = self.run(main, [1000])
assert log.result == 1000
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id('unpack', """
guard_not_invalidated(descr=...)
- p90 = newstr(4)
- call_n(ConstClass(copy_raw_to_string), i55, p90, 0, 4,
descr=<Callv 0 irii EF=5>)
- guard_no_exception(descr=...)
- i91 = strgetitem(p90, 0)
- i92 = strgetitem(p90, 1)
- i93 = int_lshift(i92, 8)
- i94 = int_or(i91, i93)
- i95 = strgetitem(p90, 2)
- i96 = int_lshift(i95, 16)
- i97 = int_or(i94, i96)
- i98 = strgetitem(p90, 3)
- i99 = int_ge(i98, 128)
- guard_false(i99, descr=...)
- i100 = int_lshift(i98, 24)
- i101 = int_or(i97, i100)
- i102 = getfield_raw_i(#, descr=<FieldS pypysig_long_struct.c_value
0>)
- i103 = int_lt(i102, 0)
- guard_false(i103, descr=...)
+ i66 = raw_load_i(i53, 0, descr=<ArrayS 4>)
+ --TICK--
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -110,38 +110,6 @@
loops = log.loops_by_id('sleep')
assert len(loops) == 1 # make sure that we actually JITted the loop
- def test_ctypes_call(self):
- from rpython.rlib.test.test_clibffi import get_libm_name
- def main(libm_name):
- import ctypes
- libm = ctypes.CDLL(libm_name)
- fabs = libm.fabs
- fabs.argtypes = [ctypes.c_double]
- fabs.restype = ctypes.c_double
- x = -4
- i = 0
- while i < 300:
- x = fabs(x)
- x = x - 100
- i += 1
- return fabs._ptr.getaddr(), x
-
- libm_name = get_libm_name(sys.platform)
- log = self.run(main, [libm_name], import_site=True)
- fabs_addr, res = log.result
- assert res == -4.0
- loop, = log.loops_by_filename(self.filepath)
- ops = loop.allops()
- opnames = log.opnames(ops)
- assert opnames.count('new_with_vtable') == 1 # only the virtualref
- py.test.skip("XXX re-optimize _ffi for the JIT?")
- assert opnames.count('call_release_gil') == 1
- idx = opnames.index('call_release_gil')
- call = ops[idx]
- assert (call.args[0] == 'ConstClass(fabs)' or # e.g. OS/X
- int(call.args[0]) == fabs_addr)
-
-
def test__ffi_struct(self):
def main():
from _rawffi.alt import _StructDescr, Field, types
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
@@ -30,32 +30,33 @@
loop, = log.loops_by_filename(self.filepath)
# This could, of course stand some improvement, to remove all these
# arithmatic ops, but we've removed all the core overhead.
- assert loop.match_by_id("pack", """
- guard_not_invalidated(descr=...)
- # struct.pack
- %s
- i11 = int_and(i4, 255)
- i13 = int_rshift(i4, 8)
- i14 = int_and(i13, 255)
- i16 = int_rshift(i13, 8)
- i17 = int_and(i16, 255)
- i19 = int_rshift(i16, 8)
- i20 = int_and(i19, 255)
- """ % extra)
+ if sys.byteorder == 'little':
+ # on little endian machines, we take the fast path and store the
+ # value using gc_store_indexed
+ assert loop.match_by_id("pack", """
+ guard_not_invalidated(descr=...)
+ # struct.pack
+ %s
+ p75 = newstr(4)
+ gc_store_indexed(p75, 0, _, 1, _, 4, descr=...)
+ """ % extra)
+ else:
+ assert loop.match_by_id("pack", """
+ guard_not_invalidated(descr=...)
+ # struct.pack
+ %s
+ i11 = int_and(i4, 255)
+ i13 = int_rshift(i4, 8)
+ i14 = int_and(i13, 255)
+ i16 = int_rshift(i13, 8)
+ i17 = int_and(i16, 255)
+ i19 = int_rshift(i16, 8)
+ i20 = int_and(i19, 255)
+ """ % extra)
if sys.byteorder == 'little':
- # 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
- # 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", """
# struct.unpack
- p88 = newstr(4)
- strsetitem(p88, 0, i11)
- strsetitem(p88, 1, i14)
- strsetitem(p88, 2, i17)
- strsetitem(p88, 3, i20)
i91 = gc_load_indexed_i(p88, 0, 1, _, -4)
""")
else:
@@ -93,27 +94,106 @@
assert loop.match_by_id('pack', """
guard_not_invalidated(descr=...)
# struct.pack
+ p85 = newstr(8)
+ gc_store_indexed(p85, 0, -1, 1, _, 4, descr=...)
%s
- i11 = int_and(i4, 255)
- i13 = int_rshift(i4, 8)
- i14 = int_and(i13, 255)
- i16 = int_rshift(i13, 8)
- i17 = int_and(i16, 255)
- i19 = int_rshift(i16, 8)
- i20 = int_and(i19, 255)
+ gc_store_indexed(p85, 4, _, 1, _, 4, descr=...)
""" % extra)
assert loop.match_by_id('unpack', """
# struct.unpack
- 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)
""")
+
+ def test_unpack_raw_buffer(self):
+ def main(n):
+ import array
+ import struct
+ buf = struct.pack('H', 0x1234)
+ buf = array.array('b', buf)
+ i = 1
+ res = 0
+ while i < n:
+ val = struct.unpack("h", buf)[0] # ID: unpack
+ res += val
+ i += 1
+ return res
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id('unpack', """
+ guard_not_invalidated(descr=...)
+ i65 = raw_load_i(i49, 0, descr=<ArrayS 2>)
+ """)
+
+ def test_unpack_bytearray(self):
+ def main(n):
+ import struct
+ buf = struct.pack('H', 0x1234)
+ buf = bytearray(buf)
+ i = 1
+ res = 0
+ while i < n:
+ val = struct.unpack("h", buf)[0] # ID: unpack
+ res += val
+ i += 1
+ return res
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ # the offset of gc_load_indexed_i used to be the constant 0. However,
+ # now it is 'i46' because we need to add 0 to
+ # W_BytearrayObject._offset
+ assert loop.match_by_id('unpack', """
+ guard_not_invalidated(descr=...)
+ i70 = gc_load_indexed_i(p48, i46, 1, _, -2)
+ """)
+
+ def test_pack_into_raw_buffer(self):
+ def main(n):
+ import array
+ import struct
+ buf = array.array('b', '\x00'*8)
+ i = 1
+ while i < n:
+ struct.pack_into("h", buf, 4, i) # ID: pack_into
+ i += 1
+ return i
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id('pack_into', """\
+ guard_not_invalidated(descr=...)
+ i65 = int_le(i58, 32767)
+ guard_true(i65, descr=...)
+ raw_store(i55, 4, i58, descr=<ArrayS 2>)
+ """)
+
+ def test_pack_into_bytearray(self):
+ def main(n):
+ import struct
+ buf = bytearray(8)
+ i = 1
+ while i < n:
+ struct.pack_into("h", buf, 4, i) # ID: pack_into
+ i += 1
+ return i
+ log = self.run(main, [1000])
+ assert log.result == main(1000)
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match_by_id('pack_into', """\
+ guard_not_invalidated(descr=...)
+ p68 = getfield_gc_r(p14, descr=<FieldP
pypy.objspace.std.bytearrayobject.W_BytearrayObject.inst__data \d+>)
+ i69 = getfield_gc_i(p68, descr=<FieldS list.length \d+>)
+ i70 = getfield_gc_i(p14, descr=<FieldS
pypy.objspace.std.bytearrayobject.W_BytearrayObject.inst__offset \d+>)
+ i71 = int_sub(i69, i70)
+ i73 = int_sub(i71, 4)
+ i75 = int_lt(i73, 2)
+ guard_false(i75, descr=...)
+ i77 = int_le(i62, 32767)
+ guard_true(i77, descr=...)
+ p78 = getfield_gc_r(p68, descr=<FieldP list.items \d+>)
+ i81 = int_add(4, i70)
+ gc_store_indexed(p78, i81, i62, 1, _, 2, descr=<ArrayS 2>)
+ """)
diff --git a/pypy/module/struct/formatiterator.py
b/pypy/module/struct/formatiterator.py
--- a/pypy/module/struct/formatiterator.py
+++ b/pypy/module/struct/formatiterator.py
@@ -2,7 +2,6 @@
maxint, intmask)
from rpython.rlib import jit
from rpython.rlib.objectmodel import specialize
-from rpython.rlib.rstring import StringBuilder
from rpython.rlib.rstruct.error import StructError
from rpython.rlib.rstruct.formatiterator import FormatIterator
@@ -10,11 +9,15 @@
class PackFormatIterator(FormatIterator):
- def __init__(self, space, args_w, size):
+ def __init__(self, space, wbuf, args_w):
self.space = space
self.args_w = args_w
self.args_index = 0
- self.result = StringBuilder(size)
+ self.pos = 0
+ self.wbuf = wbuf
+
+ def advance(self, count):
+ self.pos += count
# This *should* be always unroll safe, the only way to get here is by
# unroll the interpret function, which means the fmt is const, and thus
@@ -31,8 +34,10 @@
@jit.unroll_safe
def align(self, mask):
- pad = (-self.result.getlength()) & mask
- self.result.append_multiple_char('\x00', pad)
+ pad = (-self.pos) & mask
+ for i in range(self.pos, self.pos+pad):
+ self.wbuf.setitem(i, '\x00')
+ self.advance(pad)
def finished(self):
if self.args_index != len(self.args_w):
@@ -135,15 +140,22 @@
if value != self.length:
raise StructError("unpack str size too long for format")
- def read(self, count):
+ def can_advance(self, count):
if self.strides:
count = self.strides[0]
end = self.pos + count
- if end > self.length:
+ return end <= self.length
+
+ def advance(self, count):
+ if not self.can_advance(count):
raise StructError("unpack str size too short for format")
- s = self.buf.getslice(self.pos, end, 1, count)
- self.pos = end
- return s
+ self.pos += count
+
+ def read(self, count):
+ curpos = self.pos
+ end = curpos + count
+ self.advance(count) # raise if we are out of bound
+ return self.buf.getslice(curpos, end, 1, count)
@specialize.argtype(1)
def appendobj(self, value):
@@ -162,9 +174,8 @@
def get_pos(self):
return self.pos
- def get_buffer_as_string_maybe(self):
- string, pos = self.buf.as_str_and_offset_maybe()
- return string, pos+self.pos
+ def get_buffer_and_pos(self):
+ return self.buf, self.pos
def skip(self, count):
# assumption: UnpackFormatIterator only iterates over
diff --git a/pypy/module/struct/interp_struct.py
b/pypy/module/struct/interp_struct.py
--- a/pypy/module/struct/interp_struct.py
+++ b/pypy/module/struct/interp_struct.py
@@ -1,5 +1,6 @@
from rpython.rlib import jit
from rpython.rlib.buffer import SubBuffer
+from rpython.rlib.mutbuffer import MutableStringBuffer
from rpython.rlib.rstruct.error import StructError, StructOverflowError
from rpython.rlib.rstruct.formatiterator import CalcSizeFormatIterator
@@ -48,18 +49,17 @@
def _pack(space, format, args_w):
"""Return string containing values v1, v2, ... packed according to fmt."""
- if jit.isconstant(format):
- size = _calcsize(space, format)
- else:
- size = 8
- fmtiter = PackFormatIterator(space, args_w, size)
+ size = _calcsize(space, format)
+ wbuf = MutableStringBuffer(size)
+ fmtiter = PackFormatIterator(space, wbuf, args_w)
try:
fmtiter.interpret(format)
except StructOverflowError as e:
raise OperationError(space.w_OverflowError, space.newtext(e.msg))
except StructError as e:
raise OperationError(get_error(space), space.newtext(e.msg))
- return fmtiter.result.build()
+ assert fmtiter.pos == wbuf.getlength(), 'missing .advance() or wrong
calcsize()'
+ return wbuf.finish()
def pack(space, w_format, args_w):
@@ -79,21 +79,27 @@
format = text_or_bytes_w(space, w_format)
return do_pack_into(space, format, w_buffer, offset, args_w)
-# XXX inefficient
def do_pack_into(space, format, w_buffer, offset, args_w):
""" Pack the values v1, v2, ... according to fmt.
Write the packed bytes into the writable buffer buf starting at offset
"""
- res = _pack(space, format, args_w)
+ size = _calcsize(space, format)
buf = space.writebuf_w(w_buffer)
if offset < 0:
offset += buf.getlength()
- size = len(res)
if offset < 0 or (buf.getlength() - offset) < size:
raise oefmt(get_error(space),
"pack_into requires a buffer of at least %d bytes",
size)
- buf.setslice(offset, res)
+ #
+ wbuf = SubBuffer(buf, offset, size)
+ fmtiter = PackFormatIterator(space, wbuf, args_w)
+ try:
+ fmtiter.interpret(format)
+ except StructOverflowError as e:
+ raise OperationError(space.w_OverflowError, space.newtext(e.msg))
+ except StructError as e:
+ raise OperationError(get_error(space), space.newtext(e.msg))
def _unpack(space, format, buf):
diff --git a/pypy/module/struct/test/test_struct.py
b/pypy/module/struct/test/test_struct.py
--- a/pypy/module/struct/test/test_struct.py
+++ b/pypy/module/struct/test/test_struct.py
@@ -591,7 +591,7 @@
class AppTestFastPath(object):
- spaceconfig = dict(usemodules=['struct', '__pypy__'])
+ spaceconfig = dict(usemodules=['array', 'struct', '__pypy__'])
def setup_class(cls):
from rpython.rlib.rstruct import standardfmttable
@@ -610,7 +610,43 @@
from rpython.rlib.rstruct import standardfmttable
standardfmttable.ALLOW_SLOWPATH = True
+ def test_unpack_simple(self):
+ buf = self.struct.pack("iii", 0, 42, 43)
+ assert self.struct.unpack("iii", buf) == (0, 42, 43)
+
def test_unpack_from(self):
buf = self.struct.pack("iii", 0, 42, 43)
offset = self.struct.calcsize("i")
assert self.struct.unpack_from("ii", buf, offset) == (42, 43)
+
+ def test_unpack_bytearray(self):
+ data = self.struct.pack("iii", 0, 42, 43)
+ buf = bytearray(data)
+ assert self.struct.unpack("iii", buf) == (0, 42, 43)
+
+ def test_unpack_array(self):
+ import array
+ data = self.struct.pack("iii", 0, 42, 43)
+ buf = array.array('c', data)
+ assert self.struct.unpack("iii", buf) == (0, 42, 43)
+
+ def test_pack_into_bytearray(self):
+ expected = self.struct.pack("ii", 42, 43)
+ buf = bytearray(len(expected))
+ self.struct.pack_into("ii", buf, 0, 42, 43)
+ assert buf == expected
+
+ def test_pack_into_bytearray_padding(self):
+ expected = self.struct.pack("xxi", 42)
+ buf = bytearray(len(expected))
+ self.struct.pack_into("xxi", buf, 0, 42)
+ assert buf == expected
+
+ def test_pack_into_bytearray_delete(self):
+ expected = self.struct.pack("i", 42)
+ # force W_BytearrayObject._delete_from_start
+ buf = bytearray(64)
+ del buf[:8]
+ self.struct.pack_into("i", buf, 0, 42)
+ buf = buf[:len(expected)]
+ assert buf == expected
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,10 +8,11 @@
from rpython.rlib.debug import check_list_of_chars, check_nonneg
from rpython.rtyper.lltypesystem import rffi
from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
- nonmoving_raw_ptr_for_resizable_list)
+ nonmoving_raw_ptr_for_resizable_list)
from rpython.rlib import jit
-from rpython.rlib.buffer import Buffer
-
+from rpython.rlib.buffer import (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
from pypy.objspace.std.bytesobject import makebytesdata_w, newbytesdata_w
@@ -1274,7 +1275,8 @@
start += step
-class BytearrayBuffer(Buffer):
[email protected]
+class BytearrayBuffer(GCBuffer):
_immutable_ = True
def __init__(self, ba, readonly=False):
@@ -1304,7 +1306,7 @@
if start != 0 or stop != len(data):
data = data[start:stop]
return "".join(data)
- return Buffer.getslice(self, start, stop, step, size)
+ return GCBuffer.getslice(self, start, stop, step, size)
def setslice(self, start, string):
# No bounds checks.
@@ -1319,6 +1321,16 @@
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_extra_offset(self):
+ return self.ba._offset
+
+ def _get_gc_data(self):
+ return get_gc_data_for_list_of_chars(self.ba._data)
+
@specialize.argtype(1)
def _memcmp(selfvalue, buffer, length):
diff --git a/pypy/objspace/std/marshal_impl.py
b/pypy/objspace/std/marshal_impl.py
--- a/pypy/objspace/std/marshal_impl.py
+++ b/pypy/objspace/std/marshal_impl.py
@@ -1,5 +1,6 @@
from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint
-from rpython.rlib.rstring import StringBuilder, assert_str0
+from rpython.rlib.rstring import assert_str0
+from rpython.rlib.mutbuffer import MutableStringBuffer
from rpython.rlib.rstruct import ieee
from rpython.rlib.unroll import unrolling_iterable
from rpython.rlib import objectmodel
@@ -213,9 +214,9 @@
def pack_float(f):
- result = StringBuilder(8)
- ieee.pack_float(result, f, 8, False)
- return result.build()
+ buf = MutableStringBuffer(8)
+ ieee.pack_float(buf, 0, f, 8, False)
+ return buf.finish()
def unpack_float(s):
return ieee.unpack_float(s, False)
@@ -408,7 +409,7 @@
stacksize = u.get_int()
flags = u.get_int()
code = space.bytes_w(u.get_w_obj())
- consts_w = _unmarshal_tuple_w(u)
+ consts_w = _unmarshal_tuple_w(u)
names = _unmarshal_strlist(u)
varnames = _unmarshal_strlist(u)
freevars = _unmarshal_strlist(u)
diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py
--- a/rpython/annotator/binaryop.py
+++ b/rpython/annotator/binaryop.py
@@ -514,13 +514,13 @@
ne = eq
def lt((tup1, tup2)):
- raise Exception("unsupported: (...) < (...)")
+ raise AnnotatorError("unsupported: (...) < (...)")
def le((tup1, tup2)):
- raise Exception("unsupported: (...) <= (...)")
+ raise AnnotatorError("unsupported: (...) <= (...)")
def gt((tup1, tup2)):
- raise Exception("unsupported: (...) > (...)")
+ raise AnnotatorError("unsupported: (...) > (...)")
def ge((tup1, tup2)):
- raise Exception("unsupported: (...) >= (...)")
+ raise AnnotatorError("unsupported: (...) >= (...)")
class __extend__(pairtype(SomeDict, SomeDict)):
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -15,7 +15,8 @@
SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
s_None, s_ImpossibleValue, SomeBool, SomeTuple, SomeException,
SomeImpossibleValue, SomeUnicodeString, SomeList, HarmlesslyBlocked,
- SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty)
+ SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty,
+ AnnotatorError)
from rpython.annotator.classdesc import ClassDef, ClassDesc
from rpython.annotator.listdef import ListDef, ListItem
from rpython.annotator.dictdef import DictDef
@@ -343,7 +344,7 @@
elif x is None:
return s_None
else:
- raise Exception("Don't know how to represent %r" % (x,))
+ raise AnnotatorError("Don't know how to represent %r" % (x,))
result.const = x
return result
@@ -363,7 +364,7 @@
result = self.newfuncdesc(pyobj)
elif isinstance(pyobj, (type, types.ClassType)):
if pyobj is object:
- raise Exception("ClassDesc for object not supported")
+ raise AnnotatorError("ClassDesc for object not supported")
if pyobj.__module__ == '__builtin__': # avoid making classdefs
for builtin types
result = self.getfrozen(pyobj)
else:
@@ -400,7 +401,7 @@
msg = "object with a __call__ is not RPython"
else:
msg = "unexpected prebuilt constant"
- raise Exception("%s: %r" % (msg, pyobj))
+ raise AnnotatorError("%s: %r" % (msg, pyobj))
result = self.getfrozen(pyobj)
self.descs[obj_key] = result
return result
@@ -589,7 +590,7 @@
for name, value in dict.iteritems():
if value is func:
return cls, name
- raise Exception("could not match bound-method to attribute name: %r" %
(boundmeth,))
+ raise AnnotatorError("could not match bound-method to attribute name: %r"
% (boundmeth,))
def ishashable(x):
try:
diff --git a/rpython/annotator/classdesc.py b/rpython/annotator/classdesc.py
--- a/rpython/annotator/classdesc.py
+++ b/rpython/annotator/classdesc.py
@@ -550,8 +550,8 @@
"with _mixin_: %r" % (cls,))
base = b1
if mixins_before and mixins_after:
- raise Exception("unsupported: class %r has mixin bases both"
- " before and after the regular base" % (self,))
+ raise AnnotatorError("unsupported: class %r has mixin bases both"
+ " before and after the regular base" %
(self,))
self.add_mixins(mixins_after, check_not_in=base)
self.add_mixins(mixins_before)
self.add_sources_for_class(cls)
@@ -569,8 +569,8 @@
attrs.update(decl)
if self.basedesc is not None:
if self.basedesc.all_enforced_attrs is None:
- raise Exception("%r has slots or _attrs_, "
- "but not its base class" % (cls,))
+ raise AnnotatorError("%r has slots or _attrs_, "
+ "but not its base class" % (cls,))
attrs.update(self.basedesc.all_enforced_attrs)
self.all_enforced_attrs = attrs
@@ -714,8 +714,8 @@
try:
args.fixedunpack(0)
except ValueError:
- raise Exception("default __init__ takes no argument"
- " (class %s)" % (self.name,))
+ raise AnnotatorError("default __init__ takes no argument"
+ " (class %s)" % (self.name,))
elif self.pyobj is Exception:
# check explicitly against "raise Exception, x" where x
# is a low-level exception pointer
@@ -824,8 +824,8 @@
# actual copy in the rtyper). Tested in rpython.rtyper.test.test_rlist,
# test_immutable_list_out_of_instance.
if self._detect_invalid_attrs and attr in self._detect_invalid_attrs:
- raise Exception("field %r was migrated to %r from a subclass in "
- "which it was declared as _immutable_fields_" %
+ raise AnnotatorError("field %r was migrated to %r from a subclass
in "
+ "which it was declared as _immutable_fields_"
%
(attr, self.pyobj))
search1 = '%s[*]' % (attr,)
search2 = '%s?[*]' % (attr,)
@@ -858,7 +858,7 @@
# call to a single class, look at the result annotation
# in case it was specialized
if not isinstance(s_result, SomeInstance):
- raise Exception("calling a class didn't return an instance??")
+ raise AnnotatorError("calling a class didn't return an
instance??")
classdefs = [s_result.classdef]
else:
# call to multiple classes: specialization not supported
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -314,8 +314,8 @@
enforceargs = getattr(self.pyobj, '_annenforceargs_', None)
signature = getattr(self.pyobj, '_signature_', None)
if enforceargs and signature:
- raise Exception("%r: signature and enforceargs cannot both be "
- "used" % (self,))
+ raise AnnotatorError("%r: signature and enforceargs cannot both be
"
+ "used" % (self,))
if enforceargs:
if not callable(enforceargs):
from rpython.annotator.signature import Sig
@@ -432,7 +432,7 @@
def func_args(self, args):
from rpython.annotator.model import SomeInstance
if self.selfclassdef is None:
- raise Exception("calling %r" % (self,))
+ raise AnnotatorError("calling %r" % (self,))
s_instance = SomeInstance(self.selfclassdef, flags=self.flags)
return args.prepend(s_instance)
diff --git a/rpython/annotator/test/test_annrpython.py
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4584,7 +4584,7 @@
return Ellipsis
a = self.RPythonAnnotator()
e = py.test.raises(Exception, a.build_types, f, [])
- assert str(e.value) == "Don't know how to represent Ellipsis"
+ assert "Don't know how to represent Ellipsis" in str(e.value)
def test_must_be_light_finalizer(self):
from rpython.rlib import rgc
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -185,8 +185,8 @@
return SomeString()
def id(self):
- raise Exception("cannot use id() in RPython; "
- "see objectmodel.compute_xxx()")
+ raise AnnotatorError("cannot use id() in RPython; "
+ "see objectmodel.compute_xxx()")
def int(self):
return SomeInteger()
@@ -421,7 +421,7 @@
def setslice(self, s_start, s_stop, s_iterable):
check_negative_slice(s_start, s_stop)
if not isinstance(s_iterable, SomeList):
- raise Exception("list[start:stop] = x: x must be a list")
+ raise AnnotatorError("list[start:stop] = x: x must be a list")
self.listdef.mutate()
self.listdef.agree(getbookkeeper(), s_iterable.listdef)
self.listdef.resize()
diff --git a/rpython/jit/backend/arm/test/test_llop.py
b/rpython/jit/backend/arm/test/test_llop.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/arm/test/test_llop.py
@@ -0,0 +1,9 @@
+from rpython.jit.backend.arm.test.support import JitARMMixin
+from rpython.jit.metainterp.test.test_llop import TestLLOp as _TestLLOp
+
+
+class TestLLOp(JitARMMixin, _TestLLOp):
+ # for the individual tests see
+ # ====> ../../../metainterp/test/test_llop.py
+ pass
+
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
@@ -716,16 +716,28 @@
else:
return self.bh_raw_load_i(struct, offset, descr)
+ def _get_int_type_from_size(self, size):
+ if size == 1:
+ return rffi.UCHAR
+ elif size == 2:
+ return rffi.USHORT
+ elif size == 4:
+ return rffi.UINT
+ elif size == 8:
+ return rffi.ULONGLONG
+ elif size == -1:
+ return rffi.SIGNEDCHAR
+ elif size == -2:
+ return rffi.SHORT
+ elif size == -4:
+ return rffi.INT
+ elif size == -8:
+ return rffi.LONGLONG
+ else:
+ raise NotImplementedError(size)
+
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)
+ T = self._get_int_type_from_size(bytes)
x = llop.gc_load_indexed(T, struct, index, scale, base_ofs)
return lltype.cast_primitive(lltype.Signed, x)
@@ -735,6 +747,30 @@
return llop.gc_load_indexed(longlong.FLOATSTORAGE,
struct, index, scale, base_ofs)
+ def bh_gc_store_indexed_i(self, struct, index, val, scale, base_ofs, bytes,
+ descr):
+ T = self._get_int_type_from_size(bytes)
+ val = lltype.cast_primitive(T, val)
+ if descr.A.OF == lltype.SingleFloat:
+ val = longlong.int2singlefloat(val)
+ llop.gc_store_indexed(lltype.Void, struct, index, val, scale, base_ofs)
+
+ def bh_gc_store_indexed_f(self, struct, index, val, scale, base_ofs, bytes,
+ descr):
+ if bytes != 8:
+ raise Exception("gc_store_indexed_f is only for 'double'!")
+ val = longlong.getrealfloat(val)
+ llop.gc_store_indexed(lltype.Void, struct, index, val, scale, base_ofs)
+
+ def bh_gc_store_indexed(self, struct, index, val, scale, base_ofs, bytes,
+ descr):
+ if descr.A.OF == lltype.Float:
+ self.bh_gc_store_indexed_f(struct, index, val, scale, base_ofs,
+ bytes, descr)
+ else:
+ self.bh_gc_store_indexed_i(struct, index, val, scale, base_ofs,
+ bytes, descr)
+
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
@@ -496,6 +496,7 @@
@specialize.argtype(1)
def write_float_at_mem(self, gcref, ofs, newvalue):
llop.raw_store(lltype.Void, gcref, ofs, newvalue)
+ write_float_at_mem._annenforceargs_ = [None, None, None,
longlong.r_float_storage]
# ____________________________________________________________
@@ -754,6 +755,16 @@
offset = base_ofs + scale * index
return self.read_float_at_mem(addr, offset)
+ def bh_gc_store_indexed_i(self, addr, index, val, scale, base_ofs, bytes,
+ descr):
+ offset = base_ofs + scale * index
+ self.write_int_at_mem(addr, offset, bytes, val)
+
+ def bh_gc_store_indexed_f(self, addr, index, val, scale, base_ofs, bytes,
+ descr):
+ offset = base_ofs + scale * index
+ self.write_float_at_mem(addr, offset, val)
+
def bh_new(self, sizedescr):
return self.gc_ll_descr.gc_malloc(sizedescr)
diff --git a/rpython/jit/backend/x86/test/test_llop.py
b/rpython/jit/backend/x86/test/test_llop.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/x86/test/test_llop.py
@@ -0,0 +1,14 @@
+from rpython.jit.backend.x86.test.test_basic import Jit386Mixin
+from rpython.jit.metainterp.test.test_llop import TestLLOp as _TestLLOp
+
+
+class TestLLOp(Jit386Mixin, _TestLLOp):
+ # for the individual tests see
+ # ====> ../../../metainterp/test/test_llop.py
+
+ # do NOT test the blackhole implementation of gc_store_indexed. It cannot
+ # work inside tests because llmodel.py:bh_gc_store_indexed_* receive a
+ # symbolic as the offset. It is not a problem because it is tested anyway
+ # by the same test in test_metainterp.py
+ TEST_BLACKHOLE = False
+
diff --git a/rpython/jit/backend/x86/test/test_strstorage.py
b/rpython/jit/backend/x86/test/test_strstorage.py
deleted file mode 100644
--- a/rpython/jit/backend/x86/test/test_strstorage.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from rpython.jit.backend.x86.test.test_basic import Jit386Mixin
-from rpython.jit.metainterp.test.test_strstorage import TestStrStorage as
_TestStrStorage
-
-
-class TestStrStorage(Jit386Mixin, _TestStrStorage):
- # for the individual tests see
- # ====> ../../../metainterp/test/test_strstorage.py
- pass
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
@@ -1131,6 +1131,26 @@
[op.args[0], op.args[1],
op.args[2], op.args[3], c_bytes], op.result)
+ def rewrite_op_gc_store_indexed(self, op):
+ T = op.args[2].concretetype
+ kind = getkind(T)[0]
+ assert kind != 'r'
+ descr = self.cpu.arraydescrof(rffi.CArray(T))
+ if (not isinstance(op.args[3], Constant) or
+ not isinstance(op.args[4], Constant)):
+ raise NotImplementedError("gc_store_indexed: 'scale' and
'base_ofs'"
+ " should be constants")
+ # According to the comment in resoperation.py, "itemsize is not signed
+ # (always > 0)", so we don't need the "bytes = -bytes" line which is
+ # in rewrite_op_gc_load_indexed
+ bytes = descr.get_item_size_in_bytes()
+ c_bytes = Constant(bytes, lltype.Signed)
+ return SpaceOperation('gc_store_indexed_%s' % kind,
+ [op.args[0], op.args[1], op.args[2],
+ op.args[3], op.args[4], c_bytes, descr], None)
+
+
+
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
@@ -1478,6 +1478,18 @@
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("cpu", "r", "i", "i", "i", "i", "i", "d")
+ def bhimpl_gc_store_indexed_i(cpu, addr, index, val, scale, base_ofs,
bytes,
+ arraydescr):
+ return cpu.bh_gc_store_indexed_i(addr, index, val, scale,base_ofs,
bytes,
+ arraydescr)
+
+ @arguments("cpu", "r", "i", "f", "i", "i", "i", "d")
+ def bhimpl_gc_store_indexed_f(cpu, addr, index, val, scale, base_ofs,
bytes,
+ arraydescr):
+ return cpu.bh_gc_store_indexed_f(addr, index, val, scale,base_ofs,
bytes,
+ arraydescr)
+
@arguments("r", "d", "d")
def bhimpl_record_quasiimmut_field(struct, fielddescr, mutatefielddescr):
pass
diff --git a/rpython/jit/metainterp/compile.py
b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -110,7 +110,7 @@
"""
log_noopt = False
- def __init__(self, trace, celltoken, state, runtime_boxes,
+ def __init__(self, trace, celltoken, state,
call_pure_results=None, enable_opts=None,
inline_short_preamble=True):
self.trace = trace
@@ -119,8 +119,6 @@
self.state = state
self.call_pure_results = call_pure_results
self.inline_short_preamble = inline_short_preamble
- assert runtime_boxes is not None
- self.runtime_boxes = runtime_boxes
def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
from rpython.jit.metainterp.optimizeopt.unroll import UnrollOptimizer
@@ -128,11 +126,7 @@
assert unroll # we should not be here if it's disabled
opt = UnrollOptimizer(metainterp_sd, jitdriver_sd, optimizations)
return opt.optimize_peeled_loop(self.trace, self.celltoken, self.state,
- self.runtime_boxes, self.call_pure_results,
self.inline_short_preamble)
-
- def forget_optimization_info(self):
- self.state.forget_optimization_info()
- CompileData.forget_optimization_info(self)
+ self.call_pure_results, self.inline_short_preamble)
def show_procedures(metainterp_sd, procedure=None, error=None):
# debugging
@@ -298,7 +292,7 @@
start_descr = TargetToken(jitcell_token,
original_jitcell_token=jitcell_token)
jitcell_token.target_tokens = [start_descr]
- loop_data = UnrolledLoopData(trace, jitcell_token, start_state, jumpargs,
+ loop_data = UnrolledLoopData(trace, jitcell_token, start_state,
call_pure_results=call_pure_results,
enable_opts=enable_opts)
try:
@@ -368,7 +362,7 @@
history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
enable_opts = jitdriver_sd.warmstate.enable_opts
call_pure_results = metainterp.call_pure_results
- loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
jumpargs,
+ loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
call_pure_results=call_pure_results,
enable_opts=enable_opts)
try:
@@ -380,7 +374,6 @@
history.cut(cut)
history.record(rop.JUMP, jumpargs[:], None, descr=loop_jitcell_token)
loop_data = UnrolledLoopData(trace, loop_jitcell_token, start_state,
- jumpargs,
call_pure_results=call_pure_results,
enable_opts=enable_opts,
inline_short_preamble=False)
@@ -525,7 +518,7 @@
for item in lst:
item.set_forwarded(None)
# XXX we should really do it, but we need to remember the values
- # somehow for ContinueRunningNormally
+ # somehoe for ContinueRunningNormally
if reset_values:
item.reset_value()
diff --git a/rpython/jit/metainterp/executor.py
b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -251,6 +251,25 @@
else:
return BoxInt(cpu.bh_raw_load_i(addr, offset, arraydescr))
+def do_gc_store_indexed(cpu, _, addrbox, indexbox, valuebox, scalebox,
+ base_ofsbox, bytesbox, arraydescr):
+ addr = addrbox.getref_base()
+ index = indexbox.getint()
+ scale = scalebox.getint()
+ base_ofs = base_ofsbox.getint()
+ bytes = bytesbox.getint()
+ if arraydescr.is_array_of_pointers():
+ raise AssertionError("cannot store GC pointers in gc_store_indexed for
now")
+ elif arraydescr.is_array_of_floats():
+ floatval = valuebox.getfloatstorage()
+ cpu.bh_gc_store_indexed_f(addr, index, floatval, scale, base_ofs,
bytes,
+ arraydescr)
+ else:
+ intval = valuebox.getint()
+ cpu.bh_gc_store_indexed_i(addr, index, intval, scale, base_ofs, bytes,
+ arraydescr)
+
+
def exec_new_with_vtable(cpu, descr):
return cpu.bh_new_with_vtable(descr)
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
@@ -12,7 +12,7 @@
from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.resoperation import rop, ResOperation, OpHelpers,\
AbstractResOp, GuardResOp
-from rpython.rlib.objectmodel import we_are_translated, we_are_debug
+from rpython.rlib.objectmodel import we_are_translated
from rpython.jit.metainterp.optimizeopt import info
@@ -173,7 +173,7 @@
def _getfield(self, opinfo, descr, optheap, true_force=True):
res = opinfo.getfield(descr, optheap)
- if we_are_debug() and res:
+ if not we_are_translated() and res:
if isinstance(opinfo, info.AbstractStructPtrInfo):
assert opinfo in self.cached_infos
if isinstance(res, PreambleOp):
@@ -203,7 +203,7 @@
def _getfield(self, opinfo, descr, optheap, true_force=True):
res = opinfo.getitem(descr, self.index, optheap)
- if we_are_debug() and res:
+ if not we_are_translated() and res:
if isinstance(opinfo, info.ArrayPtrInfo):
assert opinfo in self.cached_infos
if (isinstance(res, PreambleOp) and
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py
b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -24,20 +24,9 @@
llhelper.CONST_NULLREF = llhelper.CONST_NULL
REMOVED = AbstractResOp()
-def check_no_forwarding(lsts):
- for lst in lsts:
- for op in lst:
- assert op.get_forwarded() is None
-
class LoopInfo(object):
label_op = None
- def _check_no_forwarding(self):
- pass
-
- def forget_optimization_info(self):
- pass
-
class BasicLoopInfo(LoopInfo):
def __init__(self, inputargs, quasi_immutable_deps, jump_op):
self.inputargs = inputargs
@@ -567,8 +556,7 @@
return (BasicLoopInfo(trace.inputargs, self.quasi_immutable_deps,
last_op),
self._newoperations)
- @staticmethod
- def _clean_optimization_info(lst):
+ def _clean_optimization_info(self, lst):
for op in lst:
if op.get_forwarded() is not None:
op.set_forwarded(None)
diff --git a/rpython/jit/metainterp/optimizeopt/shortpreamble.py
b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
--- a/rpython/jit/metainterp/optimizeopt/shortpreamble.py
+++ b/rpython/jit/metainterp/optimizeopt/shortpreamble.py
@@ -5,7 +5,6 @@
rop, AbstractResOp, AbstractInputArg
from rpython.jit.metainterp.history import Const, make_hashable_int,\
TreeLoop
-from rpython.jit.metainterp.optimize import InvalidLoop
from rpython.jit.metainterp.optimizeopt import info
class PreambleOp(AbstractResOp):
@@ -19,7 +18,7 @@
See force_op_from_preamble for details how the extra things are put.
"""
op = None
-
+
def __init__(self, op, preamble_op, invented_name):
self.op = op
self.preamble_op = preamble_op
@@ -52,13 +51,7 @@
class AbstractShortOp(object):
""" An operation that is potentially produced by the short preamble
"""
- res = None
-
- def _check_no_forwarding(self):
- assert self.res.get_forwarded() is None
-
- def forget_optimization_info(self):
- self.res.clear_forwarded()
+ pass
class HeapOp(AbstractShortOp):
def __init__(self, res, getfield_op):
@@ -108,14 +101,6 @@
descr=sop.getdescr())
return ProducedShortOp(self, preamble_op)
- def _check_no_forwarding(self):
- AbstractShortOp._check_no_forwarding(self)
- assert self.getfield_op.get_forwarded() is None
-
- def forget_optimization_info(self):
- AbstractShortOp.forget_optimization_info(self)
- self.getfield_op.clear_forwarded()
-
def __repr__(self):
return "HeapOp(%r)" % (self.res,)
@@ -208,16 +193,6 @@
l.append(pop)
return l
- def _check_no_forwarding(self):
- AbstractShortOp._check_no_forwarding(self)
- self.one._check_no_forwarding()
- self.two._check_no_forwarding()
-
- def forget_optimization_info(self):
- AbstractShortOp.forget_optimization_info(self)
- self.one.forget_optimization_info()
- self.two.forget_optimization_info()
-
def repr(self, memo):
return "CompoundOp(%s, %s, %s)" % (self.res.repr(memo),
self.one.repr(memo),
@@ -228,7 +203,7 @@
class ProducedShortOp(AbstractProducedShortOp):
invented_name = False
-
+
def __init__(self, short_op, preamble_op):
self.short_op = short_op
self.preamble_op = preamble_op
@@ -240,14 +215,6 @@
def repr(self, memo):
return self.short_op.repr(memo)
- def _check_no_forwarding(self):
- self.short_op._check_no_forwarding()
- assert self.preamble_op.get_forwarded() is None
-
- def forget_optimization_info(self):
- self.short_op.forget_optimization_info()
- self.preamble_op.clear_forwarded()
-
def __repr__(self):
return "%r -> %r" % (self.short_op, self.preamble_op)
@@ -268,14 +235,6 @@
def repr(self, memo):
return "INP(%s)" % (self.res.repr(memo),)
- def _check_no_forwarding(self):
- AbstractShortOp._check_no_forwarding(self)
- assert self.preamble_op.get_forwarded() is None
-
- def forget_optimization_info(self):
- AbstractShortOp.forget_optimization_info(self)
- self.preamble_op.clear_forwarded()
-
def __repr__(self):
return "INP(%r -> %r)" % (self.res, self.preamble_op)
@@ -495,23 +454,16 @@
self.sb = sb
self.extra_same_as = self.sb.extra_same_as
self.target_token = target_token
- self.build_inplace = False
def setup(self, jump_args, short, label_args):
self.jump_args = jump_args
self.short = short
self.label_args = label_args
- self.build_inplace = True
def add_preamble_op(self, preamble_op):
""" Notice that we're actually using the preamble_op, add it to
label and jump
"""
- # Could this be considered a speculative error?
- # This check should only fail when trying to jump to an existing trace
- # by forcing portions of the virtualstate.
- if not self.build_inplace:
- raise InvalidLoop("Forcing boxes would modify an existing short
preamble")
op = preamble_op.op.get_box_replacement()
if preamble_op.invented_name:
self.extra_same_as.append(op)
@@ -519,8 +471,6 @@
self.jump_args.append(preamble_op.preamble_op)
def use_box(self, box, preamble_op, optimizer=None):
- if not self.build_inplace:
- raise InvalidLoop("Forcing boxes would modify an existing short
preamble")
jump_op = self.short.pop()
AbstractShortPreambleBuilder.use_box(self, box, preamble_op, optimizer)
self.short.append(jump_op)
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -577,7 +577,6 @@
#
compile_data.enable_opts = self.enable_opts
state = optimize_trace(metainterp_sd, None, compile_data)
- state[0]._check_no_forwarding()
return state
def _convert_call_pure_results(self, d):
@@ -626,7 +625,7 @@
start_state, preamble_ops = self._do_optimize_loop(preamble_data)
preamble_data.forget_optimization_info()
loop_data = compile.UnrolledLoopData(preamble_data.trace,
- celltoken, start_state, runtime_boxes, call_pure_results)
+ celltoken, start_state, call_pure_results)
loop_info, ops = self._do_optimize_loop(loop_data)
preamble = TreeLoop('preamble')
preamble.inputargs = start_state.renamed_inputargs
diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py
b/rpython/jit/metainterp/optimizeopt/unroll.py
--- a/rpython/jit/metainterp/optimizeopt/unroll.py
+++ b/rpython/jit/metainterp/optimizeopt/unroll.py
@@ -6,7 +6,7 @@
from rpython.jit.metainterp.optimizeopt import info, intutils
from rpython.jit.metainterp.optimize import InvalidLoop, SpeculativeError
from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer,\
- Optimization, LoopInfo, MININT, MAXINT, BasicLoopInfo, check_no_forwarding
+ Optimization, LoopInfo, MININT, MAXINT, BasicLoopInfo
from rpython.jit.metainterp.optimizeopt.vstring import StrPtrInfo
from rpython.jit.metainterp.optimizeopt.virtualstate import (
VirtualStateConstructor, VirtualStatesCantMatch)
@@ -35,7 +35,7 @@
def setinfo_from_preamble_list(self, lst, infos):
for item in lst:
- if item is None or isinstance(item, Const):
+ if item is None:
continue
i = infos.get(item, None)
if i is not None:
@@ -99,6 +99,7 @@
elif isinstance(preamble_info, info.FloatConstInfo):
op.set_forwarded(preamble_info._const)
+
class UnrollOptimizer(Optimization):
"""Unroll the loop into two iterations. The first one will
become the preamble or entry bridge (don't think there is a
@@ -116,22 +117,26 @@
return modifier.get_virtual_state(args)
def _check_no_forwarding(self, lsts, check_newops=True):
- check_no_forwarding(lsts)
+ for lst in lsts:
+ for op in lst:
+ assert op.get_forwarded() is None
if check_newops:
assert not self.optimizer._newoperations
+
def optimize_preamble(self, trace, runtime_boxes, call_pure_results, memo):
info, newops = self.optimizer.propagate_all_forward(
trace.get_iter(), call_pure_results, flush=False)
exported_state = self.export_state(info.jump_op.getarglist(),
- info.inputargs, memo)
+ info.inputargs,
+ runtime_boxes, memo)
exported_state.quasi_immutable_deps = info.quasi_immutable_deps
# we need to absolutely make sure that we've cleaned up all
# the optimization info
self.optimizer._clean_optimization_info(self.optimizer._newoperations)
return exported_state, self.optimizer._newoperations
- def optimize_peeled_loop(self, trace, celltoken, state, runtime_boxes,
+ def optimize_peeled_loop(self, trace, celltoken, state,
call_pure_results, inline_short_preamble=True):
trace = trace.get_iter()
try:
@@ -183,7 +188,7 @@
try:
new_virtual_state = self.jump_to_existing_trace(
- end_jump, label_op, runtime_boxes, force_boxes=False)
+ end_jump, label_op, state.runtime_boxes, force_boxes=False)
except InvalidLoop:
# inlining short preamble failed, jump to preamble
self.jump_to_preamble(celltoken, end_jump, info)
@@ -196,7 +201,7 @@
# to the preamble.
try:
new_virtual_state = self.jump_to_existing_trace(
- end_jump, label_op, runtime_boxes, force_boxes=True)
+ end_jump, label_op, state.runtime_boxes,
force_boxes=True)
except InvalidLoop:
pass
@@ -279,7 +284,8 @@
debug_print("Retrace count reached, jumping to preamble")
return self.jump_to_preamble(cell_token, jump_op, info)
exported_state = self.export_state(info.jump_op.getarglist(),
- info.inputargs, box_names_memo)
+ info.inputargs, runtime_boxes,
+ box_names_memo)
exported_state.quasi_immutable_deps =
self.optimizer.quasi_immutable_deps
self.optimizer._clean_optimization_info(self.optimizer._newoperations)
return exported_state, self.optimizer._newoperations
@@ -443,7 +449,8 @@
continue
self._expand_info(item, infos)
- def export_state(self, original_label_args, renamed_inputargs, memo):
+ def export_state(self, original_label_args, renamed_inputargs,
+ runtime_boxes, memo):
end_args = [self.optimizer.force_box_for_end_of_preamble(a)
for a in original_label_args]
self.optimizer.flush()
@@ -464,17 +471,16 @@
op = produced_op.short_op.res
if not isinstance(op, Const):
self._expand_info(op, infos)
+ self.optimizer._clean_optimization_info(end_args)
return ExportedState(label_args, end_args, virtual_state, infos,
short_boxes, renamed_inputargs,
- short_inputargs, memo)
+ short_inputargs, runtime_boxes, memo)
def import_state(self, targetargs, exported_state):
# the mapping between input args (from old label) and what we need
# to actually emit. Update the info
assert (len(exported_state.next_iteration_args) ==
len(targetargs))
- self._check_no_forwarding([targetargs])
- exported_state._check_no_forwarding()
for i, target in enumerate(exported_state.next_iteration_args):
source = targetargs[i]
assert source is not target
@@ -530,11 +536,13 @@
* renamed_inputargs - the start label arguments in optimized version
* short_inputargs - the renamed inputargs for short preamble
* quasi_immutable_deps - for tracking quasi immutables
+ * runtime_boxes - runtime values for boxes, necessary when generating
+ guards to jump to
"""
def __init__(self, end_args, next_iteration_args, virtual_state,
exported_infos, short_boxes, renamed_inputargs,
- short_inputargs, memo):
+ short_inputargs, runtime_boxes, memo):
self.end_args = end_args
self.next_iteration_args = next_iteration_args
self.virtual_state = virtual_state
@@ -542,8 +550,8 @@
self.short_boxes = short_boxes
self.renamed_inputargs = renamed_inputargs
self.short_inputargs = short_inputargs
+ self.runtime_boxes = runtime_boxes
self.dump(memo)
- self.forget_optimization_info()
def dump(self, memo):
if have_debug_prints():
@@ -553,35 +561,5 @@
debug_print(" " + box.repr(memo))
debug_stop("jit-log-exported-state")
- def _check_no_forwarding(self):
- """ Ensures that no optimization state is attached to relevant
operations
- before importing anything. """
- # Some of these may be redunant
- check_no_forwarding([
- self.end_args,
- self.next_iteration_args,
- self.renamed_inputargs,
- self.short_inputargs,
- self.exported_infos.keys()])
- for box in self.short_boxes:
- box._check_no_forwarding()
-
- def forget_optimization_info(self):
- """ Clean up optimization info on all operations stored in the
ExportedState.
-
- This function needs to be called when exporting the optimizer state to
- prevent leaking of optimization information between invocations of the
- optimizer.
-
- That includes cleaning up in the event that optimize_peeled_loop()
fails
- with an InvalidLoop exception, as optimize_peeled_loop() mutates the
- contents of ExportedState.
- """
- Optimizer._clean_optimization_info(self.renamed_inputargs)
- for box in self.exported_infos.iterkeys():
- box.clear_forwarded()
- for box in self.short_boxes:
- box.forget_optimization_info()
-
def final(self):
return False
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
@@ -827,6 +827,21 @@
self._remove_symbolics(scalebox),
self._remove_symbolics(baseofsbox), bytesbox)
+ @arguments("box", "box", "box", "box", "box", "box", "descr")
+ def _opimpl_gc_store_indexed(self, addrbox, indexbox, valuebox,
+ scalebox, baseofsbox, bytesbox,
+ arraydescr):
+ return self.execute_with_descr(rop.GC_STORE_INDEXED,
+ arraydescr,
+ addrbox,
+ indexbox,
+ valuebox,
+ self._remove_symbolics(scalebox),
+ self._remove_symbolics(baseofsbox),
+ bytesbox)
+ opimpl_gc_store_indexed_i = _opimpl_gc_store_indexed
+ opimpl_gc_store_indexed_f = _opimpl_gc_store_indexed
+
@arguments("box")
def opimpl_hint_force_virtualizable(self, box):
self.metainterp.gen_store_back_in_vable(box)
@@ -2024,8 +2039,6 @@
self.aborted_tracing_greenkey = None
def retrace_needed(self, trace, exported_state):
- if not we_are_translated():
- exported_state._check_no_forwarding()
self.partial_trace = trace
self.retracing_from = self.potential_retrace_position
self.exported_state = exported_state
diff --git a/rpython/jit/metainterp/resoperation.py
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -52,10 +52,6 @@
llop.debug_print(lltype.Void, "setting forwarded on:",
self.__class__.__name__)
raise SettingForwardedOnAbstractValue()
- def clear_forwarded(self):
- if self.get_forwarded() is not None:
- self.set_forwarded(None)
-
@specialize.arg(1)
def get_box_replacement(op, not_const=False):
# Read the chain "op, op._forwarded, op._forwarded._forwarded..."
diff --git a/rpython/jit/metainterp/test/support.py
b/rpython/jit/metainterp/test/support.py
--- a/rpython/jit/metainterp/test/support.py
+++ b/rpython/jit/metainterp/test/support.py
@@ -19,7 +19,8 @@
supports_floats=True,
supports_longlong=False,
supports_singlefloats=False,
- translationoptions={}, **kwds):
+ translationoptions={},
+ backendopt_inline_threshold=0, **kwds):
from rpython.jit.codewriter import support
class FakeJitCell(object):
@@ -59,7 +60,7 @@
FakeWarmRunnerState.enable_opts = {}
func._jit_unroll_safe_ = True
- rtyper = support.annotate(func, values,
+ rtyper = support.annotate(func, values, inline=backendopt_inline_threshold,
translationoptions=translationoptions)
graphs = rtyper.annotator.translator.graphs
testself.all_graphs = graphs
diff --git a/rpython/jit/metainterp/test/test_llop.py
b/rpython/jit/metainterp/test/test_llop.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/metainterp/test/test_llop.py
@@ -0,0 +1,72 @@
+import py
+import sys
+import struct
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.test.test_llop import (BaseLLOpTest, str_gc_load,
+ newlist_and_gc_store)
+from rpython.jit.codewriter import longlong
+from rpython.jit.metainterp.history import getkind
+from rpython.jit.metainterp.test.support import LLJitMixin
+
+
+class TestLLOp(BaseLLOpTest, LLJitMixin):
+
+ # for the individual tests see
+ # ====> ../../../rtyper/test/test_llop.py
+ TEST_BLACKHOLE = True
+
+ def gc_load_from_string(self, TYPE, buf, offset):
+ def f(offset):
+ return str_gc_load(TYPE, buf, offset)
+ res = self.interp_operations(f, [offset], supports_singlefloats=True)
+ #
+ kind = getkind(TYPE)[0] # 'i' or 'f'
+ self.check_operations_history({'gc_load_indexed_%s' % kind: 1,
+ 'finish': 1})
+ #
+ if TYPE == lltype.SingleFloat:
+ # interp_operations returns the int version of r_singlefloat, but
+ # our tests expects to receive an r_singlefloat: let's convert it
+ # back!
+ return longlong.int2singlefloat(res)
+ return res
+
+ def newlist_and_gc_store(self, TYPE, value, expected):
+ def f(value):
+ lst = newlist_and_gc_store(TYPE, value)
+ got = ''.join(lst)
+ if got != expected:
+ # I'm not sure why, but if I use an assert, the test doesn't
fail
+ raise ValueError('got != expected')
+ return len(got)
+ #
+ if self.TEST_BLACKHOLE:
+ # we pass a big inline_threshold to ensure that
+ # newlist_and_gc_store is inlined, else the blackhole does not see
+ # (and thus we do not test!) the llop.gc_store_indexed
+ threshold = 33
+ else:
+ threshold = 0
+ return self.interp_operations(f, [value], supports_singlefloats=True,
+ backendopt_inline_threshold=threshold)
+
+
+ def test_force_virtual_str_storage(self):
+ byteorder = sys.byteorder
+ size = rffi.sizeof(lltype.Signed)
+ def f(val):
+ if byteorder == 'little':
+ x = chr(val) + '\x00'*(size-1)
+ else:
+ x = '\x00'*(size-1) + chr(val)
+ return str_gc_load(lltype.Signed, x, 0)
+ res = self.interp_operations(f, [42], supports_singlefloats=True)
+ assert res == 42
+ self.check_operations_history({
+ 'newstr': 1, # str forcing
+ 'strsetitem': 1, # str forcing
+ 'call_pure_r': 1, # str forcing (copystrcontent)
+ 'guard_no_exception': 1, # str forcing
+ 'gc_load_indexed_i': 1, # str_storage_getitem
+ 'finish': 1
+ })
diff --git a/rpython/jit/metainterp/test/test_strstorage.py
b/rpython/jit/metainterp/test/test_strstorage.py
deleted file mode 100644
--- a/rpython/jit/metainterp/test/test_strstorage.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import py
-import sys
-import struct
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.strstorage import str_storage_getitem
-from rpython.rlib.test.test_strstorage import BaseStrStorageTest
-from rpython.jit.codewriter import longlong
-from rpython.jit.metainterp.history import getkind
-from rpython.jit.metainterp.test.support import LLJitMixin
-
-class TestStrStorage(BaseStrStorageTest, LLJitMixin):
-
- # for the individual tests see
- # ====> ../../../rlib/test/test_strstorage.py
-
- def str_storage_getitem(self, TYPE, buf, offset):
- def f():
- return str_storage_getitem(TYPE, buf, offset)
- res = self.interp_operations(f, [], supports_singlefloats=True)
- #
- kind = getkind(TYPE)[0] # 'i' or 'f'
- self.check_operations_history({'gc_load_indexed_%s' % kind: 1,
- 'finish': 1})
- #
- if TYPE == lltype.SingleFloat:
- # interp_operations returns the int version of r_singlefloat, but
- # our tests expects to receive an r_singlefloat: let's convert it
- # back!
- return longlong.int2singlefloat(res)
- return res
-
- #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
- size = rffi.sizeof(lltype.Signed)
- def f(val):
- if byteorder == 'little':
- x = chr(val) + '\x00'*(size-1)
- else:
- x = '\x00'*(size-1) + chr(val)
- return str_storage_getitem(lltype.Signed, x, 0)
- res = self.interp_operations(f, [42], supports_singlefloats=True)
- assert res == 42
- self.check_operations_history({
- 'newstr': 1, # str forcing
- 'strsetitem': 1, # str forcing
- 'call_pure_r': 1, # str forcing (copystrcontent)
- 'guard_no_exception': 1, # str forcing
- 'gc_load_indexed_i': 1, # str_storage_getitem
- 'finish': 1
- })
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -1,13 +1,55 @@
"""
Buffer protocol support.
"""
-from rpython.rlib.rgc import (
- nonmoving_raw_ptr_for_resizable_list, resizable_list_supporting_raw_ptr)
+from rpython.rtyper.lltypesystem import lltype, llmemory
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.lltypesystem.rstr import STR
+from rpython.rtyper.lltypesystem.rlist import LIST_OF
+from rpython.rtyper.annlowlevel import llstr
+from rpython.rlib.objectmodel import specialize
+from rpython.rlib import jit
+from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
+ nonmoving_raw_ptr_for_resizable_list,
+ ll_for_resizable_list)
from rpython.rlib.signature import signature
from rpython.rlib import types
+from rpython.rlib import rawstorage
+
+ALLOW_UNALIGNED_ACCESS = rawstorage.misaligned_is_fine
+
[email protected]()
+def is_alignment_correct(TYPE, index):
+ if ALLOW_UNALIGNED_ACCESS:
+ return True
+ try:
+ rawstorage._check_alignment(TYPE, index)
+ except rawstorage.AlignmentError:
+ return False
+ else:
+ return True
+
+
+class CannotRead(Exception):
+ """
+ Exception raised by Buffer.typed_read in case it is not possible to
+ accomplish the request. This might be because it is not supported by the
+ specific type of buffer, or because of alignment issues.
+ """
+
+class CannotWrite(Exception):
+ """
+ Raised by Buffer.typed_write in case it is not possible to accomplish the
+ request
+ """
class Buffer(object):
- """Base class for buffers of bytes"""
+ """
+ Base class for buffers of bytes.
+
+ Most probably, you do NOT want to use this as a lone base class, but
+ either inherit from RawBuffer or GCBuffer, so that you automatically get
+ the proper implementation of typed_read and typed_write.
+ """
_attrs_ = ['readonly']
_immutable_ = True
@@ -25,14 +67,6 @@
# May be overridden.
return self.getslice(0, self.getlength(), 1, self.getlength())
- def as_str_and_offset_maybe(self):
- """
- If the buffer is backed by a string, return a pair (string, offset),
- where offset is the offset inside the string where the buffer start.
- Else, return (None, 0).
- """
- return None, 0
-
def getitem(self, index):
"Returns the index'th character in the buffer."
raise NotImplementedError # Must be overriden. No bounds checks.
@@ -60,7 +94,141 @@
for i in range(len(string)):
self.setitem(start + i, string[i])
-class ByteBuffer(Buffer):
+ @jit.look_inside_iff(lambda self, index, count:
+ jit.isconstant(count) and count <= 8)
+ def setzeros(self, index, count):
+ for i in range(index, index+count):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit