[pypy-commit] pypy value-profiling: merge default
cfbolz
noreply at buildbot.pypy.org
Sat Oct 3 12:31:49 CEST 2015
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: value-profiling
Changeset: r79948:43bd40a0945b
Date: 2015-10-03 11:42 +0100
http://bitbucket.org/pypy/pypy/changeset/43bd40a0945b/
Log: merge default
diff too long, truncating to 2000 out of 3839 lines
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -609,7 +609,7 @@
def make_accessor_locked(name):
key = 'function ' + name
if key in ffi._parser._declarations:
- tp = ffi._parser._declarations[key]
+ tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp)
try:
value = backendlib.load_function(BType, name)
@@ -620,7 +620,7 @@
#
key = 'variable ' + name
if key in ffi._parser._declarations:
- tp = ffi._parser._declarations[key]
+ tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp)
read_variable = backendlib.read_variable
write_variable = backendlib.write_variable
@@ -631,12 +631,23 @@
#
if not copied_enums:
from . import model
- for key, tp in ffi._parser._declarations.items():
+ error = None
+ for key, (tp, _) in ffi._parser._declarations.items():
if not isinstance(tp, model.EnumType):
continue
+ try:
+ tp.check_not_partial()
+ except Exception as e:
+ error = e
+ continue
for enumname, enumval in zip(tp.enumerators, tp.enumvalues):
if enumname not in library.__dict__:
library.__dict__[enumname] = enumval
+ if error is not None:
+ if name in library.__dict__:
+ return # ignore error, about a different enum
+ raise error
+
for key, val in ffi._parser._int_constants.items():
if key not in library.__dict__:
library.__dict__[key] = val
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -192,6 +192,7 @@
if not decl.name:
raise api.CDefError("typedef does not declare any name",
decl)
+ quals = 0
if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
and decl.type.type.names[-1] == '__dotdotdot__'):
realtype = self._get_unknown_type(decl)
@@ -202,8 +203,9 @@
decl.type.type.type.names == ['__dotdotdot__']):
realtype = model.unknown_ptr_type(decl.name)
else:
- realtype = self._get_type(decl.type, name=decl.name)
- self._declare('typedef ' + decl.name, realtype)
+ realtype, quals = self._get_type_and_quals(
+ decl.type, name=decl.name)
+ self._declare('typedef ' + decl.name, realtype, quals=quals)
else:
raise api.CDefError("unrecognized construct", decl)
except api.FFIError as e:
@@ -255,9 +257,9 @@
def _parse_decl(self, decl):
node = decl.type
if isinstance(node, pycparser.c_ast.FuncDecl):
- tp = self._get_type(node, name=decl.name)
+ tp, quals = self._get_type_and_quals(node, name=decl.name)
assert isinstance(tp, model.RawFunctionType)
- tp = self._get_type_pointer(tp)
+ tp = self._get_type_pointer(tp, quals)
self._declare('function ' + decl.name, tp)
else:
if isinstance(node, pycparser.c_ast.Struct):
@@ -271,9 +273,10 @@
decl)
#
if decl.name:
- tp = self._get_type(node, partial_length_ok=True)
+ tp, quals = self._get_type_and_quals(node,
+ partial_length_ok=True)
if tp.is_raw_function:
- tp = self._get_type_pointer(tp)
+ tp = self._get_type_pointer(tp, quals)
self._declare('function ' + decl.name, tp)
elif (tp.is_integer_type() and
hasattr(decl, 'init') and
@@ -287,10 +290,10 @@
_r_int_literal.match(decl.init.expr.value)):
self._add_integer_constant(decl.name,
'-' + decl.init.expr.value)
- elif self._is_constant_globalvar(node):
- self._declare('constant ' + decl.name, tp)
+ elif (quals & model.Q_CONST) and not tp.is_array_type:
+ self._declare('constant ' + decl.name, tp, quals=quals)
else:
- self._declare('variable ' + decl.name, tp)
+ self._declare('variable ' + decl.name, tp, quals=quals)
def parse_type(self, cdecl):
ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
@@ -298,40 +301,51 @@
exprnode = ast.ext[-1].type.args.params[0]
if isinstance(exprnode, pycparser.c_ast.ID):
raise api.CDefError("unknown identifier '%s'" % (exprnode.name,))
- return self._get_type(exprnode.type)
+ tp, quals = self._get_type_and_quals(exprnode.type)
+ return tp
- def _declare(self, name, obj, included=False):
+ def _declare(self, name, obj, included=False, quals=0):
if name in self._declarations:
- if self._declarations[name] is obj:
+ prevobj, prevquals = self._declarations[name]
+ if prevobj is obj and prevquals == quals:
return
if not self._override:
raise api.FFIError(
"multiple declarations of %s (for interactive usage, "
"try cdef(xx, override=True))" % (name,))
assert '__dotdotdot__' not in name.split()
- self._declarations[name] = obj
+ self._declarations[name] = (obj, quals)
if included:
self._included_declarations.add(obj)
- def _get_type_pointer(self, type, const=False, declname=None):
+ def _extract_quals(self, type):
+ quals = 0
+ if isinstance(type, (pycparser.c_ast.TypeDecl,
+ pycparser.c_ast.PtrDecl)):
+ if 'const' in type.quals:
+ quals |= model.Q_CONST
+ if 'restrict' in type.quals:
+ quals |= model.Q_RESTRICT
+ return quals
+
+ def _get_type_pointer(self, type, quals, declname=None):
if isinstance(type, model.RawFunctionType):
return type.as_function_pointer()
if (isinstance(type, model.StructOrUnionOrEnum) and
type.name.startswith('$') and type.name[1:].isdigit() and
type.forcename is None and declname is not None):
- return model.NamedPointerType(type, declname)
- if const:
- return model.ConstPointerType(type)
- return model.PointerType(type)
+ return model.NamedPointerType(type, declname, quals)
+ return model.PointerType(type, quals)
- def _get_type(self, typenode, name=None, partial_length_ok=False):
+ def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False):
# first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
len(typenode.type.names) == 1 and
('typedef ' + typenode.type.names[0]) in self._declarations):
- type = self._declarations['typedef ' + typenode.type.names[0]]
- return type
+ tp, quals = self._declarations['typedef ' + typenode.type.names[0]]
+ quals |= self._extract_quals(typenode)
+ return tp, quals
#
if isinstance(typenode, pycparser.c_ast.ArrayDecl):
# array type
@@ -340,18 +354,19 @@
else:
length = self._parse_constant(
typenode.dim, partial_length_ok=partial_length_ok)
- tp = self._get_type(typenode.type,
+ tp, quals = self._get_type_and_quals(typenode.type,
partial_length_ok=partial_length_ok)
- return model.ArrayType(tp, length)
+ return model.ArrayType(tp, length), quals
#
if isinstance(typenode, pycparser.c_ast.PtrDecl):
# pointer type
- const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl)
- and 'const' in typenode.type.quals)
- return self._get_type_pointer(self._get_type(typenode.type), const,
- declname=name)
+ itemtype, itemquals = self._get_type_and_quals(typenode.type)
+ tp = self._get_type_pointer(itemtype, itemquals, declname=name)
+ quals = self._extract_quals(typenode)
+ return tp, quals
#
if isinstance(typenode, pycparser.c_ast.TypeDecl):
+ quals = self._extract_quals(typenode)
type = typenode.type
if isinstance(type, pycparser.c_ast.IdentifierType):
# assume a primitive type. get it from .names, but reduce
@@ -379,35 +394,38 @@
names = newnames + names
ident = ' '.join(names)
if ident == 'void':
- return model.void_type
+ return model.void_type, quals
if ident == '__dotdotdot__':
raise api.FFIError(':%d: bad usage of "..."' %
typenode.coord.line)
- return resolve_common_type(ident)
+ return resolve_common_type(ident), quals
#
if isinstance(type, pycparser.c_ast.Struct):
# 'struct foobar'
- return self._get_struct_union_enum_type('struct', type, name)
+ tp = self._get_struct_union_enum_type('struct', type, name)
+ return tp, quals
#
if isinstance(type, pycparser.c_ast.Union):
# 'union foobar'
- return self._get_struct_union_enum_type('union', type, name)
+ tp = self._get_struct_union_enum_type('union', type, name)
+ return tp, quals
#
if isinstance(type, pycparser.c_ast.Enum):
# 'enum foobar'
- return self._get_struct_union_enum_type('enum', type, name)
+ tp = self._get_struct_union_enum_type('enum', type, name)
+ return tp, quals
#
if isinstance(typenode, pycparser.c_ast.FuncDecl):
# a function type
- return self._parse_function_type(typenode, name)
+ return self._parse_function_type(typenode, name), 0
#
# nested anonymous structs or unions end up here
if isinstance(typenode, pycparser.c_ast.Struct):
return self._get_struct_union_enum_type('struct', typenode, name,
- nested=True)
+ nested=True), 0
if isinstance(typenode, pycparser.c_ast.Union):
return self._get_struct_union_enum_type('union', typenode, name,
- nested=True)
+ nested=True), 0
#
raise api.FFIError(":%d: bad or unsupported type declaration" %
typenode.coord.line)
@@ -426,28 +444,21 @@
raise api.CDefError(
"%s: a function with only '(...)' as argument"
" is not correct C" % (funcname or 'in expression'))
- args = [self._as_func_arg(self._get_type(argdeclnode.type))
+ args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
for argdeclnode in params]
if not ellipsis and args == [model.void_type]:
args = []
- result = self._get_type(typenode.type)
+ result, quals = self._get_type_and_quals(typenode.type)
return model.RawFunctionType(tuple(args), result, ellipsis)
- def _as_func_arg(self, type):
+ def _as_func_arg(self, type, quals):
if isinstance(type, model.ArrayType):
- return model.PointerType(type.item)
+ return model.PointerType(type.item, quals)
elif isinstance(type, model.RawFunctionType):
return type.as_function_pointer()
else:
return type
- def _is_constant_globalvar(self, typenode):
- if isinstance(typenode, pycparser.c_ast.PtrDecl):
- return 'const' in typenode.quals
- if isinstance(typenode, pycparser.c_ast.TypeDecl):
- return 'const' in typenode.quals
- return False
-
def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
# First, a level of caching on the exact 'type' node of the AST.
# This is obscure, but needed because pycparser "unrolls" declarations
@@ -486,7 +497,7 @@
else:
explicit_name = name
key = '%s %s' % (kind, name)
- tp = self._declarations.get(key, None)
+ tp, _ = self._declarations.get(key, (None, None))
#
if tp is None:
if kind == 'struct':
@@ -528,6 +539,7 @@
fldnames = []
fldtypes = []
fldbitsize = []
+ fldquals = []
for decl in type.decls:
if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
''.join(decl.type.names) == '__dotdotdot__'):
@@ -541,7 +553,8 @@
else:
bitsize = self._parse_constant(decl.bitsize)
self._partial_length = False
- type = self._get_type(decl.type, partial_length_ok=True)
+ type, fqual = self._get_type_and_quals(decl.type,
+ partial_length_ok=True)
if self._partial_length:
self._make_partial(tp, nested)
if isinstance(type, model.StructType) and type.partial:
@@ -549,9 +562,11 @@
fldnames.append(decl.name or '')
fldtypes.append(type)
fldbitsize.append(bitsize)
+ fldquals.append(fqual)
tp.fldnames = tuple(fldnames)
tp.fldtypes = tuple(fldtypes)
tp.fldbitsize = tuple(fldbitsize)
+ tp.fldquals = tuple(fldquals)
if fldbitsize != [-1] * len(fldbitsize):
if isinstance(tp, model.StructType) and tp.partial:
raise NotImplementedError("%s: using both bitfields and '...;'"
@@ -632,14 +647,12 @@
return tp
def include(self, other):
- for name, tp in other._declarations.items():
+ for name, (tp, quals) in other._declarations.items():
if name.startswith('anonymous $enum_$'):
continue # fix for test_anonymous_enum_include
kind = name.split(' ', 1)[0]
- if kind in ('struct', 'union', 'enum', 'anonymous'):
- self._declare(name, tp, included=True)
- elif kind == 'typedef':
- self._declare(name, tp, included=True)
+ if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
+ self._declare(name, tp, included=True, quals=quals)
for k, v in other._int_constants.items():
self._add_constants(k, v)
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -4,11 +4,26 @@
from .lock import allocate_lock
+# type qualifiers
+Q_CONST = 0x01
+Q_RESTRICT = 0x02
+
+def qualify(quals, replace_with):
+ if quals & Q_CONST:
+ replace_with = ' const ' + replace_with.lstrip()
+ if quals & Q_RESTRICT:
+ # It seems that __restrict is supported by gcc and msvc.
+ # If you hit some different compiler, add a #define in
+ # _cffi_include.h for it (and in its copies, documented there)
+ replace_with = ' __restrict ' + replace_with.lstrip()
+ return replace_with
+
+
class BaseTypeByIdentity(object):
is_array_type = False
is_raw_function = False
- def get_c_name(self, replace_with='', context='a C file'):
+ def get_c_name(self, replace_with='', context='a C file', quals=0):
result = self.c_name_with_marker
assert result.count('&') == 1
# some logic duplication with ffi.getctype()... :-(
@@ -18,6 +33,7 @@
replace_with = '(%s)' % replace_with
elif not replace_with[0] in '[(':
replace_with = ' ' + replace_with
+ replace_with = qualify(quals, replace_with)
result = result.replace('&', replace_with)
if '$' in result:
from .ffiplatform import VerificationError
@@ -225,16 +241,14 @@
class PointerType(BaseType):
- _attrs_ = ('totype',)
- _base_pattern = " *&"
- _base_pattern_array = "(*&)"
+ _attrs_ = ('totype', 'quals')
- def __init__(self, totype):
+ def __init__(self, totype, quals=0):
self.totype = totype
+ self.quals = quals
+ extra = qualify(quals, " *&")
if totype.is_array_type:
- extra = self._base_pattern_array
- else:
- extra = self._base_pattern
+ extra = "(%s)" % (extra.lstrip(),)
self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
def build_backend_type(self, ffi, finishlist):
@@ -243,10 +257,8 @@
voidp_type = PointerType(void_type)
-
-class ConstPointerType(PointerType):
- _base_pattern = " const *&"
- _base_pattern_array = "(const *&)"
+def ConstPointerType(totype):
+ return PointerType(totype, Q_CONST)
const_voidp_type = ConstPointerType(void_type)
@@ -254,8 +266,8 @@
class NamedPointerType(PointerType):
_attrs_ = ('totype', 'name')
- def __init__(self, totype, name):
- PointerType.__init__(self, totype)
+ def __init__(self, totype, name, quals=0):
+ PointerType.__init__(self, totype, quals)
self.name = name
self.c_name_with_marker = name + '&'
@@ -315,11 +327,12 @@
partial = False
packed = False
- def __init__(self, name, fldnames, fldtypes, fldbitsize):
+ def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
self.name = name
self.fldnames = fldnames
self.fldtypes = fldtypes
self.fldbitsize = fldbitsize
+ self.fldquals = fldquals
self.build_c_name_with_marker()
def has_anonymous_struct_fields(self):
@@ -331,14 +344,17 @@
return False
def enumfields(self):
- for name, type, bitsize in zip(self.fldnames, self.fldtypes,
- self.fldbitsize):
+ fldquals = self.fldquals
+ if fldquals is None:
+ fldquals = (0,) * len(self.fldnames)
+ for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
+ self.fldbitsize, fldquals):
if name == '' and isinstance(type, StructOrUnion):
# nested anonymous struct/union
for result in type.enumfields():
yield result
else:
- yield (name, type, bitsize)
+ yield (name, type, bitsize, quals)
def force_flatten(self):
# force the struct or union to have a declaration that lists
@@ -347,13 +363,16 @@
names = []
types = []
bitsizes = []
- for name, type, bitsize in self.enumfields():
+ fldquals = []
+ for name, type, bitsize, quals in self.enumfields():
names.append(name)
types.append(type)
bitsizes.append(bitsize)
+ fldquals.append(quals)
self.fldnames = tuple(names)
self.fldtypes = tuple(types)
self.fldbitsize = tuple(bitsizes)
+ self.fldquals = tuple(fldquals)
def get_cached_btype(self, ffi, finishlist, can_delay=False):
BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -195,17 +195,15 @@
elif isinstance(tp, model.StructOrUnion):
if tp.fldtypes is not None and (
tp not in self.ffi._parser._included_declarations):
- for name1, tp1, _ in tp.enumfields():
+ for name1, tp1, _, _ in tp.enumfields():
self._do_collect_type(self._field_type(tp, name1, tp1))
else:
for _, x in tp._get_items():
self._do_collect_type(x)
- def _get_declarations(self):
- return sorted(self.ffi._parser._declarations.items())
-
def _generate(self, step_name):
- for name, tp in self._get_declarations():
+ lst = self.ffi._parser._declarations.items()
+ for name, (tp, quals) in sorted(lst):
kind, realname = name.split(' ', 1)
try:
method = getattr(self, '_generate_cpy_%s_%s' % (kind,
@@ -214,6 +212,7 @@
raise ffiplatform.VerificationError(
"not implemented in recompile(): %r" % name)
try:
+ self._current_quals = quals
method(tp, realname)
except Exception as e:
model.attach_exception_info(e, name)
@@ -774,7 +773,7 @@
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
@@ -789,7 +788,8 @@
ftype = ftype.item
fname = fname + '[0]'
prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname), fname))
+ ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
+ fname))
except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
@@ -823,7 +823,7 @@
c_fields = []
if reason_for_not_expanding is None:
enumfields = list(tp.enumfields())
- for fldname, fldtype, fbitsize in enumfields:
+ for fldname, fldtype, fbitsize, fqual in enumfields:
fldtype = self._field_type(tp, fldname, fldtype)
# cname is None for _add_missing_struct_unions() only
op = OP_NOOP
@@ -879,7 +879,9 @@
# because they don't have any known C name. Check that they are
# not partial (we can't complete or verify them!) and emit them
# anonymously.
- for tp in list(self._struct_unions):
+ lst = list(self._struct_unions.items())
+ lst.sort(key=lambda tp_order: tp_order[1])
+ for tp, order in lst:
if tp not in self._seen_struct_unions:
if tp.partial:
raise NotImplementedError("internal inconsistency: %r is "
@@ -1004,6 +1006,8 @@
def _enum_ctx(self, tp, cname):
type_index = self._typesdict[tp]
type_op = CffiOp(OP_ENUM, -1)
+ if self.target_is_python:
+ tp.check_not_partial()
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
self._lsts["global"].append(
GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
@@ -1081,7 +1085,8 @@
# if 'tp' were a function type, but that is not possible here.
# (If 'tp' is a function _pointer_ type, then casts from "fn_t
# **" to "void *" are again no-ops, as far as I can tell.)
- prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,)))
+ decl = '*_cffi_var_%s(void)' % (name,)
+ prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
prnt('{')
prnt(' return %s(%s);' % (ampersand, name))
prnt('}')
diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py
--- a/lib_pypy/cffi/vengine_cpy.py
+++ b/lib_pypy/cffi/vengine_cpy.py
@@ -197,7 +197,10 @@
return library
def _get_declarations(self):
- return sorted(self.ffi._parser._declarations.items())
+ lst = [(key, tp) for (key, (tp, qual)) in
+ self.ffi._parser._declarations.items()]
+ lst.sort()
+ return lst
def _generate(self, step_name):
for name, tp in self._get_declarations():
@@ -468,7 +471,7 @@
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double
@@ -477,7 +480,8 @@
# only accept exactly the type declared.
try:
prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname), fname))
+ ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
+ fname))
except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
@@ -488,7 +492,7 @@
prnt(' static Py_ssize_t nums[] = {')
prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname))
@@ -552,7 +556,7 @@
check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname),
diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py
--- a/lib_pypy/cffi/vengine_gen.py
+++ b/lib_pypy/cffi/vengine_gen.py
@@ -87,7 +87,10 @@
return library
def _get_declarations(self):
- return sorted(self.ffi._parser._declarations.items())
+ lst = [(key, tp) for (key, (tp, qual)) in
+ self.ffi._parser._declarations.items()]
+ lst.sort()
+ return lst
def _generate(self, step_name):
for name, tp in self._get_declarations():
@@ -260,7 +263,7 @@
prnt('{')
prnt(' /* only to generate compile-time warnings or errors */')
prnt(' (void)p;')
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double
@@ -269,7 +272,8 @@
# only accept exactly the type declared.
try:
prnt(' { %s = &p->%s; (void)tmp; }' % (
- ftype.get_c_name('*tmp', 'field %r'%fname), fname))
+ ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
+ fname))
except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}')
@@ -280,7 +284,7 @@
prnt(' static intptr_t nums[] = {')
prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),')
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname))
@@ -342,7 +346,7 @@
check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2
- for fname, ftype, fbitsize in tp.enumfields():
+ for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0:
continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname),
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -39,8 +39,9 @@
"_csv", "cppyy", "_pypyjson"
])
-if (sys.platform.startswith('linux') and os.uname()[4] == 'x86_64'
- and sys.maxint > 2**32): # it's not enough that we get x86_64
+if ((sys.platform.startswith('linux') or sys.platform == 'darwin')
+ and os.uname()[4] == 'x86_64' and sys.maxint > 2**32):
+ # it's not enough that we get x86_64
working_modules.add('_vmprof')
translation_modules = default_modules.copy()
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -5,8 +5,8 @@
with any external library.
Right now, there are the following possibilities of providing
-third-party modules for the PyPy python interpreter (in order of
-usefulness):
+third-party modules for the PyPy python interpreter (in order, from most
+directly useful to most messy to use with PyPy):
* Write them in pure Python and use CFFI_.
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
@@ -33,3 +33,13 @@
.. branch: remember-tracing-counts
Reenable jithooks
+
+.. branch: detect_egd2
+
+.. branch: shadowstack-no-move-2
+Issue #2141: fix a crash on Windows and OS/X and ARM when running
+at least 20 threads.
+
+.. branch: numpy-ctypes
+
+Add support for ndarray.ctypes property.
diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py
--- a/pypy/module/__builtin__/app_functional.py
+++ b/pypy/module/__builtin__/app_functional.py
@@ -5,6 +5,7 @@
from __future__ import with_statement
import operator
from __pypy__ import resizelist_hint, newlist_hint
+from __pypy__ import specialized_zip_2_lists
# ____________________________________________________________
@@ -217,11 +218,16 @@
in length to the length of the shortest argument sequence."""
l = len(sequences)
if l == 2:
+ # A very fast path if the two sequences are lists
+ seq0 = sequences[0]
+ seq1 = sequences[1]
+ try:
+ return specialized_zip_2_lists(seq0, seq1)
+ except TypeError:
+ pass
# This is functionally the same as the code below, but more
# efficient because it unrolls the loops over 'sequences'.
# Only for two arguments, which is the most common case.
- seq0 = sequences[0]
- seq1 = sequences[1]
iter0 = iter(seq0)
iter1 = iter(seq1)
hint = min(100000000, # max 100M
diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -253,27 +253,30 @@
def binaryop(self, space, w_other):
w_a, w_b = _coerce_helper(space, self, w_other)
- if w_a is None:
- w_a = self
- w_b = w_other
- if w_a is self:
- w_meth = self.getattr(space, specialname, False)
+ if isinstance(w_a, W_InstanceObject):
+ w_meth = w_a.getattr(space, specialname, False)
if w_meth is None:
return space.w_NotImplemented
return space.call_function(w_meth, w_b)
else:
+ # fall back to space.xxx() if coerce returns a non-W_Instance
+ # object as first argument
return getattr(space, objspacename)(w_a, w_b)
binaryop.func_name = name
def rbinaryop(self, space, w_other):
w_a, w_b = _coerce_helper(space, self, w_other)
- if w_a is None or w_a is self:
- w_meth = self.getattr(space, rspecialname, False)
+ if isinstance(w_a, W_InstanceObject):
+ w_meth = w_a.getattr(space, rspecialname, False)
if w_meth is None:
return space.w_NotImplemented
- return space.call_function(w_meth, w_other)
+ return space.call_function(w_meth, w_b)
else:
- return getattr(space, objspacename)(w_b, w_a)
+ # here, if coerce returns a non-W_Instance object as first
+ # argument, then give up. The idea is that this strange
+ # case should already have been handled by the binaryop()
+ # called from descroperation first.
+ return space.w_NotImplemented
rbinaryop.func_name = "r" + name
return binaryop, rbinaryop
@@ -283,7 +286,7 @@
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
- return [None, None]
+ return [w_self, w_other]
return space.fixedview(w_tup, 2)
def descr_instance_new(space, w_type, w_class, w_dict=None):
@@ -523,13 +526,9 @@
def descr_cmp(self, space, w_other): # do all the work here like CPython
w_a, w_b = _coerce_helper(space, self, w_other)
- if w_a is None:
- w_a = self
- w_b = w_other
- else:
- if (not isinstance(w_a, W_InstanceObject) and
- not isinstance(w_b, W_InstanceObject)):
- return space.cmp(w_a, w_b)
+ if (not isinstance(w_a, W_InstanceObject) and
+ not isinstance(w_b, W_InstanceObject)):
+ return space.cmp(w_a, w_b)
if isinstance(w_a, W_InstanceObject):
w_func = w_a.getattr(space, '__cmp__', False)
if w_func is not None:
@@ -636,42 +635,36 @@
def descr_pow(self, space, w_other, w_modulo=None):
if space.is_none(w_modulo):
w_a, w_b = _coerce_helper(space, self, w_other)
- if w_a is None:
- w_a = self
- w_b = w_other
- if w_a is self:
- w_func = self.getattr(space, '__pow__', False)
- if w_func is not None:
- return space.call_function(w_func, w_other)
- return space.w_NotImplemented
+ if isinstance(w_a, W_InstanceObject):
+ w_func = w_a.getattr(space, '__pow__', False)
+ if w_func is None:
+ return space.w_NotImplemented
+ return space.call_function(w_func, w_other)
else:
return space.pow(w_a, w_b, space.w_None)
else:
# CPython also doesn't try coercion in this case
w_func = self.getattr(space, '__pow__', False)
- if w_func is not None:
- return space.call_function(w_func, w_other, w_modulo)
- return space.w_NotImplemented
+ if w_func is None:
+ return space.w_NotImplemented
+ return space.call_function(w_func, w_other, w_modulo)
def descr_rpow(self, space, w_other, w_modulo=None):
if space.is_none(w_modulo):
w_a, w_b = _coerce_helper(space, self, w_other)
- if w_a is None:
- w_a = self
- w_b = w_other
- if w_a is self:
- w_func = self.getattr(space, '__rpow__', False)
- if w_func is not None:
- return space.call_function(w_func, w_other)
+ if isinstance(w_a, W_InstanceObject):
+ w_func = w_a.getattr(space, '__rpow__', False)
+ if w_func is None:
+ return space.w_NotImplemented
+ return space.call_function(w_func, w_other)
+ else:
return space.w_NotImplemented
- else:
- return space.pow(w_b, w_a, space.w_None)
else:
# CPython also doesn't try coercion in this case
w_func = self.getattr(space, '__rpow__', False)
- if w_func is not None:
- return space.call_function(w_func, w_other, w_modulo)
- return space.w_NotImplemented
+ if w_func is None:
+ return space.w_NotImplemented
+ return space.call_function(w_func, w_other, w_modulo)
def descr_next(self, space):
w_func = self.getattr(space, 'next', False)
diff --git a/pypy/module/__builtin__/test/test_classobj.py b/pypy/module/__builtin__/test/test_classobj.py
--- a/pypy/module/__builtin__/test/test_classobj.py
+++ b/pypy/module/__builtin__/test/test_classobj.py
@@ -417,6 +417,14 @@
pass
raises(TypeError, coerce, B(), [])
+ def test_coerce_inf(self):
+ class B:
+ def __coerce__(self, other):
+ return B(), B()
+ def __add__(self, other):
+ return 42
+ assert B() + B() == 42
+
def test_binaryop(self):
class A:
def __add__(self, other):
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -83,6 +83,7 @@
'newdict' : 'interp_dict.newdict',
'reversed_dict' : 'interp_dict.reversed_dict',
'strategy' : 'interp_magic.strategy', # dict,set,list
+ 'specialized_zip_2_lists' : 'interp_magic.specialized_zip_2_lists',
'set_debug' : 'interp_magic.set_debug',
'locals_to_fast' : 'interp_magic.locals_to_fast',
'save_module_content_for_future_reload':
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -147,3 +147,7 @@
@unwrap_spec(w_module=MixedModule)
def save_module_content_for_future_reload(space, w_module):
w_module.save_module_content_for_future_reload()
+
+def specialized_zip_2_lists(space, w_list1, w_list2):
+ from pypy.objspace.std.specialisedtupleobject import specialized_zip_2_lists
+ return specialized_zip_2_lists(space, w_list1, w_list2)
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -11,7 +11,8 @@
class W_CType(W_Root):
- _attrs_ = ['space', 'size', 'name', 'name_position', '_lifeline_']
+ _attrs_ = ['space', 'size', 'name', 'name_position', '_lifeline_',
+ '_pointer_type']
_immutable_fields_ = ['size?', 'name', 'name_position']
# note that 'size' is not strictly immutable, because it can change
# from -1 to the real value in the W_CTypeStruct subclass.
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -7,6 +7,7 @@
from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask
from rpython.rlib import jit
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.tool import rfficache
from pypy.interpreter.error import oefmt
from pypy.module._cffi_backend import cdataobj, misc
@@ -125,12 +126,25 @@
cdata[0] = value
+# XXX explicitly use an integer type instead of lltype.UniChar here,
+# because for now the latter is defined as unsigned by RPython (even
+# though it may be signed when 'wchar_t' is written to C).
+WCHAR_INT = {(2, False): rffi.USHORT,
+ (4, False): rffi.UINT,
+ (4, True): rffi.INT}[rffi.sizeof(lltype.UniChar),
+ rfficache.signof_c_type('wchar_t')]
+WCHAR_INTP = rffi.CArrayPtr(WCHAR_INT)
+
class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar):
_attrs_ = []
+ if rffi.r_wchar_t.SIGN:
+ def write_raw_integer_data(self, w_cdata, value):
+ w_cdata.write_raw_signed_data(value)
+
def cast_to_int(self, cdata):
- unichardata = rffi.cast(rffi.CWCHARP, cdata)
- return self.space.wrap(ord(unichardata[0]))
+ unichardata = rffi.cast(WCHAR_INTP, cdata)
+ return self.space.wrap(unichardata[0])
def convert_to_object(self, cdata):
unichardata = rffi.cast(rffi.CWCHARP, cdata)
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -168,7 +168,7 @@
class W_CTypePointer(W_CTypePtrBase):
- _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr']
+ _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr', '_array_types']
_immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr']
kind = "pointer"
cache_array_type = None
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -4,7 +4,7 @@
from rpython.rlib.objectmodel import specialize, r_dict, compute_identity_hash
from rpython.rlib.rarithmetic import ovfcheck, intmask
-from rpython.rlib import jit
+from rpython.rlib import jit, rweakref
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.rtyper.tool import rffi_platform
@@ -23,27 +23,12 @@
class UniqueCache:
def __init__(self, space):
- self.ctvoid = None # There can be only one
- self.ctvoidp = None # Cache for self.pointers[self.ctvoid]
- self.ctchara = None # Cache for self.arrays[charp, -1]
- self.primitives = {} # Keys: name
- self.pointers = {} # Keys: base_ctype
- self.arrays = {} # Keys: (ptr_ctype, length_or_-1)
- self.functions = r_dict(# Keys: (fargs, w_fresult, ellipsis)
- _func_key_eq, _func_key_hash)
-
-def _func_key_eq((fargs1, w_fresult1, ellipsis1),
- (fargs2, w_fresult2, ellipsis2)):
- return (fargs1 == fargs2 and # list equality here
- w_fresult1 is w_fresult2 and
- ellipsis1 == ellipsis2)
-
-def _func_key_hash((fargs, w_fresult, ellipsis)):
- x = compute_identity_hash(w_fresult) ^ ellipsis
- for w_arg in fargs:
- y = compute_identity_hash(w_arg)
- x = intmask((1000003 * x) ^ y)
- return x
+ self.ctvoid = None # Cache for the 'void' type
+ self.ctvoidp = None # Cache for the 'void *' type
+ self.ctchara = None # Cache for the 'char[]' type
+ self.primitives = {} # Cache for {name: primitive_type}
+ self.functions = [] # see _new_function_type()
+ self.for_testing = False
def _clean_cache(space):
"NOT_RPYTHON"
@@ -165,20 +150,24 @@
# ____________________________________________________________
+ at specialize.memo()
+def _setup_wref(has_weakref_support):
+ assert has_weakref_support, "_cffi_backend requires weakrefs"
+ ctypeobj.W_CType._pointer_type = rweakref.dead_ref
+ ctypeptr.W_CTypePointer._array_types = None
+
@unwrap_spec(w_ctype=ctypeobj.W_CType)
def new_pointer_type(space, w_ctype):
return _new_pointer_type(space, w_ctype)
@jit.elidable
def _new_pointer_type(space, w_ctype):
- unique_cache = space.fromcache(UniqueCache)
- try:
- return unique_cache.pointers[w_ctype]
- except KeyError:
- pass
- ctypepointer = ctypeptr.W_CTypePointer(space, w_ctype)
- unique_cache.pointers[w_ctype] = ctypepointer
- return ctypepointer
+ _setup_wref(rweakref.has_weakref_support())
+ ctptr = w_ctype._pointer_type()
+ if ctptr is None:
+ ctptr = ctypeptr.W_CTypePointer(space, w_ctype)
+ w_ctype._pointer_type = rweakref.ref(ctptr)
+ return ctptr
# ____________________________________________________________
@@ -195,16 +184,19 @@
@jit.elidable
def _new_array_type(space, w_ctptr, length):
- unique_cache = space.fromcache(UniqueCache)
- unique_key = (w_ctptr, length)
- try:
- return unique_cache.arrays[unique_key]
- except KeyError:
- pass
- #
+ _setup_wref(rweakref.has_weakref_support())
if not isinstance(w_ctptr, ctypeptr.W_CTypePointer):
raise OperationError(space.w_TypeError,
space.wrap("first arg must be a pointer ctype"))
+ arrays = w_ctptr._array_types
+ if arrays is None:
+ arrays = rweakref.RWeakValueDictionary(int, ctypearray.W_CTypeArray)
+ w_ctptr._array_types = arrays
+ else:
+ ctype = arrays.get(length)
+ if ctype is not None:
+ return ctype
+ #
ctitem = w_ctptr.ctitem
if ctitem.size < 0:
raise oefmt(space.w_ValueError, "array item of unknown size: '%s'",
@@ -222,7 +214,7 @@
extra = '[%d]' % length
#
ctype = ctypearray.W_CTypeArray(space, w_ctptr, length, arraysize, extra)
- unique_cache.arrays[unique_key] = ctype
+ arrays.set(length, ctype)
return ctype
# ____________________________________________________________
@@ -612,29 +604,69 @@
fargs.append(w_farg)
return _new_function_type(space, fargs, w_fresult, bool(ellipsis))
+def _func_key_hash(unique_cache, fargs, fresult, ellipsis):
+ x = compute_identity_hash(fresult)
+ for w_arg in fargs:
+ y = compute_identity_hash(w_arg)
+ x = intmask((1000003 * x) ^ y)
+ x ^= ellipsis
+ if unique_cache.for_testing: # constant-folded to False in translation;
+ x &= 3 # but for test, keep only 2 bits of hash
+ return x
+
# can't use @jit.elidable here, because it might call back to random
# space functions via force_lazy_struct()
-def _new_function_type(space, fargs, w_fresult, ellipsis=False):
+def _new_function_type(space, fargs, fresult, ellipsis=False):
+ try:
+ return _get_function_type(space, fargs, fresult, ellipsis)
+ except KeyError:
+ return _build_function_type(space, fargs, fresult, ellipsis)
+
+ at jit.elidable
+def _get_function_type(space, fargs, fresult, ellipsis):
+ # This function is elidable because if called again with exactly the
+ # same arguments (and if it didn't raise KeyError), it would give
+ # the same result, at least as long as this result is still live.
+ #
+ # 'unique_cache.functions' is a list of weak dicts, each mapping
+ # the func_hash number to a W_CTypeFunc. There is normally only
+ # one such dict, but in case of hash collision, there might be
+ # more.
+ unique_cache = space.fromcache(UniqueCache)
+ func_hash = _func_key_hash(unique_cache, fargs, fresult, ellipsis)
+ for weakdict in unique_cache.functions:
+ ctype = weakdict.get(func_hash)
+ if (ctype is not None and
+ ctype.ctitem is fresult and
+ ctype.fargs == fargs and
+ ctype.ellipsis == ellipsis):
+ return ctype
+ raise KeyError
+
+ at jit.dont_look_inside
+def _build_function_type(space, fargs, fresult, ellipsis):
from pypy.module._cffi_backend import ctypefunc
#
- unique_cache = space.fromcache(UniqueCache)
- unique_key = (fargs, w_fresult, ellipsis)
- try:
- return unique_cache.functions[unique_key]
- except KeyError:
- pass
- #
- if ((w_fresult.size < 0 and
- not isinstance(w_fresult, ctypevoid.W_CTypeVoid))
- or isinstance(w_fresult, ctypearray.W_CTypeArray)):
- if (isinstance(w_fresult, ctypestruct.W_CTypeStructOrUnion) and
- w_fresult.size < 0):
+ if ((fresult.size < 0 and
+ not isinstance(fresult, ctypevoid.W_CTypeVoid))
+ or isinstance(fresult, ctypearray.W_CTypeArray)):
+ if (isinstance(fresult, ctypestruct.W_CTypeStructOrUnion) and
+ fresult.size < 0):
raise oefmt(space.w_TypeError,
- "result type '%s' is opaque", w_fresult.name)
+ "result type '%s' is opaque", fresult.name)
else:
raise oefmt(space.w_TypeError,
- "invalid result type: '%s'", w_fresult.name)
+ "invalid result type: '%s'", fresult.name)
#
- fct = ctypefunc.W_CTypeFunc(space, fargs, w_fresult, ellipsis)
- unique_cache.functions[unique_key] = fct
+ fct = ctypefunc.W_CTypeFunc(space, fargs, fresult, ellipsis)
+ unique_cache = space.fromcache(UniqueCache)
+ func_hash = _func_key_hash(unique_cache, fargs, fresult, ellipsis)
+ for weakdict in unique_cache.functions:
+ if weakdict.get(func_hash) is None:
+ weakdict.set(func_hash, fct)
+ break
+ else:
+ weakdict = rweakref.RWeakValueDictionary(int, ctypefunc.W_CTypeFunc)
+ unique_cache.functions.append(weakdict)
+ weakdict.set(func_hash, fct)
return fct
diff --git a/pypy/module/_cffi_backend/test/test_c.py b/pypy/module/_cffi_backend/test/test_c.py
--- a/pypy/module/_cffi_backend/test/test_c.py
+++ b/pypy/module/_cffi_backend/test/test_c.py
@@ -22,7 +22,7 @@
from rpython.tool.udir import udir
from pypy.interpreter import gateway
from pypy.module._cffi_backend import Module
-from pypy.module._cffi_backend.newtype import _clean_cache
+from pypy.module._cffi_backend.newtype import _clean_cache, UniqueCache
from rpython.translator import cdir
from rpython.translator.platform import host
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -86,8 +86,10 @@
_all_test_c.find_and_load_library = func
_all_test_c._testfunc = testfunc
""")
+ UniqueCache.for_testing = True
def teardown_method(self, method):
+ UniqueCache.for_testing = False
_clean_cache(self.space)
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -241,20 +241,26 @@
res = libssl_RAND_status()
return space.wrap(res)
- @unwrap_spec(path=str)
- def RAND_egd(space, path):
- """RAND_egd(path) -> bytes
+ if HAVE_OPENSSL_RAND_EGD:
+ @unwrap_spec(path=str)
+ def RAND_egd(space, path):
+ """RAND_egd(path) -> bytes
- Queries the entropy gather daemon (EGD) on socket path. Returns number
- of bytes read. Raises socket.sslerror if connection to EGD fails or
- if it does provide enough data to seed PRNG."""
- with rffi.scoped_str2charp(path) as socket_path:
- bytes = libssl_RAND_egd(socket_path)
- if bytes == -1:
- raise ssl_error(space,
- "EGD connection failed or EGD did not return "
- "enough data to seed the PRNG")
- return space.wrap(bytes)
+ Queries the entropy gather daemon (EGD) on socket path. Returns number
+ of bytes read. Raises socket.sslerror if connection to EGD fails or
+ if it does provide enough data to seed PRNG."""
+ with rffi.scoped_str2charp(path) as socket_path:
+ bytes = libssl_RAND_egd(socket_path)
+ if bytes == -1:
+ raise ssl_error(space,
+ "EGD connection failed or EGD did not return "
+ "enough data to seed the PRNG")
+ return space.wrap(bytes)
+ else:
+ # Dummy func for platforms missing RAND_egd(). Most likely LibreSSL.
+ @unwrap_spec(path=str)
+ def RAND_egd(space, path):
+ raise ssl_error(space, "RAND_egd unavailable")
class _SSLSocket(W_Root):
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -36,7 +36,8 @@
assert isinstance(_ssl.OPENSSL_VERSION_INFO, tuple)
assert len(_ssl.OPENSSL_VERSION_INFO) == 5
assert isinstance(_ssl.OPENSSL_VERSION, str)
- assert 'openssl' in _ssl.OPENSSL_VERSION.lower()
+ lower_version = _ssl.OPENSSL_VERSION.lower()
+ assert 'openssl' in lower_version or "libressl" in lower_version
assert isinstance(_ssl.ALERT_DESCRIPTION_ACCESS_DENIED, int)
@@ -69,8 +70,9 @@
def test_sslwrap(self):
import _ssl, _socket, sys, gc
- if sys.platform == 'darwin' or 'freebsd' in sys.platform:
- skip("hangs indefinitely on OSX & FreeBSD (also on CPython)")
+ if sys.platform == 'darwin' or 'freebsd' in sys.platform or \
+ 'openbsd' in sys.platform:
+ skip("hangs indefinitely on OSX & BSD (also on CPython)")
s = _socket.socket()
if sys.version_info < (2, 7, 9):
ss = _ssl.sslwrap(s, 0)
diff --git a/pypy/module/_vmprof/test/test__vmprof.py b/pypy/module/_vmprof/test/test__vmprof.py
--- a/pypy/module/_vmprof/test/test__vmprof.py
+++ b/pypy/module/_vmprof/test/test__vmprof.py
@@ -34,6 +34,7 @@
i += 1
_, size = struct.unpack("ll", s[i:i + 2 * WORD])
i += 2 * WORD + size * struct.calcsize("P")
+ i += WORD # thread id
elif s[i] == '\x02':
i += 1
_, size = struct.unpack("ll", s[i:i + 2 * WORD])
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -844,6 +844,18 @@
b.byteswap()
assert a != b
+ def test_unicode_ord_positive(self):
+ import sys
+ if sys.maxunicode == 0xffff:
+ skip("test for 32-bit unicodes")
+ a = self.array('u', '\xff\xff\xff\xff')
+ assert len(a) == 1
+ assert repr(a[0]) == "u'\Uffffffff'"
+ if sys.maxint == 2147483647:
+ assert ord(a[0]) == -1
+ else:
+ assert ord(a[0]) == 4294967295
+
def test_weakref(self):
import weakref
a = self.array('c', 'Hi!')
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -9,6 +9,7 @@
'ndarray': 'ndarray.W_NDimArray',
'dtype': 'descriptor.W_Dtype',
'flatiter': 'flatiter.W_FlatIterator',
+ 'flagsobj': 'flagsobj.W_FlagsObject',
'_reconstruct' : 'ndarray._reconstruct',
'scalar' : 'ctors.build_scalar',
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -117,12 +117,14 @@
return W_NDimArray(impl)
@staticmethod
- def new_slice(space, offset, strides, backstrides, shape, parent, orig_arr, dtype=None):
+ def new_slice(space, offset, strides, backstrides, shape, parent, w_arr, dtype=None):
from pypy.module.micronumpy import concrete
-
+ w_base = w_arr
+ if w_arr.implementation.base() is not None:
+ w_base = w_arr.implementation.base()
impl = concrete.SliceArray(offset, strides, backstrides, shape, parent,
- orig_arr, dtype)
- return wrap_impl(space, space.type(orig_arr), orig_arr, impl)
+ w_base, dtype)
+ return wrap_impl(space, space.type(w_arr), w_arr, impl)
@staticmethod
def new_scalar(space, dtype, w_val=None):
diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py
--- a/pypy/module/micronumpy/boxes.py
+++ b/pypy/module/micronumpy/boxes.py
@@ -147,7 +147,7 @@
def get_flags(self):
return (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS |
- NPY.ARRAY_WRITEABLE | NPY.ARRAY_OWNDATA)
+ NPY.ARRAY_ALIGNED | NPY.ARRAY_OWNDATA)
def item(self, space):
return self.get_dtype(space).itemtype.to_builtin_type(space, self)
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -1,6 +1,7 @@
from pypy.interpreter.error import OperationError, oefmt
from rpython.rlib import jit, rgc
from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rlib.listsort import make_timsort_class
from rpython.rlib.buffer import Buffer
from rpython.rlib.debug import make_sure_not_resized
from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage, \
@@ -17,6 +18,19 @@
is_f_contiguous)
from rpython.rlib.objectmodel import keepalive_until_here
+TimSort = make_timsort_class()
+class StrideSort(TimSort):
+ '''
+ argsort (return the indices to sort) a list of strides
+ '''
+ def __init__(self, rangelist, strides):
+ self.strides = strides
+ TimSort.__init__(self, rangelist)
+
+ def lt(self, a, b):
+ return self.strides[a] < self.strides[b]
+
+
class BaseConcreteArray(object):
_immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]',
'strides[*]', 'backstrides[*]', 'order', 'gcstruct',
@@ -354,12 +368,15 @@
elif order != self.order:
t_strides, backstrides = calc_strides(shape, dtype, order)
else:
- mins = strides[0]
+ indx_array = range(len(strides))
+ list_sorter = StrideSort(indx_array, strides)
+ list_sorter.sort()
t_elsize = dtype.elsize
- for s in strides:
- if s < mins:
- mins = s
- t_strides = [s * t_elsize / mins for s in strides]
+ t_strides = strides[:]
+ base = dtype.elsize
+ for i in indx_array:
+ t_strides[i] = base
+ base *= shape[i]
backstrides = calc_backstrides(t_strides, shape)
impl = ConcreteArray(shape, dtype, order, t_strides, backstrides)
loop.setslice(space, impl.get_shape(), impl, self)
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -133,7 +133,9 @@
return w_arr
else:
imp = w_object.implementation
- w_base = imp.base() or w_object
+ w_base = w_object
+ if imp.base() is not None:
+ w_base = imp.base()
with imp as storage:
sz = support.product(w_object.get_shape()) * dtype.elsize
return W_NDimArray.from_shape_and_storage(space,
diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py
--- a/pypy/module/micronumpy/flagsobj.py
+++ b/pypy/module/micronumpy/flagsobj.py
@@ -57,6 +57,9 @@
self.flags & NPY.ARRAY_F_CONTIGUOUS or
self.flags & NPY.ARRAY_C_CONTIGUOUS ))
+ def descr_get_num(self, space):
+ return space.wrap(self.flags)
+
def descr_getitem(self, space, w_item):
key = space.str_w(w_item)
if key == "C" or key == "CONTIGUOUS" or key == "C_CONTIGUOUS":
@@ -122,4 +125,5 @@
aligned = GetSetProperty(W_FlagsObject.descr_get_aligned),
fnc = GetSetProperty(W_FlagsObject.descr_get_fnc),
forc = GetSetProperty(W_FlagsObject.descr_get_forc),
+ num = GetSetProperty(W_FlagsObject.descr_get_num),
)
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -747,8 +747,12 @@
return out
def descr_get_ctypes(self, space):
- raise OperationError(space.w_NotImplementedError, space.wrap(
- "ctypes not implemented yet"))
+ w_result = space.appexec([self], """(arr):
+ from numpy.core import _internal
+ p_data = arr.__array_interface__['data'][0]
+ return _internal._ctypes(arr, p_data)
+ """)
+ return w_result
def buffer_w(self, space, flags):
return self.implementation.get_buffer(space, True)
@@ -1304,6 +1308,9 @@
[space.wrap(0)]), space.wrap("b")])
builder = StringBuilder()
+ if self.get_dtype().is_object():
+ raise oefmt(space.w_NotImplementedError,
+ "reduce for 'object' dtype not supported yet")
if isinstance(self.implementation, SliceArray):
iter, state = self.implementation.create_iter()
while not iter.done(state):
diff --git a/pypy/module/micronumpy/test/test_flagsobj.py b/pypy/module/micronumpy/test/test_flagsobj.py
--- a/pypy/module/micronumpy/test/test_flagsobj.py
+++ b/pypy/module/micronumpy/test/test_flagsobj.py
@@ -30,6 +30,7 @@
assert a.flags.forc == True
assert a.flags['FNC'] == False
assert a.flags['FORC'] == True
+ assert a.flags.num == 1287
raises(KeyError, "a.flags['blah']")
raises(KeyError, "a.flags['C_CONTIGUOUS'] = False")
raises((TypeError, AttributeError), "a.flags.c_contiguous = False")
@@ -38,6 +39,7 @@
import numpy as np
a = np.int32(2)
assert a.flags.c_contiguous == True
+ assert a.flags.num == 263
def test_compare(self):
import numpy as np
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -2218,7 +2218,7 @@
assert _weakref.ref(a)
def test_astype(self):
- from numpy import array, arange
+ from numpy import array, arange, empty
b = array(1).astype(float)
assert b == 1
assert b.dtype == float
@@ -2273,14 +2273,36 @@
b = a.astype('f4', order='C', copy=False)
assert a is b
+ a = empty([3, 3, 3, 3], 'uint8')
+ a[:] = 0
+ b = a[2]
+ c = b[:, :2, :]
+ d = c.swapaxes(1, -1)
+ e = d.astype('complex128')
+ assert e.shape == (3, 3, 2)
+ assert e.strides == (96, 16, 48)
+ assert (e.real == d).all()
+
def test_base(self):
- from numpy import array
+ from numpy import array, empty
assert array(1).base is None
assert array([1, 2]).base is None
a = array([1, 2, 3, 4])
b = a[::2]
assert b.base is a
+ a = empty([3, 3, 3, 3], 'uint8')
+ a[:] = 0
+ b = a[2]
+ assert b.base.base is None
+ c = b[:, :2, :]
+ d = c.swapaxes(1, -1)
+ assert c.base.base is None
+ assert d.base.base is None
+ assert d.shape == (3, 3, 2)
+ assert d.__array_interface__['data'][0] == \
+ a.__array_interface__['data'][0] + a.strides[0] * 2
+
def test_byteswap(self):
from numpy import array
@@ -2497,10 +2519,10 @@
assert b.shape == b[...].shape
assert (b == b[...]).all()
- a = np.arange(6).reshape(2, 3)
+ a = np.arange(6)
if '__pypy__' in sys.builtin_module_names:
raises(ValueError, "a[..., ...]")
- b = a [..., 0]
+ b = a.reshape(2, 3)[..., 0]
assert (b == [0, 3]).all()
assert b.base is a
diff --git a/pypy/module/micronumpy/test/test_object_arrays.py b/pypy/module/micronumpy/test/test_object_arrays.py
--- a/pypy/module/micronumpy/test/test_object_arrays.py
+++ b/pypy/module/micronumpy/test/test_object_arrays.py
@@ -3,6 +3,8 @@
class AppTestObjectDtypes(BaseNumpyAppTest):
+ spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"])
+
def setup_class(cls):
BaseNumpyAppTest.setup_class.im_func(cls)
cls.w_runappdirect = cls.space.wrap(option.runappdirect)
@@ -187,3 +189,21 @@
assert b.shape == (1,)
assert b.dtype == np.float_
assert (b == 1.0).all()
+
+
+ def test__reduce__(self):
+ from numpy import arange, dtype
+ from cPickle import loads, dumps
+ import sys
+
+ a = arange(15).astype(object)
+ if '__pypy__' in sys.builtin_module_names:
+ raises(NotImplementedError, dumps, a)
+ skip('not implemented yet')
+ b = loads(dumps(a))
+ assert (a == b).all()
+
+ a = arange(15).astype(object).reshape((3, 5))
+ b = loads(dumps(a))
+ assert (a == b).all()
+
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -315,11 +315,12 @@
"""
ll_times = jit_hooks.stats_get_loop_run_times(None)
w_times = space.newdict()
- for i in range(len(ll_times)):
- w_key = space.newtuple([space.wrap(ll_times[i].type),
- space.wrap(ll_times[i].number)])
- space.setitem(w_times, w_key,
- space.wrap(ll_times[i].counter))
+ if ll_times:
+ for i in range(len(ll_times)):
+ w_key = space.newtuple([space.wrap(ll_times[i].type),
+ space.wrap(ll_times[i].number)])
+ space.setitem(w_times, w_key,
+ space.wrap(ll_times[i].counter))
w_counters = space.newdict()
for i, counter_name in enumerate(Counters.counter_names):
v = jit_hooks.stats_get_counter_value(None, i)
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -213,22 +213,6 @@
self.on_abort()
assert l == [('pypyjit', 'ABORT_TOO_LONG', [])]
- def test_on_optimize(self):
- import pypyjit
- l = []
-
- def hook(info):
- l.append(info.jitdriver_name)
-
- def optimize_hook(info):
- return []
-
- pypyjit.set_compile_hook(hook)
- pypyjit.set_optimize_hook(optimize_hook)
- self.on_optimize()
- self.on_compile()
- assert l == ['pypyjit']
-
def test_creation(self):
from pypyjit import ResOperation
diff --git a/pypy/module/pypyjit/test_pypy_c/test_buffers.py b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_buffers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_buffers.py
@@ -27,7 +27,7 @@
def test_struct_unpack(self):
def main(n):
- import struct
+ import _struct as struct
import array
a = array.array('c', struct.pack('i', 42))
i = 0
diff --git a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
--- a/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_jitlogparser.py
@@ -76,6 +76,6 @@
assert len(mod_bridges) in (1, 2, 3)
# check that counts are reasonable (precise # may change in the future)
- assert N - 2000 < sum(l.count for l in fn_with_bridges_loops) < N + 1000
+ assert N - 2000 < sum(l.count for l in fn_with_bridges_loops) < N + 1500
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -2,7 +2,7 @@
import py
import platform
import sys, ctypes
-from cffi import FFI, CDefError, FFIError
+from cffi import FFI, CDefError, FFIError, VerificationMissing
from pypy.module.test_lib_pypy.cffi_tests.support import *
SIZE_OF_INT = ctypes.sizeof(ctypes.c_int)
@@ -927,6 +927,14 @@
assert ffi.string(ffi.cast("enum foo", -16)) == "E"
assert ffi.string(ffi.cast("enum foo", -8)) == "F"
+ def test_enum_partial(self):
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };")
+ lib = ffi.dlopen(None)
+ assert lib.B == 0
+ py.test.raises(VerificationMissing, getattr, lib, "A")
+ assert lib.C == 1
+
def test_array_of_struct(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b; };")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_model.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_model.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_model.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_model.py
@@ -58,6 +58,11 @@
assert ptr_type.get_c_name("") == "int(const *)[5]"
assert ptr_type.get_c_name("*x") == "int(const * *x)[5]"
+def test_qual_pointer_type():
+ ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT)
+ assert ptr_type.get_c_name("") == "long long __restrict *"
+ assert const_voidp_type.get_c_name("") == "void const *"
+
def test_unknown_pointer_type():
ptr_type = unknown_ptr_type("foo_p")
assert ptr_type.get_c_name("") == "foo_p"
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_parsing.py
@@ -308,7 +308,6 @@
ffi.cdef("void f(WPARAM);")
def test__is_constant_globalvar():
- from cffi.cparser import Parser, _get_parser
for input, expected_output in [
("int a;", False),
("const int a;", True),
@@ -325,11 +324,36 @@
("int a[5][6];", False),
("const int a[5][6];", False),
]:
- p = Parser()
- ast = _get_parser().parse(input)
- decl = ast.children()[0][1]
- node = decl.type
- assert p._is_constant_globalvar(node) == expected_output
+ ffi = FFI()
+ ffi.cdef(input)
+ declarations = ffi._parser._declarations
+ assert ('constant a' in declarations) == expected_output
+ assert ('variable a' in declarations) == (not expected_output)
+
+def test_restrict():
+ from cffi import model
+ for input, expected_output in [
+ ("int a;", False),
+ ("restrict int a;", True),
+ ("int *a;", False),
+ ]:
+ ffi = FFI()
+ ffi.cdef(input)
+ tp, quals = ffi._parser._declarations['variable a']
+ assert bool(quals & model.Q_RESTRICT) == expected_output
+
+def test_different_const_funcptr_types():
+ lst = []
+ for input in [
+ "int(*)(int *a)",
+ "int(*)(int const *a)",
+ "int(*)(int * const a)",
+ "int(*)(int const a[])"]:
+ ffi = FFI(backend=FakeBackend())
+ lst.append(ffi._parser.parse_type(input))
+ assert lst[0] != lst[1]
+ assert lst[0] == lst[2]
+ assert lst[1] == lst[3]
def test_enum():
ffi = FFI()
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_verify.py
@@ -1636,11 +1636,11 @@
def test_FILE_stored_explicitly():
ffi = FFI()
- ffi.cdef("int myprintf(const char *, int); FILE *myfile;")
+ ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
- int myprintf(const char *out, int value) {
+ int myprintf11(const char *out, int value) {
return fprintf(myfile, out, value);
}
""")
@@ -1650,7 +1650,7 @@
lib.myfile = ffi.cast("FILE *", fw1)
#
fw1.write(b"X")
- r = lib.myprintf(b"hello, %d!\n", ffi.cast("int", 42))
+ r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
fw1.close()
assert r == len("hello, 42!\n")
#
@@ -2248,3 +2248,13 @@
e = py.test.raises(VerificationError, ffi.verify, "")
assert str(e.value) == ("feature not supported with ffi.verify(), but only "
"with ffi.set_source(): 'typedef unsigned long... t1'")
+
+def test_const_fields():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { const int a; void *const b; };""")
+ ffi.verify("""struct foo_s { const int a; void *const b; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'a'
+ assert foo_s.fields[0][1].type is ffi.typeof("int")
+ assert foo_s.fields[1][0] == 'b'
+ assert foo_s.fields[1][1].type is ffi.typeof("void *")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
@@ -30,6 +30,32 @@
assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]")
assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()")
+def test_ffi_type_not_immortal():
+ import weakref, gc
+ ffi = _cffi1_backend.FFI()
+ t1 = ffi.typeof("int **")
+ t2 = ffi.typeof("int *")
+ w1 = weakref.ref(t1)
+ w2 = weakref.ref(t2)
+ del t1, ffi
+ gc.collect()
+ assert w1() is None
+ assert w2() is t2
+ ffi = _cffi1_backend.FFI()
+ assert ffi.typeof(ffi.new("int **")[0]) is t2
+ #
+ ffi = _cffi1_backend.FFI()
+ t1 = ffi.typeof("int ***")
+ t2 = ffi.typeof("int **")
+ w1 = weakref.ref(t1)
+ w2 = weakref.ref(t2)
+ del t2, ffi
+ gc.collect()
+ assert w1() is t1
+ assert w2() is not None # kept alive by t1
+ ffi = _cffi1_backend.FFI()
+ assert ffi.typeof("int * *") is t1.item
+
def test_ffi_cache_type_globally():
ffi1 = _cffi1_backend.FFI()
ffi2 = _cffi1_backend.FFI()
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_re_python.py
@@ -2,7 +2,7 @@
import sys
import py
from cffi import FFI
-from cffi import recompiler, ffiplatform
+from cffi import recompiler, ffiplatform, VerificationMissing
from pypy.module.test_lib_pypy.cffi_tests.udir import udir
@@ -204,3 +204,10 @@
"foobar", _version=0x2594)
assert str(e.value).startswith(
"cffi out-of-line Python module 'foobar' has unknown version")
+
+def test_partial_enum():
+ ffi = FFI()
+ ffi.cdef("enum foo { A, B, ... };")
+ ffi.set_source('test_partial_enum', None)
+ py.test.raises(VerificationMissing, ffi.emit_python_code,
+ str(tmpdir.join('test_partial_enum.py')))
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -1192,3 +1192,92 @@
py.test.raises(ffi.error, getattr, lib, 'my_value')
e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50)
assert str(e.value) == "global variable 'my_value' is at address NULL"
+
+def test_const_fields():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { const int a; void *const b; };""")
+ lib = verify(ffi, 'test_const_fields', """
+ struct foo_s { const int a; void *const b; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'a'
+ assert foo_s.fields[0][1].type is ffi.typeof("int")
+ assert foo_s.fields[1][0] == 'b'
+ assert foo_s.fields[1][1].type is ffi.typeof("void *")
+
+def test_restrict_fields():
+ if sys.platform == 'win32':
+ py.test.skip("'__restrict__' probably not recognized")
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { void * restrict b; };""")
+ lib = verify(ffi, 'test_restrict_fields', """
+ struct foo_s { void * __restrict__ b; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'b'
+ assert foo_s.fields[0][1].type is ffi.typeof("void *")
+
+def test_const_array_fields():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { const int a[4]; };""")
+ lib = verify(ffi, 'test_const_array_fields', """
+ struct foo_s { const int a[4]; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'a'
+ assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
+
+def test_const_array_fields_varlength():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { const int a[]; ...; };""")
+ lib = verify(ffi, 'test_const_array_fields_varlength', """
+ struct foo_s { const int a[4]; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'a'
+ assert foo_s.fields[0][1].type is ffi.typeof("int[]")
+
+def test_const_array_fields_unknownlength():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { const int a[...]; ...; };""")
+ lib = verify(ffi, 'test_const_array_fields_unknownlength', """
+ struct foo_s { const int a[4]; };""")
+ foo_s = ffi.typeof("struct foo_s")
+ assert foo_s.fields[0][0] == 'a'
+ assert foo_s.fields[0][1].type is ffi.typeof("int[4]")
+
+def test_const_function_args():
+ ffi = FFI()
+ ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""")
+ lib = verify(ffi, 'test_const_function_args', """
+ int foobar(const int a, const int *b, const int c[]) {
+ return a + *b + *c;
+ }
+ """)
+ assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142
+
+def test_const_function_type_args():
+ ffi = FFI()
+ ffi.cdef("""int (*foobar)(const int a, const int *b, const int c[]);""")
+ lib = verify(ffi, 'test_const_function_type_args', """
+ int (*foobar)(const int a, const int *b, const int c[]);
+ """)
+ t = ffi.typeof(lib.foobar)
+ assert t.args[0] is ffi.typeof("int")
+ assert t.args[1] is ffi.typeof("int *")
+ assert t.args[2] is ffi.typeof("int *")
+
+def test_const_constant():
+ ffi = FFI()
+ ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""")
+ lib = verify(ffi, 'test_const_constant', """
+ struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 };
+ """)
+ assert lib.myfoo.x == 40
+ assert lib.myfoo.y == 2
+
+def test_const_via_typedef():
+ ffi = FFI()
+ ffi.cdef("""typedef const int const_t; const_t aaa;""")
+ lib = verify(ffi, 'test_const_via_typedef', """
+ typedef const int const_t;
+ #define aaa 42
+ """)
+ assert lib.aaa == 42
+ py.test.raises(AttributeError, "lib.aaa = 43")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_verify1.py
@@ -1623,11 +1623,11 @@
def test_FILE_stored_explicitly():
ffi = FFI()
- ffi.cdef("int myprintf(const char *, int); FILE *myfile;")
+ ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
- int myprintf(const char *out, int value) {
+ int myprintf11(const char *out, int value) {
return fprintf(myfile, out, value);
}
""")
@@ -1637,7 +1637,7 @@
lib.myfile = ffi.cast("FILE *", fw1)
#
fw1.write(b"X")
- r = lib.myprintf(b"hello, %d!\n", ffi.cast("int", 42))
+ r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
fw1.close()
assert r == len("hello, 42!\n")
#
@@ -1923,7 +1923,7 @@
assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>"
def test_bug_const_char_ptr_array_2():
- ffi = FFI_warnings_not_error() # ignore warnings
+ ffi = FFI()
ffi.cdef("""const int a[];""")
lib = ffi.verify("""const int a[5];""")
assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>"
diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py
--- a/pypy/module/thread/test/test_lock.py
+++ b/pypy/module/thread/test/test_lock.py
@@ -123,23 +123,26 @@
self.sig_recvd = True
old_handler = signal.signal(signal.SIGUSR1, my_handler)
try:
+ ready = thread.allocate_lock()
+ ready.acquire()
def other_thread():
# Acquire the lock in a non-main thread, so this test works for
# RLocks.
lock.acquire()
- # Wait until the main thread is blocked in the lock acquire, and
- # then wake it up with this.
- time.sleep(0.5)
+ # Notify the main thread that we're ready
+ ready.release()
+ # Wait for 5 seconds here
+ for n in range(50):
+ time.sleep(0.1)
+ # Send the signal
os.kill(os.getpid(), signal.SIGUSR1)
# Let the main thread take the interrupt, handle it, and retry
# the lock acquisition. Then we'll let it run.
- time.sleep(0.5)
+ for n in range(50):
+ time.sleep(0.1)
lock.release()
More information about the pypy-commit
mailing list