Commit 5c4de286 authored by Brett Cannon's avatar Brett Cannon

Add the co_extra field and accompanying APIs to code objects.

This completes PEP 523.
parent a9296e7f
...@@ -127,7 +127,8 @@ evaluation, etc. ...@@ -127,7 +127,8 @@ evaluation, etc.
This API is not part of the limited C API and is marked as private to This API is not part of the limited C API and is marked as private to
signal that usage of this API is expected to be limited and only signal that usage of this API is expected to be limited and only
applicable to very select, low-level use-cases. applicable to very select, low-level use-cases. Semantics of the
API will change with Python as necessary.
.. seealso:: .. seealso::
......
...@@ -187,6 +187,10 @@ PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); ...@@ -187,6 +187,10 @@ PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
#endif #endif
#ifndef Py_LIMITED_API
PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
#endif
#define Py_BEGIN_ALLOW_THREADS { \ #define Py_BEGIN_ALLOW_THREADS { \
PyThreadState *_save; \ PyThreadState *_save; \
_save = PyEval_SaveThread(); _save = PyEval_SaveThread();
......
...@@ -7,6 +7,14 @@ ...@@ -7,6 +7,14 @@
extern "C" { extern "C" {
#endif #endif
/* Holder for co_extra information */
typedef struct {
Py_ssize_t ce_size;
void **ce_extras;
} _PyCodeObjectExtra;
/* Bytecode object */ /* Bytecode object */
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
...@@ -15,6 +23,7 @@ typedef struct { ...@@ -15,6 +23,7 @@ typedef struct {
int co_nlocals; /* #local variables */ int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */ int co_stacksize; /* #entries needed for evaluation stack */
int co_flags; /* CO_..., see below */ int co_flags; /* CO_..., see below */
int co_firstlineno; /* first source line number */
PyObject *co_code; /* instruction opcodes */ PyObject *co_code; /* instruction opcodes */
PyObject *co_consts; /* list (constants used) */ PyObject *co_consts; /* list (constants used) */
PyObject *co_names; /* list of strings (names used) */ PyObject *co_names; /* list of strings (names used) */
...@@ -30,11 +39,12 @@ typedef struct { ...@@ -30,11 +39,12 @@ typedef struct {
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */ PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */ PyObject *co_name; /* unicode (name, for reference) */
int co_firstlineno; /* first source line number */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
Objects/lnotab_notes.txt for details. */ Objects/lnotab_notes.txt for details. */
void *co_zombieframe; /* for optimization only (see frameobject.c) */ void *co_zombieframe; /* for optimization only (see frameobject.c) */
PyObject *co_weakreflist; /* to support weakrefs to code objects */ PyObject *co_weakreflist; /* to support weakrefs to code objects */
/* Scratch space for extra data relating to the code object */
_PyCodeObjectExtra *co_extra;
} PyCodeObject; } PyCodeObject;
/* Masks for co_flags above */ /* Masks for co_flags above */
...@@ -128,6 +138,14 @@ PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj); ...@@ -128,6 +138,14 @@ PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj);
PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
PyObject *names, PyObject *lnotab); PyObject *names, PyObject *lnotab);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index,
void **extra);
PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
void *extra);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
......
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
extern "C" { extern "C" {
#endif #endif
/* This limitation is for performance and simplicity. If needed it can be
removed (with effort). */
#define MAX_CO_EXTRA_USERS 255
/* State shared between threads */ /* State shared between threads */
struct _ts; /* Forward */ struct _ts; /* Forward */
...@@ -141,6 +145,9 @@ typedef struct _ts { ...@@ -141,6 +145,9 @@ typedef struct _ts {
PyObject *coroutine_wrapper; PyObject *coroutine_wrapper;
int in_coroutine_wrapper; int in_coroutine_wrapper;
Py_ssize_t co_extra_user_count;
freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS];
/* XXX signal handlers should also be here */ /* XXX signal handlers should also be here */
} PyThreadState; } PyThreadState;
......
...@@ -27,7 +27,7 @@ Core and Builtins ...@@ -27,7 +27,7 @@ Core and Builtins
the braces (where the expressions are). This is a breaking change the braces (where the expressions are). This is a breaking change
from the 3.6 alpha releases. from the 3.6 alpha releases.
- Implement the frame evaluation part of PEP 523. - Implement PEP 523.
- Issue #27870: A left shift of zero by a large integer no longer attempts - Issue #27870: A left shift of zero by a large integer no longer attempts
to allocate large amounts of memory. to allocate large amounts of memory.
......
...@@ -152,6 +152,7 @@ PyCode_New(int argcount, int kwonlyargcount, ...@@ -152,6 +152,7 @@ PyCode_New(int argcount, int kwonlyargcount,
co->co_lnotab = lnotab; co->co_lnotab = lnotab;
co->co_zombieframe = NULL; co->co_zombieframe = NULL;
co->co_weakreflist = NULL; co->co_weakreflist = NULL;
co->co_extra = NULL;
return co; return co;
} }
...@@ -361,6 +362,20 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -361,6 +362,20 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
static void static void
code_dealloc(PyCodeObject *co) code_dealloc(PyCodeObject *co)
{ {
if (co->co_extra != NULL) {
PyThreadState *tstate = PyThreadState_Get();
for (Py_ssize_t i = 0; i < co->co_extra->ce_size; i++) {
freefunc free_extra = tstate->co_extra_freefuncs[i];
if (free_extra != NULL) {
free_extra(co->co_extra->ce_extras[i]);
}
}
PyMem_FREE(co->co_extra);
}
Py_XDECREF(co->co_code); Py_XDECREF(co->co_code);
Py_XDECREF(co->co_consts); Py_XDECREF(co->co_consts);
Py_XDECREF(co->co_names); Py_XDECREF(co->co_names);
...@@ -752,3 +767,79 @@ _PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds) ...@@ -752,3 +767,79 @@ _PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
return line; return line;
} }
int
_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
{
PyCodeObject *o;
assert(*extra == NULL);
if (!PyCode_Check(code)) {
PyErr_BadInternalCall();
return 1;
}
o = (PyCodeObject*) code;
if (o->co_extra == NULL || o->co_extra->ce_size <= index) {
return 0;
}
*extra = o->co_extra->ce_extras[index];
return 0;
}
int
_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
{
PyCodeObject *o;
PyThreadState *tstate = PyThreadState_Get();
if (!PyCode_Check(code) || index < 0 ||
index >= tstate->co_extra_user_count) {
PyErr_BadInternalCall();
return 1;
}
o = (PyCodeObject*) code;
if (o->co_extra == NULL) {
o->co_extra = (_PyCodeObjectExtra*) PyMem_Malloc(
sizeof(_PyCodeObjectExtra));
if (o->co_extra == NULL) {
return 1;
}
o->co_extra->ce_extras = PyMem_Malloc(
tstate->co_extra_user_count * sizeof(void*));
if (o->co_extra->ce_extras == NULL) {
return 1;
}
o->co_extra->ce_size = tstate->co_extra_user_count;
for (Py_ssize_t i = 0; i < o->co_extra->ce_size; i++) {
o->co_extra->ce_extras[i] = NULL;
}
}
else if (o->co_extra->ce_size <= index) {
o->co_extra->ce_extras = PyMem_Realloc(
o->co_extra->ce_extras, tstate->co_extra_user_count * sizeof(void*));
if (o->co_extra->ce_extras == NULL) {
return 1;
}
o->co_extra->ce_size = tstate->co_extra_user_count;
for (Py_ssize_t i = o->co_extra->ce_size; i < o->co_extra->ce_size; i++) {
o->co_extra->ce_extras[i] = NULL;
}
}
o->co_extra->ce_extras[index] = extra;
return 0;
}
...@@ -5608,3 +5608,17 @@ _Py_GetDXProfile(PyObject *self, PyObject *args) ...@@ -5608,3 +5608,17 @@ _Py_GetDXProfile(PyObject *self, PyObject *args)
} }
#endif #endif
Py_ssize_t
_PyEval_RequestCodeExtraIndex(freefunc free)
{
PyThreadState *tstate = PyThreadState_Get();
Py_ssize_t new_index;
if (tstate->co_extra_user_count == MAX_CO_EXTRA_USERS - 1) {
return -1;
}
new_index = tstate->co_extra_user_count++;
tstate->co_extra_freefuncs[new_index] = free;
return new_index;
}
...@@ -227,6 +227,7 @@ new_threadstate(PyInterpreterState *interp, int init) ...@@ -227,6 +227,7 @@ new_threadstate(PyInterpreterState *interp, int init)
tstate->coroutine_wrapper = NULL; tstate->coroutine_wrapper = NULL;
tstate->in_coroutine_wrapper = 0; tstate->in_coroutine_wrapper = 0;
tstate->co_extra_user_count = 0;
if (init) if (init)
_PyThreadState_Init(tstate); _PyThreadState_Init(tstate);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment