[Patches] PyMem [1/8] - intro

Guido van Rossum guido@python.org
Mon, 06 Mar 2000 11:12:18 -0500


OK, in my copious spare time (TM Larry Wall) I had a good look at
Vladimir's malloc patches.  I'm torn.  I like a lot of the changes,
but I don't like having two new files.  Especially the new include
file "for internal use only" seriously bothers me: people are going to
ignore the warning.  There are no precedents: all files in the Include
directory are for public use (and most are included by Python.h); all
private files live in one of the other source directories (Parser,
Objects, Python, Modules).

I also dislike the fact that extensions are made second-class citizens
who don't have a macro that expands directly to malloc().

I think I'd prefer to have the following set of APIs:

Py_Malloc c.s.: unchanged (calls PyMem_MALLOC c.s., may call PyErr_NoMemory)
_PyObject_New c.s.: unchanged
PyObject_NEW c.s.: unchanged (#define using _PyObject_New c.s.)

PyMem_MALLOC c.s.: #defined as malloc c.s., normally
PyMem_Malloc c.s.: functions calling PyMem_MALLOC c.s.

PyMem_NEW c.s.: #defined using PyMem_MALLOC c.s.

I *like* the new PyObject_DEL and _PyObject_Del.  (I would have liked
to have them for my GC experiment, but that's another story.)

I can explain the MS_COREDLL business:

This is defined on Windows because the core is in a DLL.  Since the
caller may be in another DLL, and each DLL (potentially) has a
different default allocator, and (in pre-Vladimir times) the
type-specific deallocator typically calls free(), we (Mark & I)
decided that the allocation should be done in the type-specific
allocator.  We changed the PyObject_NEW() macro to call malloc() and
pass that into _PyObject_New() as a second argument.

Looking back, I wish we had made this change unconditionally --
there's nothing wrong with doing it that way on Unix, too.

But now that Vladimir is fixing all type-specific deallocators to call
the new _PyObject_Del(), we can put the allocation back into
_PyObject_New()!

The only problem is compatibility with old DLLs on Windows.  One
solution is to keep the second argument to _PyObject_New() when
MS_COREDLL is defined, but to change the PyObject_NEW() macro to pass
NULL instead.  The code of _PyObject_New() checks whether the pointer
is NULL and then allocates the memory itself; if a non-NULL pointer is
passed, it uses that and skips its own allocation.  _PyObject_Del()
can unconditionally free the memory: old DLLs won't call it (they call
free() directly) and new DLLs will have used NULL for the second
_PyObject_New() argument.

I hate to ask this of Vladimir, but could you make a new patch set
along the lines I sketched, without a pycore.h file?

--Guido van Rossum (home page: http://www.python.org/~guido/)

> From: Vladimir Marangozov <marangoz@python.inrialpes.fr>
> 
> I'm about to send a couple of patches relative to the malloc cleanup
> discussed on python-dev. Since it affects many files in the distribution,
> I'll send a patch per directory, which will facilitate their review.
> 
> Please examine them carefully. Although I'm pretty confident in their
> correctness, some details may have escaped my eyes due to the volume
> of the modified code.
> 
> Summary:
> ========
> 
> Exported (public) interfaces
> ----------------------------
> 
>    - PyMem_{Malloc, Realloc, Free} -- don't call anything on failure
>    - Py_{Malloc, Realloc, Free}    -- call PyErr_NoMemory() on failure
>    - _PyObject_{New, NewVar, Del}  -- object constructors/destructor
> 
>    Macros:
>    - PyMem_{NEW, NEW_VAR, DEL}     -- handy, use PyMem_{Malloc...} above
>    - PyObject_{NEW, NEW_VAR, DEL}  -- handy, use _PyObject_{New...} above
> 
> Private core interfaces
> -----------------------
> 
>    In addition to the public ones:
> 
>    - PyMem_{MALLOC, REALLOC, FREE} -- Python core allocator
>    
>    Macros:
>    - PyMem_{NEW, NEW_VAR, DEL}     -- handy, use PyMem_{MALLOC...} above
>    - PyObject_DEL is inlined (PyMem_FREE)