[Python-ideas] RFC: PEP: Specialized functions with guards

Victor Stinner victor.stinner at gmail.com
Tue Jan 12 04:58:37 EST 2016


Hi,

2016-01-12 1:47 GMT+01:00 Nick Coghlan <ncoghlan at gmail.com>:
>> This method doesn't make sense at all in PyPy. The method is specific
>> to CPython since it relies on guards which have a pure C API (see
>> below). The PEP must be more explicit about that. IMHO it's perfectly
>> fine that PyPy makes this method a no-op (the method exactly does
>> nothing). It's already the case if a guard "always" fail in
>> first_check().
>
> Perhaps the specialisation call should also move to being a pure C
> API, only exposed through _testcapi for testing purposes?
>
> That would move both this and the dict versioning PEP into the same
> territory as the dynamic memory allocator PEP: low level C plumbing
> that enables interesting CPython specific extensions (like
> tracemalloc, in the dynamic allocator case) without committing other
> implementations to emulating features that aren't useful to them in
> any way.

I really like your idea :-) It solves many issues and technically it's
trivial to only add a C API and then expose it somewhere else at the
Python level (for example in my "fat" module", or as you said in
_testcapi for testing purpose).

Instead of adding func.specialize() and func.get_specialized() at
Python level, we can add *public* functions to the Python C API
(excluded of the stable ABI):

/* Add a specialized function with guards. Result:
 * - return 1 on success
 * - return 0 if the specialization has been ignored
 * - raise an exception and return -1 on error */
PyAPI_DATA(int) PyFunction_Specialize(PyObject *func, PyObject *func2,
                                      PyObject *guards);

/* Get the list of specialized functions as a list of
 * (func, guards) where func is a callable or code object and guards
 * is a list of PyFuncGuard (or subtypes) objects.
 * Raise an exception and return NULL on error. */
PyAPI_FUNC(PyObject*) PyFunction_GetSpecialized(PyObject *func);

/* Get the specialized function of a function. stack is a an array of PyObject*
 * objects: indexed arguments followed by (key, value) objects of keyword
 * arguments. na is the number of indexed arguments, nk is the number of
 * keyword arguments. stack contains na + nk * 2 objects.
 *
 * Return a callable or a code object on success.
 * Raise an exception and return NULL on error. */
PyAPI_FUNC(PyObject*) PyFunction_GetSpecializedFunc(PyObject *func,
                                                    PyObject **stack,
                                                    int na, int nk);

Again, other Python implementations which don't want to implement
function specializations can implement these functions as no-op (it's
fine with the API):

* PyFunction_Specialize() just returns 0
* PyFunction_GetSpecialized() creates an empty list
* PyFunction_GetSpecializedFunc() returns the code object of the
function (which is not something new)

Or not implement these functions at all, since it doesn't make sense for them.

--

First, I tried hard to avoid the need of a module to specialize
functions. My first API added a specialize() method to functions which
took a list of dictionaries to describe guards. The problem is this
API is that it exposes the implementation details and it avoids to
extend easily guard (implement new guards). Now the AST optimizer
injects "import fat" to optimize code when needed.

Hey, it's difficult to design a simple and obvious API!

Victor


More information about the Python-ideas mailing list