Author: Antonio Cuni <[email protected]>
Branch: cpyext-avoid-roundtrip
Changeset: r92746:5b20c5296b9f
Date: 2017-10-13 18:02 +0100
http://bitbucket.org/pypy/pypy/changeset/5b20c5296b9f/
Log: merge heads
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
@@ -633,8 +633,10 @@
'_Py_QnewFlag', 'Py_Py3kWarningFlag', 'Py_HashRandomizationFlag',
'_Py_PackageContext',
'_PyTraceMalloc_Track', '_PyTraceMalloc_Untrack', 'PyMem_Malloc',
'Py_IncRef', 'Py_DecRef', 'PyObject_Free', 'PyObject_GC_Del',
'PyType_GenericAlloc',
- '_PyObject_New', '_PyObject_NewVar', '_PyObject_GC_New',
+ '_PyObject_New', '_PyObject_NewVar',
+ '_PyObject_GC_New', '_PyObject_GC_NewVar',
'PyObject_Init', 'PyObject_InitVar', 'PyInt_FromLong',
+ 'PyTuple_New',
]
TYPES = {}
FORWARD_DECLS = []
@@ -1135,12 +1137,20 @@
[rffi.LONG], PyObject,
compilation_info=eci,
_nowrapper=True)
+ state.C._PyPy_int_dealloc = rffi.llexternal(
+ '_PyPy_int_dealloc', [PyObject], lltype.Void,
+ compilation_info=eci, _nowrapper=True)
+ state.C.PyTuple_New = rffi.llexternal(
+ mangle_name(prefix, 'PyTuple_New'),
+ [Py_ssize_t], PyObject,
+ compilation_info=eci,
+ _nowrapper=True)
+ state.C._PyPy_tuple_dealloc = rffi.llexternal(
+ '_PyPy_tuple_dealloc', [PyObject], lltype.Void,
+ compilation_info=eci, _nowrapper=True)
_, state.C.set_marker = rffi.CExternVariable(
Py_ssize_t, '_pypy_rawrefcount_w_marker_deallocating',
eci, _nowrapper=True, c_type='Py_ssize_t')
- state.C._PyPy_int_dealloc = rffi.llexternal(
- '_PyPy_int_dealloc', [PyObject], lltype.Void,
- compilation_info=eci, _nowrapper=True)
state.C._PyPy_subtype_dealloc = rffi.llexternal(
'_PyPy_subtype_dealloc', [PyObject], lltype.Void,
compilation_info=eci, _nowrapper=True)
@@ -1258,7 +1268,6 @@
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)
- builder.attach_all(space)
pypyAPI = ctypes.POINTER(ctypes.c_void_p).in_dll(bridge, 'pypyAPI')
@@ -1269,6 +1278,12 @@
ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
ctypes.c_void_p)
+ # we need to call this *after* the init code above, because it might
+ # indirectly call some functions which are attached to pypyAPI (e.g., we
+ # if do tuple_attach of the prebuilt empty tuple, we need to call
+ # _PyPy_Malloc)
+ builder.attach_all(space)
+
setup_init_functions(eci, prefix)
return modulename.new(ext='')
@@ -1464,6 +1479,7 @@
source_dir / "object.c",
source_dir / "typeobject.c",
source_dir / "intobject.c",
+ source_dir / "tupleobject.c",
]
def build_eci(code, use_micronumpy=False, translating=False):
diff --git a/pypy/module/cpyext/include/object.h
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -291,6 +291,9 @@
#define PyObject_GC_New(type, typeobj) \
( (type *) _PyObject_GC_New(typeobj) )
+#define PyObject_GC_NewVar(type, typeobj, n) \
+ ( (type *) _PyObject_GC_NewVar((typeobj), (n)) )
+
/* A dummy PyGC_Head, just to please some tests. Don't use it! */
typedef union _gc_head {
char dummy;
@@ -346,6 +349,7 @@
PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *);
PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
+PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t);
PyAPI_FUNC(PyObject *) PyObject_Init(PyObject *, PyTypeObject *);
PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *,
diff --git a/pypy/module/cpyext/include/tupleobject.h
b/pypy/module/cpyext/include/tupleobject.h
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -16,9 +16,13 @@
*/
} PyTupleObject;
+PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size);
+PyAPI_FUNC(void) _PyPy_tuple_dealloc(PyObject *);
+
/* defined in varargswrapper.c */
PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
+
/* Macro, trading safety for speed */
#define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i])
#define PyTuple_GET_SIZE(op) Py_SIZE(op)
diff --git a/pypy/module/cpyext/src/object.c b/pypy/module/cpyext/src/object.c
--- a/pypy/module/cpyext/src/object.c
+++ b/pypy/module/cpyext/src/object.c
@@ -68,6 +68,10 @@
return _PyObject_New(type);
}
+PyVarObject * _PyObject_GC_NewVar(PyTypeObject *type, Py_ssize_t nitems)
+{
+ return _PyObject_NewVar(type, nitems);
+}
static PyObject *
_generic_alloc(PyTypeObject *type, Py_ssize_t nitems)
diff --git a/pypy/module/cpyext/src/tupleobject.c
b/pypy/module/cpyext/src/tupleobject.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/src/tupleobject.c
@@ -0,0 +1,98 @@
+
+/* Tuple object implementation, stolen&adapted from CPython */
+
+#include "Python.h"
+
+/* Speed optimization to avoid frequent malloc/free of small tuples */
+#ifndef PyTuple_MAXSAVESIZE
+#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */
+#endif
+#ifndef PyTuple_MAXFREELIST
+#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to
save */
+#endif
+
+#if PyTuple_MAXSAVESIZE > 0
+/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty
+ tuple () of which at most one instance will be allocated.
+*/
+static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
+static int numfree[PyTuple_MAXSAVESIZE];
+#endif
+
+PyObject *
+PyTuple_New(register Py_ssize_t size)
+{
+ register PyTupleObject *op;
+ Py_ssize_t i;
+ if (size < 0) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+#if PyTuple_MAXSAVESIZE > 0
+ if (size == 0 && free_list[0]) {
+ op = free_list[0];
+ Py_INCREF(op);
+ return (PyObject *) op;
+ }
+ if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) {
+ free_list[size] = (PyTupleObject *) op->ob_item[0];
+ numfree[size]--;
+ _Py_NewReference((PyObject *)op);
+ }
+ else
+#endif
+ {
+ Py_ssize_t nbytes = size * sizeof(PyObject *);
+ /* Check for overflow */
+ if (nbytes / sizeof(PyObject *) != (size_t)size ||
+ (nbytes > PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject
*)))
+ {
+ return PyErr_NoMemory();
+ }
+
+ op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
+ if (op == NULL)
+ return NULL;
+ }
+ for (i=0; i < size; i++)
+ op->ob_item[i] = NULL;
+#if PyTuple_MAXSAVESIZE > 0
+ if (size == 0) {
+ free_list[0] = op;
+ ++numfree[0];
+ Py_INCREF(op); /* extra INCREF so that this is never freed */
+ }
+#endif
+ _PyObject_GC_TRACK(op);
+ return (PyObject *) op;
+}
+
+/* this is CPython's tupledealloc */
+void
+_PyPy_tuple_dealloc(register PyObject *_op)
+{
+ register PyTupleObject *op = (PyTupleObject *)_op;
+ register Py_ssize_t i;
+ register Py_ssize_t len = Py_SIZE(op);
+ PyObject_GC_UnTrack(op);
+ Py_TRASHCAN_SAFE_BEGIN(op)
+ if (len > 0) {
+ i = len;
+ while (--i >= 0)
+ Py_XDECREF(op->ob_item[i]);
+#if PyTuple_MAXSAVESIZE > 0
+ if (len < PyTuple_MAXSAVESIZE &&
+ numfree[len] < PyTuple_MAXFREELIST &&
+ Py_TYPE(op) == &PyTuple_Type)
+ {
+ op->ob_item[0] = (PyObject *) free_list[len];
+ numfree[len]++;
+ free_list[len] = op;
+ goto done; /* return */
+ }
+#endif
+ }
+ Py_TYPE(op)->tp_free((PyObject *)op);
+done:
+ Py_TRASHCAN_SAFE_END(op)
+}
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
@@ -25,6 +25,10 @@
cls.preload_builtins(space)
class CAPI:
+ def __repr__(self):
+ return '<%s.%s instance>' % (self.__class__.__module__,
+ self.__class__.__name__)
+
def __getattr__(self, name):
return getattr(cls.space, name)
cls.api = CAPI()
diff --git a/pypy/module/cpyext/test/test_tupleobject.py
b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -7,7 +7,7 @@
from rpython.rlib.debug import FatalError
from pypy.module.cpyext.tupleobject import (
PyTupleObject, PyTuple_Check, PyTuple_SetItem, PyTuple_Size)
-
+from pypy.module.cpyext.state import State
class TestTupleObject(BaseApiTest):
@@ -22,17 +22,19 @@
PyTuple_Size(space, space.newlist([]))
def test_tuple_realize_refuses_nulls(self, space, api):
- py_tuple = api.PyTuple_New(1)
+ state = space.fromcache(State)
+ py_tuple = state.C.PyTuple_New(1)
py.test.raises(FatalError, from_ref, space, py_tuple)
decref(space, py_tuple)
def test_tuple_resize(self, space, api):
+ state = space.fromcache(State)
w_42 = space.wrap(42)
w_43 = space.wrap(43)
w_44 = space.wrap(44)
ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
- py_tuple = api.PyTuple_New(3)
+ py_tuple = state.C.PyTuple_New(3)
# inside py_tuple is an array of "PyObject *" items which each hold
# a reference
rffi.cast(PyTupleObject, py_tuple).c_ob_item[0] = make_ref(space, w_42)
@@ -45,7 +47,7 @@
assert space.int_w(space.getitem(w_tuple, space.wrap(1))) == 43
decref(space, ar[0])
- py_tuple = api.PyTuple_New(3)
+ py_tuple = state.C.PyTuple_New(3)
rffi.cast(PyTupleObject, py_tuple).c_ob_item[0] = make_ref(space, w_42)
rffi.cast(PyTupleObject, py_tuple).c_ob_item[1] = make_ref(space, w_43)
rffi.cast(PyTupleObject, py_tuple).c_ob_item[2] = make_ref(space, w_44)
@@ -64,7 +66,8 @@
lltype.free(ar, flavor='raw')
def test_setitem(self, space, api):
- py_tuple = api.PyTuple_New(2)
+ state = space.fromcache(State)
+ py_tuple = state.C.PyTuple_New(2)
api.PyTuple_SetItem(py_tuple, 0, make_ref(space, space.wrap(42)))
api.PyTuple_SetItem(py_tuple, 1, make_ref(space, space.wrap(43)))
diff --git a/pypy/module/cpyext/tupleobject.py
b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -7,6 +7,7 @@
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, make_ref, from_ref, decref, incref,
track_reference, make_typedescr, get_typedescr, pyobj_has_w_obj)
+from pypy.module.cpyext.state import State
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.objspace.std.tupleobject import W_TupleObject
@@ -36,10 +37,12 @@
@bootstrap_function
def init_tupleobject(space):
"Type description of PyTupleObject"
+ state = space.fromcache(State)
make_typedescr(space.w_tuple.layout.typedef,
basestruct=PyTupleObject.TO,
attach=tuple_attach,
- dealloc=tuple_dealloc,
+ alloc=tuple_alloc,
+ dealloc=state.C._PyPy_tuple_dealloc,
realize=tuple_realize)
PyTuple_Check, PyTuple_CheckExact = build_type_checkers_flags("Tuple")
@@ -49,12 +52,20 @@
return (w_type is space.w_tuple or
space.issubtype_w(w_type, space.w_tuple))
+def tuple_alloc(typedescr, space, w_type, itemcount):
+ state = space.fromcache(State)
+ if w_type is space.w_tuple:
+ return state.C.PyTuple_New(itemcount)
+ else:
+ return BaseCpyTypedescr.allocate(typedescr, space, w_type, itemcount)
+
def new_empty_tuple(space, length):
"""
Allocate a PyTupleObject and its array of PyObject *, but without a
corresponding interpreter object. The array may be mutated, until
tuple_realize() is called. Refcount of the result is 1.
"""
+ assert False, 'kill this?'
typedescr = get_typedescr(space.w_tuple.layout.typedef)
py_obj = typedescr.allocate(space, space.w_tuple, length)
py_tup = rffi.cast(PyTupleObject, py_obj)
@@ -113,22 +124,22 @@
track_reference(space, py_obj, w_obj)
return w_obj
-@slot_function([PyObject], lltype.Void)
-def tuple_dealloc(space, py_obj):
- """Frees allocated PyTupleObject resources.
- """
- py_tup = rffi.cast(PyTupleObject, py_obj)
- p = py_tup.c_ob_item
- for i in range(py_tup.c_ob_size):
- decref(space, p[i])
- from pypy.module.cpyext.object import _dealloc
- _dealloc(space, py_obj)
+## @slot_function([PyObject], lltype.Void)
+## def tuple_dealloc(space, py_obj):
+## """Frees allocated PyTupleObject resources.
+## """
+## py_tup = rffi.cast(PyTupleObject, py_obj)
+## p = py_tup.c_ob_item
+## for i in range(py_tup.c_ob_size):
+## decref(space, p[i])
+## from pypy.module.cpyext.object import _dealloc
+## _dealloc(space, py_obj)
#_______________________________________________________________________
-@cpython_api([Py_ssize_t], PyObject, result_is_ll=True)
-def PyTuple_New(space, size):
- return new_empty_tuple(space, size)
+## @cpython_api([Py_ssize_t], PyObject, result_is_ll=True)
+## def PyTuple_New(space, size):
+## return new_empty_tuple(space, size)
@cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
def PyTuple_SetItem(space, ref, index, py_obj):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit