Author: Matti Picus <[email protected]>
Branch: pycheck-macros
Changeset: r92342:568bae2b4fa4
Date: 2017-09-06 21:26 +0300
http://bitbucket.org/pypy/pypy/changeset/568bae2b4fa4/
Log: merge default into branch
diff too long, truncating to 2000 out of 2013 lines
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -119,8 +119,15 @@
To run untranslated tests, you need the Boehm garbage collector libgc.
-On Debian and Ubuntu, this is the command to install all build-time
-dependencies::
+On recent Debian and Ubuntu (like 17.04), this is the command to install
+all build-time dependencies::
+
+ apt-get install gcc make libffi-dev pkg-config zlib1g-dev libbz2-dev \
+ libsqlite3-dev libncurses5-dev libexpat1-dev libssl-dev libgdbm-dev \
+ tk-dev libgc-dev python-cffi \
+ liblzma-dev libncursesw5-dev # these two only needed on PyPy3
+
+On older Debian and Ubuntu (12.04 to 16.04)::
apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \
libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev \
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -535,6 +535,11 @@
or ``float`` subtypes. Currently PyPy does not support the
``__class__`` attribute assignment for any non heaptype subtype.
+* In PyPy, module and class dictionaries are optimized under the assumption
+ that deleting attributes from them are rare. Because of this, e.g.
+ ``del foo.bar`` where ``foo`` is a module (or class) that contains the
+ function ``bar``, is significantly slower than CPython.
+
.. _`is ignored in PyPy`: http://bugs.python.org/issue14621
.. _`little point`:
http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -73,3 +73,7 @@
Add support for leakfinder in cpyext tests (disabled for now, due to too many
failures).
+
+.. branch: pypy_swappedbytes
+
+Added ``_swappedbytes_`` support for ``ctypes.Structure``
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1629,12 +1629,15 @@
# return text_w(w_obj) or None
return None if self.is_none(w_obj) else self.text_w(w_obj)
+ @specialize.argtype(1)
def bytes_w(self, w_obj):
""" Takes an application level :py:class:`bytes`
(on PyPy2 this equals `str`) and returns a rpython byte string.
"""
+ assert w_obj is not None
return w_obj.str_w(self)
+ @specialize.argtype(1)
def text_w(self, w_obj):
""" PyPy2 takes either a :py:class:`str` and returns a
rpython byte string, or it takes an :py:class:`unicode`
@@ -1644,6 +1647,7 @@
On PyPy3 it takes a :py:class:`str` and it will return
an utf-8 encoded rpython string.
"""
+ assert w_obj is not None
return w_obj.str_w(self)
@not_rpython # tests only; should be replaced with bytes_w or text_w
@@ -1692,6 +1696,7 @@
raise oefmt(self.w_ValueError, "byte must be in range(0, 256)")
return chr(value)
+ @specialize.argtype(1)
def int_w(self, w_obj, allow_conversion=True):
"""
Unwrap an app-level int object into an interpret-level int.
@@ -1704,26 +1709,35 @@
If allow_conversion=False, w_obj needs to be an app-level int or a
subclass.
"""
+ assert w_obj is not None
return w_obj.int_w(self, allow_conversion)
+ @specialize.argtype(1)
def int(self, w_obj):
+ assert w_obj is not None
return w_obj.int(self)
+ @specialize.argtype(1)
def uint_w(self, w_obj):
+ assert w_obj is not None
return w_obj.uint_w(self)
+ @specialize.argtype(1)
def bigint_w(self, w_obj, allow_conversion=True):
"""
Like int_w, but return a rlib.rbigint object and call __long__ if
allow_conversion is True.
"""
+ assert w_obj is not None
return w_obj.bigint_w(self, allow_conversion)
+ @specialize.argtype(1)
def float_w(self, w_obj, allow_conversion=True):
"""
Like int_w, but return an interp-level float and call __float__ if
allow_conversion is True.
"""
+ assert w_obj is not None
return w_obj.float_w(self, allow_conversion)
def realtext_w(self, w_obj):
@@ -1733,7 +1747,9 @@
raise oefmt(self.w_TypeError, "argument must be a string")
return self.bytes_w(w_obj)
+ @specialize.argtype(1)
def unicode_w(self, w_obj):
+ assert w_obj is not None
return w_obj.unicode_w(self)
def unicode0_w(self, w_obj):
@@ -1758,7 +1774,9 @@
# This is here mostly just for gateway.int_unwrapping_space_method().
return bool(self.int_w(w_obj))
+ @specialize.argtype(1)
def ord(self, w_obj):
+ assert w_obj is not None
return w_obj.ord(self)
# This is all interface for gateway.py.
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
@@ -40,6 +40,7 @@
from rpython.rlib import rawrefcount
from rpython.rlib import rthread
from rpython.rlib.debug import fatalerror_notb
+from rpython.rlib import rstackovf
from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
from pypy.module.cpyext.cparser import CTypeSpace
@@ -984,6 +985,11 @@
message = str(e)
state.set_exception(OperationError(space.w_SystemError,
space.newtext(message)))
+ except rstackovf.StackOverflow as e:
+ rstackovf.check_stack_overflow()
+ failed = True
+ state.set_exception(OperationError(space.w_RuntimeError,
+ space.newtext("maximum recursion depth exceeded")))
else:
failed = False
diff --git a/pypy/module/cpyext/test/test_cpyext.py
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -136,7 +136,7 @@
"""Base class for all cpyext tests."""
spaceconfig = dict(usemodules=['cpyext', 'thread', 'struct', 'array',
'itertools', 'time', 'binascii',
- 'micronumpy', 'mmap'
+ 'mmap'
])
@classmethod
diff --git a/pypy/module/cpyext/test/test_memoryobject.py
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -125,52 +125,6 @@
ten = foo.test_buffer(arr)
assert ten == 10
- @pytest.mark.skipif(only_pypy, reason='pypy only test')
- def test_buffer_info(self):
- try:
- from _numpypy import multiarray as np
- except ImportError:
- skip('pypy built without _numpypy')
- module = self.import_module(name='buffer_test')
- get_buffer_info = module.get_buffer_info
- raises(ValueError, get_buffer_info, np.arange(5)[::2], ('SIMPLE',))
- arr = np.zeros((1, 10), order='F')
- shape, strides = get_buffer_info(arr, ['F_CONTIGUOUS'])
- assert strides[0] == 8
- arr = np.zeros((10, 1), order='C')
- shape, strides = get_buffer_info(arr, ['C_CONTIGUOUS'])
- assert strides[-1] == 8
- dt1 = np.dtype(
- [('a', 'b'), ('b', 'i'),
- ('sub0', np.dtype('b,i')),
- ('sub1', np.dtype('b,i')),
- ('sub2', np.dtype('b,i')),
- ('sub3', np.dtype('b,i')),
- ('sub4', np.dtype('b,i')),
- ('sub5', np.dtype('b,i')),
- ('sub6', np.dtype('b,i')),
- ('sub7', np.dtype('b,i')),
- ('c', 'i')],
- )
- x = np.arange(dt1.itemsize, dtype='int8').view(dt1)
- # pytest can catch warnings from v2.8 and up, we ship 2.5
- import warnings
- warnings.filterwarnings("error")
- try:
- try:
- y = get_buffer_info(x, ['SIMPLE'])
- except UserWarning as e:
- pass
- else:
- assert False ,"PyPy-specific UserWarning not raised" \
- " on too long format string"
- finally:
- warnings.resetwarnings()
- # calling get_buffer_info on x creates a memory leak,
- # which is detected as an error at test teardown:
- # Exception TypeError: "'NoneType' object is not callable"
- # in <bound method ConcreteArray.__del__ ...> ignored
-
def test_releasebuffer(self):
module = self.import_extension('foo', [
("create_test", "METH_NOARGS",
@@ -240,3 +194,55 @@
self.debug_collect()
assert module.get_cnt() == 0
assert module.get_dealloc_cnt() == 1
+
+class AppTestBufferInfo(AppTestCpythonExtensionBase):
+ spaceconfig = AppTestCpythonExtensionBase.spaceconfig.copy()
+ spaceconfig['usemodules'].append('micronumpy')
+
+ @pytest.mark.skipif(only_pypy, reason='pypy only test')
+ def test_buffer_info(self):
+ try:
+ from _numpypy import multiarray as np
+ except ImportError:
+ skip('pypy built without _numpypy')
+ module = self.import_module(name='buffer_test')
+ get_buffer_info = module.get_buffer_info
+ raises(ValueError, get_buffer_info, np.arange(5)[::2], ('SIMPLE',))
+ arr = np.zeros((1, 10), order='F')
+ shape, strides = get_buffer_info(arr, ['F_CONTIGUOUS'])
+ assert strides[0] == 8
+ arr = np.zeros((10, 1), order='C')
+ shape, strides = get_buffer_info(arr, ['C_CONTIGUOUS'])
+ assert strides[-1] == 8
+ dt1 = np.dtype(
+ [('a', 'b'), ('b', 'i'),
+ ('sub0', np.dtype('b,i')),
+ ('sub1', np.dtype('b,i')),
+ ('sub2', np.dtype('b,i')),
+ ('sub3', np.dtype('b,i')),
+ ('sub4', np.dtype('b,i')),
+ ('sub5', np.dtype('b,i')),
+ ('sub6', np.dtype('b,i')),
+ ('sub7', np.dtype('b,i')),
+ ('c', 'i')],
+ )
+ x = np.arange(dt1.itemsize, dtype='int8').view(dt1)
+ # pytest can catch warnings from v2.8 and up, we ship 2.5
+ import warnings
+ warnings.filterwarnings("error")
+ try:
+ try:
+ y = get_buffer_info(x, ['SIMPLE'])
+ except UserWarning as e:
+ pass
+ else:
+ assert False ,"PyPy-specific UserWarning not raised" \
+ " on too long format string"
+ finally:
+ warnings.resetwarnings()
+ # calling get_buffer_info on x creates a memory leak,
+ # which is detected as an error at test teardown:
+ # Exception TypeError: "'NoneType' object is not callable"
+ # in <bound method ConcreteArray.__del__ ...> ignored
+
+
diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py
b/pypy/module/cpyext/test/test_ndarrayobject.py
--- a/pypy/module/cpyext/test/test_ndarrayobject.py
+++ b/pypy/module/cpyext/test/test_ndarrayobject.py
@@ -26,6 +26,8 @@
NULL = lltype.nullptr(rffi.VOIDP.TO)
class TestNDArrayObject(BaseApiTest):
+ spaceconfig = AppTestCpythonExtensionBase.spaceconfig.copy()
+ spaceconfig['usemodules'].append('micronumpy')
def test_Check(self, space, api):
a = array(space, [10, 5, 3])
diff --git a/pypy/module/itertools/test/test_itertools.py
b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -1,7 +1,7 @@
import py
-class AppTestItertools:
+class AppTestItertools(object):
spaceconfig = dict(usemodules=['itertools'])
def test_count(self):
@@ -330,11 +330,11 @@
def test_chain(self):
import itertools
-
+
it = itertools.chain()
raises(StopIteration, it.next)
raises(StopIteration, it.next)
-
+
it = itertools.chain([1, 2, 3])
for x in [1, 2, 3]:
assert it.next() == x
@@ -378,7 +378,7 @@
def test_imap_wrongargs(self):
import itertools
-
+
# Duplicate python 2.4 behaviour for invalid arguments
it = itertools.imap(0, [])
raises(StopIteration, it.next)
@@ -401,11 +401,11 @@
for x in obj_list:
assert it.next() == (x, )
raises(StopIteration, it.next)
-
+
it = itertools.izip([1, 2, 3], [4], [5, 6])
assert it.next() == (1, 4, 5)
raises(StopIteration, it.next)
-
+
it = itertools.izip([], [], [1], [])
raises(StopIteration, it.next)
@@ -423,7 +423,7 @@
def test_izip_wrongargs(self):
import itertools, re
-
+
# Duplicate python 2.4 behaviour for invalid arguments
raises(TypeError, itertools.izip, None, 0)
@@ -442,7 +442,7 @@
it = itertools.cycle([])
raises(StopIteration, it.next)
-
+
it = itertools.cycle([1, 2, 3])
for x in [1, 2, 3, 1, 2, 3, 1, 2, 3]:
assert it.next() == x
@@ -498,7 +498,7 @@
def test_tee_wrongargs(self):
import itertools
-
+
raises(TypeError, itertools.tee, 0)
raises(ValueError, itertools.tee, [], -1)
raises(TypeError, itertools.tee, [], None)
@@ -536,7 +536,7 @@
def test_groupby(self):
import itertools
-
+
it = itertools.groupby([])
raises(StopIteration, it.next)
@@ -613,7 +613,7 @@
assert g.next() is x
raises(StopIteration, g.next)
raises(StopIteration, it.next)
-
+
# Grouping is based on key equality
class AlwaysEqual(object):
def __eq__(self, other):
@@ -647,7 +647,7 @@
def test_iterables(self):
import itertools
-
+
iterables = [
itertools.chain(),
itertools.count(),
@@ -665,7 +665,7 @@
itertools.tee([])[0],
itertools.tee([])[1],
]
-
+
for it in iterables:
assert hasattr(it, '__iter__')
assert iter(it) is it
@@ -674,7 +674,7 @@
def test_docstrings(self):
import itertools
-
+
assert itertools.__doc__
methods = [
itertools.chain,
@@ -756,15 +756,9 @@
assert itertools.tee(a, 0) == ()
-class AppTestItertools26:
+class AppTestItertools26(object):
spaceconfig = dict(usemodules=['itertools'])
- def setup_class(cls):
- if cls.space.is_true(cls.space.appexec([], """():
- import sys; return sys.version_info < (2, 6)
- """)):
- py.test.skip("Requires Python 2.6")
-
def test_count_overflow(self):
import itertools, sys
it = itertools.count(sys.maxint - 1)
@@ -1010,16 +1004,8 @@
raises(ValueError, permutations, [1, 2], -1)
-class AppTestItertools27:
- spaceconfig = {
- "usemodules": ['itertools', 'struct', 'binascii'],
- }
-
- def setup_class(cls):
- if cls.space.is_true(cls.space.appexec([], """():
- import sys; return sys.version_info < (2, 7)
- """)):
- py.test.skip("Requires Python 2.7")
+class AppTestItertools27(object):
+ spaceconfig = {"usemodules": ['itertools', 'struct', 'binascii']}
def test_compress(self):
import itertools
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -116,10 +116,10 @@
if check_int_or_float:
for w_obj in list_w:
if type(w_obj) is W_IntObject:
- if longlong2float.can_encode_int32(space.int_w(w_obj)):
+ if longlong2float.can_encode_int32(w_obj.int_w(space)):
continue # ok
elif type(w_obj) is W_FloatObject:
- if longlong2float.can_encode_float(space.float_w(w_obj)):
+ if longlong2float.can_encode_float(w_obj.float_w(space)):
continue # ok
break
else:
diff --git a/pypy/objspace/std/specialisedtupleobject.py
b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -31,23 +31,23 @@
class cls(W_AbstractTupleObject):
_immutable_fields_ = ['value%s' % i for i in iter_n]
- def __init__(self, space, *values_w):
+ def __init__(self, space, *values):
self.space = space
- assert len(values_w) == typelen
+ assert len(values) == typelen
for i in iter_n:
- w_obj = values_w[i]
+ obj = values[i]
val_type = typetuple[i]
if val_type == int:
- unwrapped = w_obj.int_w(space)
+ assert isinstance(obj, int)
elif val_type == float:
- unwrapped = w_obj.float_w(space)
+ assert isinstance(obj, float)
elif val_type == str:
- unwrapped = w_obj.str_w(space)
+ assert isinstance(obj, str)
elif val_type == object:
- unwrapped = w_obj
+ pass
else:
raise AssertionError
- setattr(self, 'value%s' % i, unwrapped)
+ setattr(self, 'value%s' % i, obj)
def length(self):
return typelen
@@ -150,10 +150,10 @@
w_arg1, w_arg2 = list_w
if type(w_arg1) is W_IntObject:
if type(w_arg2) is W_IntObject:
- return Cls_ii(space, w_arg1, w_arg2)
+ return Cls_ii(space, space.int_w(w_arg1), space.int_w(w_arg2))
elif type(w_arg1) is W_FloatObject:
if type(w_arg2) is W_FloatObject:
- return Cls_ff(space, w_arg1, w_arg2)
+ return Cls_ff(space, space.float_w(w_arg1),
space.float_w(w_arg2))
return Cls_oo(space, w_arg1, w_arg2)
else:
raise NotSpecialised
@@ -170,10 +170,9 @@
# faster to move the decision out of the loop.
@specialize.arg(1)
-def _build_zipped_spec(space, Cls, lst1, lst2, wrap1, wrap2):
+def _build_zipped_spec(space, Cls, lst1, lst2):
length = min(len(lst1), len(lst2))
- return [Cls(space, wrap1(lst1[i]),
- wrap2(lst2[i])) for i in range(length)]
+ return [Cls(space, lst1[i], lst2[i]) for i in range(length)]
def _build_zipped_spec_oo(space, w_list1, w_list2):
strat1 = w_list1.strategy
@@ -200,8 +199,7 @@
intlist2 = w_list2.getitems_int()
if intlist2 is not None:
lst_w = _build_zipped_spec(
- space, Cls_ii, intlist1, intlist2,
- space.newint, space.newint)
+ space, Cls_ii, intlist1, intlist2)
return space.newlist(lst_w)
else:
floatlist1 = w_list1.getitems_float()
@@ -209,8 +207,7 @@
floatlist2 = w_list2.getitems_float()
if floatlist2 is not None:
lst_w = _build_zipped_spec(
- space, Cls_ff, floatlist1, floatlist2, space.newfloat,
- space.newfloat)
+ space, Cls_ff, floatlist1, floatlist2)
return space.newlist(lst_w)
lst_w = _build_zipped_spec_oo(space, w_list1, w_list2)
diff --git a/rpython/annotator/test/test_annrpython.py
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4644,6 +4644,25 @@
s_exc = a.binding(graphof(a, f).exceptblock.inputargs[1])
assert not s_exc.can_be_none()
+ def test_specialize_argtype_with_subclasses(self):
+ # checks that specialize:argtype() makes two copies of a
+ # function f(), one for the base class and one for the subclass
+ class A:
+ def foo(self):
+ return 123
+ class B(A):
+ def foo(self):
+ return 456
+ def f(x):
+ return x.foo()
+ f._annspecialcase_ = "specialize:argtype(0)"
+ def h(y):
+ if y > 5:
+ f(A())
+ return f(B())
+ a = self.RPythonAnnotator()
+ assert a.build_types(h, [int]).const == 456
+
def g(n):
return [0, 1, 2, n]
diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py
--- a/rpython/jit/codewriter/call.py
+++ b/rpython/jit/codewriter/call.py
@@ -185,8 +185,30 @@
FUNC.RESULT, EffectInfo.MOST_GENERAL)
return (fnaddr, calldescr)
+ def _raise_effect_error(self, op, extraeffect, functype, calling_graph):
+ explanation = []
+ if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
+ explanation =
self.randomeffects_analyzer.explain_analyze_slowly(op)
+ elif extraeffect == EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE:
+ explanation =
self.virtualizable_analyzer.explain_analyze_slowly(op)
+ msg = []
+ if explanation:
+ msg = [
+ "_______ ERROR AT BOTTOM ______",
+ "RPython callstack leading to problem:",
+ ]
+ msg.extend(explanation)
+ msg.append("_______ ERROR: ______")
+ msg.append("operation %r" % op)
+ msg.append("in graph %s" % (calling_graph or "<unknown>"))
+ msg.append("this calls a %s function," % (functype, ))
+ msg.append(" but this contradicts other sources (e.g. it can have
random"
+ " effects): EF=%s" % (extraeffect, ))
+ raise Exception("\n".join(msg))
+
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
- extraeffect=None, extradescr=None):
+ extraeffect=None, extradescr=None,
+ calling_graph=None):
"""Return the calldescr that describes all calls done by 'op'.
This returns a calldescr that we can put in the corresponding
call operation in the calling jitcode. It gets an effectinfo
@@ -202,13 +224,13 @@
ARGS = FUNC.ARGS
if NON_VOID_ARGS != [T for T in ARGS if T is not lltype.Void]:
raise Exception(
- "in operation %r: calling a function with signature %r, "
+ "operation %r in %s: calling a function with signature %r, "
"but passing actual arguments (ignoring voids) of types %r"
- % (op, FUNC, NON_VOID_ARGS))
+ % (op, calling_graph, FUNC, NON_VOID_ARGS))
if RESULT != FUNC.RESULT:
raise Exception(
- "in operation %r: calling a function with signature %r, "
- "but the actual return type is %r" % (op, FUNC, RESULT))
+ "%r in %s: calling a function with signature %r, "
+ "but the actual return type is %r" % (op, calling_graph, FUNC,
RESULT))
# ok
# get the 'elidable' and 'loopinvariant' flags from the function object
elidable = False
@@ -217,7 +239,7 @@
if op.opname == "direct_call":
funcobj = op.args[0].value._obj
assert getattr(funcobj, 'calling_conv', 'c') == 'c', (
- "%r: getcalldescr() with a non-default call ABI" % (op,))
+ "%r in %s: getcalldescr() with a non-default call ABI" % (op,
calling_graph))
func = getattr(funcobj, '_callable', None)
elidable = getattr(func, "_elidable_function_", False)
loopinvariant = getattr(func, "_jit_loop_invariant_", False)
@@ -245,11 +267,11 @@
if not error:
continue
raise Exception(
- "%r is an indirect call to a family of functions "
+ "%r in %s is an indirect call to a family of functions "
"(or methods) that includes %r. However, the latter "
"is marked %r. You need to use an indirection: replace "
"it with a non-marked function/method which calls the "
- "marked function." % (op, graph, error))
+ "marked function." % (op, calling_graph, graph, error))
# build the extraeffect
random_effects = self.randomeffects_analyzer.analyze(op)
if random_effects:
@@ -277,22 +299,17 @@
# check that the result is really as expected
if loopinvariant:
if extraeffect != EffectInfo.EF_LOOPINVARIANT:
- raise Exception(
- "in operation %r: this calls a _jit_loop_invariant_ function,"
- " but this contradicts other sources (e.g. it can have random"
- " effects): EF=%s" % (op, extraeffect))
+ self._raise_effect_error(op, extraeffect,
"_jit_loop_invariant_", calling_graph)
if elidable:
if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
EffectInfo.EF_ELIDABLE_OR_MEMORYERROR,
EffectInfo.EF_ELIDABLE_CAN_RAISE):
- raise Exception(
- "in operation %r: this calls an elidable function,"
- " but this contradicts other sources (e.g. it can have random"
- " effects): EF=%s" % (op, extraeffect))
+
+ self._raise_effect_error(op, extraeffect, "elidable",
calling_graph)
elif RESULT is lltype.Void:
raise Exception(
- "in operation %r: this calls an elidable function "
- "but the function has no result" % (op, ))
+ "operation %r in %s: this calls an elidable function "
+ "but the function has no result" % (op, calling_graph))
#
effectinfo = effectinfo_from_writeanalyze(
self.readwrite_analyzer.analyze(op, self.seen_rw), self.cpu,
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -64,6 +64,7 @@
self.cpu = cpu
self.callcontrol = callcontrol
self.portal_jd = portal_jd # non-None only for the portal graph(s)
+ self.graph = None
def transform(self, graph):
self.graph = graph
@@ -424,7 +425,8 @@
of 'residual_call_xxx' are the function to call, and its calldescr."""
calldescr = self.callcontrol.getcalldescr(op,
oopspecindex=oopspecindex,
extraeffect=extraeffect,
- extradescr=extradescr)
+ extradescr=extradescr,
+ calling_graph=self.graph)
op1 = self.rewrite_call(op, 'residual_call',
[op.args[0]] + extraargs, calldescr=calldescr)
if may_call_jitcodes or self.callcontrol.calldescr_canraise(calldescr):
@@ -1613,7 +1615,9 @@
if len(op.args) > 4 + 2 or have_floats:
raise Exception("Conditional call does not support floats or more
than 4 arguments")
callop = SpaceOperation('direct_call', op.args[1:], op.result)
- calldescr = self.callcontrol.getcalldescr(callop)
+ calldescr = self.callcontrol.getcalldescr(
+ callop,
+ calling_graph=self.graph)
assert not
calldescr.get_extra_info().check_forces_virtual_or_virtualizable()
op1 = self.rewrite_call(op, rewritten_opname,
op.args[:2], args=op.args[2:],
@@ -1924,7 +1928,8 @@
extradescr=None):
calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
extraeffect,
- extradescr=extradescr)
+ extradescr=extradescr,
+ calling_graph=self.graph)
if extraeffect is not None:
assert (is_test_calldescr(calldescr) # for tests
or calldescr.get_extra_info().extraeffect == extraeffect)
@@ -1954,7 +1959,8 @@
[c_func] + [varoftype(T) for T in argtypes],
varoftype(resulttype))
calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
- effectinfo)
+ effectinfo,
+ calling_graph=self.graph)
if isinstance(c_func.value, str): # in tests only
func = c_func.value
else:
diff --git a/rpython/jit/codewriter/test/test_call.py
b/rpython/jit/codewriter/test/test_call.py
--- a/rpython/jit/codewriter/test/test_call.py
+++ b/rpython/jit/codewriter/test/test_call.py
@@ -299,11 +299,23 @@
def f4(n, m):
return compute_hash(str(n) + str(m))
+ T = rffi.CArrayPtr(rffi.TIME_T)
+ external = rffi.llexternal("time", [T], rffi.TIME_T, releasegil=True)
+
+ def effect():
+ return external(lltype.nullptr(T.TO))
+
+ @jit.elidable
+ def f5(n, m):
+ effect()
+ return 1
+
def f(n, m):
a = f1(n, m)
b = f2(n, m)
c = f3(n, m)
d = f4(n, m)
+ f5(n, m)
enable_siphash24()
return a + len(b) + c + d
@@ -323,25 +335,33 @@
call_descr = cc.getcalldescr(call_op)
assert call_descr.extrainfo.extraeffect == expected
+ call_op = f_graph.startblock.operations[4]
+ assert call_op.opname == 'direct_call'
+ excinfo = py.test.raises(Exception, cc.getcalldescr, call_op)
+ lines = excinfo.value.args[0].splitlines()
+ assert "f5" in lines[2]
+ assert "effect" in lines[3]
+ assert "random effects" in lines[-1]
+
def test_raise_elidable_no_result():
from rpython.jit.backend.llgraph.runner import LLGraphCPU
l = []
@jit.elidable
def f1(n, m):
l.append(n)
- def f(n, m):
+ def fancy_graph_name(n, m):
f1(n, m)
return n + m
- rtyper = support.annotate(f, [7, 9])
+ rtyper = support.annotate(fancy_graph_name, [7, 9])
jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
cc = CallControl(LLGraphCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
res = cc.find_all_graphs(FakePolicy())
- [f_graph] = [x for x in res if x.func is f]
+ [f_graph] = [x for x in res if x.func is fancy_graph_name]
call_op = f_graph.startblock.operations[0]
assert call_op.opname == 'direct_call'
- with py.test.raises(Exception):
- call_descr = cc.getcalldescr(call_op)
+ x = py.test.raises(Exception, cc.getcalldescr, call_op,
calling_graph=f_graph)
+ assert "fancy_graph_name" in str(x.value)
def test_can_or_cannot_collect():
from rpython.jit.backend.llgraph.runner import LLGraphCPU
diff --git a/rpython/jit/codewriter/test/test_flatten.py
b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -73,7 +73,7 @@
def guess_call_kind(self, op):
return 'residual'
def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
- extraeffect=None, extradescr=None):
+ extraeffect=None, extradescr=None, calling_graph=None):
try:
name = op.args[0].value._obj._name
if 'cannot_raise' in name or name.startswith('cast_'):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py
b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -48,7 +48,7 @@
def guess_call_kind(self, op):
return 'residual'
def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
- extradescr=None):
+ extradescr=None, calling_graph=None):
return 'calldescr'
def calldescr_canraise(self, calldescr):
return True
@@ -106,7 +106,7 @@
def guess_call_kind(self, op):
return 'builtin'
def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
- extradescr=None):
+ extradescr=None, calling_graph=None):
assert oopspecindex is not None # in this test
EI = effectinfo.EffectInfo
if oopspecindex != EI.OS_ARRAYCOPY:
diff --git a/rpython/jit/codewriter/test/test_list.py
b/rpython/jit/codewriter/test/test_list.py
--- a/rpython/jit/codewriter/test/test_list.py
+++ b/rpython/jit/codewriter/test/test_list.py
@@ -39,7 +39,7 @@
class FakeCallControl:
class getcalldescr(AbstractDescr):
def __init__(self, op, oopspecindex=0, extraeffect=None,
- extradescr=None):
+ extradescr=None, calling_graph=None):
self.op = op
self.oopspecindex = oopspecindex
def __repr__(self):
diff --git a/rpython/jit/metainterp/optimizeopt/info.py
b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -329,11 +329,14 @@
def make_guards(self, op, short, optimizer):
if self._known_class is not None:
- short.append(ResOperation(rop.GUARD_NONNULL, [op]))
if not optimizer.cpu.remove_gctypeptr:
+ short.append(ResOperation(rop.GUARD_NONNULL, [op]))
short.append(ResOperation(rop.GUARD_IS_OBJECT, [op]))
- short.append(ResOperation(rop.GUARD_CLASS,
- [op, self._known_class]))
+ short.append(ResOperation(rop.GUARD_CLASS,
+ [op, self._known_class]))
+ else:
+ short.append(ResOperation(rop.GUARD_NONNULL_CLASS,
+ [op, self._known_class]))
elif self.descr is not None:
short.append(ResOperation(rop.GUARD_NONNULL, [op]))
if not optimizer.cpu.remove_gctypeptr:
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -7541,6 +7541,33 @@
"""
self.optimize_loop(ops, expected, expected_short=short)
+ def test_guards_before_getfields_in_short_preamble_removetypeptr(self,
monkeypatch):
+ monkeypatch.setattr(self.cpu, "remove_gctypeptr", True)
+ ops = """
+ [p0]
+ guard_nonnull_class(p0, ConstClass(node_vtable)) []
+ p1 = getfield_gc_r(p0, descr=nextdescr)
+ guard_nonnull_class(p1, ConstClass(node_vtable)) []
+ p2 = getfield_gc_r(p1, descr=nextdescr)
+ guard_nonnull_class(p2, ConstClass(node_vtable)) []
+ jump(p0)
+ """
+ expected = """
+ [p0, p1]
+ jump(p0, p1)
+ """
+ short = """
+ [p0]
+ guard_nonnull_class(p0, ConstClass(node_vtable)) []
+ p1 = getfield_gc_r(p0, descr=nextdescr)
+ guard_nonnull_class(p1, ConstClass(node_vtable)) []
+ p2 = getfield_gc_r(p1, descr=nextdescr)
+ guard_nonnull_class(p2, ConstClass(node_vtable)) []
+ jump(p1)
+ """
+ self.optimize_loop(ops, expected, expected_short=short)
+
+
def test_forced_virtual_pure_getfield(self):
ops = """
[p0]
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -2,6 +2,7 @@
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.tool import rffi_platform as platform
from rpython.rtyper.lltypesystem.rffi import CCHARP
+from rpython.rlib import jit
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator.platform import platform as target_platform
@@ -190,6 +191,8 @@
IPX_TYPE
+SCM_RIGHTS
+
POLLIN POLLPRI POLLOUT POLLERR POLLHUP POLLNVAL
POLLRDNORM POLLRDBAND POLLWRNORM POLLWEBAND POLLMSG
@@ -260,6 +263,7 @@
sockaddr_ptr = lltype.Ptr(lltype.ForwardReference())
addrinfo_ptr = lltype.Ptr(lltype.ForwardReference())
+
# struct types
CConfig.sockaddr = platform.Struct('struct sockaddr',
[('sa_family', rffi.INT),
@@ -343,6 +347,650 @@
[('ifr_ifindex', rffi.INT),
('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))])
+# insert handler for sendmsg / recvmsg here
+if _POSIX:
+ includes = ['stddef.h',
+ 'sys/socket.h',
+ 'unistd.h',
+ 'string.h',
+ 'stdlib.h',
+ 'errno.h',
+ 'limits.h',
+ 'stdio.h',
+ 'sys/types.h',
+ 'netinet/in.h',
+ 'arpa/inet.h']
+ separate_module_sources = ['''
+
+ // special defines for returning from recvmsg
+ #define BAD_MSG_SIZE_GIVEN -10000
+ #define BAD_ANC_SIZE_GIVEN -10001
+ #define MAL_ANC -10002
+
+ // special defines for returning from sendmsg
+ #define MUL_MSGS_NOT_SUP -1000
+ #define ANC_DATA_TOO_LARGE -1001
+ #define ANC_DATA_TOO_LARGEX -1002
+
+ /*
+ Even though you could, theoretically, receive more than one
message, IF you set the socket option,
+ CPython has hardcoded the message number to 1, and implemented the
option to receive more then 1 in a
+ different socket method: recvmsg_into
+ */
+ #define MSG_IOVLEN 1 // CPython has hardcoded this as well.
+ #if INT_MAX > 0x7fffffff
+ #define SOCKLEN_T_LIMIT 0x7fffffff
+ #else
+ #define SOCKLEN_T_LIMIT INT_MAX
+ #endif
+
+ //
################################################################################################
+ // Recvmsg implementation and associated functions
+
+ // Taken from CPython. Determines the minimum memory space required
for the ancillary data.
+ #ifdef CMSG_SPACE
+ static int
+ cmsg_min_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t space)
+ {
+ size_t cmsg_offset;
+ static const size_t cmsg_len_end = (offsetof(struct cmsghdr,
cmsg_len) +
+ sizeof(cmsgh->cmsg_len));
+
+ /* Note that POSIX allows msg_controllen to be of signed type. */
+ if (cmsgh == NULL || msg->msg_control == NULL)
+ return 0;
+ /* Note that POSIX allows msg_controllen to be of a signed type.
This is
+ annoying under OS X as it's unsigned there and so it triggers a
+ tautological comparison warning under Clang when compared
against 0.
+ Since the check is valid on other platforms, silence the
warning under
+ Clang. */
+ #ifdef __clang__
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wtautological-compare"
+ #endif
+ #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) &&
(__GNUC_MINOR__ > 5)))
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wtype-limits"
+ #endif
+ if (msg->msg_controllen < 0)
+ return 0;
+ #if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) &&
(__GNUC_MINOR__ > 5)))
+ #pragma GCC diagnostic pop
+ #endif
+ #ifdef __clang__
+ #pragma clang diagnostic pop
+ #endif
+ if (space < cmsg_len_end)
+ space = cmsg_len_end;
+ cmsg_offset = (char *)cmsgh - (char *)msg->msg_control;
+ return (cmsg_offset <= (size_t)-1 - space &&
+ cmsg_offset + space <= msg->msg_controllen);
+ }
+ #endif
+
+ // Taken from CPython.
+ #ifdef CMSG_LEN
+ /* If pointer CMSG_DATA(cmsgh) is in buffer msg->msg_control, set
+ *space to number of bytes following it in the buffer and return
+ true; otherwise, return false. Assumes cmsgh, msg->msg_control and
+ msg->msg_controllen are valid. */
+ static int
+ get_cmsg_data_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t
*space)
+ {
+ size_t data_offset;
+ char *data_ptr;
+
+ if ((data_ptr = (char *)CMSG_DATA(cmsgh)) == NULL)
+ return 0;
+ data_offset = data_ptr - (char *)msg->msg_control;
+ if (data_offset > msg->msg_controllen)
+ return 0;
+ *space = msg->msg_controllen - data_offset;
+ return 1;
+ }
+
+ // Taken from CPython.
+ /* If cmsgh is invalid or not contained in the buffer pointed to by
+ msg->msg_control, return -1. If cmsgh is valid and its associated
+ data is entirely contained in the buffer, set *data_len to the
+ length of the associated data and return 0. If only part of the
+ associated data is contained in the buffer but cmsgh is otherwise
+ valid, set *data_len to the length contained in the buffer and
+ return 1. */
+ static int
+ get_cmsg_data_len(struct msghdr *msg, struct cmsghdr *cmsgh, size_t
*data_len)
+ {
+ size_t space, cmsg_data_len;
+
+ if (!cmsg_min_space(msg, cmsgh, CMSG_LEN(0)) ||
+ cmsgh->cmsg_len < CMSG_LEN(0))
+ return -1;
+ cmsg_data_len = cmsgh->cmsg_len - CMSG_LEN(0);
+ if (!get_cmsg_data_space(msg, cmsgh, &space))
+ return -1;
+ if (space >= cmsg_data_len) {
+ *data_len = cmsg_data_len;
+ return 0;
+ }
+ *data_len = space;
+ return 1;
+ }
+ #endif /* CMSG_LEN */
+
+ /*
+ Structure meant to hold the information received after a recvmsg
is performed.
+ Essentially it holds: the address, the message, the ancillary data
and the return flags.
+ I use this structure for 2 main reasons:
+ - keep things ordered
+ - some of the ancillary parameters need to be int not long
(rffi SignedP is actually long*),
+ therefore I cannot use the parameters directly
+ */
+ struct recvmsg_info
+ {
+ struct sockaddr* address; // address fields
+ socklen_t addrlen;
+ int* length_of_messages; // message fields
+ char** messages;
+ int no_of_messages;
+ int size_of_ancillary; // ancillary fields
+ int* levels;
+ int* types;
+ char** file_descr;
+ int* descr_per_ancillary;
+ int retflag; // return flag field
+ };
+
+ /*
+ Wrapper function over recvmsg. Since it returns a lot of data,
+ in a structure that is hard to parse in rffi, it was implemented
in C.
+ All the parameters, save the socket fd, message_size,
ancillary_size
+ will be malloc'd and/or modified.
+ */
+ RPY_EXTERN
+ int recvmsg_implementation(
+ int socket_fd,
+ int message_size,
+ int ancillary_size,
+ int flags,
+ struct sockaddr* address,
+ socklen_t* addrlen,
+ long** length_of_messages,
+ char** messages,
+ long* no_of_messages,
+ long* size_of_ancillary,
+ long** levels,
+ long** types,
+ char** file_descr,
+ long** descr_per_ancillary,
+ long* retflag)
+
+ {
+
+ struct sockaddr* recvd_address;
+ socklen_t recvd_addrlen;
+ struct msghdr msg = {0};
+ void *controlbuf = NULL;
+ struct cmsghdr *cmsgh;
+ int cmsg_status;
+ struct iovec iov;
+ struct recvmsg_info* retinfo;
+ int error_flag; // variable to be set in case of special errors.
+ int cmsgdatalen = 0;
+
+ // variables that are set to 1, if the message charp has been
allocated
+ // and if the ancillary variables have been allocated. To be used
in case of failure.
+ int iov_alloc = 0;
+ int anc_alloc = 0;
+
+ retinfo = (struct recvmsg_info*) malloc(sizeof(struct
recvmsg_info));
+
+ if (ancillary_size > SOCKLEN_T_LIMIT){
+ error_flag = BAD_ANC_SIZE_GIVEN;
+ goto fail;
+ }
+
+ // Setup the messages iov struct memory
+ iov.iov_base = (char*) malloc(message_size);
+ memset(iov.iov_base, 0, message_size);
+ iov.iov_len = message_size;
+
+ // Setup the ancillary buffer memory
+ controlbuf = malloc(ancillary_size);
+
+ // Setup the recv address memory
+ recvd_addrlen = sizeof(struct sockaddr_storage);
+ recvd_address = (struct sockaddr*) malloc(recvd_addrlen);
+
+ memset(recvd_address, 0,recvd_addrlen);
+
+ // Setup the msghdr struct
+ msg.msg_name = recvd_address;
+ msg.msg_namelen = recvd_addrlen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = MSG_IOVLEN;
+ msg.msg_control = controlbuf;
+ msg.msg_controllen = ancillary_size;
+
+ // Link my structure to the msghdr fields
+ retinfo->address = msg.msg_name;
+ retinfo->length_of_messages = (int*) malloc (MSG_IOVLEN *
sizeof(int));
+ retinfo->no_of_messages = MSG_IOVLEN;
+ retinfo->messages = (char**) malloc (MSG_IOVLEN * sizeof(char*));
+ retinfo->messages[0] = msg.msg_iov->iov_base;
+
+ iov_alloc = 1;
+ ssize_t bytes_recvd = 0;
+
+ bytes_recvd = recvmsg(socket_fd, &msg, flags);
+
+ if (bytes_recvd < 0){
+ goto fail;
+ }
+
+ retinfo->addrlen = (socklen_t) msg.msg_namelen;
+ retinfo->length_of_messages[0] = msg.msg_iov->iov_len;
+
+ // Count the ancillary items & allocate the memory
+ int anc_counter = 0;
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) :
NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+
+ anc_counter++;
+ }
+ retinfo->size_of_ancillary = anc_counter;
+ retinfo->file_descr = (char**) malloc (anc_counter *
sizeof(char*));
+ retinfo->levels = (int*) malloc(anc_counter * sizeof(int));
+ retinfo->types = (int*) malloc(anc_counter * sizeof(int));
+ retinfo->descr_per_ancillary = (int*) malloc(anc_counter *
sizeof(int));
+ anc_alloc = 1;
+
+ // Extract the ancillary items
+ int i=0;
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) :
NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+ size_t local_size = 0;
+ cmsg_status = get_cmsg_data_len(&msg, cmsgh, &local_size);
+ if (cmsg_status !=0 ){
+ error_flag = MAL_ANC;
+ goto err_closefds;
+ }
+ retinfo->file_descr[i] = (char*) malloc(local_size);
+ memcpy(retinfo->file_descr[i], CMSG_DATA(cmsgh), local_size);
+ retinfo->levels[i] = cmsgh->cmsg_level;
+ retinfo->types[i] = cmsgh->cmsg_type;
+ retinfo->descr_per_ancillary[i] =local_size;
+ i++;
+
+ }
+ retinfo->retflag = msg.msg_flags;
+
+ // Set the parameters of address
+ memcpy(address,retinfo->address,retinfo->addrlen);
+ *addrlen = retinfo->addrlen;
+
+ // Set the parameters of message
+ no_of_messages[0] = retinfo->no_of_messages;
+ size_of_ancillary[0] = retinfo->size_of_ancillary;
+ *length_of_messages = (long*) malloc (sizeof(long) *
retinfo->no_of_messages);
+ //memcpy(*length_of_messages, retinfo->length_of_messages,
sizeof(int) * retinfo->no_of_messages);
+ int counter = 0;
+ for (i=0; i< retinfo->no_of_messages; i++){
+ counter += retinfo->length_of_messages[i];
+ length_of_messages[0][i] = retinfo->length_of_messages[i];
+ }
+ memset(*messages, 0, sizeof(char) * counter);
+ counter = 0;
+ for(i=0; i< retinfo->no_of_messages; i++){
+
memcpy(*messages+counter,retinfo->messages[i],retinfo->length_of_messages[i]);
+ counter += retinfo->length_of_messages[i];
+ }
+
+ // Set the parameters of ancillary
+ *levels = (long*) malloc (sizeof(long) *
retinfo->size_of_ancillary);
+ *types = (long*) malloc (sizeof(long) *
retinfo->size_of_ancillary);
+ *descr_per_ancillary = (long*) malloc (sizeof(long) *
retinfo->size_of_ancillary);
+ counter = 0;
+ for (i=0; i < retinfo->size_of_ancillary; i++){
+ counter += retinfo->descr_per_ancillary[i];
+ // Convert the int* to long*
+ levels[0][i] = (long) retinfo->levels[i];
+ types[0][i] = (long) retinfo->types[i];
+ descr_per_ancillary[0][i] = (long)
retinfo->descr_per_ancillary[i];
+ }
+ *file_descr = (char*) malloc (sizeof(char) * counter);
+ memset(*file_descr, 0, sizeof(char) * counter);
+ counter = 0;
+ for (i=0; i<retinfo->size_of_ancillary; i++){
+ memcpy(*file_descr+counter,retinfo->file_descr[i],
retinfo->descr_per_ancillary[i]);
+ counter += retinfo->descr_per_ancillary[i];
+ }
+
+ // Set the retflag
+ retflag[0] = retinfo->retflag;
+
+ // Free the memory
+ free(retinfo->address);
+ free(retinfo->length_of_messages);
+ free(retinfo->levels);
+ free(retinfo->types);
+ free(retinfo->descr_per_ancillary);
+ for(i = 0; i<retinfo->no_of_messages; i++)
+ free(retinfo->messages[i]);
+ for (i = 0; i < retinfo->size_of_ancillary; i++)
+ free(retinfo->file_descr[i]);
+ free(retinfo->file_descr);
+ free(retinfo->messages);
+ free(retinfo);
+ free(controlbuf);
+
+ return bytes_recvd;
+
+ fail:
+ if (anc_alloc){
+ free(retinfo->file_descr);
+ free(retinfo->levels);
+ free(retinfo->types);
+ free(retinfo->descr_per_ancillary);
+ free(retinfo->length_of_messages);
+ free(retinfo->messages[0]);
+ free(retinfo->messages);
+ free(retinfo->address);
+ free(retinfo);
+ free(controlbuf);
+
+ }else{
+ if (iov_alloc){
+ free(retinfo->length_of_messages);
+ free(retinfo->messages[0]);
+ free(retinfo->messages);
+ free(retinfo->address);
+ free(controlbuf);
+ free(retinfo);
+ }
+ }
+ return error_flag;
+
+ err_closefds:
+ // Special case for UNIX sockets. In case file descriptors are
received, they need to be closed.
+ // Taken from CPython
+ #ifdef SCM_RIGHTS
+ /* Close all descriptors coming from SCM_RIGHTS, so they don't
leak. */
+ for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) :
NULL);
+ cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
+ size_t dataleng;
+ cmsg_status = get_cmsg_data_len(&msg, cmsgh, &dataleng);
+ cmsgdatalen = (int) dataleng;
+ if (cmsg_status < 0)
+ break;
+ if (cmsgh->cmsg_level == SOL_SOCKET &&
+ cmsgh->cmsg_type == SCM_RIGHTS) {
+ size_t numfds;
+ int *fdp;
+
+ numfds = cmsgdatalen / sizeof(int);
+ fdp = (int *)CMSG_DATA(cmsgh);
+ while (numfds-- > 0)
+ close(*fdp++);
+ }
+ if (cmsg_status != 0)
+ break;
+ }
+ #endif /* SCM_RIGHTS */
+ goto fail;
+ }
+
+
+ //
################################################################################################
+ // Sendmsg implementation and associated functions
+
+ #ifdef CMSG_LEN
+ static int
+ get_CMSG_LEN(size_t length, size_t *result)
+ {
+ size_t tmp;
+
+ if (length > (SOCKLEN_T_LIMIT - CMSG_LEN(0)))
+ return 0;
+ tmp = CMSG_LEN(length);
+ if ((tmp > SOCKLEN_T_LIMIT) || (tmp < length))
+ return 0;
+ *result = tmp;
+ return 1;
+ }
+ #endif
+
+ #ifdef CMSG_SPACE
+ /* If length is in range, set *result to CMSG_SPACE(length) and return
+ true; otherwise, return false. */
+ static int
+ get_CMSG_SPACE(size_t length, size_t *result)
+ {
+ size_t tmp;
+
+ /* Use CMSG_SPACE(1) here in order to take account of the padding
+ necessary before *and* after the data. */
+ if (length > (SOCKLEN_T_LIMIT - CMSG_SPACE(1)))
+ return 0;
+ tmp = CMSG_SPACE(length);
+ if ((tmp > SOCKLEN_T_LIMIT) || (tmp < length))
+ return 0;
+ *result = tmp;
+ return 1;
+ }
+ #endif
+
+ /*
+ sendmsg_implementation is a wrapper over sendmsg of the API.
+ It was inspired from the way CPython did their implementation of
this.
+ The main reason that it was written in C, is the struct msghdr,
+ which contains the ancillary data in a linked list of cmsghdr
structures.
+ It was simpler to use it in C, and then push the simpler types of
data via rffi.
+ */
+ RPY_EXTERN
+ int sendmsg_implementation
+ (int socket,
+ struct sockaddr* address,
+ socklen_t addrlen,
+ long* length_of_messages,
+ char** messages,
+ int no_of_messages,
+ long* levels,
+ long* types,
+ char** file_descriptors,
+ long* no_of_fds,
+ int control_length,
+ int flag
+ )
+ {
+
+ struct msghdr msg = {0};
+ struct cmsghdr *cmsg;
+ void* controlbuf = NULL;
+ int retval;
+ size_t i;
+
+ // Prepare the msghdr structure for the send:
+
+ // Add the address
+ if (address != NULL) {
+ msg.msg_name = address;
+ msg.msg_namelen = addrlen;
+ }
+
+ // Add the message
+ struct iovec *iovs = NULL;
+ if (no_of_messages > 0){
+
+ iovs = (struct iovec*) malloc(no_of_messages * sizeof(struct
iovec));
+ memset(iovs, 0, no_of_messages * sizeof(struct iovec));
+ msg.msg_iov = iovs;
+ msg.msg_iovlen = no_of_messages;
+
+ for (i=0; i< no_of_messages; i++){
+ iovs[i].iov_base = messages[i];
+ iovs[i].iov_len = length_of_messages[i];
+ }
+ }
+
+ // Add the ancillary
+ #ifndef CMSG_SPACE
+ if (control_length > 1){
+ free(iovs);
+ return MUL_MSGS_NOT_SUP;
+ }
+ #endif
+ if (control_length > 0){
+
+ //compute the total size of the ancillary
+ //getting the exact amount of space can be tricky and os
dependent.
+ size_t total_size_of_ancillary = 0;
+ size_t space;
+ size_t controllen = 0, controllen_last = 0;
+ for (i = 0; i< control_length; i++){
+ total_size_of_ancillary = no_of_fds[i];
+ #ifdef CMSG_SPACE
+ if (!get_CMSG_SPACE(total_size_of_ancillary, &space)) {
+ #else
+ if (!get_CMSG_LEN(total_size_of_ancillary, &space)) {
+ #endif
+ if (iovs != NULL)
+ free(iovs);
+ return ANC_DATA_TOO_LARGE;
+ }
+ controllen +=space;
+ if ((controllen > SOCKLEN_T_LIMIT) || (controllen <
controllen_last)) {
+ if (iovs != NULL)
+ free(iovs);
+ return ANC_DATA_TOO_LARGEX;
+ }
+ controllen_last = controllen;
+ }
+
+ controlbuf = malloc(controllen);
+ msg.msg_control= controlbuf;
+ msg.msg_controllen = controllen;
+
+ // memset controlbuf to 0 to avoid trash in the ancillary
+ memset(controlbuf, 0, controllen);
+ cmsg = NULL;
+ for (i = 0; i< control_length; i++){
+ cmsg = (i == 0) ? CMSG_FIRSTHDR(&msg) : CMSG_NXTHDR(&msg,
cmsg);
+
+ cmsg->cmsg_level = (int) levels[i];
+ cmsg->cmsg_type = (int) types[i];
+ cmsg->cmsg_len = CMSG_LEN(sizeof(char) * no_of_fds[i]);
+ memcpy(CMSG_DATA(cmsg), file_descriptors[i], sizeof(char)
* no_of_fds[i]);
+ }
+
+
+ }
+ // Add the flags
+ msg.msg_flags = flag;
+
+ // Send the data
+ retval = sendmsg(socket, &msg, flag);
+
+ // free everything that was allocated here, and we would not need
in rsocket
+ if (iovs != NULL)
+ free(iovs);
+ if (controlbuf !=NULL)
+ free(controlbuf);
+
+ return retval;
+ }
+
+ //
################################################################################################
+ // Wrappers for CMSG_SPACE and CMSG_LEN
+
+ /*
+ These 2 functions are wrappers over sys/socket.h's CMSG_SPACE and
CMSG_LEN.
+ They are identical to CPython's.
+ */
+ #ifdef CMSG_SPACE
+ RPY_EXTERN
+ size_t CMSG_SPACE_wrapper(size_t desired_space){
+ size_t result;
+ if (!get_CMSG_SPACE(desired_space, &result)){
+ return 0;
+ }
+ return result;
+ }
+ #endif
+
+ #ifdef CMSG_LEN
+ RPY_EXTERN
+ size_t CMSG_LEN_wrapper(size_t desired_len){
+ size_t result;
+ if (!get_CMSG_LEN(desired_len, &result)){
+ return 0;
+ }
+ return result;
+ }
+ #endif
+
+ //
################################################################################################
+ // Extra functions that I needed
+
+ /*
+ This function is used to memcpy from a char* at an offset.
+ Could not get rffi.c_memcpy to do it at an offset, so I made my own.
+ */
+ RPY_EXTERN
+ int memcpy_from_CCHARP_at_offset_and_size(char* stringfrom, char**
stringto, int offset, int size){
+ *stringto = memcpy(*stringto, stringfrom + offset, size);
+ return 0;
+ }
+
+ /*
+ These functions free memory that was allocated in C (sendmsg or
recvmsg) was used in rsocket and now needs cleanup
+ */
+ RPY_EXTERN
+ int free_pointer_to_signedp(int** ptrtofree){
+ free(*ptrtofree);
+ return 0;
+ }
+
+ RPY_EXTERN
+ int free_ptr_to_charp(char** ptrtofree){
+ free(*ptrtofree);
+ return 0;
+ }
+
+ ''',]
+
+ post_include_bits =[ "RPY_EXTERN "
+ "int sendmsg_implementation(int socket, struct
sockaddr* address, socklen_t addrlen, long* length_of_messages, char**
messages, int no_of_messages, long* levels, long* types, char**
file_descriptors, long* no_of_fds, int control_length, int flag );\n"
+ "RPY_EXTERN "
+ "int recvmsg_implementation(int socket_fd, int
message_size, int ancillary_size, int flags, struct sockaddr* address,
socklen_t* addrlen, long** length_of_messages, char** messages, long*
no_of_messages, long* size_of_ancillary, long** levels, long** types, char**
file_descr, long** descr_per_ancillary, long* flag);\n"
+ "static "
+ "int cmsg_min_space(struct msghdr *msg, struct
cmsghdr *cmsgh, size_t space);\n"
+ "static "
+ "int get_cmsg_data_space(struct msghdr *msg, struct
cmsghdr *cmsgh, size_t *space);\n"
+ "static "
+ "int get_cmsg_data_len(struct msghdr *msg, struct
cmsghdr *cmsgh, size_t *data_len);\n"
+ "static "
+ "int get_CMSG_LEN(size_t length, size_t *result);\n"
+ "static "
+ "int get_CMSG_SPACE(size_t length, size_t *result);\n"
+ "RPY_EXTERN "
+ "size_t CMSG_LEN_wrapper(size_t desired_len);\n"
+ "RPY_EXTERN "
+ "size_t CMSG_SPACE_wrapper(size_t desired_space);\n"
+ "RPY_EXTERN "
+ "int memcpy_from_CCHARP_at_offset_and_size(char*
stringfrom, char** stringto, int offset, int size);\n"
+ "RPY_EXTERN "
+ "int free_pointer_to_signedp(int** ptrtofree);\n"
+ "RPY_EXTERN "
+ "int free_ptr_to_charp(char** ptrtofree);\n"
+ ]
+
+
+ compilation_info = ExternalCompilationInfo(
+ includes=includes,
+
separate_module_sources=separate_module_sources,
+ post_include_bits=post_include_bits,
+ )
+
if _WIN32:
CConfig.WSAEVENT = platform.SimpleType('WSAEVENT', rffi.VOIDP)
CConfig.WSANETWORKEVENTS = platform.Struct(
@@ -387,6 +1035,7 @@
sockaddr_ptr.TO.become(cConfig.sockaddr)
addrinfo_ptr.TO.become(cConfig.addrinfo)
+
# fill in missing constants with reasonable defaults
cConfig.NI_MAXHOST = cConfig.NI_MAXHOST or 1025
cConfig.NI_MAXSERV = cConfig.NI_MAXSERV or 32
@@ -571,11 +1220,32 @@
recvfrom = external('recvfrom', [socketfd_type, rffi.VOIDP, size_t,
rffi.INT, sockaddr_ptr, socklen_t_ptr], rffi.INT,
save_err=SAVE_ERR)
+recvmsg = jit.dont_look_inside(rffi.llexternal("recvmsg_implementation",
+ [rffi.INT, rffi.INT, rffi.INT,
rffi.INT,sockaddr_ptr, socklen_t_ptr, rffi.SIGNEDPP, rffi.CCHARPP,
+ rffi.SIGNEDP,rffi.SIGNEDP,
rffi.SIGNEDPP, rffi.SIGNEDPP, rffi.CCHARPP, rffi.SIGNEDPP, rffi.SIGNEDP],
+ rffi.INT, save_err=SAVE_ERR,
+
compilation_info=compilation_info))
+
+memcpy_from_CCHARP_at_offset =
jit.dont_look_inside(rffi.llexternal("memcpy_from_CCHARP_at_offset_and_size",
+ [rffi.CCHARP,
rffi.CCHARPP,rffi.INT,rffi.INT],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+freeccharp = jit.dont_look_inside(rffi.llexternal("free_ptr_to_charp",
+
[rffi.CCHARPP],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+freesignedp = jit.dont_look_inside(rffi.llexternal("free_pointer_to_signedp",
+
[rffi.SIGNEDPP],rffi.INT,save_err=SAVE_ERR,compilation_info=compilation_info))
+
send = external('send', [socketfd_type, rffi.CCHARP, size_t, rffi.INT],
ssize_t, save_err=SAVE_ERR)
sendto = external('sendto', [socketfd_type, rffi.VOIDP, size_t, rffi.INT,
sockaddr_ptr, socklen_t], ssize_t,
save_err=SAVE_ERR)
+sendmsg = jit.dont_look_inside(rffi.llexternal("sendmsg_implementation",
+ [rffi.INT, sockaddr_ptr, socklen_t,
rffi.SIGNEDP, rffi.CCHARPP, rffi.INT,
+ rffi.SIGNEDP, rffi.SIGNEDP, rffi.CCHARPP,
rffi.SIGNEDP, rffi.INT, rffi.INT],
+ rffi.INT, save_err=SAVE_ERR,
+ compilation_info=compilation_info))
+CMSG_SPACE =
jit.dont_look_inside(rffi.llexternal("CMSG_SPACE_wrapper",[size_t], size_t,
save_err=SAVE_ERR,compilation_info=compilation_info))
+CMSG_LEN = jit.dont_look_inside(rffi.llexternal("CMSG_LEN_wrapper",[size_t],
size_t, save_err=SAVE_ERR,compilation_info=compilation_info))
+
socketshutdown = external('shutdown', [socketfd_type, rffi.INT], rffi.INT,
save_err=SAVE_ERR)
gethostname = external('gethostname', [rffi.CCHARP, rffi.INT], rffi.INT,
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -1312,9 +1312,17 @@
@replace_os_function('link')
@specialize.argtype(0, 1)
def link(oldpath, newpath):
- oldpath = _as_bytes0(oldpath)
- newpath = _as_bytes0(newpath)
- handle_posix_error('link', c_link(oldpath, newpath))
+ if not _WIN32:
+ oldpath = _as_bytes0(oldpath)
+ newpath = _as_bytes0(newpath)
+ handle_posix_error('link', c_link(oldpath, newpath))
+ else:
+ traits = _preferred_traits(oldpath)
+ win32traits = make_win32_traits(traits)
+ oldpath = traits.as_str0(oldpath)
+ newpath = traits.as_str0(newpath)
+ if not win32traits.CreateHardLink(newpath, oldpath, None):
+ raise rwin32.lastSavedWindowsError()
@replace_os_function('symlink')
@specialize.argtype(0, 1)
diff --git a/rpython/rlib/rsocket.py b/rpython/rlib/rsocket.py
--- a/rpython/rlib/rsocket.py
+++ b/rpython/rlib/rsocket.py
@@ -963,6 +963,126 @@
return (read_bytes, address)
raise self.error_handler()
+ @jit.dont_look_inside
+ def recvmsg(self, message_size, ancbufsize = 0, flags = 0):
+ """
+ Receive up to message_size bytes from a message. Also receives
ancillary data.
+ Returns the message, ancillary, flag and address of the sender.
+ :param message_size: Maximum size of the message to be received
+ :param ancbufsize: Maximum size of the ancillary data to be received
+ :param flags: Receive flag. For more details, please check the Unix
manual
+ :return: a tuple consisting of the message, the ancillary data, return
flag and the address.
+ """
+ if message_size < 0:
+ raise RSocketError("Invalid message size")
+ if ancbufsize < 0:
+ raise RSocketError("invalid ancillary data buffer length")
+
+ self.wait_for_data(False)
+ address, addr_p, addrlen_p = self._addrbuf()
+ len_of_msgs =
lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ messages =
lltype.malloc(rffi.CCHARPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False
)
+ messages[0] = lltype.malloc(rffi.CCHARP.TO,
message_size,flavor='raw',track_allocation=True,nonmovable=False)
+ rffi.c_memset(messages[0], 0, message_size)
+ no_of_messages =
lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False
)
+ no_of_messages[0] = rffi.cast(rffi.SIGNED, 0)
+ size_of_anc =
lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False
)
+ size_of_anc[0] = rffi.cast(rffi.SIGNED,0)
+ levels =
lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ types =
lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ file_descr =
lltype.malloc(rffi.CCHARPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False
)
+ descr_per_anc =
lltype.malloc(rffi.SIGNEDPP.TO,1,flavor='raw',track_allocation=True,nonmovable=False)
+ retflag =
lltype.malloc(rffi.SIGNEDP.TO,1,flavor='raw',track_allocation=True,nonmovable=False
)
+ retflag[0] = rffi.cast(rffi.SIGNED,0)
+
+ # a mask for the SIGNEDP's that need to be cast to int. (long default)
+ reply = _c.recvmsg(self.fd, rffi.cast(lltype.Signed,message_size),
+
rffi.cast(lltype.Signed,ancbufsize),rffi.cast(lltype.Signed,flags),
+ addr_p, addrlen_p, len_of_msgs, messages,
no_of_messages,size_of_anc,
+ levels, types,file_descr,descr_per_anc,retflag)
+ if reply >= 0:
+ anc_size = rffi.cast(rffi.SIGNED,size_of_anc[0])
+ returnflag = rffi.cast(rffi.SIGNED,retflag[0])
+ addrlen = rffi.cast(rffi.SIGNED,addrlen_p[0])
+
+ retmsg = rffi.charpsize2str(messages[0],reply)
+
+ offset = 0
+ list_of_tuples = []
+
+ pre_anc = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw',
track_allocation=True, nonmovable=False)
+ for i in range(anc_size):
+ level = rffi.cast(rffi.SIGNED, levels[0][i])
+ type = rffi.cast(rffi.SIGNED, types[0][i])
+ bytes_in_anc = rffi.cast(rffi.SIGNED, descr_per_anc[0][i])
+ pre_anc[0] = lltype.malloc(rffi.CCHARP.TO,
bytes_in_anc,flavor='raw',track_allocation=True,nonmovable=False)
+ _c.memcpy_from_CCHARP_at_offset(file_descr[0],
pre_anc,rffi.cast(rffi.SIGNED,offset), bytes_in_anc)
+ anc = rffi.charpsize2str(pre_anc[0],bytes_in_anc)
+ tup = (level,type, anc)
+ list_of_tuples.append(tup)
+ offset += bytes_in_anc
+ lltype.free(pre_anc[0], flavor='raw')
+
+ if addrlen:
+ address.addrlen = addrlen
+ else:
+ address.unlock()
+ address = None
+
+ rettup = (retmsg,list_of_tuples,returnflag,address)
+
+ if address is not None:
+ address.unlock()
+ # free underlying complexity first
+ _c.freeccharp(file_descr)
+ _c.freesignedp(len_of_msgs)
+ _c.freesignedp(levels)
+ _c.freesignedp(types)
+ _c.freesignedp(descr_per_anc)
+
+ lltype.free(messages[0], flavor='raw')
+ lltype.free(pre_anc,flavor='raw')
+ lltype.free(messages,flavor='raw')
+ lltype.free(file_descr,flavor='raw')
+ lltype.free(len_of_msgs,flavor='raw')
+ lltype.free(no_of_messages, flavor='raw')
+ lltype.free(size_of_anc, flavor='raw')
+ lltype.free(levels, flavor='raw')
+ lltype.free(types, flavor='raw')
+ lltype.free(descr_per_anc, flavor='raw')
+ lltype.free(retflag, flavor='raw')
+ lltype.free(addrlen_p,flavor='raw')
+
+ return rettup
+ else:
+
+ #in case of failure the underlying complexity has already been
freed
+ lltype.free(messages[0], flavor='raw')
+ lltype.free(messages, flavor='raw')
+ lltype.free(file_descr, flavor='raw')
+ lltype.free(len_of_msgs, flavor='raw')
+ lltype.free(no_of_messages, flavor='raw')
+ lltype.free(size_of_anc, flavor='raw')
+ lltype.free(levels, flavor='raw')
+ lltype.free(types, flavor='raw')
+ lltype.free(descr_per_anc, flavor='raw')
+ lltype.free(retflag, flavor='raw')
+ lltype.free(addrlen_p, flavor='raw')
+
+ if address is not None:
+ address.unlock()
+ if _c.geterrno() == _c.EINTR:
+ raise last_error()
+ if (reply == -10000):
+ raise RSocketError("Invalid message size")
+ if (reply == -10001):
+ raise RSocketError("Invalid ancillary data buffer length")
+ if (reply == -10002):
+ raise RSocketError("received malformed or improperly truncated
ancillary data")
+ raise last_error()
+
+
+
def send_raw(self, dataptr, length, flags=0):
"""Send data from a CCHARP buffer."""
self.wait_for_data(True)
@@ -1009,6 +1129,86 @@
raise self.error_handler()
return res
+ @jit.dont_look_inside
+ def sendmsg(self, messages, ancillary=None, flags=0, address=None):
+ """
+ Send data and ancillary on a socket. For use of ancillary data, please
check the Unix manual.
+ Work on connectionless sockets via the address parameter.
+ :param messages: a message that is a list of strings
+ :param ancillary: data to be sent separate from the message body.
Needs to be a list of tuples.
+ E.g. [(level,type, bytes),...]. Default None.
+ :param flags: the flag to be set for sendmsg. Please check the Unix
manual regarding values. Default 0
+ :param address: address of the recepient. Useful for when sending on
connectionless sockets. Default None
+ :return: Bytes sent from the message
+ """
+ need_to_free_address = True
+ if address is None:
+ need_to_free_address = False
+ addr = lltype.nullptr(_c.sockaddr)
+ addrlen = 0
+ else:
+ addr = address.lock()
+ addrlen = address.addrlen
+
+ no_of_messages = len(messages)
+ messages_ptr =
lltype.malloc(rffi.CCHARPP.TO,no_of_messages+1,flavor='raw',track_allocation=True,nonmovable=False)
+ messages_length_ptr =
lltype.malloc(rffi.SIGNEDP.TO,no_of_messages,flavor='raw',zero=True,
track_allocation=True,nonmovable=False)
+ counter = 0
+ for message in messages:
+ messages_ptr[counter] = rffi.str2charp(message)
+ messages_length_ptr[counter] = rffi.cast(rffi.SIGNED, len(message))
+ counter += 1
+ messages_ptr[counter] = lltype.nullptr(rffi.CCHARP.TO)
+ if ancillary is not None:
+ size_of_ancillary = len(ancillary)
+ else:
+ size_of_ancillary = 0
+ levels = lltype.malloc(rffi.SIGNEDP.TO,
size_of_ancillary,flavor='raw',zero=True,
track_allocation=True,nonmovable=False)
+ types = lltype.malloc(rffi.SIGNEDP.TO,
size_of_ancillary,flavor='raw',zero=True,
track_allocation=True,nonmovable=False)
+ desc_per_ancillary = lltype.malloc(rffi.SIGNEDP.TO,
size_of_ancillary,flavor='raw',zero=True,
track_allocation=True,nonmovable=False)
+ file_descr = lltype.malloc(rffi.CCHARPP.TO,
size_of_ancillary,flavor='raw', track_allocation=True,nonmovable=False)
+ if ancillary is not None:
+ counter = 0
+ for level, type, content in ancillary:
+ assert isinstance(type,int)
+ assert isinstance(level, int)
+ levels[counter] = rffi.cast(rffi.SIGNED,level)
+ types[counter] = rffi.cast(rffi.SIGNED,type)
+ desc_per_ancillary[counter] = rffi.cast(rffi.SIGNED,
(len(content)))
+ file_descr[counter] = rffi.str2charp(content,
track_allocation=True)
+ counter +=1
+ else:
+ size_of_ancillary = 0
+ snd_no_msgs = rffi.cast(rffi.SIGNED, no_of_messages)
+ snd_anc_size =rffi.cast(rffi.SIGNED, size_of_ancillary)
+
+
+ bytes_sent = _c.sendmsg(self.fd, addr, addrlen, messages_length_ptr,
messages_ptr,
snd_no_msgs,levels,types,file_descr,desc_per_ancillary,snd_anc_size,flags)
+
+
+ if need_to_free_address:
+ address.unlock()
+ for i in range(len(messages)):
+ lltype.free(messages_ptr[i], flavor='raw', track_allocation=True)
+ lltype.free(messages_ptr, flavor='raw', track_allocation=True)
+ lltype.free(messages_length_ptr, flavor='raw', track_allocation=True)
+
+ if size_of_ancillary > 0:
+ for i in range(len(ancillary)):
+ lltype.free(file_descr[i], flavor='raw', track_allocation=True)
+ lltype.free(desc_per_ancillary, flavor='raw', track_allocation=True)
+ lltype.free(types, flavor='raw', track_allocation=True)
+ lltype.free(levels, flavor='raw', track_allocation=True)
+ lltype.free(file_descr, flavor='raw', track_allocation=True)
+
+ self.wait_for_data(True)
+ if (bytes_sent < 0) and (bytes_sent!=-1000) and (bytes_sent!=-1001)
and (bytes_sent!=-1002):
+ raise last_error()
+
+ return bytes_sent
+
+
+
def setblocking(self, block):
if block:
timeout = -1.0
@@ -1190,6 +1390,31 @@
return (make_socket(fd0, family, type, proto, SocketClass),
make_socket(fd1, family, type, proto, SocketClass))
+if _c._POSIX:
+ def CMSG_LEN( demanded_len):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param demanded_len: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required
size. The value is not memory alligned
+ """
+ if demanded_len < 0:
+ return 0
+ result = _c.CMSG_LEN(demanded_len)
+ return result
+
+ def CMSG_SPACE( demanded_size):
+ """
+ Socket method to determine the optimal byte size of the ancillary.
+ Recommended to be used when computing the ancillary size for recvmsg.
+ :param demanded_size: an integer with the minimum size required.
+ :return: an integer with the minimum memory needed for the required
size. The value is memory alligned
+ """
+ if demanded_size < 0:
+ return 0
+ result = _c.CMSG_SPACE(demanded_size)
+ return result
+
if _c.WIN32:
def dup(fd, inheritable=True):
with lltype.scoped_alloc(_c.WSAPROTOCOL_INFO, zero=True) as info:
diff --git a/rpython/rlib/rwin32file.py b/rpython/rlib/rwin32file.py
--- a/rpython/rlib/rwin32file.py
+++ b/rpython/rlib/rwin32file.py
@@ -234,6 +234,12 @@
rwin32.BOOL,
save_err=rffi.RFFI_SAVE_LASTERROR)
+ CreateHardLink = external(
+ 'CreateHardLink' + suffix,
+ [traits.CCHARP, traits.CCHARP, rwin32.LPSECURITY_ATTRIBUTES],
+ rwin32.BOOL,
+ save_err=rffi.RFFI_SAVE_LASTERROR)
+
return Win32Traits
def make_longlong(high, low):
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
@@ -752,7 +752,8 @@
# Signed, Signed *
SIGNED = lltype.Signed
-SIGNEDP = lltype.Ptr(lltype.Array(SIGNED, hints={'nolength': True}))
+SIGNEDP = lltype.Ptr(lltype.Array(lltype.Signed, hints={'nolength': True}))
+SIGNEDPP = lltype.Ptr(lltype.Array(SIGNEDP, hints={'nolength': True}))
# various type mapping
diff --git a/rpython/translator/backendopt/graphanalyze.py
b/rpython/translator/backendopt/graphanalyze.py
--- a/rpython/translator/backendopt/graphanalyze.py
+++ b/rpython/translator/backendopt/graphanalyze.py
@@ -4,6 +4,7 @@
class GraphAnalyzer(object):
verbose = False
+ explanation = None
def __init__(self, translator):
self.translator = translator
@@ -73,6 +74,20 @@
def compute_graph_info(self, graph):
return None
+ def explain_analyze_slowly(self, op):
+ # this is a hack! usually done before a crash
+ self.__init__(self.translator)
+ self.explanation = explanation = []
+ oldverbose = self.verbose
+ self.verbose = True
+ try:
+ self.analyze(op)
+ finally:
+ del self.explanation
+ self.verbose = oldverbose
+ explanation.reverse()
+ return explanation
+
def analyze(self, op, seen=None, graphinfo=None):
if op.opname == "direct_call":
try:
@@ -113,7 +128,11 @@
return x
def dump_info(self, info):
- print '[%s] %s' % (self.__class__.__name__, info)
+ st = '[%s] %s' % (self.__class__.__name__, info)
+ if self.explanation is not None:
+ self.explanation.append(st)
+ else:
+ print st
def analyze_direct_call(self, graph, seen=None):
if seen is None:
diff --git a/rpython/translator/backendopt/test/test_writeanalyze.py
b/rpython/translator/backendopt/test/test_writeanalyze.py
--- a/rpython/translator/backendopt/test/test_writeanalyze.py
+++ b/rpython/translator/backendopt/test/test_writeanalyze.py
@@ -531,3 +531,37 @@
typed_effects = self._analyze_graph(t, wa, typed_write)
typed_effects = self._filter_reads(typed_effects)
assert typed_effects == direct_effects
+
+ def test_explanation(self):
+ class A(object):
+ def methodname(self):
+ self.x = 1
+ return 1
+ def m(self):
+ raise ValueError
+ class B(A):
+ def methodname(self):
+ return 2
+ def m(self):
+ return 3
+ def fancyname(a):
+ return a.methodname()
+ def m(a):
+ return a.m()
+ def h(flag):
+ if flag:
+ obj = A()
+ else:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit