[pypy-commit] pypy cpyext-avoid-roundtrip: implement _PyObject_New, _PyObject_NewVar and _PyObject_GC_New in C

antocuni pypy.commits at gmail.com
Sun Oct 8 18:13:15 EDT 2017


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: cpyext-avoid-roundtrip
Changeset: r92666:e5413301904e
Date: 2017-10-09 00:12 +0200
http://bitbucket.org/pypy/pypy/changeset/e5413301904e/

Log:	implement _PyObject_New, _PyObject_NewVar and _PyObject_GC_New in C

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
@@ -627,6 +627,7 @@
     '_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',
 ]
 TYPES = {}
 FORWARD_DECLS = []
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
@@ -342,6 +342,10 @@
 #define PyObject_Del            PyObject_Free
 #define PyObject_DEL            PyObject_Free
 
+PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *);
+PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t);
+PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
+
 
 /* PyPy internal ----------------------------------- */
 PyAPI_FUNC(int) PyPyType_Register(PyTypeObject *);
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -36,24 +36,16 @@
 def _PyPy_Free(ptr):
     lltype.free(ptr, flavor='raw')
 
- at cpython_api([PyTypeObjectPtr], PyObject, result_is_ll=True)
-def _PyObject_New(space, type):
-    return _PyObject_NewVar(space, type, 0)
+ at c_only([Py_ssize_t], rffi.VOIDP)
+def _PyPy_Malloc(size):
+    # XXX: the malloc inside BaseCpyTypedescr.allocate and
+    # typeobject.type_alloc specify zero=True, so this is why we use it also
+    # here. However, CPython does a simple non-initialized malloc, so we
+    # should investigate whether we can remove zero=True as well
+    return lltype.malloc(rffi.VOIDP.TO, size,
+                         flavor='raw', zero=True,
+                         add_memory_pressure=True)
 
-# CCC port to C
- at cpython_api([PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
-def _PyObject_NewVar(space, type, itemcount):
-    w_type = from_ref(space, rffi.cast(PyObject, type))
-    assert isinstance(w_type, W_TypeObject)
-    typedescr = get_typedescr(w_type.layout.typedef)
-    py_obj = typedescr.allocate(space, w_type, itemcount=itemcount)
-    #py_obj.c_ob_refcnt = 0 --- will be set to 1 again by PyObject_Init{Var}
-    if type.c_tp_itemsize == 0:
-        w_obj = PyObject_Init(space, py_obj, type)
-    else:
-        py_objvar = rffi.cast(PyVarObject, py_obj)
-        w_obj = PyObject_InitVar(space, py_objvar, type, itemcount)
-    return py_obj
 
 def _dealloc(space, obj):
     # This frees an object after its refcount dropped to zero, so we
@@ -65,10 +57,6 @@
     if pto.c_tp_flags & Py_TPFLAGS_HEAPTYPE:
         Py_DecRef(space, rffi.cast(PyObject, pto))
 
- at cpython_api([PyTypeObjectPtr], PyObject, result_is_ll=True)
-def _PyObject_GC_New(space, type):
-    return _PyObject_New(space, type)
-
 @cpython_api([PyObject], PyObjectP, error=CANNOT_FAIL)
 def _PyObject_GetDictPtr(space, op):
     return lltype.nullptr(PyObjectP.TO)
@@ -173,6 +161,7 @@
     space.delitem(w_obj, w_key)
     return 0
 
+# CCC port to C
 @cpython_api([PyObject, PyTypeObjectPtr], PyObject, result_is_ll=True)
 def PyObject_Init(space, obj, type):
     """Initialize a newly-allocated object op with its type and initial
@@ -187,6 +176,7 @@
     obj.c_ob_refcnt = 1
     return obj
 
+# CCC port to C
 @cpython_api([PyVarObject, PyTypeObjectPtr, Py_ssize_t], PyObject, result_is_ll=True)
 def PyObject_InitVar(space, py_obj, type, size):
     """This does everything PyObject_Init() does, and also initializes the
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
@@ -2,6 +2,9 @@
 
 #include "Python.h"
 
+extern void _PyPy_Free(void *ptr);
+extern void *_PyPy_Malloc(Py_ssize_t size);
+
 void
 Py_IncRef(PyObject *o)
 {
@@ -36,8 +39,6 @@
         Py_DECREF(pto);
 }
 
-extern void _PyPy_Free(void *ptr);
-
 void
 PyObject_Free(void *obj)
 {
@@ -53,5 +54,77 @@
 PyObject *
 PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
 {
-    return _PyObject_NewVar(type, nitems);
+    return (PyObject*)_PyObject_NewVar(type, nitems);
 }
+
+PyObject *
+_PyObject_New(PyTypeObject *type)
+{
+    return (PyObject*)_PyObject_NewVar(type, 0);
+}
+
+PyObject * _PyObject_GC_New(PyTypeObject *type)
+{
+    return _PyObject_New(type);
+}
+
+
+static PyObject *
+_type_alloc(PyTypeObject *metatype)
+{
+    PyHeapTypeObject *heaptype = (PyHeapTypeObject*)_PyPy_Malloc(sizeof(PyTypeObject));
+    PyTypeObject *pto = &heaptype->ht_type;
+
+    pto->ob_refcnt = 1;
+    pto->ob_pypy_link = 0;
+    pto->ob_type = metatype;
+    pto->tp_flags |= Py_TPFLAGS_HEAPTYPE;
+    pto->tp_as_number = &heaptype->as_number;
+    pto->tp_as_sequence = &heaptype->as_sequence;
+    pto->tp_as_mapping = &heaptype->as_mapping;
+    pto->tp_as_buffer = &heaptype->as_buffer;
+    pto->tp_basicsize = -1; /* hopefully this makes malloc bail out */
+    pto->tp_itemsize = 0;
+    return (PyObject*)heaptype;
+}
+
+static PyObject *
+_generic_alloc(PyTypeObject *type, Py_ssize_t nitems)
+{
+    if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+        Py_INCREF(type);
+
+    Py_ssize_t size = type->tp_basicsize;
+    if (type->tp_itemsize)
+        size += nitems * type->tp_itemsize;
+
+    PyObject *pyobj = (PyObject*)_PyPy_Malloc(size);
+    
+    if (type->tp_itemsize)
+        ((PyVarObject*)pyobj)->ob_size = nitems;
+
+    pyobj->ob_refcnt = 1;
+    /* pyobj->ob_pypy_link should get assigned very quickly */
+    pyobj->ob_type = type;
+    return pyobj;
+}
+
+PyVarObject *
+_PyObject_NewVar(PyTypeObject *type, Py_ssize_t nitems)
+{
+    /* Note that this logic is slightly different than the one used by
+       CPython. The plan is to try to follow as closely as possible the
+       current cpyext logic here, and fix it when the migration to C is
+       completed
+    */
+    PyObject *py_obj;
+    if (type == &PyType_Type)
+        py_obj = _type_alloc(type);
+    else
+        py_obj = _generic_alloc(type, nitems);
+
+    if (type->tp_itemsize == 0)
+        return PyObject_Init(py_obj, type);
+    else
+        return PyObject_InitVar((PyVarObject*)py_obj, type, nitems);
+}


More information about the pypy-commit mailing list