Author: Remi Meier <[email protected]>
Branch: stmgc-c8
Changeset: r82417:3522d0e0b4ac
Date: 2016-02-22 23:49 +0100
http://bitbucket.org/pypy/pypy/changeset/3522d0e0b4ac/
Log: Next merge with default
diff too long, truncating to 2000 out of 5350 lines
diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,4 @@
release/
!pypy/tool/release/
rpython/_cache/
-__pycache__/
+.cache/
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -28,7 +28,7 @@
DEALINGS IN THE SOFTWARE.
-PyPy Copyright holders 2003-2015
+PyPy Copyright holders 2003-2016
-----------------------------------
Except when otherwise stated (look for LICENSE files or information at
diff --git a/lib-python/2.7/pickle.py b/lib-python/2.7/pickle.py
--- a/lib-python/2.7/pickle.py
+++ b/lib-python/2.7/pickle.py
@@ -1376,6 +1376,7 @@
def decode_long(data):
r"""Decode a long from a two's complement little-endian binary string.
+ This is overriden on PyPy by a RPython version that has linear complexity.
>>> decode_long('')
0L
@@ -1402,6 +1403,11 @@
n -= 1L << (nbytes * 8)
return n
+try:
+ from __pypy__ import decode_long
+except ImportError:
+ pass
+
# Shorthands
try:
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.4.0
+Version: 1.4.2
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.4.0"
-__version_info__ = (1, 4, 0)
+__version__ = "1.4.2"
+__version_info__ = (1, 4, 2)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -130,8 +130,13 @@
More complete example
---------------------
-.. note:: This example depends on pypy_execute_source_ptr which is not
available
- in PyPy <= 2.2.1.
+.. note:: Note that we do not make use of ``extern "Python"``, the new
+ way to do callbacks in CFFI 1.4: this is because these examples use
+ the ABI mode, not the API mode, and with the ABI mode you still have
+ to use ``ffi.callback()``. It is work in progress to integrate
+ ``extern "Python"`` with the idea of embedding (and it is expected
+ to ultimately lead to a better way to do embedding than the one
+ described here, and that would work equally well on CPython and PyPy).
Typically we need something more to do than simply execute source. The
following
is a fully fledged example, please consult cffi documentation for details.
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
@@ -5,6 +5,8 @@
.. this is a revision shortly after release-4.0.1
.. startrev: 4b5c840d0da2
+Fixed ``_PyLong_FromByteArray()``, which was buggy.
+
.. branch: numpy-1.10
Fix tests to run cleanly with -A and start to fix micronumpy for upstream numpy
@@ -44,6 +46,9 @@
.. branch: fix-setslice-can-resize
+Make rlist's ll_listsetslice() able to resize the target list to help
+simplify objspace/std/listobject.py. Was issue #2196.
+
.. branch: anntype2
A somewhat random bunch of changes and fixes following up on branch 'anntype'.
Highlights:
@@ -77,3 +82,24 @@
.. branch: always-enable-gil
Simplify a bit the GIL handling in non-jitted code. Fixes issue #2205.
+
+.. branch: flowspace-cleanups
+
+Trivial cleanups in flowspace.operation : fix comment & duplicated method
+
+.. branch: test-AF_NETLINK
+
+Add a test for pre-existing AF_NETLINK support. Was part of issue #1942.
+
+.. branch: small-cleanups-misc
+
+Trivial misc cleanups: typo, whitespace, obsolete comments
+
+.. branch: cpyext-slotdefs
+.. branch: fix-missing-canraise
+.. branch: whatsnew
+
+.. branch: fix-2211
+
+Fix the cryptic exception message when attempting to use extended slicing
+in rpython. Was issue #2211.
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -89,6 +89,7 @@
'set_code_callback' : 'interp_magic.set_code_callback',
'save_module_content_for_future_reload':
'interp_magic.save_module_content_for_future_reload',
+ 'decode_long' : 'interp_magic.decode_long',
}
if sys.platform == 'win32':
interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.pycode import CodeHookCache
from pypy.interpreter.pyframe import PyFrame
@@ -158,4 +158,13 @@
if space.is_none(w_callable):
cache._code_hook = None
else:
- cache._code_hook = w_callable
\ No newline at end of file
+ cache._code_hook = w_callable
+
+@unwrap_spec(string=str, byteorder=str, signed=int)
+def decode_long(space, string, byteorder='little', signed=1):
+ from rpython.rlib.rbigint import rbigint, InvalidEndiannessError
+ try:
+ result = rbigint.frombytes(string, byteorder, bool(signed))
+ except InvalidEndiannessError:
+ raise oefmt(space.w_ValueError, "invalid byteorder argument")
+ return space.newlong_from_rbigint(result)
diff --git a/pypy/module/__pypy__/test/test_magic.py
b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -30,4 +30,20 @@
""" in d
finally:
__pypy__.set_code_callback(None)
- assert d['f'].__code__ in l
\ No newline at end of file
+ assert d['f'].__code__ in l
+
+ def test_decode_long(self):
+ from __pypy__ import decode_long
+ assert decode_long('') == 0
+ assert decode_long('\xff\x00') == 255
+ assert decode_long('\xff\x7f') == 32767
+ assert decode_long('\x00\xff') == -256
+ assert decode_long('\x00\x80') == -32768
+ assert decode_long('\x80') == -128
+ assert decode_long('\x7f') == 127
+ assert decode_long('\x55' * 97) == (1 << (97 * 8)) // 3
+ assert decode_long('\x00\x80', 'big') == 128
+ assert decode_long('\xff\x7f', 'little', False) == 32767
+ assert decode_long('\x00\x80', 'little', False) == 32768
+ assert decode_long('\x00\x80', 'little', True) == -32768
+ raises(ValueError, decode_long, '', 'foo')
diff --git a/pypy/module/_cffi_backend/__init__.py
b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -2,7 +2,7 @@
from pypy.interpreter.mixedmodule import MixedModule
from rpython.rlib import rdynload, clibffi
-VERSION = "1.4.0"
+VERSION = "1.4.2"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
diff --git a/pypy/module/_cffi_backend/cglob.py
b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -3,6 +3,7 @@
from pypy.interpreter.typedef import TypeDef
from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend import newtype
+from rpython.rlib import rgil
from rpython.rlib.objectmodel import we_are_translated
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -26,7 +27,9 @@
if not we_are_translated():
FNPTR = rffi.CCallback([], rffi.VOIDP)
fetch_addr = rffi.cast(FNPTR, self.fetch_addr)
+ rgil.release()
result = fetch_addr()
+ rgil.acquire()
else:
# careful in translated versions: we need to call fetch_addr,
# but in a GIL-releasing way. The easiest is to invoke a
diff --git a/pypy/module/_cffi_backend/ctypefunc.py
b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -423,7 +423,9 @@
exchange_offset += rffi.getintfield(self.atypes[i], 'c_size')
# store the exchange data size
- cif_descr.exchange_size = exchange_offset
+ # we also align it to the next multiple of 8, in an attempt to
+ # work around bugs(?) of libffi (see cffi issue #241)
+ cif_descr.exchange_size = self.align_arg(exchange_offset)
def fb_extra_fields(self, cif_descr):
cif_descr.abi = self.fabi
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
# ____________________________________________________________
import sys
-assert __version__ == "1.4.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.4.2", ("This test_c.py file is for testing a version"
" of cffi that differs from the one that we"
" get from 'import _cffi_backend'")
if sys.version_info < (3,):
diff --git a/pypy/module/_file/test/test_large_file.py
b/pypy/module/_file/test/test_large_file.py
--- a/pypy/module/_file/test/test_large_file.py
+++ b/pypy/module/_file/test/test_large_file.py
@@ -1,4 +1,4 @@
-import py
+import py, sys
from pypy.module._file.test.test_file import getfile
@@ -13,6 +13,12 @@
def setup_method(self, meth):
if getattr(meth, 'need_sparse_files', False):
from rpython.translator.c.test.test_extfunc import
need_sparse_files
+ if sys.maxsize < 2**32 and not self.runappdirect:
+ # this fails because it uses ll2ctypes to call the posix
+ # functions like 'open' and 'lseek', whereas a real compiled
+ # C program would macro-define them to their longlong versions
+ py.test.skip("emulation of files can't use "
+ "larger-than-long offsets")
need_sparse_files()
def test_large_seek_offsets(self):
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
@@ -251,7 +251,7 @@
from pypy.module._socket.interp_socket import addr_as_object
if not hasattr(rsocket._c, 'sockaddr_ll'):
py.test.skip("posix specific test")
- # HACK: To get the correct interface numer of lo, which in most cases is 1,
+ # HACK: To get the correct interface number of lo, which in most cases is
1,
# but can be anything (i.e. 39), we need to call the libc function
# if_nametoindex to get the correct index
import ctypes
@@ -513,7 +513,7 @@
def test_getsetsockopt(self):
import _socket as socket
import struct
- # A socket sould start with reuse == 0
+ # A socket should start with reuse == 0
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
reuse = s.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
assert reuse == 0
@@ -627,6 +627,26 @@
self.foo = _socket.socket()
+class AppTestNetlink:
+ def setup_class(cls):
+ if not hasattr(os, 'getpid'):
+ py.test.skip("AF_NETLINK needs os.getpid()")
+ w_ok = space.appexec([], "(): import _socket; " +
+ "return hasattr(_socket, 'AF_NETLINK')")
+ if not space.is_true(w_ok):
+ py.test.skip("no AF_NETLINK on this platform")
+ cls.space = space
+
+ def test_connect_to_kernel_netlink_routing_socket(self):
+ import _socket, os
+ s = _socket.socket(_socket.AF_NETLINK, _socket.SOCK_DGRAM,
_socket.NETLINK_ROUTE)
+ assert s.getsockname() == (0L, 0L)
+ s.bind((0, 0))
+ a, b = s.getsockname()
+ assert a == os.getpid()
+ assert b == 0
+
+
class AppTestPacket:
def setup_class(cls):
if not hasattr(os, 'getuid') or os.getuid() != 0:
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -124,7 +124,7 @@
METH_COEXIST METH_STATIC METH_CLASS
METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O
Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
-Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE
+Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES
""".split()
for name in constant_names:
setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -228,26 +228,11 @@
def _PyLong_FromByteArray(space, bytes, n, little_endian, signed):
little_endian = rffi.cast(lltype.Signed, little_endian)
signed = rffi.cast(lltype.Signed, signed)
-
- result = rbigint()
- negative = False
-
- for i in range(0, n):
- if little_endian:
- c = intmask(bytes[i])
- else:
- c = intmask(bytes[n - i - 1])
- if i == 0 and signed and c & 0x80:
- negative = True
- if negative:
- c = c ^ 0xFF
- digit = rbigint.fromint(c)
-
- result = result.lshift(8)
- result = result.add(digit)
-
- if negative:
- result = result.neg()
-
+ s = rffi.charpsize2str(rffi.cast(rffi.CCHARP, bytes),
+ rffi.cast(lltype.Signed, n))
+ if little_endian:
+ byteorder = 'little'
+ else:
+ byteorder = 'big'
+ result = rbigint.frombytes(s, byteorder, signed != 0)
return space.newlong_from_rbigint(result)
-
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
@@ -4,14 +4,14 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
- cpython_api, generic_cpy_call, PyObject, Py_ssize_t)
+ cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
readbufferproc)
-from pypy.module.cpyext.pyobject import from_ref
+from pypy.module.cpyext.pyobject import from_ref, make_ref, Py_DecRef
from pypy.module.cpyext.pyerrors import PyErr_Occurred
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError, oefmt
@@ -65,22 +65,24 @@
func_binary = rffi.cast(binaryfunc, func)
check_num_args(space, w_args, 1)
args_w = space.fixedview(w_args)
-
- if not space.is_true(space.issubtype(space.type(args_w[0]),
- space.type(w_self))):
+ ref = make_ref(space, w_self)
+ if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
+ not space.is_true(space.issubtype(space.type(args_w[0]),
+ space.type(w_self)))):
return space.w_NotImplemented
-
+ Py_DecRef(space, ref)
return generic_cpy_call(space, func_binary, w_self, args_w[0])
def wrap_binaryfunc_r(space, w_self, w_args, func):
func_binary = rffi.cast(binaryfunc, func)
check_num_args(space, w_args, 1)
args_w = space.fixedview(w_args)
-
- if not space.is_true(space.issubtype(space.type(args_w[0]),
- space.type(w_self))):
+ ref = make_ref(space, w_self)
+ if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
+ not space.is_true(space.issubtype(space.type(args_w[0]),
+ space.type(w_self)))):
return space.w_NotImplemented
-
+ Py_DecRef(space, ref)
return generic_cpy_call(space, func_binary, args_w[0], w_self)
def wrap_inquirypred(space, w_self, w_args, func):
@@ -378,6 +380,17 @@
space.call_function(delattr_fn, w_self, w_name)
return 0
api_func = slot_tp_setattro.api_func
+ elif name == 'tp_getattro':
+ getattr_fn = w_type.getdictvalue(space, '__getattribute__')
+ if getattr_fn is None:
+ return
+
+ @cpython_api([PyObject, PyObject], PyObject,
+ external=True)
+ @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,))
+ def slot_tp_getattro(space, w_self, w_name):
+ return space.call_function(getattr_fn, w_self, w_name)
+ api_func = slot_tp_getattro.api_func
else:
return
diff --git a/pypy/module/cpyext/test/test_longobject.py
b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -175,10 +175,26 @@
little_endian, is_signed);
"""),
])
- assert module.from_bytearray(True, False) == 0x9ABC
- assert module.from_bytearray(True, True) == -0x6543
- assert module.from_bytearray(False, False) == 0xBC9A
- assert module.from_bytearray(False, True) == -0x4365
+ assert module.from_bytearray(True, False) == 0xBC9A
+ assert module.from_bytearray(True, True) == -0x4366
+ assert module.from_bytearray(False, False) == 0x9ABC
+ assert module.from_bytearray(False, True) == -0x6544
+
+ def test_frombytearray_2(self):
+ module = self.import_extension('foo', [
+ ("from_bytearray", "METH_VARARGS",
+ """
+ int little_endian, is_signed;
+ if (!PyArg_ParseTuple(args, "ii", &little_endian, &is_signed))
+ return NULL;
+ return _PyLong_FromByteArray("\x9A\xBC\x41", 3,
+ little_endian, is_signed);
+ """),
+ ])
+ assert module.from_bytearray(True, False) == 0x41BC9A
+ assert module.from_bytearray(True, True) == 0x41BC9A
+ assert module.from_bytearray(False, False) == 0x9ABC41
+ assert module.from_bytearray(False, True) == -0x6543BF
def test_fromunicode(self):
module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -385,12 +385,64 @@
PyErr_SetString(PyExc_ValueError, "recursive
tp_setattro");
return NULL;
}
+ if (!args->ob_type->tp_getattro)
+ {
+ PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
+ return NULL;
+ }
+ if (args->ob_type->tp_getattro ==
+ args->ob_type->tp_base->tp_getattro)
+ {
+ PyErr_SetString(PyExc_ValueError, "recursive
tp_getattro");
+ return NULL;
+ }
Py_RETURN_TRUE;
'''
)
])
assert module.test_type(type(None))
+ def test_tp_getattro(self):
+ module = self.import_extension('foo', [
+ ("test_tp_getattro", "METH_VARARGS",
+ '''
+ PyObject *obj = PyTuple_GET_ITEM(args, 0);
+ PyIntObject *value = PyTuple_GET_ITEM(args, 1);
+ if (!obj->ob_type->tp_getattro)
+ {
+ PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
+ return NULL;
+ }
+ PyObject *name = PyString_FromString("attr1");
+ PyIntObject *attr = obj->ob_type->tp_getattro(obj, name);
+ if (attr->ob_ival != value->ob_ival)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "tp_getattro returned wrong value");
+ return NULL;
+ }
+ Py_DECREF(name);
+ Py_DECREF(attr);
+ name = PyString_FromString("attr2");
+ attr = obj->ob_type->tp_getattro(obj, name);
+ if (attr == NULL &&
PyErr_ExceptionMatches(PyExc_AttributeError))
+ {
+ PyErr_Clear();
+ } else {
+ PyErr_SetString(PyExc_ValueError,
+ "tp_getattro should have raised");
+ return NULL;
+ }
+ Py_DECREF(name);
+ Py_RETURN_TRUE;
+ '''
+ )
+ ])
+ class C:
+ def __init__(self):
+ self.attr1 = 123
+ assert module.test_tp_getattro(C(), 123)
+
def test_nb_int(self):
module = self.import_extension('foo', [
("nb_int", "METH_O",
@@ -591,45 +643,92 @@
def test_binaryfunc(self):
module = self.import_extension('foo', [
- ("new_obj", "METH_NOARGS",
+ ("newInt", "METH_VARARGS",
"""
- FooObject *fooObj;
+ IntLikeObject *intObj;
+ long intval;
- Foo_Type.tp_as_number = &foo_as_number;
- foo_as_number.nb_add = foo_nb_add_call;
- if (PyType_Ready(&Foo_Type) < 0) return NULL;
- fooObj = PyObject_New(FooObject, &Foo_Type);
- if (!fooObj) {
+ if (!PyArg_ParseTuple(args, "l", &intval))
+ return NULL;
+
+ IntLike_Type.tp_as_number = &intlike_as_number;
+ IntLike_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
+ intlike_as_number.nb_add = intlike_nb_add;
+ if (PyType_Ready(&IntLike_Type) < 0) return NULL;
+ intObj = PyObject_New(IntLikeObject, &IntLike_Type);
+ if (!intObj) {
return NULL;
}
- return (PyObject *)fooObj;
+ intObj->ival = intval;
+ return (PyObject *)intObj;
+ """),
+ ("newIntNoOp", "METH_VARARGS",
+ """
+ IntLikeObjectNoOp *intObjNoOp;
+ long intval;
+
+ if (!PyArg_ParseTuple(args, "l", &intval))
+ return NULL;
+
+ IntLike_Type_NoOp.tp_flags |= Py_TPFLAGS_CHECKTYPES;
+ if (PyType_Ready(&IntLike_Type_NoOp) < 0) return NULL;
+ intObjNoOp = PyObject_New(IntLikeObjectNoOp,
&IntLike_Type_NoOp);
+ if (!intObjNoOp) {
+ return NULL;
+ }
+
+ intObjNoOp->ival = intval;
+ return (PyObject *)intObjNoOp;
""")],
"""
typedef struct
{
PyObject_HEAD
- } FooObject;
+ long ival;
+ } IntLikeObject;
static PyObject *
- foo_nb_add_call(PyObject *self, PyObject *other)
+ intlike_nb_add(PyObject *self, PyObject *other)
{
- return PyInt_FromLong(42);
+ long val1 = ((IntLikeObject *)(self))->ival;
+ if (PyInt_Check(other)) {
+ long val2 = PyInt_AsLong(other);
+ return PyInt_FromLong(val1+val2);
+ }
+
+ long val2 = ((IntLikeObject *)(other))->ival;
+ return PyInt_FromLong(val1+val2);
}
- PyTypeObject Foo_Type = {
+ PyTypeObject IntLike_Type = {
PyObject_HEAD_INIT(0)
/*ob_size*/ 0,
- /*tp_name*/ "Foo",
- /*tp_basicsize*/ sizeof(FooObject),
+ /*tp_name*/ "IntLike",
+ /*tp_basicsize*/ sizeof(IntLikeObject),
};
- static PyNumberMethods foo_as_number;
+ static PyNumberMethods intlike_as_number;
+
+ typedef struct
+ {
+ PyObject_HEAD
+ long ival;
+ } IntLikeObjectNoOp;
+
+ PyTypeObject IntLike_Type_NoOp = {
+ PyObject_HEAD_INIT(0)
+ /*ob_size*/ 0,
+ /*tp_name*/ "IntLikeNoOp",
+ /*tp_basicsize*/ sizeof(IntLikeObjectNoOp),
+ };
""")
- a = module.new_obj()
- b = module.new_obj()
+ a = module.newInt(1)
+ b = module.newInt(2)
c = 3
- assert (a + b) == 42
- raises(TypeError, "b + c")
+ d = module.newIntNoOp(4)
+ assert (a + b) == 3
+ assert (b + c) == 5
+ assert (d + a) == 5
def test_tp_new_in_subclass_of_type(self):
skip("BROKEN")
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -582,6 +582,8 @@
pto.c_tp_free = base.c_tp_free
if not pto.c_tp_setattro:
pto.c_tp_setattro = base.c_tp_setattro
+ if not pto.c_tp_getattro:
+ pto.c_tp_getattro = base.c_tp_getattro
finally:
Py_DecRef(space, base_pyo)
@@ -651,6 +653,12 @@
PyObject_GenericSetAttr.api_func.functype,
PyObject_GenericSetAttr.api_func.get_wrapper(space))
+ if not pto.c_tp_getattro:
+ from pypy.module.cpyext.object import PyObject_GenericGetAttr
+ pto.c_tp_getattro = llhelper(
+ PyObject_GenericGetAttr.api_func.functype,
+ PyObject_GenericGetAttr.api_func.get_wrapper(space))
+
if w_obj.is_cpytype():
Py_DecRef(space, pto.c_tp_dict)
w_dict = w_obj.getdict(space)
diff --git a/pypy/module/mmap/test/test_mmap.py
b/pypy/module/mmap/test/test_mmap.py
--- a/pypy/module/mmap/test/test_mmap.py
+++ b/pypy/module/mmap/test/test_mmap.py
@@ -1,6 +1,6 @@
from __future__ import with_statement
from rpython.tool.udir import udir
-import os
+import os, sys, py
class AppTestMMap:
spaceconfig = dict(usemodules=('mmap',))
@@ -8,6 +8,15 @@
def setup_class(cls):
cls.w_tmpname = cls.space.wrap(str(udir.join('mmap-')))
+ def setup_method(self, meth):
+ if getattr(meth, 'is_large', False):
+ if sys.maxsize < 2**32 and not self.runappdirect:
+ # this fails because it uses ll2ctypes to call the posix
+ # functions like 'open' and 'lseek', whereas a real compiled
+ # C program would macro-define them to their longlong versions
+ py.test.skip("emulation of files can't use "
+ "larger-than-long offsets")
+
def test_page_size(self):
import mmap
assert mmap.PAGESIZE > 0
@@ -648,6 +657,7 @@
assert m[0xFFFFFFF] == b'A'
finally:
m.close()
+ test_large_offset.is_large = True
def test_large_filesize(self):
import mmap
@@ -665,6 +675,7 @@
assert m.size() == 0x180000000
finally:
m.close()
+ test_large_filesize.is_large = True
def test_all(self):
# this is a global test, ported from test_mmap.py
diff --git a/pypy/module/posix/interp_posix.py
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -299,7 +299,7 @@
return build_stat_result(space, st)
def lstat(space, w_path):
- "Like stat(path), but do no follow symbolic links."
+ "Like stat(path), but do not follow symbolic links."
try:
st = dispatch_filename(rposix_stat.lstat)(space, w_path)
except OSError, e:
diff --git a/pypy/module/posix/test/test_posix2.py
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -93,6 +93,12 @@
def setup_method(self, meth):
if getattr(meth, 'need_sparse_files', False):
+ if sys.maxsize < 2**32 and not self.runappdirect:
+ # this fails because it uses ll2ctypes to call the posix
+ # functions like 'open' and 'lseek', whereas a real compiled
+ # C program would macro-define them to their longlong versions
+ py.test.skip("emulation of files can't use "
+ "larger-than-long offsets")
need_sparse_files()
def test_posix_is_pypy_s(self):
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
@@ -45,7 +45,7 @@
# 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
- # getarrayitem_gc_i on a virtual string. It could be improved, but it
+ # 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", """
@@ -55,17 +55,17 @@
strsetitem(p88, 1, i14)
strsetitem(p88, 2, i17)
strsetitem(p88, 3, i20)
- i91 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+ i91 = gc_load_indexed_i(p88, 0, 1, _, -4)
""")
def test_struct_object(self):
def main(n):
import struct
- s = struct.Struct("i")
+ s = struct.Struct("ii")
i = 1
while i < n:
- buf = s.pack(i) # ID: pack
- x = s.unpack(buf)[0] # ID: unpack
+ buf = s.pack(-1, i) # ID: pack
+ x = s.unpack(buf)[1] # ID: unpack
i += x / i
return i
@@ -88,10 +88,15 @@
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 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+ 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)
""")
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -30,7 +30,7 @@
space.threadlocals = stm.STMThreadLocals()
else:
from pypy.module.thread import gil
- space.threadlocals = gil.GILThreadLocals()
+ space.threadlocals = gil.GILThreadLocals(space)
space.threadlocals.initialize(space)
if prev_ec is not None:
space.threadlocals._set_ec(prev_ec)
diff --git a/pypy/module/thread/test/test_gil.py
b/pypy/module/thread/test/test_gil.py
--- a/pypy/module/thread/test/test_gil.py
+++ b/pypy/module/thread/test/test_gil.py
@@ -65,7 +65,7 @@
except Exception, e:
assert 0
thread.gc_thread_die()
- my_gil_threadlocals = gil.GILThreadLocals()
+ my_gil_threadlocals = gil.GILThreadLocals(space)
def f():
state.data = []
state.datalen1 = 0
diff --git a/pypy/module/thread/threadlocals.py
b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -1,5 +1,7 @@
-from rpython.rlib import rthread
+import weakref
+from rpython.rlib import rthread, rshrinklist
from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import r_ulonglong
from pypy.module.thread.error import wrap_thread_error
from pypy.interpreter.executioncontext import ExecutionContext
@@ -13,15 +15,51 @@
a thread finishes. This works as long as the thread was started by
os_thread.bootstrap()."""
- def __init__(self):
+ def __init__(self, space):
"NOT_RPYTHON"
- self._valuedict = {} # {thread_ident: ExecutionContext()}
+ #
+ # This object tracks code that enters and leaves threads.
+ # There are two APIs. For Python-level threads, we know when
+ # the thread starts and ends, and we call enter_thread() and
+ # leave_thread(). In a few other cases, like callbacks, we
+ # might be running in some never-seen-before thread: in this
+ # case, the callback logic needs to call try_enter_thread() at
+ # the start, and if this returns True it needs to call
+ # leave_thread() at the end.
+ #
+ # We implement an optimization for the second case (which only
+ # works if we translate with a framework GC and with
+ # rweakref). If try_enter_thread() is called in a
+ # never-seen-before thread, it still returns False and
+ # remembers the ExecutionContext with 'self._weaklist'. The
+ # next time we call try_enter_thread() again in the same
+ # thread, the ExecutionContext is reused. The optimization is
+ # not completely invisible to the user: 'thread._local()'
+ # values will remain. We can argue that it is the correct
+ # behavior to do that, and the behavior we get if the
+ # optimization is disabled is buggy (but hard to do better
+ # then).
+ #
+ # 'self._valuedict' is a dict mapping the thread idents to
+ # ExecutionContexts; it does not list the ExecutionContexts
+ # which are in 'self._weaklist'. (The latter is more precisely
+ # a list of AutoFreeECWrapper objects, defined below, which
+ # each references the ExecutionContext.)
+ #
+ self.space = space
+ self._valuedict = {}
self._cleanup_()
self.raw_thread_local = rthread.ThreadLocalReference(ExecutionContext,
loop_invariant=True)
+ def can_optimize_with_weaklist(self):
+ config = self.space.config
+ return (config.translation.rweakref and
+ rthread.ThreadLocalReference.automatic_keepalive(config))
+
def _cleanup_(self):
self._valuedict.clear()
+ self._weaklist = None
self._mainthreadident = 0
def initialize(self, space):
@@ -35,19 +73,35 @@
self._set_ec(space.createexecutioncontext())
def try_enter_thread(self, space):
- if rthread.get_ident() in self._valuedict:
+ # common case: the thread-local has already got a value
+ if self.raw_thread_local.get() is not None:
return False
- self.enter_thread(space)
- return True
- def _set_ec(self, ec):
+ # Else, make and attach a new ExecutionContext
+ ec = space.createexecutioncontext()
+ if not self.can_optimize_with_weaklist():
+ self._set_ec(ec)
+ return True
+
+ # If can_optimize_with_weaklist(), then 'rthread' keeps the
+ # thread-local values alive until the end of the thread. Use
+ # AutoFreeECWrapper as an object with a __del__; when this
+ # __del__ is called, it means the thread was really finished.
+ # In this case we don't want leave_thread() to be called
+ # explicitly, so we return False.
+ if self._weaklist is None:
+ self._weaklist = ListECWrappers()
+ self._weaklist.append(weakref.ref(AutoFreeECWrapper(ec)))
+ self._set_ec(ec, register_in_valuedict=False)
+ return False
+
+ def _set_ec(self, ec, register_in_valuedict=True):
ident = rthread.get_ident()
if self._mainthreadident == 0 or self._mainthreadident == ident:
ec._signals_enabled = 1 # the main thread is enabled
self._mainthreadident = ident
- self._valuedict[ident] = ec
- # This logic relies on hacks and _make_sure_does_not_move().
- # It only works because we keep the 'ec' alive in '_valuedict' too.
+ if register_in_valuedict:
+ self._valuedict[ident] = ec
self.raw_thread_local.set(ec)
def leave_thread(self, space):
@@ -90,7 +144,23 @@
ec._signals_enabled = new
def getallvalues(self):
- return self._valuedict
+ if self._weaklist is None:
+ return self._valuedict
+ # This logic walks the 'self._weaklist' list and adds the
+ # ExecutionContexts to 'result'. We are careful in case there
+ # are two AutoFreeECWrappers in the list which have the same
+ # 'ident'; in this case we must keep the most recent one (the
+ # older one should be deleted soon). Moreover, entries in
+ # self._valuedict have priority because they are never
+ # outdated.
+ result = {}
+ for h in self._weaklist.items():
+ wrapper = h()
+ if wrapper is not None and not wrapper.deleted:
+ result[wrapper.ident] = wrapper.ec
+ # ^^ this possibly overwrites an older ec
+ result.update(self._valuedict)
+ return result
def reinit_threads(self, space):
"Called in the child process after a fork()"
@@ -100,7 +170,31 @@
old_sig = ec._signals_enabled
if ident != self._mainthreadident:
old_sig += 1
- self._cleanup_()
+ self._cleanup_() # clears self._valuedict
self._mainthreadident = ident
self._set_ec(ec)
ec._signals_enabled = old_sig
+
+
+class AutoFreeECWrapper(object):
+ deleted = False
+
+ def __init__(self, ec):
+ # this makes a loop between 'self' and 'ec'. It should not prevent
+ # the __del__ method here from being called.
+ self.ec = ec
+ ec._threadlocals_auto_free = self
+ self.ident = rthread.get_ident()
+
+ def __del__(self):
+ from pypy.module.thread.os_local import thread_is_stopping
+ # this is always called in another thread: the thread
+ # referenced by 'self.ec' has finished at that point, and
+ # we're just after the GC which finds no more references to
+ # 'ec' (and thus to 'self').
+ self.deleted = True
+ thread_is_stopping(self.ec)
+
+class ListECWrappers(rshrinklist.AbstractShrinkList):
+ def must_keep(self, wref):
+ return wref() is not None
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -521,7 +521,6 @@
def descr_getitem(self, space, w_index):
if isinstance(w_index, W_SliceObject):
- # XXX consider to extend rlist's functionality?
length = self.length()
start, stop, step, slicelength = w_index.indices4(space, length)
assert slicelength >= 0
diff --git a/pypy/objspace/std/test/test_longobject.py
b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -358,3 +358,10 @@
assert 3L.__coerce__(4L) == (3L, 4L)
assert 3L.__coerce__(4) == (3, 4)
assert 3L.__coerce__(object()) == NotImplemented
+
+ def test_linear_long_base_16(self):
+ # never finishes if long(_, 16) is not linear-time
+ size = 100000
+ n = "a" * size
+ expected = (2 << (size * 4)) // 3
+ assert long(n, 16) == expected
diff --git a/rpython/annotator/signature.py b/rpython/annotator/signature.py
--- a/rpython/annotator/signature.py
+++ b/rpython/annotator/signature.py
@@ -100,6 +100,7 @@
self.argtypes = argtypes
def __call__(self, funcdesc, inputcells):
+ from rpython.rlib.objectmodel import NOT_CONSTANT
from rpython.rtyper.lltypesystem import lltype
args_s = []
from rpython.annotator import model as annmodel
@@ -115,6 +116,9 @@
args_s.append(s_input)
elif argtype is None:
args_s.append(inputcells[i]) # no change
+ elif argtype is NOT_CONSTANT:
+ from rpython.annotator.model import not_const
+ args_s.append(not_const(inputcells[i]))
else:
args_s.append(annotation(argtype,
bookkeeper=funcdesc.bookkeeper))
if len(inputcells) != len(args_s):
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
@@ -3516,6 +3516,32 @@
s = a.build_types(f, [unicode])
assert isinstance(s, annmodel.SomeUnicodeString)
+ def test_extended_slice(self):
+ a = self.RPythonAnnotator()
+ def f(start, end, step):
+ return [1, 2, 3][start:end:step]
+ with py.test.raises(AnnotatorError):
+ a.build_types(f, [int, int, int])
+ a = self.RPythonAnnotator()
+ with py.test.raises(AnnotatorError):
+ a.build_types(f, [annmodel.SomeInteger(nonneg=True),
+ annmodel.SomeInteger(nonneg=True),
+ annmodel.SomeInteger(nonneg=True)])
+ def f(x):
+ return x[::-1]
+ a = self.RPythonAnnotator()
+ with py.test.raises(AnnotatorError):
+ a.build_types(f, [str])
+ def f(x):
+ return x[::2]
+ a = self.RPythonAnnotator()
+ with py.test.raises(AnnotatorError):
+ a.build_types(f, [str])
+ def f(x):
+ return x[1:2:1]
+ a = self.RPythonAnnotator()
+ with py.test.raises(AnnotatorError):
+ a.build_types(f, [str])
def test_negative_slice(self):
def f(s, e):
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -441,7 +441,7 @@
def dict_contains(s_dct, s_element, position):
s_dct.dictdef.generalize_key(s_element)
if s_dct._is_empty(position):
- s_bool =SomeBool()
+ s_bool = SomeBool()
s_bool.const = False
return s_bool
return s_Bool
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -1,5 +1,5 @@
"""
-This module defines all the SpaceOeprations used in rpython.flowspace.
+This module defines all the SpaceOperations used in rpython.flowspace.
"""
import __builtin__
@@ -196,21 +196,6 @@
return cls._dispatch(type(s_arg))
@classmethod
- def get_specialization(cls, s_arg, *_ignored):
- try:
- impl = getattr(s_arg, cls.opname)
-
- def specialized(annotator, arg, *other_args):
- return impl(*[annotator.annotation(x) for x in other_args])
- try:
- specialized.can_only_throw = impl.can_only_throw
- except AttributeError:
- pass
- return specialized
- except AttributeError:
- return cls._dispatch(type(s_arg))
-
- @classmethod
def register_transform(cls, Some_cls):
def decorator(func):
cls._transform[Some_cls] = func
@@ -523,6 +508,14 @@
*[annotator.annotation(arg) for arg in self.args])
+class NewSlice(HLOperation):
+ opname = 'newslice'
+ canraise = []
+
+ def consider(self, annotator):
+ raise AnnotatorError("Cannot use extended slicing in rpython")
+
+
class Pow(PureOperation):
opname = 'pow'
arity = 3
diff --git a/rpython/jit/backend/arm/opassembler.py
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -19,7 +19,6 @@
from rpython.jit.backend.arm.locations import imm, RawSPStackLocation
from rpython.jit.backend.llsupport import symbolic
from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
-from rpython.jit.backend.llsupport.descr import InteriorFieldDescr
from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler
from rpython.jit.backend.llsupport.regalloc import get_scale
from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt,
@@ -655,31 +654,24 @@
pmc.B_offs(offset, c.EQ)
return fcond
- def emit_op_setfield_gc(self, op, arglocs, regalloc, fcond):
- value_loc, base_loc, ofs, size = arglocs
- scale = get_scale(size.value)
- self._write_to_mem(value_loc, base_loc,
- ofs, imm(scale), fcond)
+ def emit_op_gc_store(self, op, arglocs, regalloc, fcond):
+ value_loc, base_loc, ofs_loc, size_loc = arglocs
+ scale = get_scale(size_loc.value)
+ self._write_to_mem(value_loc, base_loc, ofs_loc, imm(scale), fcond)
return fcond
- emit_op_setfield_raw = emit_op_setfield_gc
- emit_op_zero_ptr_field = emit_op_setfield_gc
-
- def _genop_getfield(self, op, arglocs, regalloc, fcond):
- base_loc, ofs, res, size = arglocs
- signed = op.getdescr().is_field_signed()
- scale = get_scale(size.value)
- self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond)
+ def _emit_op_gc_load(self, op, arglocs, regalloc, fcond):
+ base_loc, ofs_loc, res_loc, nsize_loc = arglocs
+ nsize = nsize_loc.value
+ signed = (nsize < 0)
+ scale = get_scale(abs(nsize))
+ self._load_from_mem(res_loc, base_loc, ofs_loc, imm(scale),
+ signed, fcond)
return fcond
- emit_op_getfield_gc_i = _genop_getfield
- emit_op_getfield_gc_r = _genop_getfield
- emit_op_getfield_gc_f = _genop_getfield
- emit_op_getfield_gc_pure_i = _genop_getfield
- emit_op_getfield_gc_pure_r = _genop_getfield
- emit_op_getfield_gc_pure_f = _genop_getfield
- emit_op_getfield_raw_i = _genop_getfield
- emit_op_getfield_raw_f = _genop_getfield
+ emit_op_gc_load_i = _emit_op_gc_load
+ emit_op_gc_load_r = _emit_op_gc_load
+ emit_op_gc_load_f = _emit_op_gc_load
def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond):
base_loc, value_loc = arglocs
@@ -688,68 +680,21 @@
self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond)
return fcond
- def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond):
- (base_loc, index_loc, res_loc,
- ofs_loc, ofs, itemsize, fieldsize) = arglocs
- scale = get_scale(fieldsize.value)
- tmploc, save = self.get_tmp_reg([base_loc, ofs_loc])
- assert not save
- self.mc.gen_load_int(tmploc.value, itemsize.value)
- self.mc.MUL(tmploc.value, index_loc.value, tmploc.value)
- descr = op.getdescr()
- assert isinstance(descr, InteriorFieldDescr)
- signed = descr.fielddescr.is_field_signed()
- if ofs.value > 0:
- if ofs_loc.is_imm():
- self.mc.ADD_ri(tmploc.value, tmploc.value, ofs_loc.value)
- else:
- self.mc.ADD_rr(tmploc.value, tmploc.value, ofs_loc.value)
- ofs_loc = tmploc
- self._load_from_mem(res_loc, base_loc, ofs_loc,
- imm(scale), signed, fcond)
- return fcond
-
- emit_op_getinteriorfield_gc_i = _genop_getinteriorfield
- emit_op_getinteriorfield_gc_r = _genop_getinteriorfield
- emit_op_getinteriorfield_gc_f = _genop_getinteriorfield
-
- def emit_op_setinteriorfield_gc(self, op, arglocs, regalloc, fcond):
- (base_loc, index_loc, value_loc,
- ofs_loc, ofs, itemsize, fieldsize) = arglocs
- scale = get_scale(fieldsize.value)
- tmploc, save = self.get_tmp_reg([base_loc, index_loc, value_loc,
ofs_loc])
- assert not save
- self.mc.gen_load_int(tmploc.value, itemsize.value)
- self.mc.MUL(tmploc.value, index_loc.value, tmploc.value)
- if ofs.value > 0:
- if ofs_loc.is_imm():
- self.mc.ADD_ri(tmploc.value, tmploc.value, ofs_loc.value)
- else:
- self.mc.ADD_rr(tmploc.value, tmploc.value, ofs_loc.value)
- self._write_to_mem(value_loc, base_loc, tmploc, imm(scale), fcond)
- return fcond
- emit_op_setinteriorfield_raw = emit_op_setinteriorfield_gc
-
- def emit_op_arraylen_gc(self, op, arglocs, regalloc, fcond):
- res, base_loc, ofs = arglocs
- self.load_reg(self.mc, res, base_loc, ofs.value)
- return fcond
-
- def emit_op_setarrayitem_gc(self, op, arglocs, regalloc, fcond):
- value_loc, base_loc, ofs_loc, scale, ofs = arglocs
- assert ofs_loc.is_core_reg()
- if scale.value > 0:
- self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value)
- ofs_loc = r.ip
-
+ def emit_op_gc_store_indexed(self, op, arglocs, regalloc, fcond):
+ value_loc, base_loc, index_loc, size_loc, ofs_loc = arglocs
+ assert index_loc.is_core_reg()
# add the base offset
- if ofs.value > 0:
- self.mc.ADD_ri(r.ip.value, ofs_loc.value, imm=ofs.value)
- ofs_loc = r.ip
- self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond)
+ if ofs_loc.value > 0:
+ self.mc.ADD_ri(r.ip.value, index_loc.value, imm=ofs_loc.value)
+ index_loc = r.ip
+ scale = get_scale(size_loc.value)
+ self._write_to_mem(value_loc, base_loc, index_loc, imm(scale), fcond)
return fcond
def _write_to_mem(self, value_loc, base_loc, ofs_loc, scale, fcond=c.AL):
+ # Write a value of size '1 << scale' at the address
+ # 'base_ofs + ofs_loc'. Note that 'scale' is not used to scale
+ # the offset!
if scale.value == 3:
assert value_loc.is_vfp_reg()
# vstr only supports imm offsets
@@ -789,43 +734,31 @@
else:
assert 0
- emit_op_setarrayitem_raw = emit_op_setarrayitem_gc
-
- def emit_op_raw_store(self, op, arglocs, regalloc, fcond):
- value_loc, base_loc, ofs_loc, scale, ofs = arglocs
- assert ofs_loc.is_core_reg()
- self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond)
+ def _emit_op_gc_load_indexed(self, op, arglocs, regalloc, fcond):
+ res_loc, base_loc, index_loc, nsize_loc, ofs_loc = arglocs
+ assert index_loc.is_core_reg()
+ nsize = nsize_loc.value
+ signed = (nsize < 0)
+ # add the base offset
+ if ofs_loc.value > 0:
+ self.mc.ADD_ri(r.ip.value, index_loc.value, imm=ofs_loc.value)
+ index_loc = r.ip
+ #
+ scale = get_scale(abs(nsize))
+ self._load_from_mem(res_loc, base_loc, index_loc, imm(scale),
+ signed, fcond)
return fcond
- def _genop_getarrayitem(self, op, arglocs, regalloc, fcond):
- res_loc, base_loc, ofs_loc, scale, ofs = arglocs
- assert ofs_loc.is_core_reg()
- signed = op.getdescr().is_item_signed()
-
- # scale the offset as required
- # XXX we should try to encode the scale inside the "shift" part of LDR
- if scale.value > 0:
- self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value)
- ofs_loc = r.ip
- # add the base offset
- if ofs.value > 0:
- self.mc.ADD_ri(r.ip.value, ofs_loc.value, imm=ofs.value)
- ofs_loc = r.ip
- #
- self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
- return fcond
-
- emit_op_getarrayitem_gc_i = _genop_getarrayitem
- emit_op_getarrayitem_gc_r = _genop_getarrayitem
- emit_op_getarrayitem_gc_f = _genop_getarrayitem
- emit_op_getarrayitem_gc_pure_i = _genop_getarrayitem
- emit_op_getarrayitem_gc_pure_r = _genop_getarrayitem
- emit_op_getarrayitem_gc_pure_f = _genop_getarrayitem
- emit_op_getarrayitem_raw_i = _genop_getarrayitem
- emit_op_getarrayitem_raw_f = _genop_getarrayitem
+ emit_op_gc_load_indexed_i = _emit_op_gc_load_indexed
+ emit_op_gc_load_indexed_r = _emit_op_gc_load_indexed
+ emit_op_gc_load_indexed_f = _emit_op_gc_load_indexed
def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale,
signed=False, fcond=c.AL):
+ # Load a value of '1 << scale' bytes, from the memory location
+ # 'base_loc + ofs_loc'. Note that 'scale' is not used to scale
+ # the offset!
+ #
if scale.value == 3:
assert res_loc.is_vfp_reg()
# vldr only supports imm offsets
@@ -881,51 +814,6 @@
else:
assert 0
- def _genop_raw_load(self, op, arglocs, regalloc, fcond):
- res_loc, base_loc, ofs_loc, scale, ofs = arglocs
- assert ofs_loc.is_core_reg()
- # no base offset
- assert ofs.value == 0
- signed = op.getdescr().is_item_signed()
- self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
- return fcond
-
- emit_op_raw_load_i = _genop_raw_load
- emit_op_raw_load_f = _genop_raw_load
-
- def emit_op_strlen(self, op, arglocs, regalloc, fcond):
- l0, l1, res = arglocs
- if l1.is_imm():
- self.mc.LDR_ri(res.value, l0.value, l1.getint(), cond=fcond)
- else:
- self.mc.LDR_rr(res.value, l0.value, l1.value, cond=fcond)
- return fcond
-
- def emit_op_strgetitem(self, op, arglocs, regalloc, fcond):
- res, base_loc, ofs_loc, basesize = arglocs
- if ofs_loc.is_imm():
- self.mc.ADD_ri(r.ip.value, base_loc.value, ofs_loc.getint(),
- cond=fcond)
- else:
- self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value,
- cond=fcond)
-
- self.mc.LDRB_ri(res.value, r.ip.value, basesize.value, cond=fcond)
- return fcond
-
- def emit_op_strsetitem(self, op, arglocs, regalloc, fcond):
- value_loc, base_loc, ofs_loc, basesize = arglocs
- if ofs_loc.is_imm():
- self.mc.ADD_ri(r.ip.value, base_loc.value, ofs_loc.getint(),
- cond=fcond)
- else:
- self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value,
- cond=fcond)
-
- self.mc.STRB_ri(value_loc.value, r.ip.value, basesize.value,
- cond=fcond)
- return fcond
-
#from ../x86/regalloc.py:928 ff.
def emit_op_copystrcontent(self, op, arglocs, regalloc, fcond):
assert len(arglocs) == 0
@@ -1016,35 +904,6 @@
else:
raise AssertionError("bad unicode item size")
- emit_op_unicodelen = emit_op_strlen
-
- def emit_op_unicodegetitem(self, op, arglocs, regalloc, fcond):
- res, base_loc, ofs_loc, scale, basesize, itemsize = arglocs
- self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value, cond=fcond,
- imm=scale.value, shifttype=shift.LSL)
- if scale.value == 2:
- self.mc.LDR_ri(res.value, r.ip.value, basesize.value, cond=fcond)
- elif scale.value == 1:
- self.mc.LDRH_ri(res.value, r.ip.value, basesize.value, cond=fcond)
- else:
- assert 0, itemsize.value
- return fcond
-
- def emit_op_unicodesetitem(self, op, arglocs, regalloc, fcond):
- value_loc, base_loc, ofs_loc, scale, basesize, itemsize = arglocs
- self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value, cond=fcond,
- imm=scale.value, shifttype=shift.LSL)
- if scale.value == 2:
- self.mc.STR_ri(value_loc.value, r.ip.value, basesize.value,
- cond=fcond)
- elif scale.value == 1:
- self.mc.STRH_ri(value_loc.value, r.ip.value, basesize.value,
- cond=fcond)
- else:
- assert 0, itemsize.value
-
- return fcond
-
def store_force_descr(self, op, fail_locs, frame_depth):
pos = self.mc.currpos()
guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos,
c.AL)
diff --git a/rpython/jit/backend/arm/regalloc.py
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -34,9 +34,6 @@
from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.jit.codewriter.effectinfo import EffectInfo
-from rpython.jit.backend.llsupport.descr import unpack_arraydescr
-from rpython.jit.backend.llsupport.descr import unpack_fielddescr
-from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr
from rpython.rlib.rarithmetic import r_uint
from rpython.jit.backend.llsupport.descr import CallDescr
@@ -802,15 +799,12 @@
src_locations2, dst_locations2, vfptmploc)
return []
- def prepare_op_setfield_gc(self, op, fcond):
+ def prepare_op_gc_store(self, op, fcond):
boxes = op.getarglist()
- ofs, size, sign = unpack_fielddescr(op.getdescr())
- return self._prepare_op_setfield(boxes, ofs, size)
-
- def _prepare_op_setfield(self, boxes, ofs, size):
- a0, a1 = boxes
- base_loc = self.make_sure_var_in_reg(a0, boxes)
- value_loc = self.make_sure_var_in_reg(a1, boxes)
+ base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+ ofs = boxes[1].getint()
+ value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
+ size = boxes[3].getint()
ofs_size = default_imm_size if size < 8 else VMEM_imm_size
if check_imm_arg(ofs, size=ofs_size):
ofs_loc = imm(ofs)
@@ -819,19 +813,13 @@
self.assembler.load(ofs_loc, imm(ofs))
return [value_loc, base_loc, ofs_loc, imm(size)]
- prepare_op_setfield_raw = prepare_op_setfield_gc
-
- def prepare_op_zero_ptr_field(self, op, fcond):
+ def _prepare_op_gc_load(self, op, fcond):
a0 = op.getarg(0)
ofs = op.getarg(1).getint()
- return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD)
-
- def _prepare_op_getfield(self, op, fcond):
- a0 = op.getarg(0)
- ofs, size, sign = unpack_fielddescr(op.getdescr())
+ nsize = op.getarg(2).getint() # negative for "signed"
base_loc = self.make_sure_var_in_reg(a0)
immofs = imm(ofs)
- ofs_size = default_imm_size if size < 8 else VMEM_imm_size
+ ofs_size = default_imm_size if abs(nsize) < 8 else VMEM_imm_size
if check_imm_arg(ofs, size=ofs_size):
ofs_loc = immofs
else:
@@ -839,17 +827,12 @@
self.assembler.load(ofs_loc, immofs)
self.possibly_free_vars_for_op(op)
self.free_temp_vars()
- res = self.force_allocate_reg(op)
- return [base_loc, ofs_loc, res, imm(size)]
+ res_loc = self.force_allocate_reg(op)
+ return [base_loc, ofs_loc, res_loc, imm(nsize)]
- prepare_op_getfield_gc_i = _prepare_op_getfield
- prepare_op_getfield_gc_r = _prepare_op_getfield
- prepare_op_getfield_gc_f = _prepare_op_getfield
- prepare_op_getfield_raw_i = _prepare_op_getfield
- prepare_op_getfield_raw_f = _prepare_op_getfield
- prepare_op_getfield_gc_pure_i = _prepare_op_getfield
- prepare_op_getfield_gc_pure_r = _prepare_op_getfield
- prepare_op_getfield_gc_pure_f = _prepare_op_getfield
+ prepare_op_gc_load_i = _prepare_op_gc_load
+ prepare_op_gc_load_r = _prepare_op_gc_load
+ prepare_op_gc_load_f = _prepare_op_gc_load
def prepare_op_increment_debug_counter(self, op, fcond):
boxes = op.getarglist()
@@ -859,188 +842,38 @@
self.free_temp_vars()
return [base_loc, value_loc]
- def _prepare_op_getinteriorfield(self, op, fcond):
- t = unpack_interiorfielddescr(op.getdescr())
- ofs, itemsize, fieldsize, sign = t
- args = op.getarglist()
- base_loc = self.make_sure_var_in_reg(op.getarg(0), args)
- index_loc = self.make_sure_var_in_reg(op.getarg(1), args)
- immofs = imm(ofs)
- ofs_size = default_imm_size if fieldsize < 8 else VMEM_imm_size
- if check_imm_arg(ofs, size=ofs_size):
- ofs_loc = immofs
- else:
- ofs_loc = self.get_scratch_reg(INT, args)
- self.assembler.load(ofs_loc, immofs)
+ def prepare_op_gc_store_indexed(self, op, fcond):
+ boxes = op.getarglist()
+ base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+ value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
+ index_loc = self.make_sure_var_in_reg(boxes[1], boxes)
+ assert boxes[3].getint() == 1 # scale
+ ofs = boxes[4].getint()
+ size = boxes[5].getint()
+ assert check_imm_arg(ofs)
+ return [value_loc, base_loc, index_loc, imm(size), imm(ofs)]
+
+ def _prepare_op_gc_load_indexed(self, op, fcond):
+ boxes = op.getarglist()
+ base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+ index_loc = self.make_sure_var_in_reg(boxes[1], boxes)
+ assert boxes[2].getint() == 1 # scale
+ ofs = boxes[3].getint()
+ nsize = boxes[4].getint()
+ assert check_imm_arg(ofs)
self.possibly_free_vars_for_op(op)
self.free_temp_vars()
- result_loc = self.force_allocate_reg(op)
- return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs),
- imm(itemsize), imm(fieldsize)]
+ res_loc = self.force_allocate_reg(op)
+ return [res_loc, base_loc, index_loc, imm(nsize), imm(ofs)]
- prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield
- prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield
- prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield
-
- def prepare_op_setinteriorfield_gc(self, op, fcond):
- t = unpack_interiorfielddescr(op.getdescr())
- ofs, itemsize, fieldsize, sign = t
- args = op.getarglist()
- base_loc = self.make_sure_var_in_reg(op.getarg(0), args)
- index_loc = self.make_sure_var_in_reg(op.getarg(1), args)
- value_loc = self.make_sure_var_in_reg(op.getarg(2), args)
- immofs = imm(ofs)
- ofs_size = default_imm_size if fieldsize < 8 else VMEM_imm_size
- if check_imm_arg(ofs, size=ofs_size):
- ofs_loc = immofs
- else:
- ofs_loc = self.get_scratch_reg(INT, args)
- self.assembler.load(ofs_loc, immofs)
- return [base_loc, index_loc, value_loc, ofs_loc, imm(ofs),
- imm(itemsize), imm(fieldsize)]
- prepare_op_setinteriorfield_raw = prepare_op_setinteriorfield_gc
-
- def prepare_op_arraylen_gc(self, op, fcond):
- arraydescr = op.getdescr()
- assert isinstance(arraydescr, ArrayDescr)
- ofs = arraydescr.lendescr.offset
- arg = op.getarg(0)
- base_loc = self.make_sure_var_in_reg(arg)
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- res = self.force_allocate_reg(op)
- return [res, base_loc, imm(ofs)]
-
- def prepare_op_setarrayitem_gc(self, op, fcond):
- size, ofs, _ = unpack_arraydescr(op.getdescr())
- scale = get_scale(size)
- args = op.getarglist()
- base_loc = self.make_sure_var_in_reg(args[0], args)
- value_loc = self.make_sure_var_in_reg(args[2], args)
- ofs_loc = self.make_sure_var_in_reg(args[1], args)
- assert check_imm_arg(ofs)
- return [value_loc, base_loc, ofs_loc, imm(scale), imm(ofs)]
- prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc
- prepare_op_raw_store = prepare_op_setarrayitem_gc
-
- def _prepare_op_getarrayitem(self, op, fcond):
- boxes = op.getarglist()
- size, ofs, _ = unpack_arraydescr(op.getdescr())
- scale = get_scale(size)
- base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
- ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- res = self.force_allocate_reg(op)
- assert check_imm_arg(ofs)
- return [res, base_loc, ofs_loc, imm(scale), imm(ofs)]
-
- prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem
- prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem
- prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem
- prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem
- prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem
- prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem
- prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem
- prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem
- prepare_op_raw_load_i = _prepare_op_getarrayitem
- prepare_op_raw_load_f = _prepare_op_getarrayitem
-
- def prepare_op_strlen(self, op, fcond):
- args = op.getarglist()
- l0 = self.make_sure_var_in_reg(op.getarg(0))
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
- self.cpu.translate_support_code)
- immofs = imm(ofs_length)
- if check_imm_arg(ofs_length):
- l1 = immofs
- else:
- l1 = self.get_scratch_reg(INT, args)
- self.assembler.load(l1, immofs)
-
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
-
- res = self.force_allocate_reg(op)
- self.possibly_free_var(op)
- return [l0, l1, res]
-
- def prepare_op_strgetitem(self, op, fcond):
- boxes = op.getarglist()
- base_loc = self.make_sure_var_in_reg(boxes[0])
-
- a1 = boxes[1]
- imm_a1 = check_imm_box(a1)
- if imm_a1:
- ofs_loc = self.convert_to_imm(a1)
- else:
- ofs_loc = self.make_sure_var_in_reg(a1, boxes)
-
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- res = self.force_allocate_reg(op)
-
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
- self.cpu.translate_support_code)
- assert itemsize == 1
- return [res, base_loc, ofs_loc, imm(basesize)]
-
- def prepare_op_strsetitem(self, op, fcond):
- boxes = op.getarglist()
- base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
- ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
- value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
- self.cpu.translate_support_code)
- assert itemsize == 1
- return [value_loc, base_loc, ofs_loc, imm(basesize)]
+ prepare_op_gc_load_indexed_i = _prepare_op_gc_load_indexed
+ prepare_op_gc_load_indexed_r = _prepare_op_gc_load_indexed
+ prepare_op_gc_load_indexed_f = _prepare_op_gc_load_indexed
prepare_op_copystrcontent = void
prepare_op_copyunicodecontent = void
prepare_op_zero_array = void
- def prepare_op_unicodelen(self, op, fcond):
- l0 = self.make_sure_var_in_reg(op.getarg(0))
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
- self.cpu.translate_support_code)
- immofs = imm(ofs_length)
- if check_imm_arg(ofs_length):
- l1 = immofs
- else:
- l1 = self.get_scratch_reg(INT, [op.getarg(0)])
- self.assembler.load(l1, immofs)
-
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- res = self.force_allocate_reg(op)
- return [l0, l1, res]
-
- def prepare_op_unicodegetitem(self, op, fcond):
- boxes = op.getarglist()
- base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
- ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
-
- self.possibly_free_vars_for_op(op)
- self.free_temp_vars()
- res = self.force_allocate_reg(op)
-
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
- self.cpu.translate_support_code)
- scale = itemsize / 2
- return [res, base_loc, ofs_loc,
- imm(scale), imm(basesize), imm(itemsize)]
-
- def prepare_op_unicodesetitem(self, op, fcond):
- boxes = op.getarglist()
- base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
- ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
- value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
- basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
- self.cpu.translate_support_code)
- scale = itemsize / 2
- return [value_loc, base_loc, ofs_loc,
- imm(scale), imm(basesize), imm(itemsize)]
-
def _prepare_op_same_as(self, op, fcond):
arg = op.getarg(0)
imm_arg = check_imm_box(arg)
@@ -1142,8 +975,7 @@
def prepare_op_cond_call_gc_wb(self, op, fcond):
# we force all arguments in a reg because it will be needed anyway by
- # the following setfield_gc or setarrayitem_gc. It avoids loading it
- # twice from the memory.
+ # the following gc_store. It avoids loading it twice from the memory.
N = op.numargs()
args = op.getarglist()
arglocs = [self.make_sure_var_in_reg(op.getarg(i), args)
diff --git a/rpython/jit/backend/arm/runner.py
b/rpython/jit/backend/arm/runner.py
--- a/rpython/jit/backend/arm/runner.py
+++ b/rpython/jit/backend/arm/runner.py
@@ -29,6 +29,10 @@
float_regs = VFPRegisterManager.all_regs
frame_reg = fp
+ # can an ISA instruction handle a factor to the offset?
+ # XXX should be: tuple(1 << i for i in range(31))
+ load_supported_factors = (1,)
+
def __init__(self, rtyper, stats, opts=None, translate_support_code=False,
gcdescr=None):
AbstractLLCPU.__init__(self, rtyper, stats, opts,
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
@@ -13,6 +13,7 @@
from rpython.rtyper.llinterp import LLInterpreter, LLException
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
+from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rtyper import rclass
from rpython.rlib.clibffi import FFI_DEFAULT_ABI
@@ -33,7 +34,7 @@
# front-end will mutate them under our feet again. We also
# need to make sure things get freed.
_cache={}
-
+
def mapping(box):
if isinstance(box, Const) or box is None:
return box
@@ -205,7 +206,7 @@
class ArrayDescr(AbstractDescr):
all_interiorfielddescrs = None
-
+
def __init__(self, A, runner):
self.A = self.OUTERA = A
self._is_pure = A._immutable_field(None)
@@ -642,18 +643,9 @@
return array.getlength()
def _bh_getarrayitem(self, a, index, descr, pure=False):
+ a = support.cast_arg(lltype.Ptr(descr.A), a)
+ array = a._obj
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
return support.cast_result(descr.A.OF, array.getitem(index))
direct_getarrayitem_gc = _bh_getarrayitem
@@ -722,6 +714,24 @@
else:
return self.bh_raw_load_i(struct, offset, descr)
+ 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)
+ x = llop.gc_load_indexed(T, struct, index, scale, base_ofs)
+ return lltype.cast_primitive(lltype.Signed, x)
+
+ def bh_gc_load_indexed_f(self, struct, index, scale, base_ofs, bytes):
+ if bytes != 8:
+ raise Exception("gc_load_indexed_f is only for 'double'!")
+ return llop.gc_load_indexed(rffi.DOUBLE, struct, index, scale,
base_ofs)
+
def bh_increment_debug_counter(self, addr):
p = rffi.cast(rffi.CArrayPtr(lltype.Signed), addr)
p[0] += 1
@@ -1048,7 +1058,7 @@
if box.datatype == INT:
for i,a in enumerate(arg):
if isinstance(a, bool):
- arg[i] = int(a)
+ arg[i] = int(a)
assert all([lltype.typeOf(a) == lltype.Signed for a in arg])
elif box.datatype == FLOAT:
assert all([lltype.typeOf(a) == longlong.FLOATSTORAGE or \
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
@@ -764,6 +764,16 @@
def bh_raw_load_f(self, addr, offset, descr):
return self.read_float_at_mem(addr, offset)
+ def bh_gc_load_indexed_i(self, addr, index, scale, base_ofs, bytes):
+ offset = base_ofs + scale * index
+ return self.read_int_at_mem(addr, offset, abs(bytes), bytes < 0)
+
+ def bh_gc_load_indexed_f(self, addr, index, scale, base_ofs, bytes):
+ # only for 'double'!
+ assert bytes == rffi.sizeof(lltype.Float)
+ offset = base_ofs + scale * index
+ return self.read_float_at_mem(addr, offset)
+
def bh_new(self, sizedescr):
return self.gc_ll_descr.gc_malloc(sizedescr)
diff --git a/rpython/jit/backend/llsupport/rewrite.py
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -1,6 +1,6 @@
from rpython.rlib import rgc
from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rlib.rarithmetic import ovfcheck, highest_bit
from rpython.rtyper.lltypesystem import llmemory, lltype, rstr
from rpython.jit.metainterp import history
from rpython.jit.metainterp.history import ConstInt, ConstPtr
@@ -133,11 +133,11 @@
def emit_gc_store_or_indexed(self, op, ptr_box, index_box, value_box,
itemsize, factor, offset):
factor, offset, index_box = \
- self._emit_mul_add_if_factor_offset_not_supported(index_box,
+ self._emit_mul_if_factor_offset_not_supported(index_box,
factor, offset)
#
- if factor == 1 and offset == 0:
- args = [ptr_box, index_box, value_box, ConstInt(itemsize)]
+ if index_box is None:
+ args = [ptr_box, ConstInt(offset), value_box, ConstInt(itemsize)]
newload = ResOperation(rop.GC_STORE, args)
else:
args = [ptr_box, index_box, value_box, ConstInt(factor),
@@ -160,34 +160,31 @@
index_box = op.getarg(1)
self.emit_gc_load_or_indexed(op, ptr_box, index_box, itemsize, 1, ofs,
sign)
- def _emit_mul_add_if_factor_offset_not_supported(self, index_box, factor,
offset):
- orig_factor = factor
- # factor
- must_manually_load_const = False # offset != 0 and not
self.cpu.load_constant_offset
- if factor != 1 and (factor not in self.cpu.load_supported_factors or \
- (not index_box.is_constant() and
must_manually_load_const)):
- # enter here if the factor is supported by the cpu
- # OR the index is not constant and a new resop must be emitted
- # to add the offset
- if isinstance(index_box, ConstInt):
- index_box = ConstInt(index_box.value * factor)
- else:
- index_box = ResOperation(rop.INT_MUL, [index_box,
ConstInt(factor)])
+ def _emit_mul_if_factor_offset_not_supported(self, index_box,
+ factor, offset):
+ # Returns (factor, offset, index_box) where index_box is either
+ # a non-constant BoxInt or None.
+ if isinstance(index_box, ConstInt):
+ return 1, index_box.value * factor + offset, None
+ else:
+ if factor != 1 and factor not in self.cpu.load_supported_factors:
+ # the factor is supported by the cpu
+ # x & (x - 1) == 0 is a quick test for power of 2
+ assert factor > 0
+ if (factor & (factor - 1)) == 0:
+ index_box = ResOperation(rop.INT_LSHIFT,
+ [index_box, ConstInt(highest_bit(factor))])
+ else:
+ index_box = ResOperation(rop.INT_MUL,
+ [index_box, ConstInt(factor)])
self.emit_op(index_box)
- factor = 1
- # adjust the constant offset
- #if must_manually_load_const:
- # if isinstance(index_box, ConstInt):
- # index_box = ConstInt(index_box.value + offset)
- # else:
- # index_box = ResOperation(rop.INT_ADD, [index_box,
ConstInt(offset)])
- # self.emit_op(index_box)
- # offset = 0
- return factor, offset, index_box
+ factor = 1
+ return factor, offset, index_box
- def emit_gc_load_or_indexed(self, op, ptr_box, index_box, itemsize,
factor, offset, sign, type='i'):
+ def emit_gc_load_or_indexed(self, op, ptr_box, index_box, itemsize,
+ factor, offset, sign, type='i'):
factor, offset, index_box = \
- self._emit_mul_add_if_factor_offset_not_supported(index_box,
+ self._emit_mul_if_factor_offset_not_supported(index_box,
factor, offset)
#
if sign:
@@ -197,8 +194,8 @@
optype = type
if op is not None:
optype = op.type
- if factor == 1 and offset == 0:
- args = [ptr_box, index_box, ConstInt(itemsize)]
+ if index_box is None:
+ args = [ptr_box, ConstInt(offset), ConstInt(itemsize)]
newload = ResOperation(OpHelpers.get_gc_load(optype), args)
else:
args = [ptr_box, index_box, ConstInt(factor),
@@ -303,13 +300,6 @@
self.cpu.translate_support_code)
self.emit_gc_store_or_indexed(op, op.getarg(0), op.getarg(1),
op.getarg(2),
itemsize, itemsize, basesize)
- elif op.getopnum() == rop.ZERO_PTR_FIELD:
- ofs = op.getarg(1).getint()
- size = WORD
- index_box = ConstInt(0)
- value_box = ConstInt(0)
- self.emit_gc_store_or_indexed(op, op.getarg(0), index_box,
value_box,
- size, 1, ofs)
return False
@@ -548,7 +538,9 @@
return
# the ZERO_ARRAY operation will be optimized according to what
# SETARRAYITEM_GC we see before the next allocation operation.
- # See emit_pending_zeros().
+ # See emit_pending_zeros(). (This optimization is done by
+ # hacking the object 'o' in-place: e.g., o.getarg(1) may be
+ # replaced with another constant greater than 0.)
o = ResOperation(rop.ZERO_ARRAY, [v_arr, self.c_zero, v_length],
descr=arraydescr)
self.emit_op(o)
@@ -562,9 +554,8 @@
ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_depth)
if sign:
size = -size
- args = [ConstInt(frame_info), ConstInt(0), ConstInt(1),
- ConstInt(ofs), ConstInt(size)]
- size = ResOperation(rop.GC_LOAD_INDEXED_I, args)
+ args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)]
+ size = ResOperation(rop.GC_LOAD_I, args)
self.emit_op(size)
frame = ResOperation(rop.NEW_ARRAY, [size],
descr=descrs.arraydescr)
@@ -575,9 +566,8 @@
ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_size)
if sign:
size = -size
- args = [ConstInt(frame_info), ConstInt(0), ConstInt(1),
- ConstInt(ofs), ConstInt(size)]
- size = ResOperation(rop.GC_LOAD_INDEXED_I, args)
+ args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)]
+ size = ResOperation(rop.GC_LOAD_I, args)
self.emit_op(size)
frame = self.gen_malloc_nursery_varsize_frame(size)
self.gen_initialize_tid(frame, descrs.arraydescr.tid)
@@ -657,15 +647,12 @@
descr = self.cpu.getarraydescr_for_frame(arg.type)
assert self.cpu.JITFRAME_FIXED_SIZE & 1 == 0
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit