Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions Include/funcobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,48 @@
extern "C" {
#endif

/* Function guard */

typedef struct {
PyObject ob_base;

/* Initialize a guard:

- Return 0 on success
- Return 1 if the guard will always fail: PyFunction_Specialize() must
ignore the specialization
- Raise an exception and return -1 on error */
int (*init) (PyObject *guard, PyObject *func);

/* Check a guard:

- Return 0 on success
- Return 1 if the guard failed temporarely
- Return 2 if the guard will always fail:
calling the function must remove the specialized code
- Raise an exception and return -1 on error

args is a C array for positional arguments followed by values of keyword
arguments. Keys of keyword arguments are stored as a tuple of strings in
kwnames. nargs is the number of positional parameters at the beginning
of stack. The size of kwnames gives the number of keyword values in the
stack after positional arguments. */
int (*check) (PyObject *guard, PyObject **args, Py_ssize_t nargs,
PyObject *kwnames);
} PyFuncGuardObject;

PyAPI_DATA(PyTypeObject) PyFuncGuard_Type;


/* Specialized function */

typedef struct {
PyObject *code; /* callable or code object */
Py_ssize_t nb_guard;
PyObject **guards; /* PyFuncGuardObject objects */
} PySpecializedCode;


/* Function objects and code objects should not be confused with each other:
*
* Function objects are created by the execution of the 'def' statement.
Expand All @@ -33,6 +75,9 @@ typedef struct {
PyObject *func_annotations; /* Annotations, a dict or NULL */
PyObject *func_qualname; /* The qualified name */

Py_ssize_t func_nb_specialized;
PySpecializedCode *func_specialized;

/* Invariant:
* func_closure contains the bindings for func_code->co_freevars, so
* PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code)
Expand Down Expand Up @@ -72,6 +117,45 @@ PyAPI_FUNC(PyObject *) _PyFunction_FastCallKeywords(
PyObject *kwnames);
#endif

/* Specialize a function: add a specialized code with guards. code is a
* callable or code object, guards must be non-empty sequence of
* PyFuncGuardObject objects. Result:
*
* - Return 0 on success
* - Return 1 if the specialization has been ignored
* - Raise an exception and return -1 on error
*
* If code is a Python function, the code of the function is used as the
* specialized code. The specialized function must have the same parameter
* defaults, the same keyword parameter defaults, and it must not have
* specialized code.
*
* If code is a Python function or a code object, a new code object is created
* and the code name and first line number of the function code object are
* copied. The specialized code must have the same cell variables and the same
* free variables.
* */
PyAPI_DATA(int) PyFunction_Specialize(PyObject *func,
PyObject *code, PyObject *guards);

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

/* Remove one specialized code of a function with its guards by its index.
* Return 0 on success or if the index does not exist. Raise an exception and
* return -1 on error. */
PyAPI_FUNC(int) PyFunction_RemoveSpecialized(PyObject *func, Py_ssize_t index);

/* Remove all specialized codes and guards from a function.
* Return 0 on success. Raise an exception and return -1 if func is not
* a function. */
PyAPI_FUNC(int) PyFunction_RemoveAllSpecialized(PyObject *func);

/* Macros for direct access to these values. Type checks are *not*
done, so use with care. */
#define PyFunction_GET_CODE(func) \
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
_testcapi = None
import struct
import collections
import types

# The test cases here cover several paths through the function calling
# code. They depend on the METH_XXX flag that is used to define a C
Expand Down
Loading