[pypy-commit] pypy py3.5-ssl: merge py3.5
plan_rich
pypy.commits at gmail.com
Thu Dec 1 06:51:53 EST 2016
Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-ssl
Changeset: r88788:c75ec5f968ae
Date: 2016-12-01 12:51 +0100
http://bitbucket.org/pypy/pypy/changeset/c75ec5f968ae/
Log: merge py3.5
diff --git a/lib-python/3/distutils/sysconfig_pypy.py b/lib-python/3/distutils/sysconfig_pypy.py
--- a/lib-python/3/distutils/sysconfig_pypy.py
+++ b/lib-python/3/distutils/sysconfig_pypy.py
@@ -60,6 +60,8 @@
def _init_posix():
"""Initialize the module as appropriate for POSIX systems."""
+ so_list = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION]
+ so_ext = (so_list or ['.so'])[0]
g = {}
g['CC'] = "gcc -pthread"
g['CXX'] = "g++ -pthread"
@@ -67,7 +69,7 @@
g['CFLAGS'] = "-DNDEBUG -O2"
g['CCSHARED'] = "-fPIC"
g['LDSHARED'] = "gcc -pthread -shared"
- g['SO'] = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
+ g['SO'] = so_ext
g['SHLIB_SUFFIX'] = g['SO']
g['AR'] = "ar"
g['ARFLAGS'] = "rc"
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -192,6 +192,14 @@
assert self._finalize_.im_func is not W_Root._finalize_.im_func
space.finalizer_queue.register_finalizer(self)
+ def may_unregister_rpython_finalizer(self, space):
+ """Optimization hint only: if there is no user-defined __del__()
+ method, pass the hint ``don't call any finalizer'' to rgc.
+ """
+ if not self.getclass(space).hasuserdel:
+ from rpython.rlib import rgc
+ rgc.may_ignore_finalizer(self)
+
# hooks that the mapdict implementations needs:
def _get_mapdict_map(self):
return None
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -3,7 +3,7 @@
from pypy.interpreter.pyopcode import LoopBlock, SApplicationException, Yield
from pypy.interpreter.pycode import CO_YIELD_INSIDE_TRY
from pypy.interpreter.astcompiler import consts
-from rpython.rlib import jit
+from rpython.rlib import jit, rgc
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rarithmetic import r_uint
@@ -20,7 +20,7 @@
self.running = False
self._name = name # may be null, use get_name()
self._qualname = qualname # may be null, use get_qualname()
- if (isinstance(self, Coroutine) # XXX would be cool not to need this
+ if (isinstance(self, Coroutine)
or self.pycode.co_flags & CO_YIELD_INSIDE_TRY):
self.register_finalizer(self.space)
self.saved_operr = None
@@ -89,7 +89,7 @@
# if the frame is now marked as finished, it was RETURNed from
if frame.frame_finished_execution:
- self.frame = None
+ self.frame_is_finished()
if space.is_w(w_result, space.w_None):
raise OperationError(space.w_StopIteration, space.w_None)
else:
@@ -107,6 +107,14 @@
if self.saved_operr is not None:
ec.set_sys_exc_info(self.saved_operr)
self.saved_operr = None
+ #
+ # Optimization only: after we've started a Coroutine without
+ # CO_YIELD_INSIDE_TRY, then Coroutine._finalize_() will be a no-op
+ if (isinstance(self, Coroutine)
+ and frame.last_instr == -1
+ and not (self.pycode.co_flags & CO_YIELD_INSIDE_TRY)):
+ rgc.may_ignore_finalizer(self)
+ #
self.running = True
try:
w_result = frame.execute_frame(self, w_arg_or_err)
@@ -116,7 +124,7 @@
if e.match(space, space.w_StopIteration):
self._leak_stopiteration(e)
finally:
- self.frame = None
+ self.frame_is_finished()
raise
finally:
frame.f_backref = jit.vref_None
@@ -323,6 +331,10 @@
break
block = block.previous
+ def frame_is_finished(self):
+ self.frame = None
+ rgc.may_ignore_finalizer(self)
+
class GeneratorIterator(GeneratorOrCoroutine):
"An iterator created by a generator."
@@ -364,7 +376,7 @@
break
# if the frame is now marked as finished, it was RETURNed from
if frame.frame_finished_execution:
- self.frame = None
+ self.frame_is_finished()
break
results.append(w_result) # YIELDed
return unpack_into
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -121,31 +121,8 @@
return space.newtuple(tup_return)
def descr_module__repr__(self, space):
- w_loader = space.finditem(self.w_dict, space.wrap('__loader__'))
- if w_loader is not None:
- try:
- return space.call_method(w_loader, "module_repr", self)
- except OperationError:
- pass
- try:
- w_name = space.getattr(self, space.wrap('__name__'))
- name = space.unicode_w(space.repr(w_name))
- except OperationError:
- name = u"'?'"
-
- try:
- w___file__ = space.getattr(self, space.wrap('__file__'))
- except OperationError:
- w___file__ = space.w_None
- if not space.isinstance_w(w___file__, space.w_unicode):
- if w_loader is not None:
- w_loader_repr = space.unicode_w(space.repr(w_loader))
- return space.wrap(u"<module %s (%s)>" % (name, w_loader_repr))
- else:
- return space.wrap(u"<module %s>" % (name,))
- else:
- __file__ = space.unicode_w(space.repr(w___file__))
- return space.wrap(u"<module %s from %s>" % (name, __file__))
+ w_importlib = space.getbuiltinmodule('_frozen_importlib')
+ return space.call_method(w_importlib, "_module_repr", self)
def descr_getattribute(self, space, w_attr):
from pypy.objspace.descroperation import object_getattribute
diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -129,6 +129,20 @@
expected_repr = "<module 'test_module' ({})>".format(loader_repr)
assert mod_repr == expected_repr
+ def test_repr_with_loader_with_raising_module_repr2(self):
+ import sys
+ test_module = type(sys)("test_module", "doc")
+ # If an exception occurs in module_repr(), the exception is caught
+ # and discarded, and the calculation of the module’s repr continues
+ # as if module_repr() did not exist.
+ class CustomLoaderWithRaisingRepr:
+ @classmethod
+ def module_repr(cls, module):
+ raise KeyboardInterrupt
+
+ test_module.__loader__ = CustomLoaderWithRaisingRepr
+ raises(KeyboardInterrupt, 'repr(test_module)')
+
def test_repr_with_raising_loader_and___file__(self):
import sys
test_module = type(sys)("test_module", "doc")
diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -1,3 +1,4 @@
+from rpython.rlib import jit
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
@@ -67,29 +68,43 @@
# fallback to object.__getattribute__()
return space.call_function(object_getattribute(space), self, w_name)
-def _super_from_frame(space, frame):
- """super() without args -- fill in from __class__ and first local
- variable on the stack.
- """
- code = frame.pycode
- if not code:
- raise oefmt(space.w_RuntimeError, "super(): no code object")
+ at jit.elidable
+def _get_self_location(space, code):
if code.co_argcount == 0:
raise oefmt(space.w_RuntimeError, "super(): no arguments")
- w_obj = frame.locals_cells_stack_w[0]
- if not w_obj:
- raise oefmt(space.w_RuntimeError, "super(): arg[0] deleted")
+ args_to_copy = code._args_as_cellvars
+ for i in range(len(args_to_copy)):
+ if args_to_copy[i] == 0:
+ self_cell = i
+ break
+ else:
+ self_cell = -1
for index, name in enumerate(code.co_freevars):
if name == '__class__':
break
else:
raise oefmt(space.w_RuntimeError, "super(): __class__ cell not found")
+ class_cell = len(code.co_cellvars) + index
+ return self_cell, class_cell
+
+def _super_from_frame(space, frame):
+ """super() without args -- fill in from __class__ and first local
+ variable on the stack.
+ """
+ if frame is None:
+ raise oefmt(space.w_RuntimeError, "super(): no frame object")
+ self_cell, class_cell = _get_self_location(space, frame.getcode())
+ if self_cell < 0:
+ w_obj = frame.locals_cells_stack_w[0]
+ else:
+ w_obj = frame._getcell(self_cell).w_value
+ if not w_obj:
+ raise oefmt(space.w_RuntimeError, "super(): arg[0] deleted")
+
# a kind of LOAD_DEREF
- cell = frame._getcell(len(code.co_cellvars) + index)
- try:
- w_starttype = cell.get()
- except ValueError:
+ w_starttype = frame._getcell(class_cell).w_value
+ if w_starttype is None:
raise oefmt(space.w_RuntimeError, "super(): empty __class__ cell")
return w_starttype, w_obj
diff --git a/pypy/module/__builtin__/test/test_descriptor.py b/pypy/module/__builtin__/test/test_descriptor.py
--- a/pypy/module/__builtin__/test/test_descriptor.py
+++ b/pypy/module/__builtin__/test/test_descriptor.py
@@ -508,4 +508,15 @@
del __class__
super()
raises(RuntimeError, X().f)
+ class X:
+ def f(self):
+ def g():
+ print(self) # make 'self' a closure inside 'f'
+ del self
+ super()
+ raises(RuntimeError, X().f)
+ class X:
+ def f(*args):
+ super()
+ raises(RuntimeError, X().f)
"""
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -397,7 +397,7 @@
space = self.space
if space.is_none(w_destructor):
if isinstance(self, W_CDataGCP):
- self.w_destructor = None
+ self.detach_destructor()
return space.w_None
raise oefmt(space.w_TypeError,
"Can remove destructor only on a object "
@@ -604,6 +604,10 @@
self.w_destructor = None
self.space.call_function(w_destructor, self.w_original_cdata)
+ def detach_destructor(self):
+ self.w_destructor = None
+ self.may_unregister_rpython_finalizer(self.space)
+
W_CData.typedef = TypeDef(
'_cffi_backend.CData',
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
@@ -55,6 +55,7 @@
if not libhandle:
raise oefmt(self.ffi.w_FFIError, "library '%s' is already closed",
self.libname)
+ self.may_unregister_rpython_finalizer(self.ffi.space)
# Clear the dict to force further accesses to do cdlopen_fetch()
# again, and fail because the library was closed. Note that the
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -63,15 +63,47 @@
raise NotImplementedError
def read_w(self, space, w_size=None):
+ """Read and return up to n bytes.
+
+If the argument is omitted, None, or negative, reads and
+returns all data until EOF.
+
+If the argument is positive, and the underlying raw stream is
+not 'interactive', multiple raw reads may be issued to satisfy
+the byte count (unless EOF is reached first). But for
+interactive raw streams (as well as sockets and pipes), at most
+one raw read will be issued, and a short result does not imply
+that EOF is imminent.
+
+Returns an empty bytes object on EOF.
+
+Returns None if the underlying raw stream was open in non-blocking
+mode and no data is available at the moment."""
self._unsupportedoperation(space, "read")
def read1_w(self, space, w_size):
+ """Read and return up to n bytes, with at most one read() call
+to the underlying raw stream. A short result does not imply
+that EOF is imminent.
+
+Returns an empty bytes object on EOF."""
self._unsupportedoperation(space, "read1")
def write_w(self, space, w_data):
+ """Write the given buffer to the IO stream.
+
+Returns the number of bytes written, which is always the length of b
+in bytes.
+
+Raises BlockingIOError if the buffer is full and the
+underlying raw stream cannot accept more data at the moment."""
self._unsupportedoperation(space, "write")
def detach_w(self, space):
+ """Disconnect this buffer from its underlying raw stream and return it.
+
+After the raw stream has been detached, the buffer is in an unusable
+state."""
self._unsupportedoperation(space, "detach")
def readinto_w(self, space, w_buffer):
@@ -92,6 +124,20 @@
W_BufferedIOBase.typedef = TypeDef(
'_io._BufferedIOBase', W_IOBase.typedef,
+ __doc__="""Base class for buffered IO objects.
+
+The main difference with RawIOBase is that the read() method
+supports omitting the size argument, and does not have a default
+implementation that defers to readinto().
+
+In addition, read(), readinto() and write() may raise
+BlockingIOError if the underlying raw stream is in non-blocking
+mode and not ready; unlike their raw counterparts, they will never
+return None.
+
+A typical implementation should not inherit from a RawIOBase
+implementation, but wrap one.
+""",
__new__ = generic_new_descr(W_BufferedIOBase),
read = interp2app(W_BufferedIOBase.read_w),
read1 = interp2app(W_BufferedIOBase.read1_w),
@@ -112,6 +158,9 @@
def getlength(self):
return self.length
+ def getitem(self, index):
+ return self.buf[index]
+
def setitem(self, index, char):
self.buf[self.start + index] = char
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -65,6 +65,23 @@
bufio = _io.BufferedReader(MockIO())
assert bufio.read(9000) == b"abcdefg"
+ def test_valid_buffer(self):
+ import _io
+
+ class MockIO(_io._IOBase):
+ def readable(self):
+ return True
+
+ def readinto(self, buf):
+ # Check that `buf` is a valid memoryview object
+ assert buf.itemsize == 1
+ assert buf.strides == (1,)
+ assert buf.shape == (len(buf),)
+ return len(bytes(buf))
+
+ bufio = _io.BufferedReader(MockIO())
+ assert len(bufio.read(5)) == 5 # Note: PyPy zeros the buffer, CPython does not
+
def test_buffering(self):
import _io
data = b"abcdefghi"
@@ -695,7 +712,7 @@
expected[j] = 2
expected[i] = 1
assert raw.getvalue() == expected
-
+
def test_interleaved_read_write(self):
import _io as io
# Test for issue #12213
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -216,7 +216,7 @@
def descr_repr(self, space):
fd = intmask(self.sock.fd) # Force to signed type even on Windows.
return space.wrap("<socket object, fd=%d, family=%d,"
- " type=%d, protocol=%d>" %
+ " type=%d, proto=%d>" %
(fd, self.sock.family,
self.sock.type, self.sock.proto))
@@ -266,6 +266,7 @@
except SocketError:
# cpython doesn't return any errors on close
pass
+ self.may_unregister_rpython_finalizer(space)
def connect_w(self, space, w_addr):
"""connect(address)
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
@@ -373,12 +373,12 @@
import _socket
s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
try:
- expected = ('<socket object, fd=%s, family=%s, type=%s, protocol=%s>'
+ expected = ('<socket object, fd=%s, family=%s, type=%s, proto=%s>'
% (s.fileno(), s.family, s.type, s.proto))
assert repr(s) == expected
finally:
s.close()
- expected = ('<socket object, fd=-1, family=%s, type=%s, protocol=%s>'
+ expected = ('<socket object, fd=-1, family=%s, type=%s, proto=%s>'
% (s.family, s.type, s.proto))
assert repr(s) == expected
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -218,7 +218,7 @@
return self.space.w_None
return w_obj
- def descr__eq__(self, space, w_ref2):
+ def compare(self, space, w_ref2, invert):
if not isinstance(w_ref2, W_Weakref):
return space.w_NotImplemented
ref1 = self
@@ -226,11 +226,18 @@
w_obj1 = ref1.dereference()
w_obj2 = ref2.dereference()
if w_obj1 is None or w_obj2 is None:
- return space.is_(ref1, ref2)
- return space.eq(w_obj1, w_obj2)
+ w_res = space.is_(ref1, ref2)
+ else:
+ w_res = space.eq(w_obj1, w_obj2)
+ if invert:
+ w_res = space.not_(w_res)
+ return w_res
+
+ def descr__eq__(self, space, w_ref2):
+ return self.compare(space, w_ref2, invert=False)
def descr__ne__(self, space, w_ref2):
- return space.not_(space.eq(self, w_ref2))
+ return self.compare(space, w_ref2, invert=True)
def descr_callback(self, space):
return self.w_callable
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -153,6 +153,14 @@
assert not (ref1 == [])
assert ref1 != []
+ def test_ne(self):
+ import _weakref
+ class X(object):
+ pass
+ ref1 = _weakref.ref(X())
+ assert ref1.__eq__(X()) is NotImplemented
+ assert ref1.__ne__(X()) is NotImplemented
+
def test_getweakrefs(self):
import _weakref, gc
class A(object):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -272,11 +272,11 @@
_write = libc.load_function(BWrite, 'write')
i = 0
fd0, fd1 = os.pipe()
- buffer = _cffi_backend.newp(BCharP, 'A')
+ buffer = _cffi_backend.newp(BCharP, b'A')
while i < 300:
tmp = _write(fd1, buffer, 1) # ID: cfficall
assert tmp == 1
- assert os.read(fd0, 2) == 'A'
+ assert os.read(fd0, 2) == b'A'
i += 1
os.close(fd0)
os.close(fd1)
@@ -410,7 +410,7 @@
i161 = int_lt(i160, i43)
guard_true(i161, descr=...)
i162 = int_add(i160, 1)
- setfield_gc(p22, i162, descr=<FieldS pypy.module.__builtin__.functional.W_XRangeIterator.inst_current .>)
+ setfield_gc(p22, i162, descr=<FieldS pypy.module.__builtin__.functional.W_IntRangeIterator.inst_current .>)
guard_not_invalidated(descr=...)
p163 = force_token()
p164 = force_token()
diff --git a/pypy/module/pypyjit/test_pypy_c/test_globals.py b/pypy/module/pypyjit/test_pypy_c/test_globals.py
--- a/pypy/module/pypyjit/test_pypy_c/test_globals.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_globals.py
@@ -16,5 +16,6 @@
assert log.result == 500
loop, = log.loops_by_filename(self.filepath)
assert loop.match_by_id("loadglobal", """
+ p1 = getfield_gc_r(..., descr=...) # dead
guard_not_invalidated(descr=...)
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -320,3 +320,36 @@
--TICK--
jump(..., descr=...)
""")
+
+ def test_super_no_args(self):
+ def main():
+ class A(object):
+ def m(self, x):
+ return x + 1
+ class B(A):
+ def m(self, x):
+ return super().m(x)
+ i = 0
+ while i < 300:
+ i = B().m(i)
+ return i
+
+ log = self.run(main, [])
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i78 = int_lt(i72, 300)
+ guard_true(i78, descr=...)
+ guard_not_invalidated(descr=...)
+ p1 = force_token()
+ p65 = force_token()
+ p3 = force_token()
+ i81 = int_add(i72, 1)
+
+ # can't use TICK here, because of the extra setfield_gc
+ ticker0 = getfield_raw_i(#, descr=<FieldS pypysig_long_struct.c_value .*>)
+ setfield_gc(p0, p65, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+ ticker_cond0 = int_lt(ticker0, 0)
+ guard_false(ticker_cond0, descr=...)
+
+ jump(..., descr=...)
+ """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -38,7 +38,7 @@
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
...
- p76 = call_assembler_r(_, _, _, _, descr=...)
+ p76 = call_assembler_r(..., descr=...)
...
""")
loop2 = log.loops[0]
@@ -79,6 +79,6 @@
assert len(guards) < 20
assert loop.match("""
...
- p76 = call_assembler_r(_, _, _, _, descr=...)
+ p76 = call_assembler_r(..., descr=...)
...
""")
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -247,6 +247,13 @@
""")
def test_dont_trace_every_iteration(self):
+ def reference(a, b):
+ i = sa = 0
+ while i < 300:
+ sa += a % b
+ i += 1
+ return sa
+ #
def main(a, b):
i = sa = 0
while i < 300:
@@ -258,9 +265,12 @@
i += 1
return sa
#
+ log_ref = self.run(reference, [10, 20])
+ assert log_ref.result == 300 * (10 % 20)
+ #
log = self.run(main, [10, 20])
assert log.result == 300 * (10 % 20)
- assert log.jit_summary.tracing_no == 1
+ assert log.jit_summary.tracing_no == log_ref.jit_summary.tracing_no
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
i11 = int_lt(i7, 300)
@@ -274,7 +284,7 @@
#
log = self.run(main, [-10, -20])
assert log.result == 300 * (-10 % -20)
- assert log.jit_summary.tracing_no == 1
+ assert log.jit_summary.tracing_no == log_ref.jit_summary.tracing_no
def test_overflow_checking(self):
"""
@@ -297,6 +307,7 @@
self.run_and_check(main, [])
def test_global(self):
+ # check that the global read is removed even from the entry bridge
log = self.run("""
i = 0
globalinc = 1
@@ -308,7 +319,10 @@
""", [1000])
loop, = log.loops_by_id("globalread", is_entry_bridge=True)
- assert len(loop.ops_by_id("globalread")) == 0
+ assert loop.match_by_id("globalread", """
+ # only a dead read
+ p26 = getfield_gc_r(ConstPtr(ptr25), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+ """)
def test_eval(self):
def main():
@@ -349,7 +363,8 @@
def test_long_comparison(self):
def main(n):
while n:
- 12345L > 123L # ID: long_op
+ x = 12345678901234567890123456
+ x > 1231231231231231231231231 # ID: long_op
n -= 1
log = self.run(main, [300])
diff --git a/pypy/module/pypyjit/test_pypy_c/test_shift.py b/pypy/module/pypyjit/test_pypy_c/test_shift.py
--- a/pypy/module/pypyjit/test_pypy_c/test_shift.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_shift.py
@@ -196,8 +196,7 @@
"""
from sys import maxint
- def main(a, b, c):
- from sys import maxint
+ def main(a, b, c, maxint):
i = sa = 0
while i < 300:
if 0 < a < 10: pass
@@ -210,9 +209,9 @@
sa += (b<<100)>>100
sa += (c<<100)>>100
i += 1
- return long(sa)
+ return sa
for a in (1, 4, 8, 100):
for b in (-10, 10, -201, 201, -maxint/3, maxint/3):
for c in (-10, 10, -maxint/3, maxint/3):
- yield self.run_and_check, main, [a, b, c]
+ yield self.run_and_check, main, [a, b, c, maxint]
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -5,50 +5,102 @@
class TestString(BaseTestPyPyC):
+
+ def test_python3_missing_bchr(self):
+ # Check that 'bytes([i])' is special-cased into something
+ # efficient, as Python 3.5 doesn't have a bchr() function or
+ # anything more direct.
+ def main(n):
+ i = 0
+ result = b''
+ while i < n:
+ c = bytes([i])
+ result += c
+ i += 1
+ return i
+ log = self.run(main, [255])
+ assert log.result == 255
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ # nothing left like allocating a list object or doing any
+ # residual call
+ i49 = int_lt(i38, i26)
+ guard_true(i49, descr=...)
+ guard_not_invalidated(descr=...)
+ i51 = int_lt(i38, 256)
+ guard_true(i51, descr=...)
+ i53 = int_add(i38, 1)
+ --TICK--
+ i58 = strlen(p46)
+ i60 = int_add(i58, 1)
+ p61 = newstr(i60)
+ copystrcontent(p46, p61, 0, 0, i58)
+ strsetitem(p61, i58, i38)
+ p62 = newstr(1)
+ strsetitem(p62, 0, i38)
+ jump(..., descr=...)
+ """)
+
def test_lookup_default_encoding(self):
def main(n):
- import string
i = 0
- letters = string.letters
- uletters = unicode(string.letters)
+ letters = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ uletters = u'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
while i < n:
- i += letters[i % len(letters)] == uletters[i % len(letters)]
+ c = bytes([letters[i % len(uletters)]])
+ i += (c.decode() == uletters[i % len(uletters)])
return i
log = self.run(main, [300], import_site=True)
assert log.result == 300
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i14 = int_lt(i6, i9)
- guard_true(i14, descr=...)
+ i88 = int_lt(i83, i36)
+ guard_true(i88, descr=...)
+ p90 = getfield_gc_r(ConstPtr(ptr89), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
guard_not_invalidated(descr=...)
- i16 = int_eq(i6, %d)
- i19 = call_i(ConstClass(ll_int_py_mod__Signed_Signed), i6, i10, descr=<Calli . ii EF=0 OS=14>)
- i21 = int_lt(i19, 0)
- guard_false(i21, descr=...)
- i22 = int_ge(i19, i10)
- guard_false(i22, descr=...)
- i23 = strgetitem(p11, i19)
- i24 = int_ge(i19, i12)
- guard_false(i24, descr=...)
- i25 = unicodegetitem(p13, i19)
- p27 = newstr(1)
- strsetitem(p27, 0, i23)
- p30 = call_r(ConstClass(ll_str2unicode__rpy_stringPtr), p27, descr=...)
+ i92 = int_eq(i83, %d)
+ i94 = call_i(ConstClass(ll_int_py_mod__Signed_Signed), i83, i46, descr=<Calli . ii EF=0 OS=14>)
+ i96 = int_lt(i94, 0)
+ guard_false(i96, descr=...)
+ i97 = int_ge(i94, i53)
+ guard_false(i97, descr=...)
+ i98 = strgetitem(p52, i94)
+ p100 = getfield_gc_r(ConstPtr(ptr99), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+ p101 = force_token()
+ p103 = newstr(1)
+ strsetitem(p103, 0, i98)
+ p104 = new(descr=<SizeDescr ..?>)
+ p106 = newunicode(1)
+ setfield_gc(p0, p101, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+ setfield_gc(p104, p106, descr=<FieldP unicodebuilder.current_buf ..?>)
+ setfield_gc(p104, 0, descr=<FieldS unicodebuilder.current_pos ..?>)
+ setfield_gc(p104, 1, descr=<FieldS unicodebuilder.current_end ..?>)
+ setfield_gc(p104, 1, descr=<FieldS unicodebuilder.total_size 32>)
+ i113 = call_may_force_i(ConstClass(str_decode_utf_8_impl), p103, 1, ConstPtr(null), 1, 0, 0, p104, descr=<Calli . ririiir EF=7>)
+ guard_not_forced(descr=...)
guard_no_exception(descr=...)
- i32 = call_i(ConstClass(_ll_2_str_eq_checknull_char__rpy_unicodePtr_UniChar), p30, i25, descr=...)
- guard_true(i32, descr=...)
- i34 = int_add(i6, 1)
+ p116 = call_r(ConstClass(ll_build_trampoline__v1351___simple_call__function_), p104, descr=<Callr . r EF=5>)
+ guard_no_exception(descr=...)
+ guard_nonnull(p116, descr=...)
+ p118 = getfield_gc_r(ConstPtr(ptr117), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
+ guard_not_invalidated(descr=...)
+ i119 = int_ge(i94, i46)
+ guard_false(i119, descr=...)
+ i120 = unicodegetitem(p45, i94)
+ i122 = call_i(ConstClass(_ll_2_str_eq_nonnull_char__rpy_unicodePtr_UniChar), p116, i120, descr=<Calli . ri EF=0 OS=49>)
+ guard_true(i122, descr=...)
+ i124 = int_add(i83, 1)
--TICK--
jump(..., descr=...)
""" % (-sys.maxint-1,))
- def test_long(self):
+ def test_int_base_16(self):
def main(n):
- import string
i = 1
while i < n:
- i += int(long(string.digits[i % len(string.digits)], 16))
+ digits = '0123456789'
+ i += int(digits[i % len(digits)], 16)
return i
log = self.run(main, [1100], import_site=True)
@@ -61,7 +113,9 @@
assert loop.match("""
i11 = int_lt(i6, i7)
guard_true(i11, descr=...)
+ p70 = getfield_gc_r(ConstPtr(ptr69), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
guard_not_invalidated(descr=...)
+ p72 = getfield_gc_r(ConstPtr(ptr71), descr=<FieldP pypy.objspace.std.unicodeobject.W_UnicodeObject.inst__utf8 .>)
i13 = int_eq(i6, %d) # value provided below
# "mod 10" block:
@@ -73,17 +127,20 @@
i87 = int_mul(i85, 10)
i19 = int_sub(i6, i87)
- i23 = strgetitem(p10, i19)
- p25 = newstr(1)
- strsetitem(p25, 0, i23)
- p93 = call_r(ConstClass(fromstr), p25, 16, descr=<Callr . ri EF=4>)
+ i23 = unicodegetitem(ConstPtr(ptr92), i19)
+ p25 = newunicode(1)
+ unicodesetitem(p25, 0, i23)
+ p97 = call_r(ConstClass(_rpy_unicode_to_decimal_w), p25, descr=<Callr . r EF=5>)
guard_no_exception(descr=...)
- i95 = getfield_gc_i(p93, descr=<FieldS rpython.rlib.rbigint.rbigint.inst_size .*>)
- i96 = int_gt(i95, #)
- guard_false(i96, descr=...)
- i94 = call_i(ConstClass(rbigint._toint_helper), p93, descr=<Calli . r EF=4>)
+ i98 = unicodelen(p97)
+ p99 = force_token()
+ setfield_gc(p0, p99, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .>)
+ p104 = call_may_force_r(ConstClass(unicode_encode_utf_8_impl), p97, i98, ConstPtr(ptr101), 1, 1, descr=<Callr . ririi EF=7>)
+ guard_not_forced(descr=...)
guard_no_exception(descr=...)
- i95 = int_add_ovf(i6, i94)
+ i107 = call_i(ConstClass(string_to_int), p104, 16, descr=<Calli . ri EF=4>)
+ guard_no_exception(descr=...)
+ i95 = int_add_ovf(i6, i107)
guard_no_overflow(descr=...)
--TICK--
jump(..., descr=...)
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
@@ -21,7 +21,7 @@
while i < n:
buf = struct.pack("<i", i) # ID: pack
x = struct.unpack("<i", buf)[0] # ID: unpack
- i += x / i
+ i += x // i
return i
log = self.run(main, [1000])
@@ -82,7 +82,7 @@
while i < n:
buf = s.pack(-1, i) # ID: pack
x = s.unpack(buf)[1] # ID: unpack
- i += x / i
+ i += x // i
return i
log = self.run(main, [1000])
diff --git a/pypy/module/select/interp_epoll.py b/pypy/module/select/interp_epoll.py
--- a/pypy/module/select/interp_epoll.py
+++ b/pypy/module/select/interp_epoll.py
@@ -81,6 +81,7 @@
class W_Epoll(W_Root):
def __init__(self, space, epfd):
+ self.space = space
self.epfd = epfd
self.register_finalizer(space)
@@ -113,6 +114,7 @@
if not self.get_closed():
socketclose(self.epfd)
self.epfd = -1
+ self.may_unregister_rpython_finalizer(self.space)
def epoll_ctl(self, space, ctl, w_fd, eventmask, ignore_ebadf=False):
fd = space.c_filedescriptor_w(w_fd)
diff --git a/pypy/module/select/interp_kqueue.py b/pypy/module/select/interp_kqueue.py
--- a/pypy/module/select/interp_kqueue.py
+++ b/pypy/module/select/interp_kqueue.py
@@ -109,6 +109,7 @@
class W_Kqueue(W_Root):
def __init__(self, space, kqfd):
+ self.space = space
self.kqfd = kqfd
self.register_finalizer(space)
@@ -137,6 +138,7 @@
kqfd = self.kqfd
self.kqfd = -1
socketclose_no_errno(kqfd)
+ self.may_unregister_rpython_finalizer(self.space)
def check_closed(self, space):
if self.get_closed():
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -40,23 +40,22 @@
}
def setup_class(cls):
- cls.w_signal = cls.space.getbuiltinmodule('_signal')
cls.w_temppath = cls.space.wrap(
str(py.test.ensuretemp("signal").join("foo.txt")))
cls.w_appdirect = cls.space.wrap(cls.runappdirect)
def test_exported_names(self):
- import os
- self.signal.__dict__ # crashes if the interpleveldefs are invalid
+ import os, _signal
+ _signal.__dict__ # crashes if the interpleveldefs are invalid
if os.name == 'nt':
- assert self.signal.CTRL_BREAK_EVENT == 1
- assert self.signal.CTRL_C_EVENT == 0
+ assert _signal.CTRL_BREAK_EVENT == 1
+ assert _signal.CTRL_C_EVENT == 0
def test_basics(self):
- import types, os
+ import types, os, _signal
if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
skip("requires os.kill() and os.getpid()")
- signal = self.signal # the signal module to test
+ signal = _signal # the signal module to test
if not hasattr(signal, 'SIGUSR1'):
skip("requires SIGUSR1 in signal")
signum = signal.SIGUSR1
diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py
--- a/pypy/module/sys/app.py
+++ b/pypy/module/sys/app.py
@@ -112,23 +112,35 @@
class SimpleNamespace:
+ """A simple attribute-based namespace.
+
+SimpleNamespace(**kwargs)"""
+
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
- def __repr__(self, recurse=set()):
+ def __repr__(self):
ident = id(self)
- if ident in recurse:
+ if ident in sns_recurse:
return "namespace(...)"
- recurse.add(ident)
+ sns_recurse.add(ident)
try:
pairs = ('%s=%r' % item for item in sorted(self.__dict__.items()))
return "namespace(%s)" % ', '.join(pairs)
finally:
- recurse.remove(ident)
+ sns_recurse.discard(ident)
def __eq__(self, other):
- return (isinstance(other, SimpleNamespace) and
- self.__dict__ == other.__dict__)
+ if issubclass(type(other), SimpleNamespace):
+ return self.__dict__ == other.__dict__
+ return NotImplemented
+
+ def __ne__(self, other):
+ if issubclass(type(other), SimpleNamespace):
+ return self.__dict__ != other.__dict__
+ return NotImplemented
+
+sns_recurse = set()
# This class is not exposed in sys, but by the types module.
SimpleNamespace.__module__ = 'types'
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -589,6 +589,35 @@
#
raises(AttributeError, "del ns.spam")
del ns.y
+ #
+ assert ns == SimpleNamespace(z=4, x=1, w=3)
+ assert (ns != SimpleNamespace(z=4, x=1, w=3)) is False
+ assert (ns == SimpleNamespace(z=4, x=2, w=3)) is False
+ assert ns != SimpleNamespace(z=4, x=2, w=3)
+ #
+ class Foo(SimpleNamespace):
+ pass
+ assert ns == Foo(z=4, x=1, w=3)
+ assert (ns != Foo(z=4, x=1, w=3)) is False
+ assert (ns == Foo(z=4, x=2, w=3)) is False
+ assert ns != Foo(z=4, x=2, w=3)
+ #
+ class Other:
+ def __init__(self, x, z, w):
+ self.x = x
+ self.z = z
+ self.w = w
+ assert (ns == Other(z=4, x=1, w=3)) is False
+ assert ns != Other(z=4, x=1, w=3)
+ assert (Foo(z=4, x=1, w=3) == Other(z=4, x=1, w=3)) is False
+ assert Foo(z=4, x=1, w=3) != Other(z=4, x=1, w=3)
+ #
+ class Fake:
+ __class__ = SimpleNamespace
+ assert isinstance(Fake(), SimpleNamespace)
+ assert not issubclass(Fake, SimpleNamespace)
+ assert (Fake() == SimpleNamespace()) is False
+ assert SimpleNamespace() != Fake()
def test_pickle_simplenamespace(self):
import pickle, sys
diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py
--- a/pypy/module/zlib/interp_zlib.py
+++ b/pypy/module/zlib/interp_zlib.py
@@ -183,6 +183,7 @@
if mode == rzlib.Z_FINISH: # release the data structures now
rzlib.deflateEnd(self.stream)
self.stream = rzlib.null_stream
+ self.may_unregister_rpython_finalizer(space)
finally:
self.unlock()
except rzlib.RZlibError as e:
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -705,7 +705,7 @@
return w_result
raise oefmt(space.w_TypeError,
- "%(specialname)s returned non-%(targetname)s (type "
+ "%(specialname)s returned non-string (type "
"'%%T')", w_result)
assert not hasattr(DescrOperation, %(targetname)r)
DescrOperation.%(targetname)s = %(targetname)s
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -66,15 +66,16 @@
class W_MyType(W_MyObject):
name = "foobar"
flag_map_or_seq = '?'
+ hasuserdel = False
def __init__(self):
self.mro_w = [w_some_obj(), w_some_obj()]
self.dict_w = {'__str__': w_some_obj()}
+ self.hasuserdel = True
def get_module(self):
return w_some_obj()
-
def getname(self, space):
return self.name.decode('utf-8')
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -1,6 +1,6 @@
"""The builtin bytes implementation"""
-from rpython.rlib.jit import we_are_jitted
+from rpython.rlib import jit
from rpython.rlib.objectmodel import (
compute_hash, compute_unique_id, import_from_mixin, newlist_hint,
resizelist_hint, HASH_ALGORITHM)
@@ -529,10 +529,22 @@
@unwrap_spec(encoding='str_or_None', errors='str_or_None')
def descr_new(space, w_stringtype, w_source=None, encoding=None,
errors=None):
- if (w_source and space.is_w(space.type(w_source), space.w_bytes) and
- space.is_w(w_stringtype, space.w_bytes) and encoding is None
- and errors is None):
- return w_source
+ if (w_source and space.is_w(w_stringtype, space.w_bytes)
+ and encoding is None and errors is None):
+ # special-case 'bytes(byte_object)'
+ w_srctype = space.type(w_source)
+ if w_srctype is space.w_bytes:
+ return w_source
+ # special-case 'bytes([single_integer])' or 'bytes((single_int,))'
+ # for JITted performance only, when we clearly see the
+ # length of the list/tuple being constant and equal to 1
+ if w_srctype is space.w_list or w_srctype is space.w_tuple:
+ length = space.len_w(w_source)
+ if jit.isconstant(length) and length == 1:
+ w_item = space.getitem(w_source, space.wrap(0))
+ value = getbytevalue(space, w_item)
+ return W_BytesObject(value)
+ #
value = newbytesdata_w(space, w_source, encoding, errors)
w_obj = space.allocate_instance(W_BytesObject, w_stringtype)
W_BytesObject.__init__(w_obj, value)
diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -89,6 +89,13 @@
assert self.space.listview_bytes(w_bytes) == None
assert self.space.listview_int(w_bytes) == [97, 98, 99, 100]
+ def test_constructor_single_char(self, monkeypatch):
+ from rpython.rlib import jit
+ monkeypatch.setattr(jit, 'isconstant', lambda x: True)
+ space = self.space
+ w_res = space.call_function(space.w_bytes, space.wrap([42]))
+ assert space.str_w(w_res) == '*'
+
class AppTestBytesObject:
def test_constructor(self):
@@ -97,6 +104,23 @@
assert bytes(b'abc') == b'abc'
assert bytes('abc', 'ascii') == b'abc'
assert bytes(set(b'foo')) in (b'fo', b'of')
+ assert bytes([]) == b''
+ assert bytes([42]) == b'*'
+ assert bytes([0xFC]) == b'\xFC'
+ assert bytes([42, 0xCC]) == b'*\xCC'
+
+ def test_constructor_list_of_objs(self):
+ class X:
+ def __index__(self):
+ return 42
+ class Y:
+ def __int__(self):
+ return 42
+ for obj in [42, X()]:
+ assert bytes([obj]) == b'*'
+ assert bytes([obj, obj, obj]) == b'***'
+ raises(TypeError, bytes, [Y()])
+ raises(TypeError, bytes, [Y(), Y()])
def test_fromhex(self):
assert bytes.fromhex("abcd") == b'\xab\xcd'
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -1257,7 +1257,11 @@
def unicode_to_decimal_w(space, w_unistr, allow_surrogates=False):
if not isinstance(w_unistr, W_UnicodeObject):
raise oefmt(space.w_TypeError, "expected unicode, got '%T'", w_unistr)
- unistr = w_unistr._value
+ value = _rpy_unicode_to_decimal_w(space, w_unistr._value)
+ return unicodehelper.encode_utf8(space, value,
+ allow_surrogates=allow_surrogates)
+
+def _rpy_unicode_to_decimal_w(space, unistr):
result = [u'\0'] * len(unistr)
for i in xrange(len(unistr)):
uchr = ord(unistr[i])
@@ -1270,8 +1274,7 @@
except KeyError:
pass
result[i] = unichr(uchr)
- return unicodehelper.encode_utf8(space, u''.join(result),
- allow_surrogates=allow_surrogates)
+ return u''.join(result)
@jit.elidable
def g_encode_utf8(value):
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -280,7 +280,8 @@
assert operate(A()) == "hello" * n
assert type(operate(A())) is str
answer = 42
- raises(TypeError, operate, A())
+ excinfo = raises(TypeError, operate, A())
+ assert "returned non-string (type 'int')" in str(excinfo.value)
def test_string_results_unicode(self):
class A(object):
diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py
--- a/pypy/tool/pytest/apptest.py
+++ b/pypy/tool/pytest/apptest.py
@@ -21,13 +21,6 @@
pypyroot = os.path.dirname(pypydir)
-RENAMED_USEMODULES = dict(
- _winreg='winreg',
- exceptions='builtins',
- struct='_struct',
- thread='_thread',
- operator='_operator',
- )
class AppError(Exception):
def __init__(self, excinfo):
@@ -63,6 +56,11 @@
return repr(value)
+def _rename_module(name):
+ mod = __import__("pypy.module." + name, globals(), locals(), ['Module'])
+ return mod.Module.applevel_name or name
+
+
def run_with_python(python_, target_, usemodules, **definitions):
if python_ is None:
py.test.skip("Cannot find the default python3 interpreter to run with -A")
@@ -133,8 +131,7 @@
check_usemodules = ''
if usemodules:
- usemodules = [str(RENAMED_USEMODULES.get(name, name))
- for name in usemodules]
+ usemodules = [_rename_module(name) for name in usemodules]
check_usemodules = """\
missing = set(%r).difference(sys.builtin_module_names)
if missing:
diff --git a/pypy/tool/pytest/test/test_appsupport.py b/pypy/tool/pytest/test/test_appsupport.py
--- a/pypy/tool/pytest/test/test_appsupport.py
+++ b/pypy/tool/pytest/test/test_appsupport.py
@@ -135,3 +135,12 @@
info = raises(ZeroDivisionError, "x/0")
assert info.type is ZeroDivisionError
assert isinstance(info.value, ZeroDivisionError)
+
+def test_rename_module():
+ from pypy.tool.pytest.apptest import _rename_module
+ assert _rename_module("sys") == "sys"
+ if sys.platform == "win32":
+ assert _rename_module("_winreg") == "winreg"
+ assert _rename_module("struct") == "_struct"
+ assert _rename_module("operator") == "_operator"
+ assert _rename_module("signal") == "_signal"
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -155,7 +155,10 @@
# 'old_objects_pointing_to_pinned' and doesn't have to be added again.
GCFLAG_PINNED_OBJECT_PARENT_KNOWN = GCFLAG_PINNED
-_GCFLAG_FIRST_UNUSED = first_gcflag << 10 # the first unused bit
+# record that ignore_finalizer() has been called
+GCFLAG_IGNORE_FINALIZER = first_gcflag << 10
+
+_GCFLAG_FIRST_UNUSED = first_gcflag << 11 # the first unused bit
# States for the incremental GC
@@ -1161,6 +1164,11 @@
obj = self.get_forwarding_address(obj)
return self.get_type_id(obj)
+ def get_possibly_forwarded_tid(self, obj):
+ if self.is_in_nursery(obj) and self.is_forwarded(obj):
+ obj = self.get_forwarding_address(obj)
+ return self.header(obj).tid
+
def get_total_memory_used(self):
"""Return the total memory used, not counting any object in the
nursery: only objects in the ArenaCollection or raw-malloced.
@@ -1672,7 +1680,7 @@
self.rrc_minor_collection_trace()
#
# visit the "probably young" objects with finalizers. They
- # always all survive.
+ # all survive, except if IGNORE_FINALIZER is set.
if self.probably_young_objects_with_finalizers.non_empty():
self.deal_with_young_objects_with_finalizers()
#
@@ -2675,6 +2683,8 @@
while self.probably_young_objects_with_finalizers.non_empty():
obj = self.probably_young_objects_with_finalizers.popleft()
fq_nr = self.probably_young_objects_with_finalizers.popleft()
+ if self.get_possibly_forwarded_tid(obj) & GCFLAG_IGNORE_FINALIZER:
+ continue
self.singleaddr.address[0] = obj
self._trace_drag_out1(self.singleaddr)
obj = self.singleaddr.address[0]
@@ -2697,6 +2707,8 @@
fq_nr = self.old_objects_with_finalizers.popleft()
ll_assert(self._finalization_state(x) != 1,
"bad finalization state 1")
+ if self.header(x).tid & GCFLAG_IGNORE_FINALIZER:
+ continue
if self.header(x).tid & GCFLAG_VISITED:
new_with_finalizer.append(x)
new_with_finalizer.append(fq_nr)
@@ -2787,6 +2799,9 @@
self.objects_to_trace.append(obj)
self.visit_all_objects()
+ def ignore_finalizer(self, obj):
+ self.header(obj).tid |= GCFLAG_IGNORE_FINALIZER
+
# ----------
# Weakrefs
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -545,6 +545,12 @@
s_gcref],
annmodel.s_None)
+ self.ignore_finalizer_ptr = None
+ if hasattr(GCClass, 'ignore_finalizer'):
+ self.ignore_finalizer_ptr = getfn(GCClass.ignore_finalizer,
+ [s_gc, SomeAddress()],
+ annmodel.s_None)
+
def create_custom_trace_funcs(self, gc, rtyper):
custom_trace_funcs = tuple(rtyper.custom_trace_funcs)
rtyper.custom_trace_funcs = custom_trace_funcs
@@ -1572,6 +1578,13 @@
hop.genop("cast_adr_to_ptr", [v_adr],
resultvar = hop.spaceop.result)
+ def gct_gc_ignore_finalizer(self, hop):
+ if self.ignore_finalizer_ptr is not None:
+ v_adr = hop.genop("cast_ptr_to_adr", [hop.spaceop.args[0]],
+ resulttype=llmemory.Address)
+ hop.genop("direct_call", [self.ignore_finalizer_ptr,
+ self.c_const_gc, v_adr])
+
class TransformerLayoutBuilder(gctypelayout.TypeLayoutBuilder):
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -4,7 +4,7 @@
"""
import os, stat, errno, sys
-from rpython.rlib import rposix
+from rpython.rlib import rposix, rgc
from rpython.rlib.objectmodel import enforceargs
from rpython.rlib.rarithmetic import intmask
from rpython.rlib.rstring import StringBuilder
@@ -294,6 +294,7 @@
if ll_file:
# double close is allowed
self._ll_file = lltype.nullptr(FILEP.TO)
+ rgc.may_ignore_finalizer(self)
do_close = self._close2[0]
try:
if do_close:
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -527,6 +527,14 @@
hop.exception_cannot_occur()
return hop.inputconst(lltype.Signed, hop.s_result.const)
+ at jit.dont_look_inside
+ at specialize.argtype(0)
+def may_ignore_finalizer(obj):
+ """Optimization hint: says that it is valid for any finalizer
+ for 'obj' to be ignored, depending on the GC."""
+ from rpython.rtyper.lltypesystem.lloperation import llop
+ llop.gc_ignore_finalizer(lltype.Void, obj)
+
# ____________________________________________________________
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -486,6 +486,7 @@
'gc_add_memory_pressure': LLOp(),
'gc_fq_next_dead' : LLOp(),
'gc_fq_register' : LLOp(),
+ 'gc_ignore_finalizer' : LLOp(canrun=True),
'gc_rawrefcount_init': LLOp(),
'gc_rawrefcount_create_link_pypy': LLOp(),
diff --git a/rpython/rtyper/lltypesystem/opimpl.py b/rpython/rtyper/lltypesystem/opimpl.py
--- a/rpython/rtyper/lltypesystem/opimpl.py
+++ b/rpython/rtyper/lltypesystem/opimpl.py
@@ -736,6 +736,9 @@
assert isinstance(x, bool)
return x
+def op_gc_ignore_finalizer(obj):
+ pass
+
# ____________________________________________________________
def get_op_impl(opname):
diff --git a/rpython/translator/c/src/mem.h b/rpython/translator/c/src/mem.h
--- a/rpython/translator/c/src/mem.h
+++ b/rpython/translator/c/src/mem.h
@@ -152,6 +152,7 @@
#define OP_GC_IS_RPY_INSTANCE(x, r) r = 0
#define OP_GC_DUMP_RPY_HEAP(fd, r) r = 0
#define OP_GC_SET_EXTRA_THRESHOLD(x, r) /* nothing */
+#define OP_GC_IGNORE_FINALIZER(x, r) /* nothing */
/****************************/
/* The "asmgcc" root finder */
diff --git a/rpython/translator/c/test/test_boehm.py b/rpython/translator/c/test/test_boehm.py
--- a/rpython/translator/c/test/test_boehm.py
+++ b/rpython/translator/c/test/test_boehm.py
@@ -409,7 +409,9 @@
#
def fn():
for i in range(1000):
- fq.register_finalizer(A(i))
+ x = A(i)
+ fq.register_finalizer(x)
+ rgc.may_ignore_finalizer(x) # this is ignored with Boehm
rgc.collect()
rgc.collect()
if glob.triggered == 0:
diff --git a/rpython/translator/c/test/test_newgc.py b/rpython/translator/c/test/test_newgc.py
--- a/rpython/translator/c/test/test_newgc.py
+++ b/rpython/translator/c/test/test_newgc.py
@@ -1705,6 +1705,38 @@
res = self.run("limited_memory_linux", -1, runner=myrunner)
assert res == 42
+ def define_ignore_finalizer(cls):
+ class X(object):
+ pass
+ class FQ(rgc.FinalizerQueue):
+ Class = X
+ def finalizer_trigger(self):
+ pass
+ queue = FQ()
+ def g():
+ x1 = X()
+ x2 = X()
+ queue.register_finalizer(x1)
+ queue.register_finalizer(x2)
+ rgc.may_ignore_finalizer(x1)
+ g._dont_inline_ = True
+ def f():
+ g()
+ rgc.collect()
+ seen = 0
+ while True:
+ obj = queue.next_dead()
+ if obj is None:
+ break
+ seen += 1
+ return seen
+ assert f() == 2 # untranslated: may_ignore_finalizer() is ignored
+ return f
+
+ def test_ignore_finalizer(self):
+ res = self.run("ignore_finalizer")
+ assert res == 1 # translated: x1 is removed from the list
+
# ____________________________________________________________________
More information about the pypy-commit
mailing list