Author: Matti Picus <[email protected]>
Branch: cpyext-from2
Changeset: r89395:7e0eb703936d
Date: 2017-01-06 15:46 +0200
http://bitbucket.org/pypy/pypy/changeset/7e0eb703936d/
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
@@ -87,3 +87,7 @@
Implement StringBuffer.get_raw_address (missing feature for the buffer
protocol).
More generally it is now possible to obtain the address of any object (if it
is readonly) without pinning it.
+
+.. branch: cpyext-cleanup
+
+Refactor cpyext initialisation.
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -219,7 +219,7 @@
# cpyext types that may have only old buffer interface
w_impl = space.lookup(self, '__wbuffer__')
if w_impl is not None:
- w_result = space.get_and_call_function(w_impl, self,
+ w_result = space.get_and_call_function(w_impl, self,
space.newint(flags))
if space.isinstance_w(w_result, space.w_buffer):
return w_result.buffer_w(space, flags)
@@ -665,9 +665,6 @@
def setup_builtin_modules(self):
"NOT_RPYTHON: only for initializing the space."
- if self.config.objspace.usemodules.cpyext:
- from pypy.module.cpyext.state import State
- self.fromcache(State).build_api(self)
self.getbuiltinmodule('sys')
self.getbuiltinmodule('imp')
self.getbuiltinmodule('__builtin__')
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -1,5 +1,4 @@
from pypy.interpreter.mixedmodule import MixedModule
-from pypy.interpreter import gateway
from pypy.module.cpyext.state import State
from pypy.module.cpyext import api
@@ -13,12 +12,17 @@
atexit_funcs = []
+ def setup_after_space_initialization(self):
+ state = self.space.fromcache(State)
+ state.setup_rawrefcount()
+ state.build_api()
+
def startup(self, space):
space.fromcache(State).startup(space)
method = pypy.module.cpyext.typeobject.get_new_method_def(space)
w_obj = pypy.module.cpyext.methodobject.W_PyCFunctionObject(space,
method, space.wrap(''))
space.appexec([space.type(w_obj)], """(methodtype):
- from pickle import Pickler
+ from pickle import Pickler
Pickler.dispatch[methodtype] = Pickler.save_global
""")
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
@@ -1,5 +1,6 @@
import ctypes
import sys, os
+from collections import defaultdict
import py
@@ -71,7 +72,6 @@
class CConfig_constants:
_compilation_info_ = CConfig._compilation_info_
-VA_LIST_P = rffi.VOIDP # rffi.COpaquePtr('va_list')
CONST_STRING = lltype.Ptr(lltype.Array(lltype.Char,
hints={'nolength': True}),
use_cache=False)
@@ -364,8 +364,8 @@
func_name = func.func_name
if header is not None:
c_name = None
- assert func_name not in FUNCTIONS, (
- "%s already registered" % func_name)
+ if func_name in FUNCTIONS_BY_HEADER[header]:
+ raise ValueError("%s already registered" % func_name)
else:
c_name = func_name
api_function = ApiFunction(argtypes, restype, func, error,
@@ -463,9 +463,7 @@
return res
if header is not None:
- if header == DEFAULT_HEADER:
- FUNCTIONS[func_name] = api_function
- FUNCTIONS_BY_HEADER.setdefault(header, {})[func_name] =
api_function
+ FUNCTIONS_BY_HEADER[header][func_name] = api_function
INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests
return unwrapper # used in 'normal' RPython code.
return decorate
@@ -489,8 +487,7 @@
GLOBALS[name] = (typ, expr)
INTERPLEVEL_API = {}
-FUNCTIONS = {}
-FUNCTIONS_BY_HEADER = {}
+FUNCTIONS_BY_HEADER = defaultdict(dict)
# These are C symbols which cpyext will export, but which are defined in .c
# files somewhere in the implementation of cpyext (rather than being defined in
@@ -526,6 +523,8 @@
'PyCapsule_SetPointer', 'PyCapsule_SetName', 'PyCapsule_SetDestructor',
'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type',
'_Py_get_capsule_type',
+ 'PyComplex_AsCComplex', 'PyComplex_FromCComplex',
+
'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer',
'PyObject_CheckReadBuffer',
'PyOS_getsig', 'PyOS_setsig',
@@ -572,7 +571,9 @@
# PyExc_AttributeError, PyExc_OverflowError, PyExc_ImportError,
# PyExc_NameError, PyExc_MemoryError, PyExc_RuntimeError,
# PyExc_UnicodeEncodeError, PyExc_UnicodeDecodeError, ...
- for exc_name in exceptions.Module.interpleveldefs.keys():
+ global all_exceptions
+ all_exceptions = list(exceptions.Module.interpleveldefs)
+ for exc_name in all_exceptions:
register_global('PyExc_' + exc_name,
'PyTypeObject*',
'space.gettypeobject(interp_exceptions.W_%s.typedef)'% (exc_name,
))
@@ -616,14 +617,6 @@
% (cpyname, ))
build_exported_objects()
-def get_structtype_for_ctype(ctype):
- from pypy.module.cpyext.typeobjectdefs import PyTypeObjectPtr
- from pypy.module.cpyext.cdatetime import PyDateTime_CAPI
- from pypy.module.cpyext.intobject import PyIntObject
- return {"PyObject*": PyObject, "PyTypeObject*": PyTypeObjectPtr,
- "PyIntObject*": PyIntObject,
- "PyDateTime_CAPI*": lltype.Ptr(PyDateTime_CAPI)}[ctype]
-
# Note: as a special case, "PyObject" is the pointer type in RPython,
# corresponding to "PyObject *" in C. We do that only for PyObject.
# For example, "PyTypeObject" is the struct type even in RPython.
@@ -672,12 +665,6 @@
# a pointer to PyObject
PyObjectP = rffi.CArrayPtr(PyObject)
-VA_TP_LIST = {}
-#{'int': lltype.Signed,
-# 'PyObject*': PyObject,
-# 'PyObject**': PyObjectP,
-# 'int*': rffi.INTP}
-
def configure_types():
for config in (CConfig, CConfig2):
for name, TYPE in rffi_platform.configure(config).iteritems():
@@ -951,21 +938,8 @@
wrapper_second_level._dont_inline_ = True
return wrapper_second_level
-def process_va_name(name):
- return name.replace('*', '_star')
-def setup_va_functions(eci):
- for name, TP in VA_TP_LIST.iteritems():
- name_no_star = process_va_name(name)
- func = rffi.llexternal('pypy_va_get_%s' % name_no_star, [VA_LIST_P],
- TP, compilation_info=eci)
- globals()['va_get_%s' % name_no_star] = func
-
-def setup_init_functions(eci, translating):
- if translating:
- prefix = 'PyPy'
- else:
- prefix = 'cpyexttest'
+def setup_init_functions(eci, prefix):
# jump through hoops to avoid releasing the GIL during initialization
# of the cpyext module. The C functions are called with no wrapper,
# but must not do anything like calling back PyType_Ready(). We
@@ -1027,23 +1001,27 @@
# Do not call this more than once per process
def build_bridge(space):
"NOT_RPYTHON"
- from pypy.module.cpyext.pyobject import make_ref
from rpython.translator.c.database import LowLevelDatabase
use_micronumpy = setup_micronumpy(space)
db = LowLevelDatabase()
- prefix ='cpyexttest'
+ prefix = 'cpyexttest'
- functions = generate_decls_and_callbacks(db, prefix=prefix)
+ generate_decls_and_callbacks(db, prefix=prefix)
# Structure declaration code
+ functions = []
members = []
structindex = {}
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if not func:
- # added only for the macro, not the decl
- continue
restype, args = c_function_signature(db, func)
+ callargs = ', '.join('arg%d' % (i,)
+ for i in range(len(func.argtypes)))
+ if func.restype is lltype.Void:
+ body = "{ _pypyAPI.%s(%s); }" % (name, callargs)
+ else:
+ body = "{ return _pypyAPI.%s(%s); }" % (name, callargs)
+ functions.append('%s %s(%s)\n%s' % (restype, name, args, body))
members.append('%s (*%s)(%s);' % (restype, name, args))
structindex[name] = len(structindex)
structmembers = '\n'.join(members)
@@ -1055,15 +1033,8 @@
""" % dict(members=structmembers)
global_objects = []
- for name, (typ, expr) in GLOBALS.iteritems():
- if '#' in name:
- continue
- if typ == 'PyDateTime_CAPI*':
- continue
- elif name.startswith('PyExc_'):
- global_objects.append('%s _%s;' % (typ[:-1], name))
- else:
- global_objects.append('%s %s = NULL;' % (typ, name))
+ for name in all_exceptions:
+ global_objects.append('PyTypeObject _PyExc_%s;' % name)
global_code = '\n'.join(global_objects)
prologue = ("#include <Python.h>\n"
@@ -1080,90 +1051,69 @@
'\n' +
'\n'.join(functions))
- eci = build_eci(True, code, use_micronumpy)
+ eci = build_eci(code, use_micronumpy, translating=False)
eci = eci.compile_shared_lib(
outputfilename=str(udir / "module_cache" / "pypyapi"))
+ space.fromcache(State).install_dll(eci)
modulename = py.path.local(eci.libraries[-1])
- def dealloc_trigger():
- from pypy.module.cpyext.pyobject import decref
- print 'dealloc_trigger...'
- while True:
- ob = rawrefcount.next_dead(PyObject)
- if not ob:
- break
- print 'deallocating PyObject', ob
- decref(space, ob)
- print 'dealloc_trigger DONE'
- return "RETRY"
- rawrefcount.init(dealloc_trigger)
-
run_bootstrap_functions(space)
# load the bridge, and init structure
bridge = ctypes.CDLL(str(modulename), mode=ctypes.RTLD_GLOBAL)
- space.fromcache(State).install_dll(eci)
+ # populate static data
+ builder = space.fromcache(State).builder = TestingObjBuilder()
+ for name, (typ, expr) in GLOBALS.iteritems():
+ if '#' in name:
+ name, header = name.split('#')
+ assert typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*')
+ isptr = False
+ elif name.startswith('PyExc_'):
+ isptr = False
+ elif typ == 'PyDateTime_CAPI*':
+ isptr = True
+ else:
+ raise ValueError("Unknown static data: %s %s" % (typ, name))
- # populate static data
- builder = space.fromcache(StaticObjectBuilder)
- for name, (typ, expr) in GLOBALS.iteritems():
from pypy.module import cpyext # for the eval() below
w_obj = eval(expr)
- if '#' in name:
- name = name.split('#')[0]
- isptr = False
- else:
- isptr = True
- if name.startswith('PyExc_'):
- isptr = False
-
INTERPLEVEL_API[name] = w_obj
- name = name.replace('Py', prefix)
+ mname = mangle_name(prefix, name)
if isptr:
- ptr = ctypes.c_void_p.in_dll(bridge, name)
- if typ == 'PyObject*':
- value = make_ref(space, w_obj)
- elif typ == 'PyDateTime_CAPI*':
- value = w_obj
- else:
- assert False, "Unknown static pointer: %s %s" % (typ, name)
+ assert typ == 'PyDateTime_CAPI*'
+ value = w_obj
+ ptr = ctypes.c_void_p.in_dll(bridge, mname)
ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value),
ctypes.c_void_p).value
- elif typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*'):
- if name.startswith('PyPyExc_') or
name.startswith('cpyexttestExc_'):
+ else:
+ if name.startswith('PyExc_'):
# we already have the pointer
- in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge,
name)
+ in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge,
mname)
py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll)
else:
# we have a structure, get its address
- in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge,
name)
+ in_dll = ll2ctypes.get_ctypes_type(PyObject.TO).in_dll(bridge,
mname)
py_obj = ll2ctypes.ctypes2lltype(PyObject,
ctypes.pointer(in_dll))
builder.prepare(py_obj, w_obj)
- else:
- assert False, "Unknown static object: %s %s" % (typ, name)
- builder.attach_all()
+ builder.attach_all(space)
pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
# implement structure initialization code
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if name.startswith('cpyext_') or func is None: # XXX hack
- continue
pypyAPI[structindex[name]] = ctypes.cast(
ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
ctypes.c_void_p)
- setup_va_functions(eci)
- setup_init_functions(eci, translating=False)
+ setup_init_functions(eci, prefix)
return modulename.new(ext='')
-class StaticObjectBuilder:
- def __init__(self, space):
- self.space = space
+class StaticObjectBuilder(object):
+ def __init__(self):
self.static_pyobjs = []
self.static_objs_w = []
self.cpyext_type_init = None
@@ -1179,13 +1129,12 @@
self.static_pyobjs.append(py_obj)
self.static_objs_w.append(w_obj)
- def attach_all(self):
+ def attach_all(self, space):
# this is RPython, called once in pypy-c when it imports cpyext
from pypy.module.cpyext.pyobject import get_typedescr, make_ref
from pypy.module.cpyext.typeobject import finish_type_1, finish_type_2
from pypy.module.cpyext.pyobject import track_reference
#
- space = self.space
static_pyobjs = self.get_static_pyobjs()
static_objs_w = self.static_objs_w
for i in range(len(static_objs_w)):
@@ -1206,6 +1155,12 @@
finish_type_1(space, pto)
finish_type_2(space, pto, w_type)
+class TestingObjBuilder(StaticObjectBuilder):
+ """The StaticObjectBuilder used in tests."""
+
+class TranslationObjBuilder(StaticObjectBuilder):
+ """The StaticObjectBuilder used during translation."""
+
def mangle_name(prefix, name):
if name.startswith('Py'):
@@ -1213,23 +1168,26 @@
elif name.startswith('_Py'):
return '_' + prefix + name[3:]
else:
- return None
+ raise ValueError("Error converting '%s'" % name)
-def generate_decls_and_callbacks(db, api_struct=True, prefix=''):
+def write_header(header_name, decls):
+ lines = [
+ '#define Signed long /* xxx temporary fix */',
+ '#define Unsigned unsigned long /* xxx temporary fix */',
+ '',] + decls + [
+ '',
+ '#undef Signed /* xxx temporary fix */',
+ '#undef Unsigned /* xxx temporary fix */',
+ '']
+ decl_h = udir.join(header_name)
+ decl_h.write('\n'.join(lines))
+
+def generate_decls_and_callbacks(db, prefix=''):
"NOT_RPYTHON"
pypy_macros = []
- export_symbols = sorted(FUNCTIONS) + sorted(SYMBOLS_C) + sorted(GLOBALS)
- for name in export_symbols:
- if '#' in name:
- name, header = name.split('#')
- else:
- header = pypy_decl
+ for name in SYMBOLS_C:
newname = mangle_name(prefix, name)
- assert newname, name
- if header == pypy_decl:
- pypy_macros.append('#define %s %s' % (name, newname))
- if name.startswith("PyExc_"):
- pypy_macros.append('#define _%s _%s' % (name, newname))
+ pypy_macros.append('#define %s %s' % (name, newname))
# Generate defines
for macro_name, size in [
@@ -1249,50 +1207,18 @@
pypy_macros_h = udir.join('pypy_macros.h')
pypy_macros_h.write('\n'.join(pypy_macros))
- # implement function callbacks and generate function decls
- functions = []
- decls = {}
- pypy_decls = decls[pypy_decl] = []
- pypy_decls.append('#define Signed long /* xxx temporary fix
*/\n')
- pypy_decls.append('#define Unsigned unsigned long /* xxx temporary fix
*/\n')
-
+ # generate function decls
+ decls = defaultdict(list)
for decl in FORWARD_DECLS:
- pypy_decls.append("%s;" % (decl,))
+ decls[pypy_decl].append("%s;" % (decl,))
for header_name, header_functions in FUNCTIONS_BY_HEADER.iteritems():
- if header_name not in decls:
- header = decls[header_name] = []
- header.append('#define Signed long /* xxx temporary
fix */\n')
- header.append('#define Unsigned unsigned long /* xxx temporary
fix */\n')
- else:
- header = decls[header_name]
-
+ header = decls[header_name]
for name, func in sorted(header_functions.iteritems()):
- if not func:
- continue
- if header == DEFAULT_HEADER:
- _name = name
- else:
- # this name is not included in pypy_macros.h
- _name = mangle_name(prefix, name)
- assert _name is not None, 'error converting %s' % name
- header.append("#define %s %s" % (name, _name))
+ _name = mangle_name(prefix, name)
+ header.append("#define %s %s" % (name, _name))
restype, args = c_function_signature(db, func)
- header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, _name, args))
- if api_struct:
- callargs = ', '.join('arg%d' % (i,)
- for i in range(len(func.argtypes)))
- if func.restype is lltype.Void:
- body = "{ _pypyAPI.%s(%s); }" % (_name, callargs)
- else:
- body = "{ return _pypyAPI.%s(%s); }" % (_name, callargs)
- functions.append('%s %s(%s)\n%s' % (restype, name, args, body))
- for name in VA_TP_LIST:
- name_no_star = process_va_name(name)
- header = ('%s pypy_va_get_%s(va_list* vp)' %
- (name, name_no_star))
- pypy_decls.append('RPY_EXTERN ' + header + ';')
- functions.append(header + '\n{return va_arg(*vp, %s);}\n' % name)
+ header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args))
for name, (typ, expr) in GLOBALS.iteritems():
if '#' in name:
@@ -1301,19 +1227,11 @@
elif name.startswith('PyExc_'):
typ = 'PyObject*'
header = pypy_decl
- if header != pypy_decl:
- decls[header].append('#define %s %s' % (name, mangle_name(prefix,
name)))
+ decls[header].append('#define %s %s' % (name, mangle_name(prefix,
name)))
decls[header].append('PyAPI_DATA(%s) %s;' % (typ, name))
- for header_name in FUNCTIONS_BY_HEADER.keys():
- header = decls[header_name]
- header.append('#undef Signed /* xxx temporary fix */\n')
- header.append('#undef Unsigned /* xxx temporary fix */\n')
-
for header_name, header_decls in decls.iteritems():
- decl_h = udir.join(header_name)
- decl_h.write('\n'.join(header_decls))
- return functions
+ write_header(header_name, header_decls)
separate_module_files = [source_dir / "varargwrapper.c",
source_dir / "pyerrors.c",
@@ -1325,6 +1243,7 @@
source_dir / "pythonrun.c",
source_dir / "sysmodule.c",
source_dir / "bufferobject.c",
+ source_dir / "complexobject.c",
source_dir / "cobject.c",
source_dir / "structseq.c",
source_dir / "capsule.c",
@@ -1334,14 +1253,16 @@
source_dir / "pymem.c",
]
-def build_eci(building_bridge, code, use_micronumpy=False):
+def build_eci(code, use_micronumpy=False, translating=False):
"NOT_RPYTHON"
# Build code and get pointer to the structure
kwds = {}
compile_extra=['-DPy_BUILD_CORE']
- if building_bridge:
+ if translating:
+ kwds["includes"] = ['Python.h'] # this is our Python.h
+ else:
if sys.platform == "win32":
# '%s' undefined; assuming extern returning int
compile_extra.append("/we4013")
@@ -1351,8 +1272,6 @@
elif sys.platform.startswith('linux'):
compile_extra.append("-Werror=implicit-function-declaration")
compile_extra.append('-g')
- else:
- kwds["includes"] = ['Python.h'] # this is our Python.h
# Generate definitions for global structures
structs = ["#include <Python.h>"]
@@ -1403,9 +1322,7 @@
return use_micronumpy
# import registers api functions by side-effect, we also need HEADER
from pypy.module.cpyext.ndarrayobject import HEADER
- global FUNCTIONS_BY_HEADER, separate_module_files
- for func_name in ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']:
- FUNCTIONS_BY_HEADER.setdefault(HEADER, {})[func_name] = None
+ global separate_module_files
register_global("PyArray_Type",
'PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)",
header=HEADER)
@@ -1419,21 +1336,19 @@
db = LowLevelDatabase()
prefix = 'PyPy'
- functions = generate_decls_and_callbacks(db, api_struct=False,
prefix=prefix)
+ generate_decls_and_callbacks(db, prefix=prefix)
+
code = "#include <Python.h>\n"
if use_micronumpy:
code += "#include <pypy_numpy.h> /* api.py line 1290 */\n"
- code += "\n".join(functions)
- eci = build_eci(False, code, use_micronumpy)
-
+ eci = build_eci(code, use_micronumpy, translating=True)
space.fromcache(State).install_dll(eci)
run_bootstrap_functions(space)
- setup_va_functions(eci)
# emit uninitialized static data
- builder = space.fromcache(StaticObjectBuilder)
+ builder = space.fromcache(State).builder = TranslationObjBuilder()
lines = ['PyObject *pypy_static_pyobjs[] = {\n']
include_lines = ['RPY_EXTERN PyObject *pypy_static_pyobjs[];\n']
for name, (typ, expr) in sorted(GLOBALS.items()):
@@ -1441,17 +1356,15 @@
name, header = name.split('#')
assert typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*')
typ = typ[:-1]
- if header != pypy_decl:
- # since the #define is not in pypy_macros, do it here
- mname = mangle_name(prefix, name)
- include_lines.append('#define %s %s\n' % (name, mname))
+ mname = mangle_name(prefix, name)
+ include_lines.append('#define %s %s\n' % (name, mname))
elif name.startswith('PyExc_'):
typ = 'PyTypeObject'
name = '_' + name
elif typ == 'PyDateTime_CAPI*':
continue
else:
- assert False, "Unknown static data: %s %s" % (typ, name)
+ raise ValueError("Unknown static data: %s %s" % (typ, name))
from pypy.module import cpyext # for the eval() below
w_obj = eval(expr)
@@ -1471,20 +1384,15 @@
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if not func:
- continue
- newname = mangle_name('PyPy', name) or name
+ newname = mangle_name(prefix, name)
deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
relax=True)
deco(func.get_wrapper(space))
- setup_init_functions(eci, translating=True)
+ setup_init_functions(eci, prefix)
trunk_include = pypydir.dirpath() / 'include'
copy_header_files(trunk_include, use_micronumpy)
-def init_static_data_translated(space):
- builder = space.fromcache(StaticObjectBuilder)
- builder.attach_all()
def _load_from_cffi(space, name, path, initptr):
from pypy.module._cffi_backend import cffi1_module
diff --git a/pypy/module/cpyext/include/complexobject.h
b/pypy/module/cpyext/include/complexobject.h
--- a/pypy/module/cpyext/include/complexobject.h
+++ b/pypy/module/cpyext/include/complexobject.h
@@ -16,23 +16,8 @@
Py_complex cval;
} PyComplexObject;
-/* generated function */
-PyAPI_FUNC(int) _PyComplex_AsCComplex(PyObject *, Py_complex *);
-PyAPI_FUNC(PyObject *) _PyComplex_FromCComplex(Py_complex *);
-
-Py_LOCAL_INLINE(Py_complex) PyComplex_AsCComplex(PyObject *obj)
-{
- Py_complex result;
- _PyComplex_AsCComplex(obj, &result);
- return result;
-}
-
-// shmuller 2013/07/30: Make a function, since macro will fail in C++ due to
-// const correctness if called with "const Py_complex"
-//#define PyComplex_FromCComplex(c) _PyComplex_FromCComplex(&c)
-Py_LOCAL_INLINE(PyObject *) PyComplex_FromCComplex(Py_complex c) {
- return _PyComplex_FromCComplex(&c);
-}
+PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *obj);
+PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex c);
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -7,7 +7,7 @@
from rpython.rlib import rgc # Force registration of gc.collect
from pypy.module.cpyext.api import (
cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES,
- mangle_name, pypy_decl, Py_buffer, Py_bufferP)
+ pypy_decl, Py_buffer, Py_bufferP)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
@@ -351,7 +351,7 @@
else:
#do not call twice
return
- if self.releasebufferproc:
+ if self.releasebufferproc:
func_target = rffi.cast(releasebufferproc, self.releasebufferproc)
with lltype.scoped_alloc(Py_buffer) as pybuf:
pybuf.c_buf = self.ptr
@@ -416,7 +416,7 @@
size = generic_cpy_call(space, func_target, w_self, index, ptr)
if size < 0:
space.fromcache(State).check_and_raise_exception(always=True)
- buf = CPyBuffer(space, ptr[0], size, w_self,
+ buf = CPyBuffer(space, ptr[0], size, w_self,
releasebuffer=releasebuffer)
fq.register_finalizer(buf)
return space.newbuffer(buf)
@@ -522,7 +522,7 @@
w_type = space.gettypeobject(typedef)
header = pypy_decl
- if mangle_name('', typedef.name) is None:
+ if not (name.startswith('Py') or name.startswith('_Py')):
header = None
handled = False
# unary functions
diff --git a/pypy/module/cpyext/src/complexobject.c
b/pypy/module/cpyext/src/complexobject.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/src/complexobject.c
@@ -0,0 +1,16 @@
+
+#include "Python.h"
+
+Py_complex
+PyComplex_AsCComplex(PyObject *obj)
+{
+ Py_complex result;
+ _PyComplex_AsCComplex(obj, &result);
+ return result;
+}
+
+PyObject *
+PyComplex_FromCComplex(Py_complex c)
+{
+ return _PyComplex_FromCComplex(&c);
+}
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -2,7 +2,6 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter import executioncontext
-from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.annlowlevel import llhelper
from rpython.rlib.rdynload import DLLHANDLE
from rpython.rlib import rawrefcount
@@ -14,9 +13,7 @@
self.reset()
self.programname = lltype.nullptr(rffi.CCHARP.TO)
self.version = lltype.nullptr(rffi.CCHARP.TO)
- if space.config.translation.gc != "boehm":
- pyobj_dealloc_action = PyObjDeallocAction(space)
- self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
+ self.builder = None
def reset(self):
from pypy.module.cpyext.modsupport import PyMethodDef
@@ -57,22 +54,40 @@
"Function returned an error result without setting an "
"exception")
- def build_api(self, space):
+ def setup_rawrefcount(self):
+ space = self.space
+ if not self.space.config.translating:
+ def dealloc_trigger():
+ from pypy.module.cpyext.pyobject import PyObject, decref
+ print 'dealloc_trigger...'
+ while True:
+ ob = rawrefcount.next_dead(PyObject)
+ if not ob:
+ break
+ print 'deallocating PyObject', ob
+ decref(space, ob)
+ print 'dealloc_trigger DONE'
+ return "RETRY"
+ rawrefcount.init(dealloc_trigger)
+ else:
+ if space.config.translation.gc == "boehm":
+ action = BoehmPyObjDeallocAction(space)
+ space.actionflag.register_periodic_action(action,
+ use_bytecode_counter=True)
+ else:
+ pyobj_dealloc_action = PyObjDeallocAction(space)
+ self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
+
+ def build_api(self):
"""NOT_RPYTHON
This function is called when at object space creation,
and drives the compilation of the cpyext library
"""
from pypy.module.cpyext import api
- state = self.space.fromcache(State)
if not self.space.config.translating:
- state.api_lib = str(api.build_bridge(self.space))
+ self.api_lib = str(api.build_bridge(self.space))
else:
api.setup_library(self.space)
- #
- if self.space.config.translation.gc == "boehm":
- action = BoehmPyObjDeallocAction(self.space)
- self.space.actionflag.register_periodic_action(action,
- use_bytecode_counter=True)
def install_dll(self, eci):
"""NOT_RPYTHON
@@ -84,17 +99,17 @@
def startup(self, space):
"This function is called when the program really starts"
-
from pypy.module.cpyext.typeobject import setup_new_method_def
from pypy.module.cpyext.api import INIT_FUNCTIONS
- from pypy.module.cpyext.api import init_static_data_translated
if we_are_translated():
if space.config.translation.gc != "boehm":
+ # This must be called in RPython, the untranslated version
+ # does something different. Sigh.
rawrefcount.init(
llhelper(rawrefcount.RAWREFCOUNT_DEALLOC_TRIGGER,
self.dealloc_trigger))
- init_static_data_translated(space)
+ self.builder.attach_all(space)
setup_new_method_def(space)
diff --git a/pypy/module/cpyext/test/test_api.py
b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -89,9 +89,9 @@
def test_typedef(self, space):
from rpython.translator.c.database import LowLevelDatabase
db = LowLevelDatabase()
- assert (api.c_function_signature(db,
api.FUNCTIONS['PyPy_TypedefTest1'])
+ assert (api.c_function_signature(db, PyPy_TypedefTest1.api_func)
== ('Py_ssize_t', 'Py_ssize_t arg0'))
- assert (api.c_function_signature(db,
api.FUNCTIONS['PyPy_TypedefTest2'])
+ assert (api.c_function_signature(db, PyPy_TypedefTest2.api_func)
== ('Py_ssize_t *', 'Py_ssize_t *arg0'))
PyPy_TypedefTest1(space, 0)
@@ -100,7 +100,7 @@
PyPy_TypedefTest2(space, ppos)
lltype.free(ppos, flavor='raw')
[email protected](os.environ.get('USER')=='root',
[email protected](os.environ.get('USER')=='root',
reason='root can write to all files')
def test_copy_header_files(tmpdir):
api.copy_header_files(tmpdir, True)
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
@@ -27,8 +27,9 @@
class TestApi:
def test_signature(self):
- assert 'PyModule_Check' in api.FUNCTIONS
- assert api.FUNCTIONS['PyModule_Check'].argtypes == [api.PyObject]
+ common_functions = api.FUNCTIONS_BY_HEADER[api.pypy_decl]
+ assert 'PyModule_Check' in common_functions
+ assert common_functions['PyModule_Check'].argtypes == [api.PyObject]
class SpaceCompiler(SystemCompilationInfo):
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -87,7 +87,7 @@
py_getsetdef.c_set = rffi.cast(setter, 0)
py_getsetdef.c_closure = rffi.cast(rffi.VOIDP, 0)
return py_getsetdef
-
+
class W_MemberDescr(GetSetProperty):
name = 'member_descriptor'
@@ -711,7 +711,7 @@
pto.c_tp_free = llslot(space, PyObject_Free)
pto.c_tp_alloc = llslot(space, PyType_GenericAlloc)
- builder = space.fromcache(StaticObjectBuilder)
+ builder = space.fromcache(State).builder
if ((pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE) != 0
and builder.cpyext_type_init is None):
# this ^^^ is not None only during startup of cpyext. At that
diff --git a/pypy/objspace/std/stringmethods.py
b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -548,6 +548,10 @@
sub = self._op_val(space, w_old)
by = self._op_val(space, w_new)
+ # the following two lines are for being bug-to-bug compatible
+ # with CPython: see issue #2448
+ if count >= 0 and len(input) == 0:
+ return self._empty()
try:
res = replace(input, sub, by, count)
except OverflowError:
diff --git a/pypy/objspace/std/test/test_bytesobject.py
b/pypy/objspace/std/test/test_bytesobject.py
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -809,6 +809,16 @@
s = b"a" * (2**16)
raises(OverflowError, s.replace, b"", s)
+ def test_replace_issue2448(self):
+ # CPython's replace() method has a bug that makes
+ # ''.replace('', 'x') gives a different answer than
+ # ''.replace('', 'x', 1000). This is the case in all
+ # known versions, at least until 2.7.13. Some people
+ # call that a feature on the CPython issue report and
+ # the discussion dies out, so it might never be fixed.
+ assert ''.replace('', 'x') == 'x'
+ assert ''.replace('', 'x', 1000) == ''
+
def test_getslice(self):
assert "foobar".__getslice__(4, 4321) == "ar"
s = b"abc"
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -1770,11 +1770,11 @@
#
# clear the arena between the last pinned object (or arena start)
# and the pinned object
- pinned_obj_size = llarena.getfakearenaaddress(cur) - prev
+ free_range_size = llarena.getfakearenaaddress(cur) - prev
if self.gc_nursery_debug:
- llarena.arena_reset(prev, pinned_obj_size, 3)
+ llarena.arena_reset(prev, free_range_size, 3)
else:
- llarena.arena_reset(prev, pinned_obj_size, 0)
+ llarena.arena_reset(prev, free_range_size, 0)
#
# clean up object's flags
obj = cur + size_gc_header
@@ -1784,7 +1784,7 @@
nursery_barriers.append(cur)
#
# update 'prev' to the end of the 'cur' object
- prev = prev + pinned_obj_size + \
+ prev = prev + free_range_size + \
(size_gc_header + self.get_size(obj))
#
# reset everything after the last pinned object till the end of the
arena
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit