Author: Richard Plangger <[email protected]>
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)
[email protected](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)'
[email protected](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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit