Author: Ronan Lamy <[email protected]>
Branch: exctrans
Changeset: r81592:7bf2e87a1dfe
Date: 2016-01-05 17:12 +0100
http://bitbucket.org/pypy/pypy/changeset/7bf2e87a1dfe/
Log: hg merge default
diff too long, truncating to 2000 out of 6946 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/cPickle.py b/lib_pypy/cPickle.py
--- a/lib_pypy/cPickle.py
+++ b/lib_pypy/cPickle.py
@@ -559,6 +559,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
@@ -592,6 +593,11 @@
n -= 1L << (nbytes << 3)
return n
+try:
+ from __pypy__ import decode_long
+except ImportError:
+ pass
+
def load(f):
return Unpickler(f).load()
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/stm.rst b/pypy/doc/stm.rst
--- a/pypy/doc/stm.rst
+++ b/pypy/doc/stm.rst
@@ -83,30 +83,27 @@
**pypy-stm requires 64-bit Linux for now.**
-Development is done in the branch `stmgc-c7`_. If you are only
-interested in trying it out, you can download a Ubuntu binary here__
-(``pypy-stm-2.*.tar.bz2``, for Ubuntu 12.04-14.04). The current version
-supports four "segments", which means that it will run up to four
-threads in parallel. (Development recently switched to `stmgc-c8`_,
-but that is not ready for trying out yet.)
+Development is done in the branch `stmgc-c8`_. If you are only
+interested in trying it out, please pester us until we upload a recent
+prebuilt binary. The current version supports four "segments", which
+means that it will run up to four threads in parallel.
To build a version from sources, you first need to compile a custom
-version of clang(!); we recommend downloading `llvm and clang like
-described here`__, but at revision 201645 (use ``svn co -r 201645 <path>``
-for all checkouts). Then apply all the patches in `this directory`__:
-they are fixes for a clang-only feature that hasn't been used so heavily
-in the past (without the patches, you get crashes of clang). Then get
-the branch `stmgc-c7`_ of PyPy and run::
+version of gcc(!). See the instructions here:
+https://bitbucket.org/pypy/stmgc/src/default/gcc-seg-gs/
+(Note that these patches are being incorporated into gcc. It is likely
+that future versions of gcc will not need to be patched any more.)
+
+Then get the branch `stmgc-c8`_ of PyPy and run::
cd pypy/goal
../../rpython/bin/rpython -Ojit --stm
- PYTHONPATH=. ./pypy-c pypy/tool/build_cffi_imports.py
-.. _`stmgc-c7`: https://bitbucket.org/pypy/pypy/src/stmgc-c7/
+At the end, this will try to compile the generated C code by calling
+``gcc-seg-gs``, which must be the script you installed in the
+instructions above.
+
.. _`stmgc-c8`: https://bitbucket.org/pypy/pypy/src/stmgc-c8/
-.. __: https://bitbucket.org/pypy/pypy/downloads/
-.. __: http://clang.llvm.org/get_started.html
-.. __: https://bitbucket.org/pypy/stmgc/src/default/c7/llvmfix/
.. _caveats:
@@ -114,6 +111,12 @@
Current status (stmgc-c7)
-------------------------
+.. warning::
+
+ THIS PAGE IS OLD, THE REST IS ABOUT STMGC-C7 WHEREAS THE CURRENT
+ DEVELOPMENT WORK IS DONE ON STMGC-C8
+
+
* **NEW:** It seems to work fine, without crashing any more. Please `report
any crash`_ you find (or other bugs).
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:
@@ -73,3 +78,35 @@
Move wrappers for OS functions from `rpython/rtyper` to `rpython/rlib` and
turn them into regular RPython functions. Most RPython-compatible `os.*`
functions are now directly accessible as `rpython.rposix.*`.
+
+.. 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.
+
+.. branch: ec-keepalive
+
+Optimize the case where, in a new C-created thread, we keep invoking
+short-running Python callbacks. (CFFI on CPython has a hack to achieve
+the same result.) This can also be seen as a bug fix: previously,
+thread-local objects would be reset between two such calls.
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -933,6 +933,8 @@
def test_dont_fold_equal_code_objects(self):
yield self.st, "f=lambda:1;g=lambda:1.0;x=g()", 'type(x)', float
+ yield (self.st, "x=(lambda: (-0.0, 0.0), lambda: (0.0, -0.0))[1]()",
+ 'repr(x)', '(0.0, -0.0)')
class AppTestCompiler:
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/call_python.py
b/pypy/module/_cffi_backend/call_python.py
--- a/pypy/module/_cffi_backend/call_python.py
+++ b/pypy/module/_cffi_backend/call_python.py
@@ -40,10 +40,9 @@
at least 8 bytes in size.
"""
from pypy.module._cffi_backend.ccallback import reveal_callback
+ from rpython.rlib import rgil
- after = rffi.aroundstate.after
- if after:
- after()
+ rgil.acquire()
rffi.stackcounter.stacks_counter += 1
llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
@@ -71,9 +70,7 @@
cerrno._errno_before(rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO)
rffi.stackcounter.stacks_counter -= 1
- before = rffi.aroundstate.before
- if before:
- before()
+ rgil.release()
def get_ll_cffi_call_python():
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))
@@ -602,6 +602,7 @@
# Make the wrapper for the cases (1) and (2)
def make_wrapper(space, callable, gil=None):
"NOT_RPYTHON"
+ from rpython.rlib import rgil
names = callable.api_func.argnames
argtypes_enum_ui =
unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
[name.startswith("w_") for name in names])))
@@ -617,9 +618,7 @@
# we hope that malloc removal removes the newtuple() that is
# inserted exactly here by the varargs specializer
if gil_acquire:
- after = rffi.aroundstate.after
- if after:
- after()
+ rgil.acquire()
rffi.stackcounter.stacks_counter += 1
llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
retval = fatal_value
@@ -692,9 +691,7 @@
pypy_debug_catch_fatal_exception()
rffi.stackcounter.stacks_counter -= 1
if gil_release:
- before = rffi.aroundstate.before
- if before:
- before()
+ rgil.release()
return retval
callable._always_inline_ = 'try'
wrapper.__name__ = "wrapper for %r" % (callable, )
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/signal/__init__.py b/pypy/module/signal/__init__.py
--- a/pypy/module/signal/__init__.py
+++ b/pypy/module/signal/__init__.py
@@ -48,3 +48,6 @@
use_bytecode_counter=False)
space.actionflag.__class__ = interp_signal.SignalActionFlag
# xxx yes I know the previous line is a hack
+
+ def startup(self, space):
+ space.check_signal_action.startup(space)
diff --git a/pypy/module/signal/interp_signal.py
b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -63,19 +63,25 @@
AsyncAction.__init__(self, space)
self.pending_signal = -1
self.fire_in_another_thread = False
- if self.space.config.objspace.usemodules.thread:
- from pypy.module.thread import gil
- gil.after_thread_switch = self._after_thread_switch
+ #
+ @rgc.no_collect
+ def _after_thread_switch():
+ if self.fire_in_another_thread:
+ if self.space.threadlocals.signals_enabled():
+ self.fire_in_another_thread = False
+ self.space.actionflag.rearm_ticker()
+ # this occurs when we just switched to the main thread
+ # and there is a signal pending: we force the ticker to
+ # -1, which should ensure perform() is called quickly.
+ self._after_thread_switch = _after_thread_switch
+ # ^^^ so that 'self._after_thread_switch' can be annotated as a
+ # constant
- @rgc.no_collect
- def _after_thread_switch(self):
- if self.fire_in_another_thread:
- if self.space.threadlocals.signals_enabled():
- self.fire_in_another_thread = False
- self.space.actionflag.rearm_ticker()
- # this occurs when we just switched to the main thread
- # and there is a signal pending: we force the ticker to
- # -1, which should ensure perform() is called quickly.
+ def startup(self, space):
+ # this is translated
+ if space.config.objspace.usemodules.thread:
+ from rpython.rlib import rgil
+ rgil.invoke_after_thread_switch(self._after_thread_switch)
def perform(self, executioncontext, frame):
self._poll_for_signals()
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1353,8 +1353,8 @@
ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo;")
from cffi import __version_info__
- if __version_info__ < (1, 4):
- py.test.skip("re-enable me in version 1.4")
+ if __version_info__ < (1, 5):
+ py.test.skip("re-enable me in version 1.5")
e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
assert str(e.value) == (
"'enum foo' has no values explicitly defined: refusing to guess "
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
@@ -27,7 +27,7 @@
from pypy.module.thread import gil
MixedModule.__init__(self, space, *args)
prev_ec = space.threadlocals.get_ec()
- 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/gil.py b/pypy/module/thread/gil.py
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -11,7 +11,6 @@
from pypy.module.thread.error import wrap_thread_error
from pypy.interpreter.executioncontext import PeriodicAsyncAction
from pypy.module.thread.threadlocals import OSThreadLocals
-from rpython.rlib.objectmodel import invoke_around_extcall
class GILThreadLocals(OSThreadLocals):
"""A version of OSThreadLocals that enforces a GIL."""
@@ -23,34 +22,21 @@
space.actionflag.register_periodic_action(GILReleaseAction(space),
use_bytecode_counter=True)
- def _initialize_gil(self, space):
- rgil.gil_allocate()
-
def setup_threads(self, space):
"""Enable threads in the object space, if they haven't already been."""
if not self.gil_ready:
- self._initialize_gil(space)
+ # Note: this is a quasi-immutable read by module/pypyjit/interp_jit
+ # It must be changed (to True) only if it was really False before
+ rgil.allocate()
self.gil_ready = True
result = True
else:
result = False # already set up
-
- # add the GIL-releasing callback around external function calls.
- #
- # XXX we assume a single space, but this is not quite true during
- # testing; for example, if you run the whole of test_lock you get
- # a deadlock caused by the first test's space being reused by
- # test_lock_again after the global state was cleared by
- # test_compile_lock. As a workaround, we repatch these global
- # fields systematically.
- invoke_around_extcall(before_external_call, after_external_call)
return result
- def reinit_threads(self, space):
- "Called in the child process after a fork()"
- OSThreadLocals.reinit_threads(self, space)
- if self.gil_ready: # re-initialize the gil if needed
- self._initialize_gil(space)
+ ## def reinit_threads(self, space):
+ ## "Called in the child process after a fork()"
+ ## OSThreadLocals.reinit_threads(self, space)
class GILReleaseAction(PeriodicAsyncAction):
@@ -59,43 +45,4 @@
"""
def perform(self, executioncontext, frame):
- do_yield_thread()
-
-
-after_thread_switch = lambda: None # hook for signal.py
-
-def before_external_call():
- # this function must not raise, in such a way that the exception
- # transformer knows that it cannot raise!
- rgil.gil_release()
-before_external_call._gctransformer_hint_cannot_collect_ = True
-before_external_call._dont_reach_me_in_del_ = True
-
-def after_external_call():
- rgil.gil_acquire()
- rthread.gc_thread_run()
- after_thread_switch()
-after_external_call._gctransformer_hint_cannot_collect_ = True
-after_external_call._dont_reach_me_in_del_ = True
-
-# The _gctransformer_hint_cannot_collect_ hack is needed for
-# translations in which the *_external_call() functions are not inlined.
-# They tell the gctransformer not to save and restore the local GC
-# pointers in the shadow stack. This is necessary because the GIL is
-# not held after the call to before_external_call() or before the call
-# to after_external_call().
-
-def do_yield_thread():
- # explicitly release the gil, in a way that tries to give more
- # priority to other threads (as opposed to continuing to run in
- # the same thread).
- if rgil.gil_yield_thread():
- rthread.gc_thread_run()
- after_thread_switch()
-do_yield_thread._gctransformer_hint_close_stack_ = True
-do_yield_thread._dont_reach_me_in_del_ = True
-do_yield_thread._dont_inline_ = True
-
-# do_yield_thread() needs a different hint: _gctransformer_hint_close_stack_.
-# The *_external_call() functions are themselves called only from the rffi
-# module from a helper function that also has this hint.
+ rgil.yield_thread()
diff --git a/pypy/module/thread/test/support.py
b/pypy/module/thread/test/support.py
--- a/pypy/module/thread/test/support.py
+++ b/pypy/module/thread/test/support.py
@@ -5,7 +5,7 @@
import errno
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.module.thread import gil
+from rpython.rlib import rgil
NORMAL_TIMEOUT = 300.0 # 5 minutes
@@ -15,9 +15,9 @@
adaptivedelay = 0.04
limit = time.time() + delay * NORMAL_TIMEOUT
while time.time() <= limit:
- gil.before_external_call()
+ rgil.release()
time.sleep(adaptivedelay)
- gil.after_external_call()
+ rgil.acquire()
gc.collect()
if space.is_true(space.call_function(w_condition)):
return
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
@@ -1,5 +1,6 @@
import time
from pypy.module.thread import gil
+from rpython.rlib import rgil
from rpython.rlib.test import test_rthread
from rpython.rlib import rthread as thread
from rpython.rlib.objectmodel import we_are_translated
@@ -55,7 +56,7 @@
assert state.datalen3 == len(state.data)
assert state.datalen4 == len(state.data)
debug_print(main, i, state.datalen4)
- gil.do_yield_thread()
+ rgil.yield_thread()
assert i == j
j += 1
def bootstrap():
@@ -64,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
@@ -82,9 +83,9 @@
if not still_waiting:
raise ValueError("time out")
still_waiting -= 1
- if not we_are_translated(): gil.before_external_call()
+ if not we_are_translated(): rgil.release()
time.sleep(0.01)
- if not we_are_translated(): gil.after_external_call()
+ if not we_are_translated(): rgil.acquire()
debug_print("leaving!")
i1 = i2 = 0
for tid, i in state.data:
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 enter_thread(self, space):
@@ -29,19 +67,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):
@@ -84,7 +138,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()"
@@ -94,7 +164,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
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit