Author: Matti Picus <[email protected]>
Branch: cpyext-werror
Changeset: r84071:1846e020572e
Date: 2016-04-30 23:25 +0300
http://bitbucket.org/pypy/pypy/changeset/1846e020572e/
Log: merge default into branch
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
@@ -24,7 +24,11 @@
remove-objspace-options.
.. branch: cpyext-for-merge
-Update cpyext C-API support:
+
+Update cpyext C-API support After this branch, we are almost able to support
+upstream numpy via cpyext, so we created (yet another) fork of numpy at
+github.com/pypy/numpy with the needed changes. Among the significant changes
+to cpyext:
- allow c-snippet tests to be run with -A so we can verify we are compatible
- fix many edge cases exposed by fixing tests to run with -A
- issequence() logic matches cpython
@@ -40,6 +44,8 @@
- rewrite slot assignment for typeobjects
- improve tracking of PyObject to rpython object mapping
- support tp_as_{number, sequence, mapping, buffer} slots
-After this branch, we are almost able to support upstream numpy via cpyext, so
-we created (yet another) fork of numpy at github.com/pypy/numpy with the needed
-changes
+
+.. branch: share-mapdict-methods-2
+
+Reduce generated code for subclasses by using the same function objects in all
+generated subclasses.
diff --git a/pypy/module/cpyext/ndarrayobject.py
b/pypy/module/cpyext/ndarrayobject.py
--- a/pypy/module/cpyext/ndarrayobject.py
+++ b/pypy/module/cpyext/ndarrayobject.py
@@ -253,12 +253,8 @@
check_return, w_signature):
funcs_w = [None] * ntypes
dtypes_w = [None] * ntypes * (nin + nout)
- # XXX For some reason funcs[i] segfaults, but this does not:
- # cast(gufunctype, cast(CArrayPtr(CArrayPtr(gufunctype)), funcs)[i])
- # Something is very wrong here.
- funcs_wrong_type = rffi.cast(rffi.CArrayPtr(rffi.CArrayPtr(gufunctype)),
funcs)
for i in range(ntypes):
- funcs_w[i] = ufuncs.W_GenericUFuncCaller(rffi.cast(gufunctype,
funcs_wrong_type[i]), data)
+ funcs_w[i] = ufuncs.W_GenericUFuncCaller(funcs[i], data)
for i in range(ntypes*(nin+nout)):
dtypes_w[i] = get_dtype_cache(space).dtypes_by_num[ord(types[i])]
w_funcs = space.newlist(funcs_w)
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
@@ -366,7 +366,7 @@
def test_ufunc(self):
if self.runappdirect:
from numpy import arange
- py.test.xfail('why does this segfault on cpython?')
+ py.test.xfail('segfaults on cpython: PyUFunc_API == NULL?')
else:
from _numpypy.multiarray import arange
mod = self.import_extension('foo', [
diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py
b/rpython/rtyper/lltypesystem/ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/ll2ctypes.py
@@ -231,17 +231,7 @@
assert max_n >= 0
ITEM = A.OF
ctypes_item = get_ctypes_type(ITEM, delayed_builders)
- # Python 2.5 ctypes can raise OverflowError on 64-bit builds
- for n in [maxint, 2**31]:
- MAX_SIZE = n/64
- try:
- PtrType = ctypes.POINTER(MAX_SIZE * ctypes_item)
- except (OverflowError, AttributeError), e:
- pass # ^^^ bah, blame ctypes
- else:
- break
- else:
- raise e
+ ctypes_item_ptr = ctypes.POINTER(ctypes_item)
class CArray(ctypes.Structure):
if is_emulated_long:
@@ -265,35 +255,9 @@
bigarray.length = n
return bigarray
- _ptrtype = None
-
- @classmethod
- def _get_ptrtype(cls):
- if cls._ptrtype:
- return cls._ptrtype
- # ctypes can raise OverflowError on 64-bit builds
- # on windows it raises AttributeError even for 2**31 (_length_
missing)
- if _MS_WINDOWS:
- other_limit = 2**31-1
- else:
- other_limit = 2**31
- for n in [maxint, other_limit]:
- cls.MAX_SIZE = n / ctypes.sizeof(ctypes_item)
- try:
- cls._ptrtype = ctypes.POINTER(cls.MAX_SIZE * ctypes_item)
- except (OverflowError, AttributeError), e:
- pass
- else:
- break
- else:
- raise e
- return cls._ptrtype
-
def _indexable(self, index):
- PtrType = self._get_ptrtype()
- assert index + 1 < self.MAX_SIZE
- p = ctypes.cast(ctypes.pointer(self.items), PtrType)
- return p.contents
+ p = ctypes.cast(self.items, ctypes_item_ptr)
+ return p
def _getitem(self, index, boundscheck=True):
if boundscheck:
@@ -1045,12 +1009,22 @@
container = _array_of_known_length(T.TO)
container._storage = type(cobj)(cobj.contents)
elif isinstance(T.TO, lltype.FuncType):
+ # cobj is a CFunctionType object. We naively think
+ # that it should be a function pointer. No no no. If
+ # it was read out of an array, say, then it is a *pointer*
+ # to a function pointer. In other words, the read doesn't
+ # read anything, it just takes the address of the function
+ # pointer inside the array. If later the array is modified
+ # or goes out of scope, then we crash. CTypes is fun.
+ # It works if we cast it now to an int and back.
cobjkey = intmask(ctypes.cast(cobj, ctypes.c_void_p).value)
if cobjkey in _int2obj:
container = _int2obj[cobjkey]
else:
+ name = getattr(cobj, '__name__', '?')
+ cobj = ctypes.cast(cobjkey, type(cobj))
_callable = get_ctypes_trampoline(T.TO, cobj)
- return lltype.functionptr(T.TO, getattr(cobj, '__name__',
'?'),
+ return lltype.functionptr(T.TO, name,
_callable=_callable)
elif isinstance(T.TO, lltype.OpaqueType):
if T == llmemory.GCREF:
diff --git a/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
b/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
--- a/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
+++ b/rpython/rtyper/lltypesystem/test/test_ll2ctypes.py
@@ -1405,6 +1405,45 @@
a2 = ctypes2lltype(lltype.Ptr(A), lltype2ctypes(a))
assert a2._obj.getitem(0)._obj._parentstructure() is a2._obj
+ def test_array_of_function_pointers(self):
+ c_source = py.code.Source(r"""
+ #include "src/precommondefs.h"
+ #include <stdio.h>
+
+ typedef int(*funcptr_t)(void);
+ static int forty_two(void) { return 42; }
+ static int forty_three(void) { return 43; }
+ static funcptr_t testarray[2];
+ RPY_EXPORTED void runtest(void cb(funcptr_t *)) {
+ testarray[0] = &forty_two;
+ testarray[1] = &forty_three;
+ fprintf(stderr, "&forty_two = %p\n", testarray[0]);
+ fprintf(stderr, "&forty_three = %p\n", testarray[1]);
+ cb(testarray);
+ testarray[0] = 0;
+ testarray[1] = 0;
+ }
+ """)
+ eci = ExternalCompilationInfo(include_dirs=[cdir],
+ separate_module_sources=[c_source])
+
+ PtrF = lltype.Ptr(lltype.FuncType([], rffi.INT))
+ ArrayPtrF = rffi.CArrayPtr(PtrF)
+ CALLBACK = rffi.CCallback([ArrayPtrF], lltype.Void)
+
+ runtest = rffi.llexternal('runtest', [CALLBACK], lltype.Void,
+ compilation_info=eci)
+ seen = []
+
+ def callback(testarray):
+ seen.append(testarray[0]) # read a PtrF out of testarray
+ seen.append(testarray[1])
+
+ runtest(callback)
+ assert seen[0]() == 42
+ assert seen[1]() == 43
+
+
class TestPlatform(object):
def test_lib_on_libpaths(self):
from rpython.translator.platform import platform
diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py
--- a/rpython/rtyper/rpbc.py
+++ b/rpython/rtyper/rpbc.py
@@ -544,6 +544,21 @@
ll_compress = compression_function(r_set)
return llops.gendirectcall(ll_compress, v)
+class __extend__(pairtype(FunctionReprBase, FunctionReprBase)):
+ def rtype_is_((robj1, robj2), hop):
+ if hop.s_result.is_constant():
+ return inputconst(Bool, hop.s_result.const)
+ s_pbc = annmodel.unionof(robj1.s_pbc, robj2.s_pbc)
+ r_pbc = hop.rtyper.getrepr(s_pbc)
+ v1, v2 = hop.inputargs(r_pbc, r_pbc)
+ assert v1.concretetype == v2.concretetype
+ if v1.concretetype == Char:
+ return hop.genop('char_eq', [v1, v2], resulttype=Bool)
+ elif isinstance(v1.concretetype, Ptr):
+ return hop.genop('ptr_eq', [v1, v2], resulttype=Bool)
+ else:
+ raise TyperError("unknown type %r" % (v1.concretetype,))
+
def conversion_table(r_from, r_to):
if r_to in r_from._conversion_tables:
diff --git a/rpython/rtyper/test/test_rpbc.py b/rpython/rtyper/test/test_rpbc.py
--- a/rpython/rtyper/test/test_rpbc.py
+++ b/rpython/rtyper/test/test_rpbc.py
@@ -1497,6 +1497,47 @@
res = self.interpret(f, [2])
assert res == False
+ def test_is_among_functions_2(self):
+ def g1(): pass
+ def g2(): pass
+ def f(n):
+ if n > 5:
+ g = g2
+ else:
+ g = g1
+ g()
+ return g is g2
+ res = self.interpret(f, [2])
+ assert res == False
+ res = self.interpret(f, [8])
+ assert res == True
+
+ def test_is_among_functions_3(self):
+ def g0(): pass
+ def g1(): pass
+ def g2(): pass
+ def g3(): pass
+ def g4(): pass
+ def g5(): pass
+ def g6(): pass
+ def g7(): pass
+ glist = [g0, g1, g2, g3, g4, g5, g6, g7]
+ def f(n):
+ if n > 5:
+ g = g2
+ else:
+ g = g1
+ h = glist[n]
+ g()
+ h()
+ return g is h
+ res = self.interpret(f, [2])
+ assert res == False
+ res = self.interpret(f, [1])
+ assert res == True
+ res = self.interpret(f, [6])
+ assert res == False
+
def test_shrink_pbc_set(self):
def g1():
return 10
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit