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

Reply via email to