[pypy-commit] pypy py3.6: hg merge py3.5
mjacob
pypy.commits at gmail.com
Mon Mar 19 12:19:36 EDT 2018
Author: Manuel Jacob <me at manueljacob.de>
Branch: py3.6
Changeset: r94007:a756aa082d6b
Date: 2018-03-19 17:14 +0100
http://bitbucket.org/pypy/pypy/changeset/a756aa082d6b/
Log: hg merge py3.5
diff too long, truncating to 2000 out of 2599 lines
diff --git a/lib-python/3/distutils/msvc9compiler.py b/lib-python/3/distutils/msvc9compiler.py
--- a/lib-python/3/distutils/msvc9compiler.py
+++ b/lib-python/3/distutils/msvc9compiler.py
@@ -223,6 +223,7 @@
that fails it falls back to the VS90COMNTOOLS env var.
"""
vsbase = VS_BASE % version
+ batfile = 'vcvarsall.bat'
try:
productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
"productdir")
@@ -235,9 +236,14 @@
toolsdir = os.environ.get(toolskey, None)
if toolsdir and os.path.isdir(toolsdir):
- productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
- productdir = os.path.abspath(productdir)
+ if os.path.exists(os.path.join(toolsdir, 'VsDevCmd.bat')):
+ productdir = toolsdir
+ batfile = 'VsDevCmd.bat'
+ else:
+ productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
+ productdir = os.path.abspath(productdir)
if not os.path.isdir(productdir):
+
log.debug("%s is not a valid directory" % productdir)
return None
else:
@@ -245,7 +251,7 @@
if not productdir:
log.debug("No productdir found")
return None
- vcvarsall = os.path.join(productdir, "vcvarsall.bat")
+ vcvarsall = os.path.join(productdir, batfile)
if os.path.isfile(vcvarsall):
return vcvarsall
log.debug("Unable to find vcvarsall.bat")
@@ -289,6 +295,7 @@
if len(result) != len(interesting):
raise ValueError(str(list(result.keys())))
+ log.debug('Got', result)
return result
# More globals
diff --git a/lib_pypy/_dbm.py b/lib_pypy/_dbm.py
--- a/lib_pypy/_dbm.py
+++ b/lib_pypy/_dbm.py
@@ -168,7 +168,14 @@
def open(filename, flag='r', mode=0o666):
"open a DBM database"
if not isinstance(filename, str):
- raise TypeError("expected string")
+ if sys.version_info < (3,) and isinstance(filename, unicode):
+ # unlike CPython we'll encode 'filename' with filesystemencoding
+ # instead of defaultencoding, because that seems like a far
+ # better idea. But I'm also open for saying that we should
+ # rather go for bug-to-bug compatibility instead.
+ filename = filename.encode(sys.getfilesystemencoding())
+ else:
+ raise TypeError("expected string")
filename = filename.encode(sys.getdefaultencoding())
openflag = 0
diff --git a/lib_pypy/_pypy_testcapi.py b/lib_pypy/_pypy_testcapi.py
--- a/lib_pypy/_pypy_testcapi.py
+++ b/lib_pypy/_pypy_testcapi.py
@@ -3,7 +3,7 @@
import importlib.machinery
-def get_hashed_dir(cfile):
+def _get_hashed_filename(cfile):
with open(cfile,'r') as fid:
content = fid.read()
# from cffi's Verifier()
@@ -23,10 +23,28 @@
username = os.environ['USERNAME'] #windows
except KeyError:
username = os.getuid()
- output_dir = tempfile.gettempdir() + os.path.sep + 'tmp_%s_%s%s' % (
+ return tempfile.gettempdir() + os.path.sep + 'testcapi_%s_%s%s' % (
username, k1, k2)
- if not os.path.exists(output_dir):
+
+def get_hashed_dir(cfile):
+ hashed_fn = _get_hashed_filename(cfile)
+ try:
+ with open(hashed_fn) as f:
+ dirname = f.read(1024)
+ except IOError:
+ dirname = ''
+ tmpdir = tempfile.gettempdir()
+ if (not dirname or '/' in dirname or '\\' in dirname or '\x00' in dirname
+ or not os.path.isdir(os.path.join(tmpdir, dirname))):
+ dirname = binascii.hexlify(os.urandom(8))
+ if not isinstance(dirname, str): # Python 3
+ dirname = dirname.decode('ascii')
+ dirname = 'testcapi_' + dirname
+ output_dir = os.path.join(tmpdir, dirname)
+ try:
os.mkdir(output_dir)
+ except OSError:
+ pass
return output_dir
@@ -35,13 +53,12 @@
return suffixes[0] if suffixes else None
-def compile_shared(csource, modulename, output_dir=None):
+def compile_shared(csource, modulename, output_dir):
"""Compile '_testcapi.c' or '_ctypes_test.c' into an extension module,
and import it.
"""
thisdir = os.path.dirname(__file__)
- if output_dir is None:
- output_dir = tempfile.mkdtemp()
+ assert output_dir is not None
from distutils.ccompiler import new_compiler
@@ -85,4 +102,16 @@
# Now import the newly created library, it will replace the original
# module in sys.modules
fp, filename, description = imp.find_module(modulename, path=[output_dir])
- imp.load_module(modulename, fp, filename, description)
+ with fp:
+ imp.load_module(modulename, fp, filename, description)
+
+ # If everything went fine up to now, write the name of this new
+ # directory to 'hashed_fn', for future processes (and to avoid a
+ # growing number of temporary directories that are not completely
+ # obvious to clean up on Windows)
+ hashed_fn = _get_hashed_filename(os.path.join(thisdir, csource))
+ try:
+ with open(hashed_fn, 'w') as f:
+ f.write(os.path.basename(output_dir))
+ except IOError:
+ pass
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.11.4
+Version: 1.11.5
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
from .error import CDefError, FFIError, VerificationError, VerificationMissing
-__version__ = "1.11.4"
-__version_info__ = (1, 11, 4)
+__version__ = "1.11.5"
+__version_info__ = (1, 11, 5)
# 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/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -146,32 +146,6 @@
PyGILState_STATE state;
PyObject *pycode=NULL, *global_dict=NULL, *x;
-#if PY_MAJOR_VERSION >= 3
- /* see comments in _cffi_carefully_make_gil() about the
- Python2/Python3 difference
- */
-#else
- /* Acquire the GIL. We have no threadstate here. If Python is
- already initialized, it is possible that there is already one
- existing for this thread, but it is not made current now.
- */
- PyEval_AcquireLock();
-
- _cffi_py_initialize();
-
- /* The Py_InitializeEx() sometimes made a threadstate for us, but
- not always. Indeed Py_InitializeEx() could be called and do
- nothing. So do we have a threadstate, or not? We don't know,
- but we can replace it with NULL in all cases.
- */
- (void)PyThreadState_Swap(NULL);
-
- /* Now we can release the GIL and re-acquire immediately using the
- logic of PyGILState(), which handles making or installing the
- correct threadstate.
- */
- PyEval_ReleaseLock();
-#endif
state = PyGILState_Ensure();
/* Call the initxxx() function from the present module. It will
@@ -247,7 +221,7 @@
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.11.4"
+ "\ncompiled with cffi version: 1.11.5"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
@@ -278,16 +252,14 @@
that we don't hold the GIL before (if it exists), and we don't
hold it afterwards.
- What it really does is completely different in Python 2 and
- Python 3.
+ (What it really does used to be completely different in Python 2
+ and Python 3, with the Python 2 solution avoiding the spin-lock
+ around the Py_InitializeEx() call. However, after recent changes
+ to CPython 2.7 (issue #358) it no longer works. So we use the
+ Python 3 solution everywhere.)
- Python 2
- ========
-
- Initialize the GIL, without initializing the rest of Python,
- by calling PyEval_InitThreads().
-
- PyEval_InitThreads() must not be called concurrently at all.
+ This initializes Python by calling Py_InitializeEx().
+ Important: this must not be called concurrently at all.
So we use a global variable as a simple spin lock. This global
variable must be from 'libpythonX.Y.so', not from this
cffi-based extension module, because it must be shared from
@@ -297,18 +269,6 @@
string "ENDMARKER". We change it temporarily to point to the
next character in that string. (Yes, I know it's REALLY
obscure.)
-
- Python 3
- ========
-
- In Python 3, PyEval_InitThreads() cannot be called before
- Py_InitializeEx() any more. So this function calls
- Py_InitializeEx() first. It uses the same obscure logic to
- make sure we never call it concurrently.
-
- Arguably, this is less good on the spinlock, because
- Py_InitializeEx() takes much longer to run than
- PyEval_InitThreads(). But I didn't find a way around it.
*/
#ifdef WITH_THREAD
@@ -332,8 +292,7 @@
}
#endif
-#if PY_MAJOR_VERSION >= 3
- /* Python 3: call Py_InitializeEx() */
+ /* call Py_InitializeEx() */
{
PyGILState_STATE state = PyGILState_UNLOCKED;
if (!Py_IsInitialized())
@@ -344,17 +303,6 @@
PyEval_InitThreads();
PyGILState_Release(state);
}
-#else
- /* Python 2: call PyEval_InitThreads() */
-# ifdef WITH_THREAD
- if (!PyEval_ThreadsInitialized()) {
- PyEval_InitThreads(); /* makes the GIL */
- PyEval_ReleaseLock(); /* then release it */
- }
- /* else: there is already a GIL, but we still needed to do the
- spinlock dance to make sure that we see it as fully ready */
-# endif
-#endif
#ifdef WITH_THREAD
/* release the lock */
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -143,6 +143,13 @@
self._libraries.append(lib)
return lib
+ def dlclose(self, lib):
+ """Close a library obtained with ffi.dlopen(). After this call,
+ access to functions or variables from the library will fail
+ (possibly with a segmentation fault).
+ """
+ type(lib).__cffi_close__(lib)
+
def _typeof_locked(self, cdecl):
# call me with the lock!
key = cdecl
@@ -898,6 +905,9 @@
return addressof_var(name)
raise AttributeError("cffi library has no function or "
"global variable named '%s'" % (name,))
+ def __cffi_close__(self):
+ backendlib.close_lib()
+ self.__dict__.clear()
#
if libname is not None:
try:
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -352,21 +352,20 @@
self.fldquals = fldquals
self.build_c_name_with_marker()
- def has_anonymous_struct_fields(self):
- if self.fldtypes is None:
- return False
- for name, type in zip(self.fldnames, self.fldtypes):
- if name == '' and isinstance(type, StructOrUnion):
- return True
- return False
+ def anonymous_struct_fields(self):
+ if self.fldtypes is not None:
+ for name, type in zip(self.fldnames, self.fldtypes):
+ if name == '' and isinstance(type, StructOrUnion):
+ yield type
- def enumfields(self):
+ def enumfields(self, expand_anonymous_struct_union=True):
fldquals = self.fldquals
if fldquals is None:
fldquals = (0,) * len(self.fldnames)
for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
self.fldbitsize, fldquals):
- if name == '' and isinstance(type, StructOrUnion):
+ if (name == '' and isinstance(type, StructOrUnion)
+ and expand_anonymous_struct_union):
# nested anonymous struct/union
for result in type.enumfields():
yield result
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -836,6 +836,10 @@
def _struct_collecttype(self, tp):
self._do_collect_type(tp)
+ if self.target_is_python:
+ # also requires nested anon struct/unions in ABI mode, recursively
+ for fldtype in tp.anonymous_struct_fields():
+ self._struct_collecttype(fldtype)
def _struct_decl(self, tp, cname, approxname):
if tp.fldtypes is None:
@@ -884,7 +888,7 @@
named_ptr not in self.ffi._parser._included_declarations)):
if tp.fldtypes is None:
pass # opaque
- elif tp.partial or tp.has_anonymous_struct_fields():
+ elif tp.partial or any(tp.anonymous_struct_fields()):
pass # field layout obtained silently from the C compiler
else:
flags.append("_CFFI_F_CHECK_FIELDS")
@@ -896,7 +900,8 @@
flags = '|'.join(flags) or '0'
c_fields = []
if reason_for_not_expanding is None:
- enumfields = list(tp.enumfields())
+ expand_anonymous_struct_union = not self.target_is_python
+ enumfields = list(tp.enumfields(expand_anonymous_struct_union))
for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
self._check_not_opaque(fldtype,
diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py
--- a/lib_pypy/cffi/setuptools_ext.py
+++ b/lib_pypy/cffi/setuptools_ext.py
@@ -81,8 +81,13 @@
it doesn't so far, creating troubles. That's why we check
for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent
of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)
+
+ On Windows, it's better not to use py_limited_api until issue #355
+ can be resolved (by having virtualenv copy PYTHON3.DLL). See also
+ the start of _cffi_include.h.
"""
- if 'py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount'):
+ if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
+ and sys.platform != 'win32'):
import setuptools
try:
setuptools_major_version = int(setuptools.__version__.partition('.')[0])
@@ -143,8 +148,8 @@
def _add_py_module(dist, ffi, module_name):
from distutils.dir_util import mkpath
- from distutils.command.build_py import build_py
- from distutils.command.build_ext import build_ext
+ from setuptools.command.build_py import build_py
+ from setuptools.command.build_ext import build_ext
from distutils import log
from cffi import recompiler
@@ -164,6 +169,17 @@
generate_mod(os.path.join(self.build_lib, *module_path))
dist.cmdclass['build_py'] = build_py_make_mod
+ # distutils and setuptools have no notion I could find of a
+ # generated python module. If we don't add module_name to
+ # dist.py_modules, then things mostly work but there are some
+ # combination of options (--root and --record) that will miss
+ # the module. So we add it here, which gives a few apparently
+ # harmless warnings about not finding the file outside the
+ # build directory.
+ if dist.py_modules is None:
+ dist.py_modules = []
+ dist.py_modules.append(module_name)
+
# the following is only for "build_ext -i"
base_class_2 = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class_2):
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -567,6 +567,11 @@
versions of PyPy may have to rename the arguments if CPython starts
accepting them too.
+* PyPy3: ``distutils`` has been enhanced to allow finding ``VsDevCmd.bat`` in the
+ directory pointed to by the ``VS%0.f0COMNTOOLS`` (typically ``VS140COMNTOOLS``)
+ environment variable. CPython searches for ``vcvarsall.bat`` somewhere **above**
+ that value.
+
.. _`is ignored in PyPy`: http://bugs.python.org/issue14621
.. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
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
@@ -48,3 +48,17 @@
.. branch: winapi
Update _winapi and internal _winbase_cffi (via _winbase_build) for python 3
+
+.. branch: refactor-slots
+
+Refactor cpyext slots.
+
+
+.. branch: call-loopinvariant-into-bridges
+
+Speed up branchy code that does a lot of function inlining by saving one call
+to read the TLS in most bridges.
+
+.. branch: rpython-sprint
+
+Refactor in rpython signatures
diff --git a/pypy/interpreter/test/test_zpy.py b/pypy/interpreter/test/test_zpy.py
--- a/pypy/interpreter/test/test_zpy.py
+++ b/pypy/interpreter/test/test_zpy.py
@@ -113,6 +113,7 @@
def test_pytrace():
output = run(sys.executable, pypypath, '-S',
stdin="__pytrace__ = 1\nx = 5\nx")
+ output = output.replace('\r\n', '\n')
assert ('\t<module>: LOAD_CONST 0 (5)\n'
'\t<module>: STORE_NAME 0 (x)\n'
'\t<module>: LOAD_CONST 1 (None)\n'
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
@@ -3,7 +3,7 @@
from rpython.rlib import rdynload, clibffi
from rpython.rtyper.lltypesystem import rffi
-VERSION = "1.11.4"
+VERSION = "1.11.5"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -53,8 +53,7 @@
self.libhandle = rffi.cast(DLLHANDLE, 0)
if not libhandle:
- raise oefmt(self.ffi.w_FFIError, "library '%s' is already closed",
- self.libname)
+ return
self.may_unregister_rpython_finalizer(self.ffi.space)
# Clear the dict to force further accesses to do cdlopen_fetch()
diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py
--- a/pypy/module/_cffi_backend/libraryobj.py
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -38,9 +38,16 @@
space = self.space
return space.newtext("<clibrary '%s'>" % self.name)
+ def check_closed(self):
+ if self.handle == rffi.cast(DLLHANDLE, 0):
+ raise oefmt(self.space.w_ValueError,
+ "library '%s' has already been closed",
+ self.name)
+
@unwrap_spec(w_ctype=W_CType, name='text')
def load_function(self, w_ctype, name):
from pypy.module._cffi_backend import ctypeptr, ctypearray
+ self.check_closed()
space = self.space
#
if not isinstance(w_ctype, ctypeptr.W_CTypePtrOrArray):
@@ -60,6 +67,7 @@
@unwrap_spec(w_ctype=W_CType, name='text')
def read_variable(self, w_ctype, name):
+ self.check_closed()
space = self.space
try:
cdata = dlsym(self.handle, name)
@@ -71,6 +79,7 @@
@unwrap_spec(w_ctype=W_CType, name='text')
def write_variable(self, w_ctype, name, w_value):
+ self.check_closed()
space = self.space
try:
cdata = dlsym(self.handle, name)
@@ -80,6 +89,9 @@
name, self.name)
w_ctype.convert_from_object(rffi.cast(rffi.CCHARP, cdata), w_value)
+ def close_lib(self):
+ self._finalize_()
+
W_Library.typedef = TypeDef(
'_cffi_backend.Library',
@@ -87,6 +99,7 @@
load_function = interp2app(W_Library.load_function),
read_variable = interp2app(W_Library.read_variable),
write_variable = interp2app(W_Library.write_variable),
+ close_lib = interp2app(W_Library.close_lib),
)
W_Library.typedef.acceptable_as_base_class = False
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.11.4", ("This test_c.py file is for testing a version"
+assert __version__ == "1.11.5", ("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,):
@@ -395,6 +395,10 @@
# the next one is from 'libm', not 'libc', but we assume
# that it is already loaded too, so it should work
assert x.load_function(BVoidP, 'sqrt')
+ #
+ x.close_lib()
+ py.test.raises(ValueError, x.load_function, BVoidP, 'sqrt')
+ x.close_lib()
def test_no_len_on_nonarray():
p = new_primitive_type("int")
@@ -1210,6 +1214,9 @@
ll = find_and_load_library('c')
stderr = ll.read_variable(BVoidP, "stderr")
assert stderr == cast(BVoidP, _testfunc(8))
+ #
+ ll.close_lib()
+ py.test.raises(ValueError, ll.read_variable, BVoidP, "stderr")
def test_read_variable_as_unknown_length_array():
## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
@@ -1236,6 +1243,9 @@
assert not ll.read_variable(BVoidP, "stderr")
ll.write_variable(BVoidP, "stderr", stderr)
assert ll.read_variable(BVoidP, "stderr") == stderr
+ #
+ ll.close_lib()
+ py.test.raises(ValueError, ll.write_variable, BVoidP, "stderr", stderr)
def test_callback():
BInt = new_primitive_type("int")
diff --git a/pypy/module/_cffi_backend/test/test_re_python.py b/pypy/module/_cffi_backend/test/test_re_python.py
--- a/pypy/module/_cffi_backend/test/test_re_python.py
+++ b/pypy/module/_cffi_backend/test/test_re_python.py
@@ -114,12 +114,10 @@
from re_python_pysrc import ffi
lib = ffi.dlopen(self.extmod)
ffi.dlclose(lib)
- e = raises(ffi.error, ffi.dlclose, lib)
- assert str(e.value) == (
- "library '%s' is already closed" % (self.extmod,))
e = raises(ffi.error, getattr, lib, 'add42')
assert str(e.value) == (
"library '%s' has been closed" % (self.extmod,))
+ ffi.dlclose(lib) # does not raise
def test_constant_via_lib(self):
self.fix_path()
diff --git a/pypy/module/_posixsubprocess/test/test_subprocess.py b/pypy/module/_posixsubprocess/test/test_subprocess.py
--- a/pypy/module/_posixsubprocess/test/test_subprocess.py
+++ b/pypy/module/_posixsubprocess/test/test_subprocess.py
@@ -1,4 +1,9 @@
from os.path import dirname
+import py, sys
+
+if sys.platform == 'win32':
+ py.test.skip("not used on win32")
+
class AppTestSubprocess:
spaceconfig = dict(usemodules=('_posixsubprocess', 'signal',
diff --git a/pypy/module/_posixsubprocess/test/test_ztranslation.py b/pypy/module/_posixsubprocess/test/test_ztranslation.py
--- a/pypy/module/_posixsubprocess/test/test_ztranslation.py
+++ b/pypy/module/_posixsubprocess/test/test_ztranslation.py
@@ -1,4 +1,8 @@
from pypy.objspace.fake.checkmodule import checkmodule
+import py, sys
+
+if sys.platform == 'win32':
+ py.test.skip("not used on win32")
def test_posixsubprocess_translates():
checkmodule('_posixsubprocess')
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
@@ -813,10 +813,10 @@
def test_recv_send_timeout(self):
from _socket import socket, timeout, SOL_SOCKET, SO_RCVBUF, SO_SNDBUF
cli = socket()
+ cli.settimeout(1.0)
cli.connect(self.serv.getsockname())
fileno, addr = self.serv._accept()
t = socket(fileno=fileno)
- cli.settimeout(1.0)
# test recv() timeout
t.send(b'*')
buf = cli.recv(100)
diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py
--- a/pypy/module/_sre/interp_sre.py
+++ b/pypy/module/_sre/interp_sre.py
@@ -407,8 +407,11 @@
if not (last_pos == ctx.match_start
== ctx.match_end and n > 0):
# the above ignores empty matches on latest position
+ last_pos = ctx.match_end
if filter_is_callable:
w_match = self.getmatch(ctx, True)
+ # make a copy of 'ctx'; see test_sub_matches_stay_valid
+ ctx = ctx.fresh_copy(start) # match_start/match_end dropped
w_piece = space.call_function(w_filter, w_match)
if not space.is_w(w_piece, space.w_None):
assert strbuilder is None and unicodebuilder is None
@@ -425,7 +428,6 @@
unicodebuilder.append(filter_as_unicode)
else:
sublist_w.append(w_filter)
- last_pos = ctx.match_end
n += 1
elif last_pos >= ctx.end:
break # empty match at the end: finished
diff --git a/pypy/module/_sre/test/test_app_sre.py b/pypy/module/_sre/test/test_app_sre.py
--- a/pypy/module/_sre/test/test_app_sre.py
+++ b/pypy/module/_sre/test/test_app_sre.py
@@ -395,6 +395,18 @@
KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
raises(TypeError, KEYCRE.sub, "hello", {"%(": 1})
+ def test_sub_matches_stay_valid(self):
+ import re
+ matches = []
+ def callback(match):
+ matches.append(match)
+ return "x"
+ result = re.compile(r"[ab]").sub(callback, "acb")
+ assert result == "xcx"
+ assert len(matches) == 2
+ assert matches[0].group() == "a"
+ assert matches[1].group() == "b"
+
class AppTestSreScanner:
diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -175,7 +175,7 @@
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
with rffi.scoped_unicode2wcharp(filename) as wide_filename:
c_filename = rffi.cast(rffi.CCHARP, wide_filename)
- ret = rwinreg.RegLoadKey(hkey, c_subkey, c_filename)
+ ret = rwinreg.RegLoadKeyW(hkey, c_subkey, c_filename)
if ret != 0:
raiseWindowsError(space, ret, 'RegLoadKey')
@@ -196,7 +196,7 @@
hkey = hkey_w(w_hkey, space)
with rffi.scoped_unicode2wcharp(filename) as wide_filename:
c_filename = rffi.cast(rffi.CCHARP, wide_filename)
- ret = rwinreg.RegSaveKey(hkey, c_filename, None)
+ ret = rwinreg.RegSaveKeyW(hkey, c_filename, None)
if ret != 0:
raiseWindowsError(space, ret, 'RegSaveKey')
@@ -226,7 +226,7 @@
c_subkey = rffi.cast(rffi.CCHARP, subkey)
with rffi.scoped_unicode2wcharp(value) as dataptr:
c_dataptr = rffi.cast(rffi.CCHARP, dataptr)
- ret = rwinreg.RegSetValue(hkey, c_subkey, rwinreg.REG_SZ,
+ ret = rwinreg.RegSetValueW(hkey, c_subkey, rwinreg.REG_SZ,
c_dataptr, len(value))
if ret != 0:
raiseWindowsError(space, ret, 'RegSetValue')
@@ -250,7 +250,7 @@
with rffi.scoped_unicode2wcharp(subkey) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
with lltype.scoped_alloc(rwin32.PLONG.TO, 1) as bufsize_p:
- ret = rwinreg.RegQueryValue(hkey, c_subkey, None, bufsize_p)
+ ret = rwinreg.RegQueryValueW(hkey, c_subkey, None, bufsize_p)
bufSize = intmask(bufsize_p[0])
if ret == rwinreg.ERROR_MORE_DATA:
bufSize = 256
@@ -259,7 +259,7 @@
while True:
with lltype.scoped_alloc(rffi.CCHARP.TO, bufSize) as buf:
- ret = rwinreg.RegQueryValue(hkey, c_subkey, buf, bufsize_p)
+ ret = rwinreg.RegQueryValueW(hkey, c_subkey, buf, bufsize_p)
if ret == rwinreg.ERROR_MORE_DATA:
print 'bufSize was %d, too small' % bufSize
# Resize and retry
@@ -440,7 +440,7 @@
try:
with rffi.scoped_unicode2wcharp(value_name) as wide_vn:
c_vn = rffi.cast(rffi.CCHARP, wide_vn)
- ret = rwinreg.RegSetValueEx(hkey, c_vn, 0, typ, buf, buflen)
+ ret = rwinreg.RegSetValueExW(hkey, c_vn, 0, typ, buf, buflen)
finally:
lltype.free(buf, flavor='raw')
if ret != 0:
@@ -460,7 +460,7 @@
with rffi.scoped_unicode2wcharp(subkey) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as retDataSize:
- ret = rwinreg.RegQueryValueEx(hkey, c_subkey, null_dword, null_dword,
+ ret = rwinreg.RegQueryValueExW(hkey, c_subkey, null_dword, null_dword,
None, retDataSize)
bufSize = intmask(retDataSize[0])
if ret == rwinreg.ERROR_MORE_DATA:
@@ -472,7 +472,7 @@
with lltype.scoped_alloc(rffi.CCHARP.TO, bufSize) as databuf:
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as retType:
- ret = rwinreg.RegQueryValueEx(hkey, c_subkey, null_dword,
+ ret = rwinreg.RegQueryValueExW(hkey, c_subkey, null_dword,
retType, databuf, retDataSize)
if ret == rwinreg.ERROR_MORE_DATA:
# Resize and retry
@@ -505,7 +505,7 @@
with rffi.scoped_unicode2wcharp(subkey) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
with lltype.scoped_alloc(rwinreg.PHKEY.TO, 1) as rethkey:
- ret = rwinreg.RegCreateKey(hkey, c_subkey, rethkey)
+ ret = rwinreg.RegCreateKeyW(hkey, c_subkey, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'CreateKey')
return W_HKEY(space, rethkey[0])
@@ -527,7 +527,7 @@
with rffi.scoped_unicode2wcharp(sub_key) as wide_sub_key:
c_subkey = rffi.cast(rffi.CCHARP, wide_sub_key)
with lltype.scoped_alloc(rwinreg.PHKEY.TO, 1) as rethkey:
- ret = rwinreg.RegCreateKeyEx(hkey, c_subkey, reserved, None, 0,
+ ret = rwinreg.RegCreateKeyExW(hkey, c_subkey, reserved, None, 0,
access, None, rethkey,
lltype.nullptr(rwin32.LPDWORD.TO))
if ret != 0:
@@ -549,7 +549,7 @@
hkey = hkey_w(w_hkey, space)
with rffi.scoped_unicode2wcharp(subkey) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
- ret = rwinreg.RegDeleteKey(hkey, c_subkey)
+ ret = rwinreg.RegDeleteKeyW(hkey, c_subkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegDeleteKey')
@@ -562,7 +562,7 @@
hkey = hkey_w(w_hkey, space)
with rffi.scoped_unicode2wcharp(subkey) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
- ret = rwinreg.RegDeleteValue(hkey, c_subkey)
+ ret = rwinreg.RegDeleteValueW(hkey, c_subkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegDeleteValue')
@@ -582,7 +582,7 @@
with rffi.scoped_unicode2wcharp(sub_key) as wide_subkey:
c_subkey = rffi.cast(rffi.CCHARP, wide_subkey)
with lltype.scoped_alloc(rwinreg.PHKEY.TO, 1) as rethkey:
- ret = rwinreg.RegOpenKeyEx(hkey, c_subkey, reserved, access, rethkey)
+ ret = rwinreg.RegOpenKeyExW(hkey, c_subkey, reserved, access, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegOpenKeyEx')
return W_HKEY(space, rethkey[0])
@@ -607,7 +607,7 @@
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as retValueSize:
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as retDataSize:
- ret = rwinreg.RegQueryInfoKey(
+ ret = rwinreg.RegQueryInfoKeyW(
hkey, None, null_dword, null_dword,
null_dword, null_dword, null_dword,
null_dword, retValueSize, retDataSize,
@@ -628,7 +628,7 @@
with lltype.scoped_alloc(rwin32.LPDWORD.TO,
1) as retType:
c_valuebuf = rffi.cast(rffi.CCHARP, valuebuf)
- ret = rwinreg.RegEnumValue(
+ ret = rwinreg.RegEnumValueW(
hkey, index, c_valuebuf, retValueSize,
null_dword, retType, databuf, retDataSize)
if ret == rwinreg.ERROR_MORE_DATA:
@@ -673,7 +673,7 @@
with lltype.scoped_alloc(rffi.CCHARP.TO, 257) as buf:
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as retValueSize:
retValueSize[0] = r_uint(257) # includes NULL terminator
- ret = rwinreg.RegEnumKeyEx(hkey, index, buf, retValueSize,
+ ret = rwinreg.RegEnumKeyExW(hkey, index, buf, retValueSize,
null_dword, None, null_dword,
lltype.nullptr(rwin32.PFILETIME.TO))
if ret != 0:
@@ -695,7 +695,7 @@
with lltype.scoped_alloc(rwin32.LPDWORD.TO, 1) as nValues:
with lltype.scoped_alloc(rwin32.PFILETIME.TO, 1) as ft:
null_dword = lltype.nullptr(rwin32.LPDWORD.TO)
- ret = rwinreg.RegQueryInfoKey(
+ ret = rwinreg.RegQueryInfoKeyW(
hkey, None, null_dword, null_dword,
nSubKeys, null_dword, null_dword,
nValues, null_dword, null_dword,
@@ -722,7 +722,7 @@
machine = space.text_or_none_w(w_machine)
hkey = hkey_w(w_hkey, space)
with lltype.scoped_alloc(rwinreg.PHKEY.TO, 1) as rethkey:
- ret = rwinreg.RegConnectRegistry(machine, hkey, rethkey)
+ ret = rwinreg.RegConnectRegistryW(machine, hkey, rethkey)
if ret != 0:
raiseWindowsError(space, ret, 'RegConnectRegistry')
return W_HKEY(space, rethkey[0])
diff --git a/pypy/module/_winreg/test/test_winreg.py b/pypy/module/_winreg/test/test_winreg.py
--- a/pypy/module/_winreg/test/test_winreg.py
+++ b/pypy/module/_winreg/test/test_winreg.py
@@ -207,18 +207,20 @@
except:
pass
- key = OpenKey(self.root_key, self.test_key_name, 0, KEY_ALL_ACCESS)
- SaveKey(key, self.tmpfilename)
+ with OpenKey(self.root_key, self.test_key_name, 0, KEY_ALL_ACCESS) as key:
+ SaveKey(key, self.tmpfilename)
def test_expand_environment_string(self):
from winreg import ExpandEnvironmentStrings
import nt
r = ExpandEnvironmentStrings("%windir%\\test")
assert isinstance(r, str)
- if 'WINDIR' in list(nt.environ.keys()):
+ if 'WINDIR' in nt.environ:
assert r == nt.environ["WINDIR"] + "\\test"
+ elif 'windir' in nt.environ:
+ assert r == nt.environ["windir"] + "\\test"
else:
- assert r == nt.environ["windir"] + "\\test"
+ skip('nt.environ not filled in for untranslated tests')
def test_long_key(self):
from winreg import (
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -189,33 +189,6 @@
decref(space, view.c_obj)
return 0
-def fill_buffer(space, view, pybuf, py_obj):
- view.c_buf = cts.cast('void *', pybuf.get_raw_address())
- view.c_obj = py_obj
- if py_obj:
- incref(space, py_obj)
- view.c_len = pybuf.getlength()
- view.c_itemsize = pybuf.getitemsize()
- rffi.setintfield(view, 'c_readonly', int(pybuf.readonly))
- rffi.setintfield(view, 'c_ndim', pybuf.getndim())
- view.c_format = rffi.str2charp(pybuf.getformat())
- shape = pybuf.getshape()
- if not shape:
- view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
- else:
- view.c_shape = cts.cast('Py_ssize_t*', view.c__shape)
- for i, n in enumerate(shape):
- view.c_shape[i] = n
- strides = pybuf.getstrides()
- if not strides:
- view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
- else:
- view.c_strides = cts.cast('Py_ssize_t*', view.c__strides)
- for i, n in enumerate(strides):
- view.c_strides[i] = n
- view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
- view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
-
DEFAULT_FMT = rffi.str2charp("B")
@cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
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
@@ -688,12 +688,46 @@
return space.call_args(space.get(new_fn, w_self), args)
return slot_tp_new
+ at slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real],
+ rffi.INT_real, error=-1)
+def bytes_getbuffer(space, w_str, view, flags):
+ from pypy.module.cpyext.bytesobject import PyBytes_AsString
+ from pypy.module.cpyext.buffer import PyBuffer_FillInfo
+ c_buf = rffi.cast(rffi.VOIDP, PyBytes_AsString(space, w_str))
+ return PyBuffer_FillInfo(space, view, w_str, c_buf,
+ space.len_w(w_str), 1, flags)
+
+def slot_from_buffer_w(space, typedef):
+ name = 'bf_getbuffer'
+ @slot_function([PyObject, Py_bufferP, rffi.INT_real],
+ rffi.INT_real, error=-1)
+ @func_renamer("cpyext_%s_%s" % (name, typedef.name))
+ def buff_w(space, w_self, c_view, flags):
+ w_obj = w_self
+ if c_view:
+ #like PyObject_GetBuffer
+ flags = widen(flags)
+ buf = space.buffer_w(w_obj, flags)
+ try:
+ c_view.c_buf = rffi.cast(rffi.VOIDP, buf.get_raw_address())
+ c_view.c_obj = make_ref(space, w_obj)
+ except ValueError:
+ s = buf.as_str()
+ w_s = space.newbytes(s)
+ c_view.c_obj = make_ref(space, w_s)
+ c_view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(
+ s, track_allocation=False))
+ rffi.setintfield(c_view, 'c_readonly', 1)
+ ret = fill_Py_buffer(space, buf, c_view)
+ return ret
+ return 0
+ return buff_w
+
@slot_factory('tp_as_buffer.c_bf_getbuffer')
def make_bf_getbuffer(space, typedef, name, attr):
w_type = space.gettypeobject(typedef)
- buff_fn = w_type.lookup('__buffer__')
- if buff_fn is not None:
- return slot_from___buffer__(space, typedef, buff_fn)
+ if space.is_w(w_type, space.w_bytes):
+ return bytes_getbuffer
elif typedef.buffer:
return slot_from_buffer_w(space, typedef)
else:
@@ -739,59 +773,6 @@
return slot_tp_descr_set
-def slot_from___buffer__(space, typedef, buff_fn):
- name = 'bf_getbuffer'
- @slot_function([PyObject, Py_bufferP, rffi.INT_real],
- rffi.INT_real, error=-1)
- @func_renamer("cpyext_%s_%s" % (name, typedef.name))
- def buff_w(space, w_self, c_view, flags):
- args = Arguments(space, [space.newint(flags)])
- w_obj = space.call_args(space.get(buff_fn, w_self), args)
- if c_view:
- #like PyObject_GetBuffer
- flags = widen(flags)
- buf = space.buffer_w(w_obj, flags)
- try:
- c_view.c_buf = rffi.cast(rffi.VOIDP, buf.get_raw_address())
- c_view.c_obj = make_ref(space, w_obj)
- except ValueError:
- s = buf.as_str()
- w_s = space.newbytes(s)
- c_view.c_obj = make_ref(space, w_s)
- c_view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(
- s, track_allocation=False))
- rffi.setintfield(c_view, 'c_readonly', 1)
- ret = fill_Py_buffer(space, buf, c_view)
- return ret
- return 0
- return buff_w
-
-def slot_from_buffer_w(space, typedef):
- name = 'bf_getbuffer'
- @slot_function([PyObject, Py_bufferP, rffi.INT_real],
- rffi.INT_real, error=-1)
- @func_renamer("cpyext_%s_%s" % (name, typedef.name))
- def buff_w(space, w_self, c_view, flags):
- w_obj = w_self
- if c_view:
- #like PyObject_GetBuffer
- flags = widen(flags)
- buf = space.buffer_w(w_obj, flags)
- try:
- c_view.c_buf = rffi.cast(rffi.VOIDP, buf.get_raw_address())
- c_view.c_obj = make_ref(space, w_obj)
- except ValueError:
- s = buf.as_str()
- w_s = space.newbytes(s)
- c_view.c_obj = make_ref(space, w_s)
- c_view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(
- s, track_allocation=False))
- rffi.setintfield(c_view, 'c_readonly', 1)
- ret = fill_Py_buffer(space, buf, c_view)
- return ret
- return 0
- return buff_w
-
missing_wrappers = ['wrap_indexargfunc', 'wrap_del']
for name in missing_wrappers:
assert name not in globals()
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
@@ -640,6 +640,33 @@
self.attr1 = 123
assert module.test_tp_getattro(C(), 123)
+ def test_issue_2760_getattr(self):
+ module = self.import_extension('foo', [
+ ("get_foo", "METH_O",
+ '''
+ char* name = "foo";
+ PyTypeObject *tp = Py_TYPE(args);
+ PyObject *res;
+ if (tp->tp_getattr != NULL) {
+ res = (*tp->tp_getattr)(args, name);
+ }
+ else if (tp->tp_getattro != NULL) {
+ PyObject *w = PyUnicode_FromString(name);
+ res = (*tp->tp_getattro)(args, w);
+ Py_DECREF(w);
+ }
+ else {
+ res = Py_None;
+ }
+ return res;
+ ''')])
+ class Passthrough(object):
+ def __getattr__(self, name):
+ return name
+
+ obj = Passthrough()
+ assert module.get_foo(obj) == 'foo'
+
def test_nb_int(self):
module = self.import_extension('foo', [
("nb_int", "METH_VARARGS",
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
@@ -236,11 +236,6 @@
def update_all_slots(space, w_type, pto):
# fill slots in pto
- # Not very sure about it, but according to
- # test_call_tp_dealloc, we should not
- # overwrite slots that are already set: these ones are probably
- # coming from a parent C type.
-
for method_name, slot_name, slot_names, slot_apifunc in slotdefs_for_tp_slots:
slot_func_helper = None
w_descr = w_type.dict_w.get(method_name, None)
@@ -276,8 +271,7 @@
def fill_slot(space, pto, w_type, slot_names, slot_func_helper):
# XXX special case wrapper-functions and use a "specific" slot func
if len(slot_names) == 1:
- if not getattr(pto, slot_names[0]):
- setattr(pto, slot_names[0], slot_func_helper)
+ setattr(pto, slot_names[0], slot_func_helper)
elif ((w_type is space.w_list or w_type is space.w_tuple) and
slot_names[0] == 'c_tp_as_number'):
# XXX hack - how can we generalize this? The problem is method
@@ -312,8 +306,7 @@
struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
setattr(pto, slot_names[0], struct)
- if not getattr(struct, slot_names[1]):
- setattr(struct, slot_names[1], slot_func_helper)
+ setattr(struct, slot_names[1], slot_func_helper)
def add_operators(space, dict_w, pto, name):
from pypy.module.cpyext.object import PyObject_HashNotImplemented
@@ -526,33 +519,6 @@
realize=type_realize,
dealloc=type_dealloc)
- at slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, error=-1)
-def bytes_getbuffer(space, w_str, view, flags):
- from pypy.module.cpyext.bytesobject import PyBytes_AsString
- from pypy.module.cpyext.buffer import PyBuffer_FillInfo
- c_buf = rffi.cast(rffi.VOIDP, PyBytes_AsString(space, w_str))
- return PyBuffer_FillInfo(space, view, w_str, c_buf,
- space.len_w(w_str), 1, flags)
-
- at slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real, error=-1)
-def bf_getbuffer(space, w_obj, view, flags):
- from pypy.module.cpyext.buffer import fill_buffer
- buf = space.buffer_w(w_obj, rffi.cast(lltype.Signed, flags))
- fill_buffer(space, view, buf, as_pyobj(space, w_obj))
- return 0
-
-def setup_buffer_procs(space, w_type, pto):
- bufspec = w_type.layout.typedef.buffer
- if not bufspec:
- return
- c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
- lltype.render_immortal(c_buf)
- if space.is_w(w_type, space.w_bytes):
- c_buf.c_bf_getbuffer = llslot(space, bytes_getbuffer)
- else:
- c_buf.c_bf_getbuffer = llslot(space, bf_getbuffer)
- pto.c_tp_as_buffer = c_buf
-
@slot_function([PyObject], lltype.Void)
def type_dealloc(space, obj):
from pypy.module.cpyext.object import _dealloc
@@ -611,8 +577,6 @@
pto.c_tp_itemsize = 1
elif space.is_w(w_type, space.w_tuple):
pto.c_tp_itemsize = rffi.sizeof(PyObject)
- # buffer protocol
- setup_buffer_procs(space, w_type, pto)
state = space.fromcache(State)
pto.c_tp_free = state.C.PyObject_Free
@@ -730,7 +694,6 @@
pto.c_tp_as_buffer = base.c_tp_as_buffer
if base.c_tp_as_buffer:
# inherit base.c_tp_as_buffer functions not inherited from w_type
- # note: builtin types are handled in setup_buffer_procs
pto_as = pto.c_tp_as_buffer
base_as = base.c_tp_as_buffer
if not pto_as.c_bf_getbuffer:
diff --git a/pypy/module/cpyext/userslot.py b/pypy/module/cpyext/userslot.py
--- a/pypy/module/cpyext/userslot.py
+++ b/pypy/module/cpyext/userslot.py
@@ -106,7 +106,7 @@
return space.getitem(w_obj1, w_obj2)
@slot_function([PyObject, PyObject], PyObject)
-def slot_tp_getattr(space, w_obj1, w_obj2):
+def slot_tp_getattr_hook(space, w_obj1, w_obj2):
return space.getattr(w_obj1, w_obj2)
@slot_function([PyObject, PyObject, PyObject], PyObject)
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -82,7 +82,7 @@
import imp
for suffix, mode, type in imp.get_suffixes():
if type == imp.PY_SOURCE:
- assert suffix == '.py'
+ assert suffix in ('.py', '.pyw')
assert mode == 'r'
elif type == imp.PY_COMPILED:
assert suffix == '.pyc'
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
@@ -1092,9 +1092,11 @@
if sys.platform == 'win32':
os.chmod(my_path, 0o400)
assert (os.stat(my_path).st_mode & 0o600) == 0o400
+ os.chmod(self.path, 0o700)
else:
os.chmod(my_path, 0o200)
assert (os.stat(my_path).st_mode & 0o777) == 0o200
+ os.chmod(self.path, 0o700)
if hasattr(os, 'fchmod'):
def test_fchmod(self):
@@ -1406,6 +1408,22 @@
if len(e.value.args) > 2:
assert e.value.args[2] == "\\foo\\bar\\baz"
+ @py.test.mark.skipif("sys.platform != 'win32'")
+ def test_rename(self):
+ os = self.posix
+ fname = self.path2 + 'rename.txt'
+ with open(fname, "w") as f:
+ f.write("this is a rename test")
+ unicode_name = str(self.udir) + u'/test\u03be.txt'
+ os.rename(fname, unicode_name)
+ with open(unicode_name) as f:
+ assert f.read() == 'this is a rename test'
+ os.rename(unicode_name, fname)
+ with open(fname) as f:
+ assert f.read() == 'this is a rename test'
+ os.unlink(fname)
+
+
def test_device_encoding(self):
import sys
encoding = self.posix.device_encoding(sys.stdout.fileno())
@@ -1509,6 +1527,8 @@
def test_environ(self):
import sys, os
environ = os.environ
+ if not environ:
+ skip('environ not filled in for untranslated tests')
for k, v in environ.items():
assert type(k) is str
assert type(v) is str
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
@@ -500,3 +500,21 @@
""")
m = ffi.dlopen(lib_m)
assert dir(m) == ['MYE1', 'MYE2', 'MYFOO', 'myconst', 'myfunc', 'myvar']
+
+ def test_dlclose(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("not with the ctypes backend")
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("int foobar(void); int foobaz;")
+ lib = ffi.dlopen(lib_m)
+ ffi.dlclose(lib)
+ e = py.test.raises(ValueError, getattr, lib, 'foobar')
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ e = py.test.raises(ValueError, getattr, lib, 'foobaz')
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ e = py.test.raises(ValueError, setattr, lib, 'foobaz', 42)
+ assert str(e.value).startswith("library '")
+ assert str(e.value).endswith("' has already been closed")
+ ffi.dlclose(lib) # does not raise
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ownlib.py
@@ -115,8 +115,12 @@
if sys.platform == 'win32':
import os
# did we already build it?
- if os.path.exists(str(udir.join('testownlib.dll'))):
- cls.module = str(udir.join('testownlib.dll'))
+ if cls.Backend is CTypesBackend:
+ dll_path = str(udir) + '\\testownlib1.dll' # only ascii for the ctypes backend
+ else:
+ dll_path = str(udir) + '\\' + (u+'testownlib\u03be.dll') # non-ascii char
+ if os.path.exists(dll_path):
+ cls.module = dll_path
return
# try (not too hard) to find the version used to compile this python
# no mingw
@@ -136,8 +140,9 @@
if os.path.isfile(vcvarsall):
cmd = '"%s" %s' % (vcvarsall, arch) + ' & cl.exe testownlib.c ' \
' /LD /Fetestownlib.dll'
- subprocess.check_call(cmd, cwd = str(udir), shell=True)
- cls.module = str(udir.join('testownlib.dll'))
+ subprocess.check_call(cmd, cwd = str(udir), shell=True)
+ os.rename(str(udir) + '\\testownlib.dll', dll_path)
+ cls.module = dll_path
else:
subprocess.check_call(
'cc testownlib.c -shared -fPIC -o testownlib.so',
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
@@ -1,9 +1,10 @@
# Generated by pypy/tool/import_cffi.py
-import sys
+import sys, os
import py
from cffi import FFI
from cffi import recompiler, ffiplatform, VerificationMissing
from pypy.module.test_lib_pypy.cffi_tests.udir import udir
+from pypy.module.test_lib_pypy.cffi_tests.support import u
def setup_module(mod):
@@ -36,6 +37,13 @@
'globalconst42', 'globalconsthello']
)
outputfilename = ffiplatform.compile(str(tmpdir), ext)
+ if sys.platform == "win32":
+ # test with a non-ascii char
+ outputfn1 = outputfilename
+ ofn, oext = os.path.splitext(outputfn1)
+ outputfilename = ofn + (u+'\u03be') + oext
+ #print(repr(outputfn1) + ' ==> ' + repr(outputfilename))
+ os.rename(outputfn1, outputfilename)
mod.extmod = outputfilename
mod.tmpdir = tmpdir
#
@@ -56,6 +64,9 @@
typedef struct bar_s { int x; signed char a[]; } bar_t;
enum foo_e { AA, BB, CC };
int strlen(const char *);
+ struct with_union { union { int a; char b; }; };
+ union with_struct { struct { int a; char b; }; };
+ struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
""")
ffi.set_source('re_python_pysrc', None)
ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
@@ -105,12 +116,14 @@
from re_python_pysrc import ffi
lib = ffi.dlopen(extmod)
ffi.dlclose(lib)
- e = py.test.raises(ffi.error, ffi.dlclose, lib)
- assert str(e.value).startswith(
- "library '%s' is already closed" % (extmod,))
+ if type(extmod) is not str: # unicode, on python 2
+ str_extmod = extmod.encode('utf-8')
+ else:
+ str_extmod = extmod
e = py.test.raises(ffi.error, getattr, lib, 'add42')
assert str(e.value) == (
- "library '%s' has been closed" % (extmod,))
+ "library '%s' has been closed" % (str_extmod,))
+ ffi.dlclose(lib) # does not raise
def test_constant_via_lib():
from re_python_pysrc import ffi
@@ -213,3 +226,23 @@
ffi.set_source('test_partial_enum', None)
py.test.raises(VerificationMissing, ffi.emit_python_code,
str(tmpdir.join('test_partial_enum.py')))
+
+def test_anonymous_union_inside_struct():
+ # based on issue #357
+ from re_python_pysrc import ffi
+ INT = ffi.sizeof("int")
+ assert ffi.offsetof("struct with_union", "a") == 0
+ assert ffi.offsetof("struct with_union", "b") == 0
+ assert ffi.sizeof("struct with_union") == INT
+ #
+ assert ffi.offsetof("union with_struct", "a") == 0
+ assert ffi.offsetof("union with_struct", "b") == INT
+ assert ffi.sizeof("union with_struct") >= INT + 1
+ #
+ FLOAT = ffi.sizeof("float")
+ assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
+ assert ffi.offsetof("struct NVGcolor", "rgba") == 0
+ assert ffi.offsetof("struct NVGcolor", "r") == 0
+ assert ffi.offsetof("struct NVGcolor", "g") == FLOAT
+ assert ffi.offsetof("struct NVGcolor", "b") == FLOAT * 2
+ assert ffi.offsetof("struct NVGcolor", "a") == FLOAT * 3
diff --git a/pypy/module/test_lib_pypy/test_dbm_extra.py b/pypy/module/test_lib_pypy/test_dbm_extra.py
--- a/pypy/module/test_lib_pypy/test_dbm_extra.py
+++ b/pypy/module/test_lib_pypy/test_dbm_extra.py
@@ -1,4 +1,4 @@
-import py
+import py, os
from rpython.tool.udir import udir
try:
from lib_pypy import dbm
@@ -73,3 +73,8 @@
assert 'key_with_empty_value' in d
assert d['key_with_empty_value'] == ''
d.close()
+
+def test_unicode_filename():
+ path = str(udir) + os.sep + u'test_dbm_extra.test_unicode_filename'
+ d = dbm.open(path, 'c')
+ d.close()
diff --git a/pypy/module/unicodedata/test/test_hyp.py b/pypy/module/unicodedata/test/test_hyp.py
--- a/pypy/module/unicodedata/test/test_hyp.py
+++ b/pypy/module/unicodedata/test/test_hyp.py
@@ -1,6 +1,7 @@
+import sys
import pytest
try:
- from hypothesis import given, strategies as st, example, settings
+ from hypothesis import given, strategies as st, example, settings, assume
except ImportError:
pytest.skip("hypothesis required")
@@ -40,9 +41,14 @@
@pytest.mark.parametrize('NF1, NF2, NF3', compositions)
@example(s=u'---\uafb8\u11a7---') # issue 2289
- at example(s=u'\ufacf')
@settings(max_examples=1000)
@given(s=st.text())
def test_composition(s, space, NF1, NF2, NF3):
+ # 'chr(0xfacf) normalizes to chr(0x2284a), which is too big')
+ assume(not (s == u'\ufacf' and sys.maxunicode == 65535))
norm1, norm2, norm3 = [make_normalization(space, form) for form in [NF1, NF2, NF3]]
assert norm2(norm1(s)) == norm3(s)
+
+if sys.maxunicode != 65535:
+ # conditionally generate the example via an unwrapped decorator
+ test_composition = example(s=u'\ufacf')(test_composition)
diff --git a/rpython/annotator/signature.py b/rpython/annotator/signature.py
--- a/rpython/annotator/signature.py
+++ b/rpython/annotator/signature.py
@@ -14,16 +14,16 @@
def _annotation_key(t):
from rpython.rtyper import extregistry
- if type(t) is list:
+ if isinstance(t, list):
assert len(t) == 1
return ('list', _annotation_key(t[0]))
- elif type(t) is dict:
+ elif isinstance(t, dict):
assert len(t.keys()) == 1
return ('dict', _annotation_key(t.items()[0]))
elif isinstance(t, tuple):
return tuple([_annotation_key(i) for i in t])
elif extregistry.is_registered(t):
- # XXX should it really be always different?
+ # XXX do we want to do something in this case?
return t
return t
@@ -38,24 +38,36 @@
return t
return _compute_annotation(t, bookkeeper)
+
+def _validate_annotation_size(t):
+ try:
+ _ = iter(t)
+ except TypeError: # if it's not an iterable, just return
+ return t # (size does not matter)
+ if isinstance(t, tuple): # we accept tuples with any length, because
+ return t # their in-memory representation is predictable
+ if len(t) > 1:
+ raise TypeError("Cannot specify multiple types in a %s (try using tuple)", type(t))
+
+
def _compute_annotation(t, bookkeeper=None):
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.llannotation import lltype_to_annotation
+ _validate_annotation_size(t)
if isinstance(t, SomeObject):
return t
elif isinstance(t, lltype.LowLevelType):
return lltype_to_annotation(t)
elif isinstance(t, list):
- assert len(t) == 1, "We do not support type joining in list"
- listdef = ListDef(bookkeeper, annotation(t[0]), mutated=True, resized=True)
- return SomeList(listdef)
+ return SomeList(
+ ListDef(bookkeeper, annotation(t[0]),
+ mutated=True, resized=True))
elif isinstance(t, tuple):
return SomeTuple(tuple([annotation(i) for i in t]))
elif isinstance(t, dict):
- assert len(t) == 1, "We do not support type joining in dict"
- result = SomeDict(DictDef(bookkeeper, annotation(t.keys()[0]),
- annotation(t.values()[0])))
- return result
+ return SomeDict(
+ DictDef(bookkeeper,
+ annotation(t.keys()[0]), annotation(t.values()[0])))
elif type(t) is types.NoneType:
return s_None
elif extregistry.is_registered(t):
@@ -84,13 +96,12 @@
elif t is types.NoneType:
return s_None
elif bookkeeper and extregistry.is_registered_type(t):
- entry = extregistry.lookup_type(t)
- return entry.compute_annotation_bk(bookkeeper)
+ return (extregistry.lookup_type(t)
+ .compute_annotation_bk(bookkeeper))
elif t is type:
return SomeType()
elif bookkeeper and not hasattr(t, '_freeze_'):
- classdef = bookkeeper.getuniqueclassdef(t)
- return SomeInstance(classdef)
+ return SomeInstance(bookkeeper.getuniqueclassdef(t))
else:
raise AssertionError("annotationoftype(%r)" % (t,))
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
@@ -354,7 +354,7 @@
else:
# this is dead code, but in case we have a gc that does
# not have a write barrier and does not zero memory, we would
- # need to clal it
+ # need to call it
if op.getopnum() == rop.SETFIELD_GC:
self.consider_setfield_gc(op)
elif op.getopnum() == rop.SETARRAYITEM_GC:
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -30,7 +30,7 @@
class CompileData(object):
memo = None
log_noopt = True
-
+
def forget_optimization_info(self):
for arg in self.trace.inputargs:
arg.set_forwarded(None)
@@ -67,19 +67,26 @@
""" This represents label() ops jump with no extra info associated with
the label
"""
- def __init__(self, trace, call_pure_results=None,
+ def __init__(self, trace, resumestorage=None, call_pure_results=None,
enable_opts=None):
self.trace = trace
+ self.resumestorage = resumestorage
self.call_pure_results = call_pure_results
self.enable_opts = enable_opts
def optimize(self, metainterp_sd, jitdriver_sd, optimizations, unroll):
from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer
+ from rpython.jit.metainterp.optimizeopt.bridgeopt import deserialize_optimizer_knowledge
#assert not unroll
opt = Optimizer(metainterp_sd, jitdriver_sd, optimizations)
- return opt.propagate_all_forward(self.trace.get_iter(),
- self.call_pure_results)
+ traceiter = self.trace.get_iter()
+ if self.resumestorage:
+ frontend_inputargs = self.trace.inputargs
+ deserialize_optimizer_knowledge(opt, self.resumestorage,
+ frontend_inputargs,
+ traceiter.inputargs)
+ return opt.propagate_all_forward(traceiter, self.call_pure_results)
class BridgeCompileData(CompileData):
""" This represents ops() with a jump at the end that goes to some
@@ -518,7 +525,7 @@
for item in lst:
item.set_forwarded(None)
# XXX we should really do it, but we need to remember the values
- # somehoe for ContinueRunningNormally
+ # somehow for ContinueRunningNormally
if reset_values:
item.reset_value()
@@ -671,38 +678,16 @@
raise jitexc.ExitFrameWithExceptionRef(cpu, value)
-class TerminatingLoopToken(JitCellToken): # FIXME: kill?
- terminating = True
-
- def __init__(self, nargs, finishdescr):
- self.finishdescr = finishdescr
-
-def make_done_loop_tokens():
- done_with_this_frame_descr_void = DoneWithThisFrameDescrVoid()
- done_with_this_frame_descr_int = DoneWithThisFrameDescrInt()
- done_with_this_frame_descr_ref = DoneWithThisFrameDescrRef()
- done_with_this_frame_descr_float = DoneWithThisFrameDescrFloat()
- exit_frame_with_exception_descr_ref = ExitFrameWithExceptionDescrRef()
-
- # pseudo loop tokens to make the life of optimize.py easier
- d = {'loop_tokens_done_with_this_frame_int': [
- TerminatingLoopToken(1, done_with_this_frame_descr_int)
- ],
- 'loop_tokens_done_with_this_frame_ref': [
- TerminatingLoopToken(1, done_with_this_frame_descr_ref)
- ],
- 'loop_tokens_done_with_this_frame_float': [
- TerminatingLoopToken(1, done_with_this_frame_descr_float)
- ],
- 'loop_tokens_done_with_this_frame_void': [
- TerminatingLoopToken(0, done_with_this_frame_descr_void)
- ],
- 'loop_tokens_exit_frame_with_exception_ref': [
- TerminatingLoopToken(1, exit_frame_with_exception_descr_ref)
- ],
- }
- d.update(locals())
- return d
+def make_and_attach_done_descrs(targets):
+ for name, cls in [
+ ("done_with_this_frame_descr_void", DoneWithThisFrameDescrVoid),
+ ("done_with_this_frame_descr_int", DoneWithThisFrameDescrInt),
+ ("done_with_this_frame_descr_ref", DoneWithThisFrameDescrRef),
+ ("done_with_this_frame_descr_float", DoneWithThisFrameDescrFloat),
+ ("exit_frame_with_exception_descr_ref", ExitFrameWithExceptionDescrRef)]:
+ descr = cls()
+ for target in targets:
+ setattr(target, name, descr)
class ResumeDescr(AbstractFailDescr):
_attrs_ = ()
@@ -726,6 +711,9 @@
TY_REF = 0x04
TY_FLOAT = 0x06
+ def get_resumestorage(self):
+ raise NotImplementedError("abstract base class")
+
def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd):
if (self.must_compile(deadframe, metainterp_sd, jitdriver_sd)
and not rstack.stack_almost_full()):
@@ -854,15 +842,23 @@
class ResumeGuardCopiedDescr(AbstractResumeGuardDescr):
_attrs_ = ('status', 'prev')
+ def __init__(self, prev):
+ AbstractResumeGuardDescr.__init__(self)
+ assert isinstance(prev, ResumeGuardDescr)
+ self.prev = prev
+
def copy_all_attributes_from(self, other):
assert isinstance(other, ResumeGuardCopiedDescr)
self.prev = other.prev
def clone(self):
- cloned = ResumeGuardCopiedDescr()
- cloned.copy_all_attributes_from(self)
+ cloned = ResumeGuardCopiedDescr(self.prev)
return cloned
+ def get_resumestorage(self):
+ prev = self.prev
+ assert isinstance(prev, ResumeGuardDescr)
+ return prev
class ResumeGuardDescr(AbstractResumeGuardDescr):
_attrs_ = ('rd_numb', 'rd_consts', 'rd_virtuals',
@@ -873,8 +869,7 @@
rd_pendingfields = lltype.nullptr(PENDINGFIELDSP.TO)
def copy_all_attributes_from(self, other):
- if isinstance(other, ResumeGuardCopiedDescr):
- other = other.prev
+ other = other.get_resumestorage()
assert isinstance(other, ResumeGuardDescr)
self.rd_consts = other.rd_consts
self.rd_pendingfields = other.rd_pendingfields
@@ -895,6 +890,9 @@
cloned.copy_all_attributes_from(self)
return cloned
+ def get_resumestorage(self):
+ return self
+
class ResumeGuardExcDescr(ResumeGuardDescr):
pass
@@ -936,22 +934,22 @@
ptr = cpu.ts.cast_to_baseclass(gcref)
return cast_base_ptr_to_instance(AllVirtuals, ptr)
-def invent_fail_descr_for_op(opnum, optimizer, copied_guard=False):
+def invent_fail_descr_for_op(opnum, optimizer, copied_from_descr=None):
if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2:
- assert not copied_guard
+ assert copied_from_descr is None
resumedescr = ResumeGuardForcedDescr()
resumedescr._init(optimizer.metainterp_sd, optimizer.jitdriver_sd)
elif opnum in (rop.GUARD_IS_OBJECT, rop.GUARD_SUBCLASS, rop.GUARD_GC_TYPE):
# note - this only happens in tests
resumedescr = ResumeAtPositionDescr()
elif opnum in (rop.GUARD_EXCEPTION, rop.GUARD_NO_EXCEPTION):
- if copied_guard:
- resumedescr = ResumeGuardCopiedExcDescr()
+ if copied_from_descr is not None:
+ resumedescr = ResumeGuardCopiedExcDescr(copied_from_descr)
else:
resumedescr = ResumeGuardExcDescr()
else:
- if copied_guard:
- resumedescr = ResumeGuardCopiedDescr()
+ if copied_from_descr is not None:
+ resumedescr = ResumeGuardCopiedDescr(copied_from_descr)
else:
resumedescr = ResumeGuardDescr()
return resumedescr
@@ -1036,6 +1034,9 @@
self.original_greenkey, jitcell_token)
metainterp_sd.stats.add_jitcell_token(jitcell_token)
+ def get_resumestorage(self):
+ return None
+
def compile_trace(metainterp, resumekey, runtime_boxes):
"""Try to compile a new bridge leading from the beginning of the history
@@ -1067,22 +1068,15 @@
enable_opts = jitdriver_sd.warmstate.enable_opts
call_pure_results = metainterp.call_pure_results
+ resumestorage = resumekey.get_resumestorage()
if metainterp.history.ends_with_jump:
- if isinstance(resumekey, ResumeGuardCopiedDescr):
- key = resumekey.prev
- assert isinstance(key, ResumeGuardDescr)
- elif isinstance(resumekey, ResumeFromInterpDescr):
- key = None
- else:
- key = resumekey
- assert isinstance(key, ResumeGuardDescr)
- data = BridgeCompileData(trace, runtime_boxes, key,
+ data = BridgeCompileData(trace, runtime_boxes, resumestorage,
call_pure_results=call_pure_results,
enable_opts=enable_opts,
inline_short_preamble=inline_short_preamble)
else:
- data = SimpleCompileData(trace,
+ data = SimpleCompileData(trace, resumestorage,
call_pure_results=call_pure_results,
enable_opts=enable_opts)
try:
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -404,7 +404,6 @@
target_tokens = None
failed_states = None
retraced_count = 0
- terminating = False # see TerminatingLoopToken in compile.py
invalidated = False
outermost_jitdriver_sd = None
# and more data specified by the backend when the loop is compiled
@@ -935,7 +934,7 @@
return insns
def check_simple_loop(self, expected=None, **check):
- """ Usefull in the simplest case when we have only one trace ending with
+ """ Useful in the simplest case when we have only one trace ending with
a jump back to itself and possibly a few bridges.
Only the operations within the loop formed by that single jump will
be counted.
diff --git a/rpython/jit/metainterp/optimizeopt/bridgeopt.py b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
--- a/rpython/jit/metainterp/optimizeopt/bridgeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
@@ -17,11 +17,17 @@
# <length>
# (<box1> <descr> <box2>) length times, if getfield(box1, descr) == box2
# both boxes should be in the liveboxes
+# (or constants)
#
# <length>
# (<box1> <index> <descr> <box2>) length times, if getarrayitem_gc(box1, index, descr) == box2
# both boxes should be in the liveboxes
+# (or constants)
#
+# ---- call_loopinvariant knowledge
+# <length>
+# (<const> <box2>) length times, if call_loopinvariant(const) == box2
+# box2 should be in liveboxes
# ----
@@ -55,11 +61,11 @@
return box
def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, liveboxes_from_env, memo):
+ from rpython.jit.metainterp.history import ConstInt
available_boxes = {}
for box in liveboxes:
if box is not None and box in liveboxes_from_env:
available_boxes[box] = None
- metainterp_sd = optimizer.metainterp_sd
# class knowledge is stored as bits, true meaning the class is known, false
# means unknown. on deserializing we look at the bits, and read the runtime
@@ -106,7 +112,19 @@
numb_state.append_int(0)
numb_state.append_int(0)
+ if optimizer.optrewrite:
+ tuples_loopinvariant = optimizer.optrewrite.serialize_optrewrite(
+ available_boxes)
+ numb_state.append_int(len(tuples_loopinvariant))
+ for constarg0, box in tuples_loopinvariant:
+ numb_state.append_short(
+ tag_box(ConstInt(constarg0), liveboxes_from_env, memo))
+ numb_state.append_short(tag_box(box, liveboxes_from_env, memo))
+ else:
+ numb_state.append_int(0)
+
def deserialize_optimizer_knowledge(optimizer, resumestorage, frontend_boxes, liveboxes):
+ from rpython.jit.metainterp.history import ConstInt
reader = resumecode.Reader(resumestorage.rd_numb)
assert len(frontend_boxes) == len(liveboxes)
metainterp_sd = optimizer.metainterp_sd
@@ -131,8 +149,6 @@
optimizer.make_constant_class(box, cls)
# heap knowledge
- if not optimizer.optheap:
- return
length = reader.next_item()
result_struct = []
for i in range(length):
@@ -154,4 +170,19 @@
tagged = reader.next_item()
box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
result_array.append((box1, index, descr, box2))
- optimizer.optheap.deserialize_optheap(result_struct, result_array)
+ if optimizer.optheap:
+ optimizer.optheap.deserialize_optheap(result_struct, result_array)
+
+ # call_loopinvariant knowledge
+ length = reader.next_item()
+ result_loopinvariant = []
+ for i in range(length):
+ tagged1 = reader.next_item()
+ const = decode_box(resumestorage, tagged1, liveboxes, metainterp_sd.cpu)
+ assert isinstance(const, ConstInt)
+ i = const.getint()
+ tagged2 = reader.next_item()
+ box = decode_box(resumestorage, tagged2, liveboxes, metainterp_sd.cpu)
+ result_loopinvariant.append((i, box))
+ if optimizer.optrewrite:
+ optimizer.optrewrite.deserialize_optrewrite(result_loopinvariant)
diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py
--- a/rpython/jit/metainterp/optimizeopt/optimizer.py
+++ b/rpython/jit/metainterp/optimizeopt/optimizer.py
@@ -688,12 +688,10 @@
def _copy_resume_data_from(self, guard_op, last_guard_op):
- descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self, True)
last_descr = last_guard_op.getdescr()
+ descr = compile.invent_fail_descr_for_op(guard_op.getopnum(), self, last_descr)
assert isinstance(last_descr, compile.ResumeGuardDescr)
- if isinstance(descr, compile.ResumeGuardCopiedDescr):
- descr.prev = last_descr
- else:
+ if not isinstance(descr, compile.ResumeGuardCopiedDescr):
descr.copy_all_attributes_from(last_descr)
guard_op.setdescr(descr)
guard_op.setfailargs(last_guard_op.getfailargs())
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -877,6 +877,18 @@
optimize_SAME_AS_R = optimize_SAME_AS_I
optimize_SAME_AS_F = optimize_SAME_AS_I
+ def serialize_optrewrite(self, available_boxes):
+ res = []
+ for i, box in self.loop_invariant_results.iteritems():
+ box = self.get_box_replacement(box)
+ if box in available_boxes:
+ res.append((i, box))
+ return res
+
+ def deserialize_optrewrite(self, tups):
+ for i, box in tups:
+ self.loop_invariant_results[i] = box
+
dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
default=OptRewrite.emit)
optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -31,8 +31,8 @@
expected = convert_old_style_to_targets(exp, jump=True)
call_pure_results = self._convert_call_pure_results(call_pure_results)
trace = convert_loop_to_trace(loop, FakeMetaInterpStaticData(self.cpu))
- compile_data = compile.SimpleCompileData(trace,
- call_pure_results)
+ compile_data = compile.SimpleCompileData(
+ trace, call_pure_results=call_pure_results)
info, ops = self._do_optimize_loop(compile_data)
label_op = ResOperation(rop.LABEL, info.inputargs)
loop.inputargs = info.inputargs
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1854,12 +1854,7 @@
self._addr2name_keys = []
self._addr2name_values = []
- self.__dict__.update(compile.make_done_loop_tokens())
- for val in ['int', 'float', 'ref', 'void']:
- fullname = 'done_with_this_frame_descr_' + val
- setattr(self.cpu, fullname, getattr(self, fullname))
- d = self.exit_frame_with_exception_descr_ref
- self.cpu.exit_frame_with_exception_descr_ref = d
+ compile.make_and_attach_done_descrs([self, cpu])
def _freeze_(self):
return True
@@ -1909,8 +1904,8 @@
history.REF: 'ref',
history.FLOAT: 'float',
history.VOID: 'void'}[jd.result_type]
- tokens = getattr(self, 'loop_tokens_done_with_this_frame_%s' % name)
- jd.portal_finishtoken = tokens[0].finishdescr
+ token = getattr(self, 'done_with_this_frame_descr_%s' % name)
+ jd.portal_finishtoken = token
jd.propagate_exc_descr = exc_descr
#
self.cpu.propagate_exception_descr = exc_descr
@@ -2463,10 +2458,7 @@
def handle_guard_failure(self, resumedescr, deadframe):
debug_start('jit-tracing')
self.staticdata.profiler.start_tracing()
- if isinstance(resumedescr, compile.ResumeGuardCopiedDescr):
- key = resumedescr.prev
- else:
- key = resumedescr
+ key = resumedescr.get_resumestorage()
assert isinstance(key, compile.ResumeGuardDescr)
# store the resumekey.wref_original_loop_token() on 'self' to make
# sure that it stays alive as long as this MetaInterp
@@ -2770,21 +2762,19 @@
if result_type == history.VOID:
assert exitbox is None
exits = []
- loop_tokens = sd.loop_tokens_done_with_this_frame_void
+ token = sd.done_with_this_frame_descr_void
elif result_type == history.INT:
exits = [exitbox]
- loop_tokens = sd.loop_tokens_done_with_this_frame_int
+ token = sd.done_with_this_frame_descr_int
elif result_type == history.REF:
exits = [exitbox]
- loop_tokens = sd.loop_tokens_done_with_this_frame_ref
+ token = sd.done_with_this_frame_descr_ref
elif result_type == history.FLOAT:
exits = [exitbox]
- loop_tokens = sd.loop_tokens_done_with_this_frame_float
+ token = sd.done_with_this_frame_descr_float
else:
assert False
- # FIXME: kill TerminatingLoopToken?
# FIXME: can we call compile_trace?
- token = loop_tokens[0].finishdescr
self.history.record(rop.FINISH, exits, None, descr=token)
self.history.trace.done()
target_token = compile.compile_trace(self, self.resumekey, exits)
@@ -2810,7 +2800,7 @@
def compile_exit_frame_with_exception(self, valuebox):
self.store_token_in_vable()
sd = self.staticdata
- token = sd.loop_tokens_exit_frame_with_exception_ref[0].finishdescr
+ token = sd.exit_frame_with_exception_descr_ref
self.history.record(rop.FINISH, [valuebox], None, descr=token)
self.history.trace.done()
target_token = compile.compile_trace(self, self.resumekey, [valuebox])
diff --git a/rpython/jit/metainterp/test/test_bridgeopt.py b/rpython/jit/metainterp/test/test_bridgeopt.py
--- a/rpython/jit/metainterp/test/test_bridgeopt.py
+++ b/rpython/jit/metainterp/test/test_bridgeopt.py
@@ -1,6 +1,9 @@
# tests that check that information is fed from the optimizer into the bridges
+import pytest
+
import math
+
from rpython.rlib import jit
from rpython.jit.metainterp.test.support import LLJitMixin
from rpython.jit.metainterp.optimizeopt.bridgeopt import serialize_optimizer_knowledge
@@ -27,6 +30,7 @@
class FakeOptimizer(object):
metainterp_sd = None
optheap = None
+ optrewrite = None
def __init__(self, dct={}, cpu=None):
self.dct = dct
@@ -61,7 +65,8 @@
serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
- assert unpack_numbering(numb_state.create_numbering()) == [1, 0b010000, 0, 0]
+ assert unpack_numbering(numb_state.create_numbering()) == [
+ 1, 0b010000, 0, 0, 0]
rbox1 = InputArgRef()
rbox2 = InputArgRef()
@@ -100,7 +105,7 @@
serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
- assert len(numb_state.create_numbering().code) == 3 + math.ceil(len(refboxes) / 6.0)
+ assert len(numb_state.create_numbering().code) == 4 + math.ceil(len(refboxes) / 6.0)
More information about the pypy-commit
mailing list