Author: Richard Plangger <planri...@gmail.com> Branch: py3.5-ssl Changeset: r88738:709cadb7f491 Date: 2016-11-29 13:02 +0100 http://bitbucket.org/pypy/pypy/changeset/709cadb7f491/
Log: merge py3.5 diff too long, truncating to 2000 out of 2056 lines diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py --- a/lib-python/2.7/distutils/sysconfig_pypy.py +++ b/lib-python/2.7/distutils/sysconfig_pypy.py @@ -74,6 +74,19 @@ g['LIBDIR'] = os.path.join(sys.prefix, 'lib') g['VERSION'] = get_python_version() + if sys.platform[:6] == "darwin": + import platform + if platform.machine() == 'i386': + if platform.architecture()[0] == '32bit': + arch = 'i386' + else: + arch = 'x86_64' + else: + # just a guess + arch = platform.machine() + g['LDSHARED'] += ' -undefined dynamic_lookup' + g['CC'] += ' -arch %s' % (arch,) + global _config_vars _config_vars = g @@ -109,6 +122,12 @@ _config_vars['prefix'] = PREFIX _config_vars['exec_prefix'] = EXEC_PREFIX + # OS X platforms require special customization to handle + # multi-architecture, multi-os-version installers + if sys.platform == 'darwin': + import _osx_support + _osx_support.customize_config_vars(_config_vars) + if args: vals = [] for name in args: diff --git a/lib-python/3/_weakrefset.py b/lib-python/3/_weakrefset.py --- a/lib-python/3/_weakrefset.py +++ b/lib-python/3/_weakrefset.py @@ -65,7 +65,14 @@ yield item def __len__(self): - return len(self.data) - len(self._pending_removals) + # PyPy change: we can't rely on len(self.data) at all, because + # the weakref callbacks may be called at an unknown later time. +# return len(self.data) - len(self._pending_removals) +# + result = 0 + for wr in self.data: + result += (wr() is not None) + return result def __contains__(self, item): try: diff --git a/lib-python/3/test/test_asyncio/test_base_events.py b/lib-python/3/test/test_asyncio/test_base_events.py --- a/lib-python/3/test/test_asyncio/test_base_events.py +++ b/lib-python/3/test/test_asyncio/test_base_events.py @@ -510,6 +510,7 @@ fut.add_done_callback(lambda *args: self.loop.stop()) self.loop.run_forever() fut = None # Trigger Future.__del__ or futures._TracebackLogger + support.gc_collect() if PY34: # Future.__del__ in Python 3.4 logs error with # an actual exception context diff --git a/lib-python/3/test/test_asyncio/test_futures.py b/lib-python/3/test/test_asyncio/test_futures.py --- a/lib-python/3/test/test_asyncio/test_futures.py +++ b/lib-python/3/test/test_asyncio/test_futures.py @@ -238,6 +238,7 @@ fut.set_exception(RuntimeError('boom')) del fut test_utils.run_briefly(self.loop) + support.gc_collect() self.assertTrue(m_log.error.called) @mock.patch('asyncio.base_events.logger') diff --git a/lib-python/3/test/test_complex.py b/lib-python/3/test/test_complex.py --- a/lib-python/3/test/test_complex.py +++ b/lib-python/3/test/test_complex.py @@ -310,7 +310,7 @@ self.assertRaises(TypeError, float, 5+3j) self.assertRaises(ValueError, complex, "") self.assertRaises(TypeError, complex, None) - self.assertRaisesRegex(TypeError, "not 'NoneType'", complex, None) + self.assertRaisesRegex(TypeError, " 'NoneType'", complex, None) self.assertRaises(ValueError, complex, "\0") self.assertRaises(ValueError, complex, "3\09") self.assertRaises(TypeError, complex, "1", "2") diff --git a/lib-python/3/test/test_exceptions.py b/lib-python/3/test/test_exceptions.py --- a/lib-python/3/test/test_exceptions.py +++ b/lib-python/3/test/test_exceptions.py @@ -1013,6 +1013,7 @@ self.assertNotEqual(wr(), None) else: self.fail("RecursionError not raised") + gc_collect() self.assertEqual(wr(), None) def test_errno_ENOTDIR(self): diff --git a/lib-python/3/test/test_sys.py b/lib-python/3/test/test_sys.py --- a/lib-python/3/test/test_sys.py +++ b/lib-python/3/test/test_sys.py @@ -811,7 +811,12 @@ ref = AtExit() """ rc, stdout, stderr = assert_python_ok('-c', code) - self.assertEqual(stdout.rstrip(), b'True') + if test.support.check_impl_detail(cpython=True): + self.assertEqual(stdout.rstrip(), b'True') + else: + # the __del__ method may or may not have been called + # in other Python implementations + self.assertIn(stdout.rstrip(), {b'True', b''}) @test.support.cpython_only diff --git a/lib-python/3/test/test_weakref.py b/lib-python/3/test/test_weakref.py --- a/lib-python/3/test/test_weakref.py +++ b/lib-python/3/test/test_weakref.py @@ -1103,7 +1103,7 @@ # Keep an iterator alive it = dct.items() try: - next(it) + print(next(it)) except StopIteration: pass del items @@ -1112,7 +1112,10 @@ del it gc.collect() gc.collect() + print(list(dct.items())) n2 = len(dct) + print(len(dct)) + print(weakref) # one item may be kept alive inside the iterator self.assertIn(n1, (0, 1)) self.assertEqual(n2, 0) diff --git a/lib-python/3/unittest/test/test_assertions.py b/lib-python/3/unittest/test/test_assertions.py --- a/lib-python/3/unittest/test/test_assertions.py +++ b/lib-python/3/unittest/test/test_assertions.py @@ -2,6 +2,7 @@ import warnings import weakref import unittest +from test.support import gc_collect from itertools import product @@ -124,8 +125,10 @@ self.foo() Foo("test_functional").run() + gc_collect() self.assertIsNone(wr()) Foo("test_with").run() + gc_collect() self.assertIsNone(wr()) def testAssertNotRegex(self): diff --git a/lib-python/3/unittest/test/test_case.py b/lib-python/3/unittest/test/test_case.py --- a/lib-python/3/unittest/test/test_case.py +++ b/lib-python/3/unittest/test/test_case.py @@ -18,7 +18,7 @@ TestEquality, TestHashing, LoggingResult, LegacyLoggingResult, ResultWithNoStartTestRunStopTestRun ) -from test.support import captured_stderr +from test.support import captured_stderr, gc_collect log_foo = logging.getLogger('foo') @@ -1737,6 +1737,7 @@ for method_name in ('test1', 'test2'): testcase = TestCase(method_name) testcase.run() + gc_collect() self.assertEqual(MyException.ninstance, 0) diff --git a/lib-python/3/weakref.py b/lib-python/3/weakref.py --- a/lib-python/3/weakref.py +++ b/lib-python/3/weakref.py @@ -147,7 +147,14 @@ del self.data[key] def __len__(self): - return len(self.data) - len(self._pending_removals) + # PyPy change: we can't rely on len(self.data) at all, because + # the weakref callbacks may be called at an unknown later time. +# return len(self.data) - len(self._pending_removals) +# + result = 0 + for wr in self.data.values(): + result += (wr() is not None) + return result def __contains__(self, key): try: @@ -376,11 +383,18 @@ return self.data[ref(key)] def __len__(self): - if self._dirty_len and self._pending_removals: - # self._pending_removals may still contain keys which were - # explicitly removed, we have to scrub them (see issue #21173). - self._scrub_removals() - return len(self.data) - len(self._pending_removals) + # PyPy change: we can't rely on len(self.data) at all, because + # the weakref callbacks may be called at an unknown later time. +# if self._dirty_len and self._pending_removals: +# # self._pending_removals may still contain keys which were +# # explicitly removed, we have to scrub them (see issue #21173). +# self._scrub_removals() +# return len(self.data) - len(self._pending_removals) +# + result = 0 + for wr in self.data: + result += (wr() is not None) + return result def __repr__(self): return "<%s at %#x>" % (self.__class__.__name__, id(self)) 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 @@ -34,3 +34,7 @@ Add jit.conditional_call_elidable(), a way to tell the JIT "conditonally call this function" returning a result. + +.. branch: desc-specialize + +Refactor FunctionDesc.specialize() and related code (RPython annotator). diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -302,6 +302,12 @@ elif config.objspace.usemodules.pypyjit: config.translation.jit = True + if config.objspace.usemodules.cpyext: + if config.translation.gc != 'incminimark': + raise Exception("The 'cpyext' module requires the 'incminimark'" + " GC. You need either 'targetpypystandalone.py" + " --withoutmod-cpyext' or '--gc=incminimark'") + config.translating = True import translate diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -595,7 +595,7 @@ # set up the Ctrl-C => KeyboardInterrupt signal handler, if the # signal module is available try: - import signal + import _signal as signal except ImportError: pass else: diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -559,8 +559,9 @@ space.wrap(msg)) return OperationError(exc, w_error) +@specialize.arg(3) def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError', - w_exception_class=None): + w_exception_class=None, w_filename2=None): assert isinstance(e, OSError) if _WINDOWS and isinstance(e, WindowsError): @@ -580,25 +581,31 @@ else: exc = w_exception_class if w_filename is not None: - w_error = space.call_function(exc, space.wrap(errno), - space.wrap(msg), w_filename) + if w_filename2 is not None: + w_error = space.call_function(exc, space.wrap(errno), + space.wrap(msg), w_filename, + space.w_None, w_filename2) + else: + w_error = space.call_function(exc, space.wrap(errno), + space.wrap(msg), w_filename) else: w_error = space.call_function(exc, space.wrap(errno), space.wrap(msg)) return OperationError(exc, w_error) -wrap_oserror2._annspecialcase_ = 'specialize:arg(3)' +@specialize.arg(3) def wrap_oserror(space, e, filename=None, exception_name='w_OSError', - w_exception_class=None): + w_exception_class=None, filename2=None): + w_filename = None + w_filename2 = None if filename is not None: - return wrap_oserror2(space, e, space.wrap(filename), - exception_name=exception_name, - w_exception_class=w_exception_class) - else: - return wrap_oserror2(space, e, None, - exception_name=exception_name, - w_exception_class=w_exception_class) -wrap_oserror._annspecialcase_ = 'specialize:arg(3)' + w_filename = space.wrap(filename) + if filename2 is not None: + w_filename2 = space.wrap(filename2) + return wrap_oserror2(space, e, w_filename, + exception_name=exception_name, + w_exception_class=w_exception_class, + w_filename2=w_filename2) def exception_from_saved_errno(space, w_type): from rpython.rlib.rposix import get_saved_errno diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -20,7 +20,8 @@ self.running = False self._name = name # may be null, use get_name() self._qualname = qualname # may be null, use get_qualname() - if self.pycode.co_flags & CO_YIELD_INSIDE_TRY: + if (isinstance(self, Coroutine) # XXX would be cool not to need this + or self.pycode.co_flags & CO_YIELD_INSIDE_TRY): self.register_finalizer(self.space) self.saved_operr = None @@ -385,7 +386,7 @@ self.frame.last_instr == -1: space = self.space msg = u"coroutine '%s' was never awaited" % self.get_qualname() - space.warn(space.w_RuntimeWarning, space.wrap(msg)) + space.warn(space.wrap(msg), space.w_RuntimeWarning) GeneratorOrCoroutine._finalize_(self) diff --git a/pypy/interpreter/test/test_coroutine.py b/pypy/interpreter/test/test_coroutine.py --- a/pypy/interpreter/test/test_coroutine.py +++ b/pypy/interpreter/test/test_coroutine.py @@ -160,3 +160,20 @@ else: assert False, "should have raised" """ + + def test_runtime_warning(self): """ + import gc, warnings + async def foobaz(): + pass + with warnings.catch_warnings(record=True) as l: + foobaz() + gc.collect() + gc.collect() + gc.collect() + + assert len(l) == 1, repr(l) + w = l[0].message + assert isinstance(w, RuntimeWarning) + assert str(w).startswith("coroutine ") + assert str(w).endswith("foobaz' was never awaited") + """ diff --git a/pypy/module/_collections/interp_deque.py b/pypy/module/_collections/interp_deque.py --- a/pypy/module/_collections/interp_deque.py +++ b/pypy/module/_collections/interp_deque.py @@ -1,4 +1,5 @@ import sys +from rpython.rlib.objectmodel import specialize from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef, make_weakref_descr @@ -7,7 +8,6 @@ from pypy.interpreter.error import OperationError, oefmt from pypy.objspace.std.sliceobject import unwrap_start_stop from rpython.rlib.debug import check_nonneg -from rpython.rlib.objectmodel import specialize # A `dequeobject` is composed of a doubly-linked list of `block` nodes. diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py --- a/pypy/module/cppyy/test/test_zjit.py +++ b/pypy/module/cppyy/test/test_zjit.py @@ -124,13 +124,13 @@ assert isinstance(w_obj, FakeFloat) return w_obj.val + @specialize.arg(1) def interp_w(self, RequiredClass, w_obj, can_be_None=False): if can_be_None and w_obj is None: return None if not isinstance(w_obj, RequiredClass): raise TypeError return w_obj - interp_w._annspecialcase_ = 'specialize:arg(1)' def getarg_w(self, code, w_obj): # for retrieving buffers return FakeBuffer(w_obj) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -35,8 +35,6 @@ from rpython.rlib.objectmodel import specialize from pypy.module import exceptions from pypy.module.exceptions import interp_exceptions -# CPython 2.4 compatibility -from py.builtin import BaseException from rpython.tool.sourcetools import func_with_new_name from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib import rawrefcount @@ -1622,9 +1620,8 @@ miniglobals = {'__name__': __name__, # for module name propagation } exec source.compile() in miniglobals - call_external_function = miniglobals['cpy_call_external'] + call_external_function = specialize.ll()(miniglobals['cpy_call_external']) call_external_function._dont_inline_ = True - call_external_function._annspecialcase_ = 'specialize:ll' call_external_function._gctransformer_hint_close_stack_ = True # don't inline, as a hack to guarantee that no GC pointer is alive # anywhere in call_external_function diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -15,6 +15,7 @@ from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.annlowlevel import llhelper from rpython.rlib import rawrefcount +from rpython.rlib.debug import fatalerror #________________________________________________________ @@ -192,6 +193,8 @@ rawrefcount.create_link_pypy(w_obj, py_obj) +w_marker_deallocating = W_Root() + def from_ref(space, ref): """ Finds the interpreter object corresponding to the given reference. If the @@ -202,7 +205,23 @@ return None w_obj = rawrefcount.to_obj(W_Root, ref) if w_obj is not None: - return w_obj + if w_obj is not w_marker_deallocating: + return w_obj + fatalerror( + "*** Invalid usage of a dying CPython object ***\n" + "\n" + "cpyext, the emulation layer, detected that while it is calling\n" + "an object's tp_dealloc, the C code calls back a function that\n" + "tries to recreate the PyPy version of the object. Usually it\n" + "means that tp_dealloc calls some general PyXxx() API. It is\n" + "a dangerous and potentially buggy thing to do: even in CPython\n" + "the PyXxx() function could, in theory, cause a reference to the\n" + "object to be taken and stored somewhere, for an amount of time\n" + "exceeding tp_dealloc itself. Afterwards, the object will be\n" + "freed, making that reference point to garbage.\n" + ">>> PyPy could contain some workaround to still work if\n" + "you are lucky, but it is not done so far; better fix the bug in\n" + "the CPython extension.") # This reference is not yet a real interpreter object. # Realize it. @@ -233,7 +252,8 @@ INTERPLEVEL_API['as_pyobj'] = as_pyobj def pyobj_has_w_obj(pyobj): - return rawrefcount.to_obj(W_Root, pyobj) is not None + w_obj = rawrefcount.to_obj(W_Root, pyobj) + return w_obj is not None and w_obj is not w_marker_deallocating INTERPLEVEL_API['pyobj_has_w_obj'] = staticmethod(pyobj_has_w_obj) @@ -335,6 +355,7 @@ pto = obj.c_ob_type #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \ # "'s type which is", rffi.charp2str(pto.c_tp_name) + rawrefcount.mark_deallocating(w_marker_deallocating, obj) generic_cpy_call(space, pto.c_tp_dealloc, obj) @cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL) diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -446,6 +446,7 @@ self.w_errno = space.w_None self.w_strerror = space.w_None self.w_filename = space.w_None + self.w_filename2 = space.w_None self.written = -1 # only for BlockingIOError. W_BaseException.__init__(self, space) @@ -471,15 +472,17 @@ @staticmethod def _parse_init_args(space, args_w): - if 2 <= len(args_w) <= 3: + if 2 <= len(args_w) <= 5: w_errno = args_w[0] w_strerror = args_w[1] - if len(args_w) == 3: + w_filename = None + w_filename2 = None + if len(args_w) > 2: w_filename = args_w[2] - else: - w_filename = None - return w_errno, w_strerror, w_filename - return None, None, None + if len(args_w) > 4: + w_filename2 = args_w[4] + return w_errno, w_strerror, w_filename, w_filename2 + return None, None, None, None @staticmethod def descr_new(space, w_subtype, __args__): @@ -487,11 +490,12 @@ w_errno = None w_strerror = None w_filename = None + w_filename2 = None if not W_OSError._use_init(space, w_subtype): if kwds_w: raise oefmt(space.w_TypeError, "OSError does not take keyword arguments") - (w_errno, w_strerror, w_filename, + (w_errno, w_strerror, w_filename, w_filename2 ) = W_OSError._parse_init_args(space, args_w) if (not space.is_none(w_errno) and space.is_w(w_subtype, space.gettypeobject(W_OSError.typedef))): @@ -509,7 +513,8 @@ exc = space.allocate_instance(W_OSError, w_subtype) W_OSError.__init__(exc, space) if not W_OSError._use_init(space, w_subtype): - exc._init_error(space, args_w, w_errno, w_strerror, w_filename) + exc._init_error(space, args_w, w_errno, w_strerror, w_filename, + w_filename2) return space.wrap(exc) def descr_init(self, space, __args__): @@ -520,11 +525,13 @@ if kwds_w: raise oefmt(space.w_TypeError, "OSError does not take keyword arguments") - (w_errno, w_strerror, w_filename + (w_errno, w_strerror, w_filename, w_filename2 ) = W_OSError._parse_init_args(space, args_w) - self._init_error(space, args_w, w_errno, w_strerror, w_filename) + self._init_error(space, args_w, w_errno, w_strerror, w_filename, + w_filename2) - def _init_error(self, space, args_w, w_errno, w_strerror, w_filename): + def _init_error(self, space, args_w, w_errno, w_strerror, w_filename, + w_filename2): W_BaseException.descr_init(self, space, args_w) if w_errno: self.w_errno = w_errno @@ -540,17 +547,21 @@ self.w_filename = w_filename else: self.w_filename = w_filename + if not space.is_none(w_filename2): + self.w_filename2 = w_filename2 # filename is removed from the args tuple (for compatibility # purposes, see test_exceptions.py) self.args_w = [w_errno, w_strerror] # since we rebind args_w, we need special reduce, grump def descr_reduce(self, space): + extra = [] if not space.is_w(self.w_filename, space.w_None): - lst = [self.getclass(space), space.newtuple( - self.args_w + [self.w_filename])] - else: - lst = [self.getclass(space), space.newtuple(self.args_w)] + extra.append(self.w_filename) + if not space.is_w(self.w_filename2, space.w_None): + extra.append(space.w_None) + extra.append(self.w_filename2) + lst = [self.getclass(space), space.newtuple(self.args_w + extra)] if self.w_dict is not None and space.is_true(self.w_dict): lst = lst + [self.w_dict] return space.newtuple(lst) @@ -561,6 +572,12 @@ errno = space.unicode_w(space.str(self.w_errno)) strerror = space.unicode_w(space.str(self.w_strerror)) if not space.is_w(self.w_filename, space.w_None): + if not space.is_w(self.w_filename2, space.w_None): + return space.wrap(u"[Errno %s] %s: %s -> %s" % ( + errno, + strerror, + space.unicode_w(space.repr(self.w_filename)), + space.unicode_w(space.repr(self.w_filename2)))) return space.wrap(u"[Errno %s] %s: %s" % ( errno, strerror, @@ -590,6 +607,7 @@ errno = readwrite_attrproperty_w('w_errno', W_OSError), strerror = readwrite_attrproperty_w('w_strerror', W_OSError), filename = readwrite_attrproperty_w('w_filename', W_OSError), + filename2= readwrite_attrproperty_w('w_filename2',W_OSError), characters_written = GetSetProperty(W_OSError.descr_get_written, W_OSError.descr_set_written), ) diff --git a/pypy/module/exceptions/test/test_exc.py b/pypy/module/exceptions/test/test_exc.py --- a/pypy/module/exceptions/test/test_exc.py +++ b/pypy/module/exceptions/test/test_exc.py @@ -374,6 +374,23 @@ e = SubOSErrorWithNew("some message", baz="baz") assert e.baz == "baz" assert e.args == ("some message",) + assert e.filename is None + assert e.filename2 is None + + def test_oserror_3_args(self): + e = OSError(42, "bar", "baz") + assert e.args == (42, "bar") + assert e.filename == "baz" + assert e.filename2 is None + assert str(e) == "[Errno 42] bar: 'baz'" + + def test_oserror_5_args(self): + # NB. argument 4 is only parsed on Windows + e = OSError(42, "bar", "baz", None, "bok") + assert e.args == (42, "bar") + assert e.filename == "baz" + assert e.filename2 == "bok" + assert str(e) == "[Errno 42] bar: 'baz' -> 'bok'" # Check the heuristic for print & exec covers significant cases # As well as placing some limits on false positives diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py --- a/pypy/module/posix/interp_posix.py +++ b/pypy/module/posix/interp_posix.py @@ -484,7 +484,8 @@ def __init__(self, space): self.stat_float_times = True -def stat_float_times(space, w_value=None): +@unwrap_spec(newval=int) +def stat_float_times(space, newval=-1): """stat_float_times([newval]) -> oldval Determine whether os.[lf]stat represents time stamps as float objects. @@ -494,10 +495,10 @@ """ state = space.fromcache(StatState) - if w_value is None: + if newval == -1: return space.wrap(state.stat_float_times) else: - state.stat_float_times = space.bool_w(w_value) + state.stat_float_times = (newval != 0) @unwrap_spec(fd=c_int) @@ -1008,7 +1009,7 @@ else: dispatch_filename_2(rposix.rename)(space, w_src, w_dst) except OSError as e: - raise wrap_oserror(space, e) + raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst) @unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT), dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT)) @@ -1115,7 +1116,7 @@ rposix.kill(os.getpid(), signal.SIGABRT) @unwrap_spec( - src='fsencode', dst='fsencode', + src='fsencode', dst='fsencode', # <- simpler: link() is never on Windows src_dir_fd=DirFD(rposix.HAVE_LINKAT), dst_dir_fd=DirFD(rposix.HAVE_LINKAT), follow_symlinks=bool) def link( @@ -1144,7 +1145,7 @@ else: rposix.link(src, dst) except OSError as e: - raise wrap_oserror(space, e) + raise wrap_oserror(space, e, filename=src, filename2=dst) @unwrap_spec(dir_fd=DirFD(rposix.HAVE_SYMLINKAT)) @@ -1171,7 +1172,7 @@ else: dispatch_filename_2(rposix.symlink)(space, w_src, w_dst) except OSError as e: - raise wrap_oserror(space, e) + raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst) @unwrap_spec( @@ -2219,13 +2220,20 @@ @unwrap_spec(fd=c_int) def get_blocking(space, fd): - return space.newbool(rposix.get_status_flags(fd) & rposix.O_NONBLOCK == 0) + try: + flags = rposix.get_status_flags(fd) + except OSError as e: + raise wrap_oserror(space, e) + return space.newbool(flags & rposix.O_NONBLOCK == 0) @unwrap_spec(fd=c_int, blocking=int) def set_blocking(space, fd, blocking): - flags = rposix.get_status_flags(fd) - if blocking: - flags &= ~rposix.O_NONBLOCK - else: - flags |= rposix.O_NONBLOCK - rposix.set_status_flags(fd, flags) + try: + flags = rposix.get_status_flags(fd) + if blocking: + flags &= ~rposix.O_NONBLOCK + else: + flags |= rposix.O_NONBLOCK + rposix.set_status_flags(fd, flags) + except OSError as e: + raise wrap_oserror(space, e) diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -159,11 +159,14 @@ st = posix.stat(path) assert isinstance(st.st_mtime, float) assert st[7] == int(st.st_atime) + assert posix.stat_float_times(-1) is True posix.stat_float_times(False) st = posix.stat(path) assert isinstance(st.st_mtime, int) assert st[7] == st.st_atime + assert posix.stat_float_times(-1) is False + finally: posix.stat_float_times(current) @@ -1148,6 +1151,11 @@ assert posix.get_blocking(fd) is True posix.close(fd) + def test_blocking_error(self): + posix = self.posix + raises(OSError, posix.get_blocking, 1234567) + raises(OSError, posix.set_blocking, 1234567, True) + def test_urandom(self): os = self.posix @@ -1214,6 +1222,18 @@ self.posix.RTLD_GLOBAL self.posix.RTLD_LOCAL + def test_error_message(self): + e = raises(OSError, self.posix.open, 'nonexistentfile1', 0) + assert str(e.value).endswith(": 'nonexistentfile1'") + + e = raises(OSError, self.posix.link, 'nonexistentfile1', 'bok') + assert str(e.value).endswith(": 'nonexistentfile1' -> 'bok'") + e = raises(OSError, self.posix.rename, 'nonexistentfile1', 'bok') + assert str(e.value).endswith(": 'nonexistentfile1' -> 'bok'") + + e = raises(OSError, self.posix.symlink, 'bok', '/nonexistentdir/boz') + assert str(e.value).endswith(": 'bok' -> '/nonexistentdir/boz'") + class AppTestEnvironment(object): def setup_class(cls): diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -4,11 +4,11 @@ from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.unicodehelper import encode_utf8 from rpython.rlib import rgc, jit +from rpython.rlib.objectmodel import specialize from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rtyper.tool import rffi_platform from rpython.translator.tool.cbuild import ExternalCompilationInfo from rpython.translator.platform import platform -from rpython.rlib.objectmodel import specialize import sys import weakref diff --git a/pypy/module/signal/__init__.py b/pypy/module/signal/__init__.py --- a/pypy/module/signal/__init__.py +++ b/pypy/module/signal/__init__.py @@ -3,6 +3,8 @@ import os class Module(MixedModule): + applevel_name = '_signal' + interpleveldefs = { 'signal': 'interp_signal.signal', 'getsignal': 'interp_signal.getsignal', 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 @@ -14,7 +14,7 @@ def test_checksignals(self): space = self.space w_received = space.appexec([], """(): - import signal + import _signal as signal received = [] def myhandler(signum, frame): received.append(signum) @@ -40,7 +40,7 @@ } def setup_class(cls): - cls.w_signal = cls.space.getbuiltinmodule('signal') + 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) @@ -92,7 +92,7 @@ """ Test that signal.signal returns SIG_DFL if that is the current handler. """ - from signal import signal, SIGINT, SIG_DFL, SIG_IGN + from _signal import signal, SIGINT, SIG_DFL, SIG_IGN try: for handler in SIG_DFL, SIG_IGN, lambda *a: None: @@ -105,7 +105,7 @@ """ Test that signal.signal returns SIG_IGN if that is the current handler. """ - from signal import signal, SIGINT, SIG_DFL, SIG_IGN + from _signal import signal, SIGINT, SIG_DFL, SIG_IGN try: for handler in SIG_DFL, SIG_IGN, lambda *a: None: @@ -119,7 +119,7 @@ Test that signal.signal returns a Python object if one is the current handler. """ - from signal import signal, SIGINT, SIG_DFL, SIG_IGN + from _signal import signal, SIGINT, SIG_DFL, SIG_IGN def installed(*a): pass @@ -134,7 +134,7 @@ """ Test that signal.getsignal returns the currently installed handler. """ - from signal import getsignal, signal, SIGINT, SIG_DFL, SIG_IGN + from _signal import getsignal, signal, SIGINT, SIG_DFL, SIG_IGN def handler(*a): pass @@ -153,7 +153,7 @@ def test_check_signum(self): import sys - from signal import getsignal, signal, NSIG + from _signal import getsignal, signal, NSIG # signum out of range fails raises(ValueError, getsignal, NSIG) @@ -166,7 +166,7 @@ def test_alarm(self): try: - from signal import alarm, signal, SIG_DFL, SIGALRM + from _signal import alarm, signal, SIG_DFL, SIGALRM except: skip('no alarm on this platform') import time @@ -186,7 +186,7 @@ def test_set_wakeup_fd(self): try: - import signal, posix, fcntl + import _signal as signal, posix, fcntl except ImportError: skip('cannot import posix or fcntl') def myhandler(signum, frame): @@ -222,13 +222,13 @@ signal.signal(signal.SIGINT, signal.SIG_DFL) def test_set_wakeup_fd_invalid(self): - import signal + import _signal as signal with open(self.temppath, 'wb') as f: fd = f.fileno() raises(ValueError, signal.set_wakeup_fd, fd) def test_siginterrupt(self): - import signal, os, time + import _signal as signal, os, time if not hasattr(signal, 'siginterrupt'): skip('non siginterrupt in signal') signum = signal.SIGUSR1 @@ -267,7 +267,7 @@ def test_alarm_raise(self): try: - from signal import alarm, signal, SIG_DFL, SIGALRM + from _signal import alarm, signal, SIG_DFL, SIGALRM except ImportError: skip("no SIGALRM on this platform") import _socket @@ -299,7 +299,7 @@ py.test.skip("Unix only") def test_itimer_real(self): - import signal + import _signal as signal def sig_alrm(*args): self.called = True @@ -316,7 +316,7 @@ assert self.called def test_itimer_exc(self): - import signal + import _signal as signal raises(signal.ItimerError, signal.setitimer, -1, 0) @@ -324,7 +324,7 @@ spaceconfig = dict(usemodules=['signal', 'thread', 'time']) def test_pthread_kill(self): - import signal + import _signal as signal import _thread signum = signal.SIGUSR1 def handler(signum, frame): @@ -334,7 +334,7 @@ raises(ZeroDivisionError, signal.pthread_kill, tid, signum) def test_sigwait(self): - import signal + import _signal as signal def handler(signum, frame): 1/0 signal.signal(signal.SIGALRM, handler) @@ -343,7 +343,7 @@ assert received == signal.SIGALRM def test_sigmask(self): - import signal, posix + import _signal as signal, posix signum1 = signal.SIGUSR1 signum2 = signal.SIGUSR2 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 @@ -208,6 +208,7 @@ def newunicode(self, x): return w_some_obj() + @specialize.argtype(1) def wrap(self, x): if not we_are_translated(): if isinstance(x, gateway.interp2app): @@ -221,7 +222,6 @@ return w_some_obj() self._wrap_not_rpython(x) return w_some_obj() - wrap._annspecialcase_ = "specialize:argtype(1)" def _wrap_not_rpython(self, x): "NOT_RPYTHON" @@ -314,10 +314,10 @@ is_root(w_complex) return 1.1, 2.2 + @specialize.arg(1) def allocate_instance(self, cls, w_subtype): is_root(w_subtype) return instantiate(cls) - allocate_instance._annspecialcase_ = "specialize:arg(1)" def decode_index(self, w_index_or_slice, seqlength): is_root(w_index_or_slice) diff --git a/pypy/objspace/fake/test/test_checkmodule.py b/pypy/objspace/fake/test/test_checkmodule.py --- a/pypy/objspace/fake/test/test_checkmodule.py +++ b/pypy/objspace/fake/test/test_checkmodule.py @@ -9,9 +9,9 @@ def make_checker(): check = [] + @specialize.memo() def see(): check.append(True) - see._annspecialcase_ = 'specialize:memo' return see, check def test_wrap_interp2app(): diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -2,12 +2,12 @@ import sys from rpython.rlib import jit +from rpython.rlib.objectmodel import specialize from rpython.rlib.rarithmetic import INT_MAX from rpython.rlib.rfloat import DTSF_ALT, formatd, isnan, isinf from rpython.rlib.rstring import StringBuilder, UnicodeBuilder from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError, oefmt @@ -483,24 +483,28 @@ "character code not in range(256)") self.std_wp(s) return - if space.isinstance_w(w_value, space.w_str): - s = space.str_w(w_value) + if not do_unicode: + if space.isinstance_w(w_value, space.w_str): + s = space.str_w(w_value) + elif space.isinstance_w(w_value, space.w_bytearray): + s = w_value.buffer_w(space, 0).as_str() + else: + s = '' if len(s) == 1: self.std_wp(s) return - elif space.isinstance_w(w_value, space.w_unicode): - if not do_unicode: - raise NeedUnicodeFormattingError - ustr = space.unicode_w(w_value) - if len(ustr) == 1: - self.std_wp(ustr) - return - if do_unicode: + raise oefmt(space.w_TypeError, "%c requires int or single byte") + else: + if space.isinstance_w(w_value, space.w_unicode): + ustr = space.unicode_w(w_value) + if len(ustr) == 1: + self.std_wp(ustr) + return raise oefmt(space.w_TypeError, "%c requires int or char") - else: - raise oefmt(space.w_TypeError, "%c requires int or single byte") def fmt_b(self, w_value): + if do_unicode: + self.unknown_fmtchar() space = self.space # cpython explicitly checks for bytes & bytearray if space.isinstance_w(w_value, space.w_bytes): @@ -522,7 +526,7 @@ return raise oefmt(space.w_TypeError, - "requires bytes, or an object that" \ + "requires bytes, or an object that " "implements __bytes__, not '%T'", w_value) return StringFormatter diff --git a/pypy/objspace/std/test/test_stringformat.py b/pypy/objspace/std/test/test_stringformat.py --- a/pypy/objspace/std/test/test_stringformat.py +++ b/pypy/objspace/std/test/test_stringformat.py @@ -178,6 +178,7 @@ raises(TypeError, '%c'.__mod__, ("bla",)) raises(TypeError, '%c'.__mod__, ("",)) raises(TypeError, '%c'.__mod__, (['c'],)) + raises(TypeError, '%c'.__mod__, b'A') def test___int__index__(self): class MyInt(object): @@ -320,6 +321,10 @@ f = 4 raises(ValueError, '"%\u1234" % (f,)') + def test_invalid_b_with_unicode(self): + raises(ValueError, '"%b" % b"A"') + raises(ValueError, '"%b" % 42') + def test_formatting_huge_precision(self): prec = 2**31 format_string = u"%.{}f".format(prec) @@ -368,6 +373,11 @@ assert b"<%c>" % 48 == b"<0>" assert b"<%c>" % b"?" == b"<?>" raises(TypeError, 'b"<%c>" % "?"') + assert b"<%c>" % bytearray(b"?") == b"<?>" + class X: + def __bytes__(self): + return b'5' + raises(TypeError, 'b"<%c>" % X()') def test_bytes_bytes(self): assert b"<%b>" % b"123" == b"<123>" @@ -421,6 +431,8 @@ assert bytearray(b"<%c>") % 48 == bytearray(b"<0>") assert bytearray(b"<%c>") % b"?" == bytearray(b"<?>") raises(TypeError, 'bytearray(b"<%c>") % "?"') + assert bytearray(b"<%c>") % bytearray(b"?") == bytearray(b"<?>") + raises(TypeError, 'bytearray(b"<%c>") % memoryview(b"X")') def test_bytes_bytes(self): assert bytearray(b"<%b>") % b"123" == bytearray(b"<123>") diff --git a/pypy/tool/cpyext/extbuild.py b/pypy/tool/cpyext/extbuild.py --- a/pypy/tool/cpyext/extbuild.py +++ b/pypy/tool/cpyext/extbuild.py @@ -206,6 +206,10 @@ pass from distutils.ccompiler import new_compiler from distutils import sysconfig + + # XXX for Darwin running old versions of CPython 2.7.x + sysconfig.get_config_vars() + compiler = new_compiler(force=1) sysconfig.customize_compiler(compiler) # XXX objects = [] diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py --- a/rpython/annotator/annrpython.py +++ b/rpython/annotator/annrpython.py @@ -2,6 +2,7 @@ import types from collections import defaultdict +from contextlib import contextmanager from rpython.tool.ansi_print import AnsiLogger from rpython.tool.pairtype import pair @@ -83,22 +84,17 @@ annmodel.TLS.check_str_without_nul = ( self.translator.config.translation.check_str_without_nul) - flowgraph, inputs_s = self.get_call_parameters(function, args_s, policy) + with self.using_policy(policy): + flowgraph, inputs_s = self.get_call_parameters(function, args_s) if main_entry_point: self.translator.entry_point_graph = flowgraph return self.build_graph_types(flowgraph, inputs_s, complete_now=complete_now) - def get_call_parameters(self, function, args_s, policy): - desc = self.bookkeeper.getdesc(function) - prevpolicy = self.policy - self.policy = policy - self.bookkeeper.enter(None) - try: + def get_call_parameters(self, function, args_s): + with self.bookkeeper.at_position(None): + desc = self.bookkeeper.getdesc(function) return desc.get_call_parameters(args_s) - finally: - self.bookkeeper.leave() - self.policy = prevpolicy def annotate_helper(self, function, args_s, policy=None): if policy is None: @@ -107,21 +103,29 @@ # XXX hack annmodel.TLS.check_str_without_nul = ( self.translator.config.translation.check_str_without_nul) - graph, inputcells = self.get_call_parameters(function, args_s, policy) - self.build_graph_types(graph, inputcells, complete_now=False) - self.complete_helpers(policy) + with self.using_policy(policy): + graph, inputcells = self.get_call_parameters(function, args_s) + self.build_graph_types(graph, inputcells, complete_now=False) + self.complete_helpers() return graph - def complete_helpers(self, policy): - saved = self.policy, self.added_blocks - self.policy = policy + def complete_helpers(self): + saved = self.added_blocks + self.added_blocks = {} try: - self.added_blocks = {} self.complete() # invoke annotation simplifications for the new blocks self.simplify(block_subset=self.added_blocks) finally: - self.policy, self.added_blocks = saved + self.added_blocks = saved + + @contextmanager + def using_policy(self, policy): + """A context manager that temporarily replaces the annotator policy""" + old_policy = self.policy + self.policy = policy + yield + self.policy = old_policy def build_graph_types(self, flowgraph, inputcells, complete_now=True): checkgraph(flowgraph) diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py --- a/rpython/annotator/bookkeeper.py +++ b/rpython/annotator/bookkeeper.py @@ -9,6 +9,7 @@ from collections import OrderedDict from rpython.flowspace.model import Constant +from rpython.flowspace.bytecode import cpython_code_signature from rpython.annotator.model import ( SomeOrderedDict, SomeString, SomeChar, SomeFloat, unionof, SomeInstance, SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint, @@ -21,6 +22,7 @@ from rpython.annotator import description from rpython.annotator.signature import annotationoftype from rpython.annotator.argument import simple_args +from rpython.annotator.specialize import memo from rpython.rlib.objectmodel import r_dict, r_ordereddict, Symbolic from rpython.tool.algo.unionfind import UnionFind from rpython.rtyper import extregistry @@ -358,7 +360,7 @@ return self.descs[obj_key] except KeyError: if isinstance(pyobj, types.FunctionType): - result = description.FunctionDesc(self, pyobj) + result = self.newfuncdesc(pyobj) elif isinstance(pyobj, (type, types.ClassType)): if pyobj is object: raise Exception("ClassDesc for object not supported") @@ -403,6 +405,23 @@ self.descs[obj_key] = result return result + def newfuncdesc(self, pyfunc): + name = pyfunc.__name__ + if hasattr(pyfunc, '_generator_next_method_of_'): + from rpython.flowspace.argument import Signature + signature = Signature(['entry']) # haaaaaack + defaults = () + else: + signature = cpython_code_signature(pyfunc.func_code) + defaults = pyfunc.func_defaults + # get the specializer based on the tag of the 'pyobj' + # (if any), according to the current policy + tag = getattr(pyfunc, '_annspecialcase_', None) + specializer = self.annotator.policy.get_specializer(tag) + if specializer is memo: + return description.MemoDesc(self, pyfunc, name, signature, defaults, specializer) + return description.FunctionDesc(self, pyfunc, name, signature, defaults, specializer) + def getfrozen(self, pyobj): return description.FrozenDesc(self, pyobj) diff --git a/rpython/annotator/classdesc.py b/rpython/annotator/classdesc.py --- a/rpython/annotator/classdesc.py +++ b/rpython/annotator/classdesc.py @@ -608,7 +608,7 @@ if mixin: # make a new copy of the FunctionDesc for this class, # but don't specialize further for all subclasses - funcdesc = FunctionDesc(self.bookkeeper, value) + funcdesc = self.bookkeeper.newfuncdesc(value) self.classdict[name] = funcdesc return # NB. if value is, say, AssertionError.__init__, then we diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -3,11 +3,10 @@ from rpython.annotator.signature import ( enforce_signature_args, enforce_signature_return, finish_type) from rpython.flowspace.model import FunctionGraph -from rpython.flowspace.bytecode import cpython_code_signature from rpython.annotator.argument import rawshape, ArgErr, simple_args from rpython.tool.sourcetools import valid_identifier from rpython.tool.pairtype import extendabletype -from rpython.annotator.model import AnnotatorError, s_ImpossibleValue +from rpython.annotator.model import AnnotatorError, s_ImpossibleValue, unionof class CallFamily(object): """A family of Desc objects that could be called from common call sites. @@ -117,7 +116,6 @@ self.s_value = s_ImpossibleValue # union of possible values def update(self, other): - from rpython.annotator.model import unionof self.descs.update(other.descs) self.read_locations.update(other.read_locations) self.s_value = unionof(self.s_value, other.s_value) @@ -192,24 +190,12 @@ class FunctionDesc(Desc): knowntype = types.FunctionType - def __init__(self, bookkeeper, pyobj=None, - name=None, signature=None, defaults=None, + def __init__(self, bookkeeper, pyobj, name, signature, defaults, specializer=None): super(FunctionDesc, self).__init__(bookkeeper, pyobj) - if name is None: - name = pyobj.func_name - if signature is None: - if hasattr(pyobj, '_generator_next_method_of_'): - from rpython.flowspace.argument import Signature - signature = Signature(['entry']) # haaaaaack - defaults = () - else: - signature = cpython_code_signature(pyobj.func_code) - if defaults is None: - defaults = pyobj.func_defaults self.name = name self.signature = signature - self.defaults = defaults or () + self.defaults = defaults if defaults is not None else () # 'specializer' is a function with the following signature: # specializer(funcdesc, args_s) => graph # or => s_result (overridden/memo cases) @@ -288,12 +274,43 @@ getattr(self.bookkeeper, "position_key", None) is not None): _, block, i = self.bookkeeper.position_key op = block.operations[i] - if self.specializer is None: - # get the specializer based on the tag of the 'pyobj' - # (if any), according to the current policy - tag = getattr(self.pyobj, '_annspecialcase_', None) - policy = self.bookkeeper.annotator.policy - self.specializer = policy.get_specializer(tag) + self.normalize_args(inputcells) + if getattr(self.pyobj, '_annspecialcase_', '').endswith("call_location"): + return self.specializer(self, inputcells, op) + else: + return self.specializer(self, inputcells) + + def pycall(self, whence, args, s_previous_result, op=None): + inputcells = self.parse_arguments(args) + graph = self.specialize(inputcells, op) + assert isinstance(graph, FunctionGraph) + # if that graph has a different signature, we need to re-parse + # the arguments. + # recreate the args object because inputcells may have been changed + new_args = args.unmatch_signature(self.signature, inputcells) + inputcells = self.parse_arguments(new_args, graph) + annotator = self.bookkeeper.annotator + result = annotator.recursivecall(graph, whence, inputcells) + signature = getattr(self.pyobj, '_signature_', None) + if signature: + sigresult = enforce_signature_return(self, signature[1], result) + if sigresult is not None: + annotator.addpendingblock( + graph, graph.returnblock, [sigresult]) + result = sigresult + # Some specializations may break the invariant of returning + # annotations that are always more general than the previous time. + # We restore it here: + result = unionof(result, s_previous_result) + return result + + def normalize_args(self, inputs_s): + """ + Canonicalize argument annotations into the exact parameter + annotations of a specific specialized graph. + + Note: this method has no return value but mutates its argument instead. + """ enforceargs = getattr(self.pyobj, '_annenforceargs_', None) signature = getattr(self.pyobj, '_signature_', None) if enforceargs and signature: @@ -304,39 +321,9 @@ from rpython.annotator.signature import Sig enforceargs = Sig(*enforceargs) self.pyobj._annenforceargs_ = enforceargs - enforceargs(self, inputcells) # can modify inputcells in-place + enforceargs(self, inputs_s) # can modify inputs_s in-place if signature: - enforce_signature_args(self, signature[0], inputcells) # mutates inputcells - if getattr(self.pyobj, '_annspecialcase_', '').endswith("call_location"): - return self.specializer(self, inputcells, op) - else: - return self.specializer(self, inputcells) - - def pycall(self, whence, args, s_previous_result, op=None): - inputcells = self.parse_arguments(args) - result = self.specialize(inputcells, op) - if isinstance(result, FunctionGraph): - graph = result # common case - annotator = self.bookkeeper.annotator - # if that graph has a different signature, we need to re-parse - # the arguments. - # recreate the args object because inputcells may have been changed - new_args = args.unmatch_signature(self.signature, inputcells) - inputcells = self.parse_arguments(new_args, graph) - result = annotator.recursivecall(graph, whence, inputcells) - signature = getattr(self.pyobj, '_signature_', None) - if signature: - sigresult = enforce_signature_return(self, signature[1], result) - if sigresult is not None: - annotator.addpendingblock( - graph, graph.returnblock, [sigresult]) - result = sigresult - # Some specializations may break the invariant of returning - # annotations that are always more general than the previous time. - # We restore it here: - from rpython.annotator.model import unionof - result = unionof(result, s_previous_result) - return result + enforce_signature_args(self, signature[0], inputs_s) # mutates inputs_s def get_graph(self, args, op): inputs_s = self.parse_arguments(args) @@ -405,6 +392,16 @@ return s_sigs +class MemoDesc(FunctionDesc): + def pycall(self, whence, args, s_previous_result, op=None): + inputcells = self.parse_arguments(args) + s_result = self.specialize(inputcells, op) + if isinstance(s_result, FunctionGraph): + s_result = s_result.getreturnvar().annotation + s_result = unionof(s_result, s_previous_result) + return s_result + + class MethodDesc(Desc): knowntype = types.MethodType diff --git a/rpython/annotator/specialize.py b/rpython/annotator/specialize.py --- a/rpython/annotator/specialize.py +++ b/rpython/annotator/specialize.py @@ -3,11 +3,13 @@ from rpython.tool.sourcetools import func_with_new_name from rpython.tool.algo.unionfind import UnionFind -from rpython.flowspace.model import Block, Link, Variable, SpaceOperation +from rpython.flowspace.model import Block, Link, Variable from rpython.flowspace.model import checkgraph from rpython.flowspace.operation import op from rpython.annotator import model as annmodel from rpython.flowspace.argument import Signature +from rpython.annotator.model import SomePBC, SomeImpossibleValue, SomeBool +from rpython.annotator.model import unionof def flatten_star_args(funcdesc, args_s): argnames, vararg, kwarg = funcdesc.signature @@ -127,7 +129,6 @@ def finish(self): if self.do_not_process: return - from rpython.annotator.model import unionof assert self.graph is None, "MemoTable already finished" # list of which argument positions can take more than one value example_args, example_value = self.table.iteritems().next() @@ -246,34 +247,36 @@ args_s.append(unionof(*values_s)) annotator.addpendinggraph(self.graph, args_s) +def all_values(s): + """Return the exhaustive list of possible values matching annotation `s`. -def memo(funcdesc, arglist_s): - from rpython.annotator.model import SomePBC, SomeImpossibleValue, SomeBool - from rpython.annotator.model import unionof + Raises `AnnotatorError` if no such (reasonably small) finite list exists. + """ + if s.is_constant(): + return [s.const] + elif isinstance(s, SomePBC): + values = [] + assert not s.can_be_None, "memo call: cannot mix None and PBCs" + for desc in s.descriptions: + if desc.pyobj is None: + raise annmodel.AnnotatorError( + "memo call with a class or PBC that has no " + "corresponding Python object (%r)" % (desc,)) + values.append(desc.pyobj) + return values + elif isinstance(s, SomeImpossibleValue): + return [] + elif isinstance(s, SomeBool): + return [False, True] + else: + raise annmodel.AnnotatorError("memo call: argument must be a class " + "or a frozen PBC, got %r" % (s,)) + +def memo(funcdesc, args_s): # call the function now, and collect possible results - argvalues = [] - for s in arglist_s: - if s.is_constant(): - values = [s.const] - elif isinstance(s, SomePBC): - values = [] - assert not s.can_be_None, "memo call: cannot mix None and PBCs" - for desc in s.descriptions: - if desc.pyobj is None: - raise annmodel.AnnotatorError( - "memo call with a class or PBC that has no " - "corresponding Python object (%r)" % (desc,)) - values.append(desc.pyobj) - elif isinstance(s, SomeImpossibleValue): - return s # we will probably get more possible args later - elif isinstance(s, SomeBool): - values = [False, True] - else: - raise annmodel.AnnotatorError("memo call: argument must be a class " - "or a frozen PBC, got %r" % (s,)) - argvalues.append(values) + # the list of all possible tuples of arguments to give to the memo function - possiblevalues = cartesian_product(argvalues) + possiblevalues = cartesian_product([all_values(s_arg) for s_arg in args_s]) # a MemoTable factory -- one MemoTable per family of arguments that can # be called together, merged via a UnionFind. 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 @@ -2936,6 +2936,12 @@ self._pyobj(pyobject).ob_pypy_link = objint # there is no rrc_o_dict + def rawrefcount_mark_deallocating(self, gcobj, pyobject): + ll_assert(self.rrc_enabled, "rawrefcount.init not called") + obj = llmemory.cast_ptr_to_adr(gcobj) # should be a prebuilt obj + objint = llmemory.cast_adr_to_int(obj, "symbolic") + self._pyobj(pyobject).ob_pypy_link = objint + def rawrefcount_from_obj(self, gcobj): obj = llmemory.cast_ptr_to_adr(gcobj) if self.is_in_nursery(obj): 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 @@ -476,6 +476,10 @@ GCClass.rawrefcount_create_link_pyobj, [s_gc, s_gcref, SomeAddress()], annmodel.s_None) + self.rawrefcount_mark_deallocating = getfn( + GCClass.rawrefcount_mark_deallocating, + [s_gc, s_gcref, SomeAddress()], + annmodel.s_None) self.rawrefcount_from_obj_ptr = getfn( GCClass.rawrefcount_from_obj, [s_gc, s_gcref], SomeAddress(), inline = True) @@ -1281,6 +1285,14 @@ [self.rawrefcount_create_link_pyobj_ptr, self.c_const_gc, v_gcobj, v_pyobject]) + def gct_gc_rawrefcount_mark_deallocating(self, hop): + [v_gcobj, v_pyobject] = hop.spaceop.args + assert v_gcobj.concretetype == llmemory.GCREF + assert v_pyobject.concretetype == llmemory.Address + hop.genop("direct_call", + [self.rawrefcount_mark_deallocating, self.c_const_gc, + v_gcobj, v_pyobject]) + def gct_gc_rawrefcount_from_obj(self, hop): [v_gcobj] = hop.spaceop.args assert v_gcobj.concretetype == llmemory.GCREF diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -3,7 +3,7 @@ import py from rpython.rlib.nonconst import NonConstant -from rpython.rlib.objectmodel import CDefinedIntSymbolic, keepalive_until_here, specialize, not_rpython +from rpython.rlib.objectmodel import CDefinedIntSymbolic, keepalive_until_here, specialize, not_rpython, we_are_translated from rpython.rlib.unroll import unrolling_iterable from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.tool.sourcetools import rpython_wrapper @@ -1221,7 +1221,8 @@ x = jit.conditional_call_elidable(self.cache, _compute_and_cache, ...) """ - if we_are_jitted(): + if we_are_translated() and we_are_jitted(): + #^^^ the occasional test patches we_are_jitted() to True return _jit_conditional_call_value(value, function, *args) else: if isinstance(value, int): diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py --- a/rpython/rlib/rarithmetic.py +++ b/rpython/rlib/rarithmetic.py @@ -25,6 +25,10 @@ lltype.Unsigned, widen it to lltype.Signed. Useful because the translator doesn't support arithmetic on the smaller types. +ovfcheck_int32_add/sub/mul(x, y) + perform an add/sub/mul between two regular integers, + but assumes that they fit inside signed 32-bit ints + and raises OverflowError if the result no longer does These are meant to be erased by translation, r_uint in the process should mark unsigned values, ovfcheck should @@ -796,6 +800,47 @@ return longlong2float(rffi.cast(rffi.LONGLONG, res)) return rffi.cast(T, res) +if sys.maxint == 2147483647: + def ovfcheck_int32_add(x, y): + return ovfcheck(x + y) + def ovfcheck_int32_sub(x, y): + return ovfcheck(x - y) + def ovfcheck_int32_mul(x, y): + return ovfcheck(x * y) +else: + def ovfcheck_int32_add(x, y): + """x and y are assumed to fit inside the 32-bit rffi.INT; + raises OverflowError if the result doesn't fit rffi.INT""" + from rpython.rtyper.lltypesystem import lltype, rffi + x = rffi.cast(lltype.Signed, x) + y = rffi.cast(lltype.Signed, y) + z = x + y + if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)): + raise OverflowError + return z + + def ovfcheck_int32_sub(x, y): + """x and y are assumed to fit inside the 32-bit rffi.INT; + raises OverflowError if the result doesn't fit rffi.INT""" + from rpython.rtyper.lltypesystem import lltype, rffi + x = rffi.cast(lltype.Signed, x) + y = rffi.cast(lltype.Signed, y) + z = x - y + if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)): + raise OverflowError + return z + + def ovfcheck_int32_mul(x, y): + """x and y are assumed to fit inside the 32-bit rffi.INT; + raises OverflowError if the result doesn't fit rffi.INT""" + from rpython.rtyper.lltypesystem import lltype, rffi + x = rffi.cast(lltype.Signed, x) + y = rffi.cast(lltype.Signed, y) + z = x * y + if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)): + raise OverflowError + return z + # String parsing support # --------------------------- diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py --- a/rpython/rlib/rawrefcount.py +++ b/rpython/rlib/rawrefcount.py @@ -36,6 +36,7 @@ _pypy2ob = {} _pypy2ob_rev = {} _d_list = [] + _d_marker = None _dealloc_trigger_callback = dealloc_trigger_callback @not_rpython @@ -62,6 +63,14 @@ _o_list.append(ob) @not_rpython +def mark_deallocating(marker, ob): + """mark the PyObject as deallocating, by storing 'marker' + inside its ob_pypy_link field""" + assert ob._obj not in _pypy2ob_rev + assert not ob.c_ob_pypy_link + ob.c_ob_pypy_link = _build_pypy_link(marker) + +@not_rpython def from_obj(OB_PTR_TYPE, p): ob = _pypy2ob.get(p) if ob is None: @@ -221,7 +230,7 @@ class Entry(ExtRegistryEntry): - _about_ = (create_link_pypy, create_link_pyobj) + _about_ = (create_link_pypy, create_link_pyobj, mark_deallocating) def compute_result_annotation(self, s_p, s_ob): pass @@ -231,6 +240,8 @@ name = 'gc_rawrefcount_create_link_pypy' elif self.instance is create_link_pyobj: name = 'gc_rawrefcount_create_link_pyobj' + elif self.instance is mark_deallocating: + name = 'gc_rawrefcount_mark_deallocating' v_p, v_ob = hop.inputargs(*hop.args_r) hop.exception_cannot_occur() hop.genop(name, [_unspec_p(hop, v_p), _unspec_ob(hop, v_ob)]) diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py --- a/rpython/rlib/rjitlog/rjitlog.py +++ b/rpython/rlib/rjitlog/rjitlog.py @@ -13,6 +13,7 @@ from rpython.jit.metainterp.resoperation import rop from rpython.jit.metainterp.history import ConstInt, ConstFloat from rpython.rlib.objectmodel import we_are_translated +from rpython.rlib.rarithmetic import r_longlong from rpython.rtyper.lltypesystem import lltype, llmemory, rffi from rpython.rlib.objectmodel import compute_unique_id, always_inline from rpython.rlib.objectmodel import we_are_translated, specialize @@ -113,6 +114,7 @@ @always_inline def encode_le_64bit(val): + val = r_longlong(val) # force 64-bit, even on 32-bit return ''.join([chr((val >> 0) & 0xff), chr((val >> 8) & 0xff), chr((val >> 16) & 0xff), diff --git a/rpython/rlib/rurandom.py b/rpython/rlib/rurandom.py --- a/rpython/rlib/rurandom.py +++ b/rpython/rlib/rurandom.py @@ -75,16 +75,6 @@ return rffi.charpsize2str(rffi.cast(rffi.CCHARP, buf), n) -elif 0: # __VMS - from rpython.rlib.ropenssl import libssl_RAND_pseudo_bytes - def init_urandom(): - pass - - def urandom(context, n): - with rffi.scoped_alloc_buffer(n) as buf: - if libssl_RAND_pseudo_bytes(self.raw, n) < 0: - raise ValueError("RAND_pseudo_bytes") - return buf.str(n) else: # Posix implementation @not_rpython def init_urandom(): diff --git a/rpython/rlib/rvmprof/src/vmprof_getpc.h b/rpython/rlib/rvmprof/src/vmprof_getpc.h --- a/rpython/rlib/rvmprof/src/vmprof_getpc.h +++ b/rpython/rlib/rvmprof/src/vmprof_getpc.h @@ -126,13 +126,14 @@ // how we'd get the PC (using StackWalk64?) // http://msdn2.microsoft.com/en-us/library/ms680650.aspx -#include "base/logging.h" // for RAW_LOG -#ifndef HAVE_CYGWIN_SIGNAL_H -typedef int ucontext_t; -#endif +// #include "base/logging.h" // for RAW_LOG +// #ifndef HAVE_CYGWIN_SIGNAL_H +// typedef int ucontext_t; +// #endif intptr_t GetPC(ucontext_t *signal_ucontext) { - RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); + // RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n"); + fprintf(stderr, "GetPC is not yet implemented on Windows\n"); return NULL; } diff --git a/rpython/rlib/test/test_rarithmetic.py b/rpython/rlib/test/test_rarithmetic.py --- a/rpython/rlib/test/test_rarithmetic.py +++ b/rpython/rlib/test/test_rarithmetic.py @@ -675,3 +675,11 @@ assert a ^ r_uint32(42) == "a^42" assert r_uint32(42) ** a == "42**a" assert a ** r_uint32(42) == "a**42" + +def test_ovfcheck_int32(): + assert ovfcheck_int32_add(-2**30, -2**30) == -2**31 + py.test.raises(OverflowError, ovfcheck_int32_add, 2**30, 2**30) + assert ovfcheck_int32_sub(-2**30, 2**30) == -2**31 + py.test.raises(OverflowError, ovfcheck_int32_sub, 2**30, -2**30) + assert ovfcheck_int32_mul(-2**16, 2**15) == -2**31 + py.test.raises(OverflowError, ovfcheck_int32_mul, -2**16, -2**15) diff --git a/rpython/rlib/test/test_rawrefcount.py b/rpython/rlib/test/test_rawrefcount.py --- a/rpython/rlib/test/test_rawrefcount.py +++ b/rpython/rlib/test/test_rawrefcount.py @@ -212,6 +212,15 @@ assert rawrefcount.to_obj(W_Root, ob) == p lltype.free(ob, flavor='raw') + def test_mark_deallocating(self): + ob = lltype.malloc(PyObjectS, flavor='raw', zero=True) + w_marker = W_Root(42) + rawrefcount.mark_deallocating(w_marker, ob) + assert rawrefcount.to_obj(W_Root, ob) is w_marker + rawrefcount._collect() + assert rawrefcount.to_obj(W_Root, ob) is w_marker + lltype.free(ob, flavor='raw') + class TestTranslated(StandaloneTests): @@ -222,6 +231,7 @@ state.seen = [] def dealloc_trigger(): state.seen.append(1) + w_marker = W_Root(-1) def make_p(): p = W_Root(42) @@ -257,6 +267,13 @@ if rawrefcount.next_dead(PyObject) != lltype.nullptr(PyObjectS): print "NEXT_DEAD second time != NULL" return 1 + if rawrefcount.to_obj(W_Root, ob) is not None: + print "to_obj(dead) is not None?" + return 1 + rawrefcount.mark_deallocating(w_marker, ob) + if rawrefcount.to_obj(W_Root, ob) is not w_marker: + print "to_obj(marked-dead) is not w_marker" + return 1 print "OK!" lltype.free(ob, flavor='raw') return 0 diff --git a/rpython/rtyper/annlowlevel.py b/rpython/rtyper/annlowlevel.py --- a/rpython/rtyper/annlowlevel.py +++ b/rpython/rtyper/annlowlevel.py @@ -138,11 +138,12 @@ # get the graph of the mix-level helper ll_function and prepare it for # being annotated. Annotation and RTyping should be done in a single shot # at the end with finish(). - graph, args_s = self.rtyper.annotator.get_call_parameters( - ll_function, args_s, policy = self.policy) + ann = self.rtyper.annotator + with ann.using_policy(self.policy): + graph, args_s = ann.get_call_parameters(ll_function, args_s) for v_arg, s_arg in zip(graph.getargs(), args_s): - self.rtyper.annotator.setbinding(v_arg, s_arg) - self.rtyper.annotator.setbinding(graph.getreturnvar(), s_result) + ann.setbinding(v_arg, s_arg) + ann.setbinding(graph.getreturnvar(), s_result) #self.rtyper.annotator.annotated[graph.returnblock] = graph self.pending.append((ll_function, graph, args_s, s_result)) return graph @@ -224,16 +225,17 @@ bk = ann.bookkeeper translator = ann.translator original_graph_count = len(translator.graphs) - for ll_function, graph, args_s, s_result in self.pending: - # mark the return block as already annotated, because the return var - # annotation was forced in getgraph() above. This prevents temporary - # less general values reaching the return block from crashing the - # annotator (on the assert-that-new-binding-is-not-less-general). - ann.annotated[graph.returnblock] = graph - s_function = bk.immutablevalue(ll_function) - bk.emulate_pbc_call(graph, s_function, args_s) - self.newgraphs.add(graph) - ann.complete_helpers(self.policy) + with ann.using_policy(self.policy): + for ll_function, graph, args_s, s_result in self.pending: + # mark the return block as already annotated, because the return var + # annotation was forced in getgraph() above. This prevents temporary + # less general values reaching the return block from crashing the + # annotator (on the assert-that-new-binding-is-not-less-general). + ann.annotated[graph.returnblock] = graph + s_function = bk.immutablevalue(ll_function) + bk.emulate_pbc_call(graph, s_function, args_s) + self.newgraphs.add(graph) + ann.complete_helpers() for ll_function, graph, args_s, s_result in self.pending: s_real_result = ann.binding(graph.getreturnvar()) if s_real_result != s_result: diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -959,6 +959,9 @@ def op_gc_rawrefcount_create_link_pypy(self, *args): raise NotImplementedError("gc_rawrefcount_create_link_pypy") + def op_gc_rawrefcount_mark_deallocating(self, *args): + raise NotImplementedError("gc_rawrefcount_mark_deallocating") + def op_do_malloc_fixedsize(self): raise NotImplementedError("do_malloc_fixedsize") def op_do_malloc_fixedsize_clear(self): diff --git a/rpython/rtyper/lltypesystem/llmemory.py b/rpython/rtyper/lltypesystem/llmemory.py --- a/rpython/rtyper/lltypesystem/llmemory.py +++ b/rpython/rtyper/lltypesystem/llmemory.py @@ -384,7 +384,6 @@ def _sizeof_none(TYPE): assert not TYPE._is_varsize() return ItemOffset(TYPE) -_sizeof_none._annspecialcase_ = 'specialize:memo' @specialize.memo() def _internal_array_field(TYPE): 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 @@ -490,6 +490,7 @@ 'gc_rawrefcount_init': LLOp(), 'gc_rawrefcount_create_link_pypy': LLOp(), 'gc_rawrefcount_create_link_pyobj': LLOp(), + 'gc_rawrefcount_mark_deallocating': LLOp(), 'gc_rawrefcount_from_obj': LLOp(sideeffects=False), 'gc_rawrefcount_to_obj': LLOp(sideeffects=False), diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -7,7 +7,7 @@ from rpython.rtyper.lltypesystem.llmemory import itemoffsetof from rpython.rtyper.llannotation import lltype_to_annotation from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib.objectmodel import Symbolic +from rpython.rlib.objectmodel import Symbolic, specialize from rpython.rlib.objectmodel import keepalive_until_here, enforceargs from rpython.rlib import rarithmetic, rgc from rpython.rtyper.extregistry import ExtRegistryEntry @@ -74,7 +74,7 @@ def llexternal(name, args, result, _callable=None, compilation_info=ExternalCompilationInfo(), sandboxsafe=False, releasegil='auto', - _nowrapper=False, calling_conv='c', + _nowrapper=False, calling_conv=None, elidable_function=False, macro=None, random_effects_on_gcobjs='auto', save_err=RFFI_ERR_NONE): @@ -96,7 +96,17 @@ we consider that the function is really short-running and don't bother releasing the GIL. An explicit True or False overrides this logic. + + calling_conv: if 'unknown' or 'win', the C function is not directly seen + by the JIT. If 'c', it can be seen (depending on + releasegil=False). For tests only, or if _nowrapper, + it defaults to 'c'. """ + if calling_conv is None: + if sys.platform == 'win32' and not _nowrapper: + calling_conv = 'unknown' + else: + calling_conv = 'c' if _callable is not None: assert callable(_callable) ext_type = lltype.FuncType(args, result) @@ -107,7 +117,8 @@ _callable = generate_macro_wrapper( name, macro, ext_type, compilation_info) else: - _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv) + _callable = ll2ctypes.LL2CtypesCallable(ext_type, + 'c' if calling_conv == 'unknown' else calling_conv) else: assert macro is None, "'macro' is useless if you specify '_callable'" if elidable_function: @@ -205,11 +216,17 @@ else: # if we don't have to invoke the GIL handling, we can just call # the low-level function pointer carelessly - if macro is None and save_err == RFFI_ERR_NONE: + # ...well, unless it's a macro, in which case we still have + # to hide it from the JIT... + need_wrapper = (macro is not None or save_err != RFFI_ERR_NONE) + # ...and unless we're on Windows and the calling convention is + # 'win' or 'unknown' + if calling_conv != 'c': + need_wrapper = True + # + if not need_wrapper: call_external_function = funcptr else: - # ...well, unless it's a macro, in which case we still have - # to hide it from the JIT... argnames = ', '.join(['a%d' % i for i in range(len(args))]) source = py.code.Source(""" def call_external_function(%(argnames)s): @@ -308,10 +325,6 @@ # for debugging, stick ll func ptr to that wrapper._ptr = funcptr wrapper = func_with_new_name(wrapper, name) - - if calling_conv != "c": - wrapper = jit.dont_look_inside(wrapper) - return wrapper @@ -1288,10 +1301,12 @@ c_memcpy = llexternal("memcpy", [VOIDP, VOIDP, SIZE_T], lltype.Void, - releasegil=False + releasegil=False, + calling_conv='c', ) c_memset = llexternal("memset", [VOIDP, lltype.Signed, SIZE_T], lltype.Void, - releasegil=False + releasegil=False, + calling_conv='c', ) diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py --- a/rpython/rtyper/rpbc.py +++ b/rpython/rtyper/rpbc.py @@ -362,9 +362,9 @@ def get_concrete_llfn(self, s_pbc, args_s, op): bk = self.rtyper.annotator.bookkeeper funcdesc, = s_pbc.descriptions - args = simple_args(args_s) with bk.at_position(None): - graph = funcdesc.get_graph(args, op) + argspec = simple_args(args_s) + graph = funcdesc.get_graph(argspec, op) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit