[Patches] GC patch 3 and 4

Vladimir Marangozov Vladimir.Marangozov@inrialpes.fr
Wed, 28 Jun 2000 03:02:07 +0200 (CEST)


I'm concerned about the following with these patches:

1. The PyObject_GC API

   This is related with #2 below.
   
   As it was discussed previously, PyObject_GC_NEW is useless. I think
   that the same applies to PyObject_GC_DEL - we don't need it.

   I'd suggest to officialize the following API -- better names are welcome:

   PyObject_FROM_GC(gp)  - returns a pointer to a Python object given a
                           pointer to a GC_INFO struct. This is the current
                           PyGC_INFO macro.

   PyObject_AS_GC(op)    - returns a pointer to a GC_INFO struct given an
                           object pointer. This is the reverse macro
                           (the current PyGC_OBJ macro)

   PyObject_GC_Init(op)  - init an object for GC (usually, at the end of the 
                           constructor, cf. comments in objimpl.h)

   PyObject_GC_Fini(op)  - finalize an object subject to GC (usually, in the
                           beginning of the destructor, cf. objimpl.h)

   BTW, I'd really prefer a more Pythonic name for GC_INFO, like GC_HEAD
   as per Greg Stein's comments on these patches.


2. Extension types that participate in GC

   The GC code implemented in the (core) object constructors is #ifdef'ed
   which is not what one is expected to do for custom extension types.
   If I am about to implement a GC'd type with the proposed patches, I'll
   have to #ifdef things which is not really what I want.

   GC or not, I'd prefer to see the same code in the object constructors
   and destructors (be they core or extension objects).

   PyObject_GC_Init/Fini are fine. They are empty macros without GC,
   so why not using the same approach for the inlined #ifdef'ed code?

   For example, the PyList_New code reads:

   ...
        if (op == NULL) {
                return PyErr_NoMemory();
        }
   #ifdef WITH_CYCLE_GC
        op = (PyListObject *) PyGC_OBJ((PyGCInfo *)op);
   #endif
   ...


   I'd expect to see something like this instead:

   ...
        if (op == NULL) {
                return PyErr_NoMemory();
        }
        op = (PyListObject *) PyObject_FROM_GC(op);
   ...


   where:

   #ifdef WITH_CYCLE_GC
   #define PyObject_FROM_GC(gp)  PyGC_INFO((PyGCInfo *)(gp))
   #else
   #define PyObject_FROM_GC(gp)  (gp)
   #endif


   The same goes for the object destructors, where PyObject_GC_DEL(op)
   would be replaced by:  op = PyObject_AS_GC(op); PyObject_DEL(op)


Neil Schemenauer wrote:
[snip]
> 
> + /*
> +  * Garbage Collection Support
> +  * ==========================
> +  */
>   
> + /* To make a new object participate in garbage collection use
> +    PyObject_{New, VarNew, Del} to manage the memory.  Set the type flag
                      ^^^^^^

                      NewVar

> +    Py_TPFLAGS_GC and define the type method tp_recurse.  You should also
> +    add the method tp_clear if your object is mutable.  Include
> +    PyGC_INFO_SIZE in the calculation of tp_basicsize.  Call
> +    PyObject_GC_Init after the pointers followed by tp_recurse become
> +    valid (usually just before returning the object from the allocation
> +    method.  Call PyObject_GC_Fini before those pointers become invalid
> +    (usually at the top of the deallocation method).  */
>   
[snip]

-- 
       Vladimir MARANGOZOV          | Vladimir.Marangozov@inrialpes.fr
http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252