GH-100987: Allow objects other than code objects as the "executable" of an internal frame. (GH-105727)

* Add table describing possible executable classes for out-of-process debuggers.

* Remove shim code object creation code as it is no longer needed.

* Make lltrace a bit more robust w.r.t. non-standard frames.
This commit is contained in:
Mark Shannon 2023-06-14 13:46:37 +01:00 committed by GitHub
parent ad56340b66
commit 7199584ac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 541 additions and 606 deletions

View File

@ -447,19 +447,6 @@ adaptive_counter_backoff(uint16_t counter) {
return adaptive_counter_bits(value, backoff); return adaptive_counter_bits(value, backoff);
} }
/* Line array cache for tracing */
typedef struct _PyShimCodeDef {
const uint8_t *code;
int codelen;
int stacksize;
const char *cname;
} _PyShimCodeDef;
extern PyCodeObject *
_Py_MakeShimCode(const _PyShimCodeDef *code);
extern uint32_t _Py_next_func_version; extern uint32_t _Py_next_func_version;

View File

@ -47,7 +47,7 @@ enum _frameowner {
}; };
typedef struct _PyInterpreterFrame { typedef struct _PyInterpreterFrame {
PyCodeObject *f_code; /* Strong reference */ PyObject *f_executable; /* Strong reference */
struct _PyInterpreterFrame *previous; struct _PyInterpreterFrame *previous;
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
@ -73,20 +73,25 @@ typedef struct _PyInterpreterFrame {
} _PyInterpreterFrame; } _PyInterpreterFrame;
#define _PyInterpreterFrame_LASTI(IF) \ #define _PyInterpreterFrame_LASTI(IF) \
((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) ((int)((IF)->prev_instr - _PyCode_CODE(_PyFrame_GetCode(IF))))
static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
assert(PyCode_Check(f->f_executable));
return (PyCodeObject *)f->f_executable;
}
static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
return f->localsplus + f->f_code->co_nlocalsplus; return f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus;
} }
static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) { static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) {
assert(f->stacktop > f->f_code->co_nlocalsplus); assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus);
assert(f->localsplus[f->stacktop-1] != NULL); assert(f->localsplus[f->stacktop-1] != NULL);
return f->localsplus[f->stacktop-1]; return f->localsplus[f->stacktop-1];
} }
static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) { static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) {
assert(f->stacktop > f->f_code->co_nlocalsplus); assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus);
f->stacktop--; f->stacktop--;
return f->localsplus[f->stacktop]; return f->localsplus[f->stacktop];
} }
@ -119,7 +124,7 @@ _PyFrame_Initialize(
PyObject *locals, PyCodeObject *code, int null_locals_from) PyObject *locals, PyCodeObject *code, int null_locals_from)
{ {
frame->f_funcobj = (PyObject *)func; frame->f_funcobj = (PyObject *)func;
frame->f_code = (PyCodeObject *)Py_NewRef(code); frame->f_executable = Py_NewRef(code);
frame->f_builtins = func->func_builtins; frame->f_builtins = func->func_builtins;
frame->f_globals = func->func_globals; frame->f_globals = func->func_globals;
frame->f_locals = locals; frame->f_locals = locals;
@ -172,8 +177,11 @@ _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer)
static inline bool static inline bool
_PyFrame_IsIncomplete(_PyInterpreterFrame *frame) _PyFrame_IsIncomplete(_PyInterpreterFrame *frame)
{ {
if (frame->owner == FRAME_OWNED_BY_CSTACK) {
return true;
}
return frame->owner != FRAME_OWNED_BY_GENERATOR && return frame->owner != FRAME_OWNED_BY_GENERATOR &&
frame->prev_instr < _PyCode_CODE(frame->f_code) + frame->f_code->_co_firsttraceable; frame->prev_instr < _PyCode_CODE(_PyFrame_GetCode(frame)) + _PyFrame_GetCode(frame)->_co_firsttraceable;
} }
static inline _PyInterpreterFrame * static inline _PyInterpreterFrame *
@ -272,6 +280,14 @@ PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame)
return (PyGenObject *)(((char *)frame) - offset_in_gen); return (PyGenObject *)(((char *)frame) - offset_in_gen);
} }
#define PY_EXECUTABLE_KIND_SKIP 0
#define PY_EXECUTABLE_KIND_PY_FUNCTION 1
#define PY_EXECUTABLE_KIND_BUILTIN_FUNCTION 3
#define PY_EXECUTABLE_KIND_METHOD_DESCRIPTOR 4
#define PY_EXECUTABLE_KINDS 5
PyAPI_DATA(const PyTypeObject *) const PyUnstable_ExecutableKinds[PY_EXECUTABLE_KINDS+1];
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -565,7 +565,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(newline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(newline));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(open_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(open_br));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(percent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(percent));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(shim_name));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED));

View File

@ -51,7 +51,6 @@ struct _Py_global_strings {
STRUCT_FOR_STR(newline, "\n") STRUCT_FOR_STR(newline, "\n")
STRUCT_FOR_STR(open_br, "{") STRUCT_FOR_STR(open_br, "{")
STRUCT_FOR_STR(percent, "%") STRUCT_FOR_STR(percent, "%")
STRUCT_FOR_STR(shim_name, "<shim>")
STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(type_params, ".type_params")
STRUCT_FOR_STR(utf_8, "utf-8") STRUCT_FOR_STR(utf_8, "utf-8")
} literals; } literals;

View File

@ -159,7 +159,6 @@ struct _is {
struct ast_state ast; struct ast_state ast;
struct types_state types; struct types_state types;
struct callable_cache callable_cache; struct callable_cache callable_cache;
PyCodeObject *interpreter_trampoline;
_PyOptimizerObject *optimizer; _PyOptimizerObject *optimizer;
uint16_t optimizer_resume_threshold; uint16_t optimizer_resume_threshold;
uint16_t optimizer_backedge_threshold; uint16_t optimizer_backedge_threshold;

View File

@ -557,7 +557,6 @@ extern "C" {
INIT_STR(newline, "\n"), \ INIT_STR(newline, "\n"), \
INIT_STR(open_br, "{"), \ INIT_STR(open_br, "{"), \
INIT_STR(percent, "%"), \ INIT_STR(percent, "%"), \
INIT_STR(shim_name, "<shim>"), \
INIT_STR(type_params, ".type_params"), \ INIT_STR(type_params, ".type_params"), \
INIT_STR(utf_8, "utf-8"), \ INIT_STR(utf_8, "utf-8"), \
} }

View File

@ -0,0 +1,4 @@
Allow objects other than code objects as the "executable" in internal
frames. In the long term, this can help tools like Cython and PySpy interact
more efficiently. In the shorter term, it allows us to perform some
optimizations more simply.

View File

@ -2316,76 +2316,3 @@ _PyStaticCode_Init(PyCodeObject *co)
} }
#define MAX_CODE_UNITS_PER_LOC_ENTRY 8 #define MAX_CODE_UNITS_PER_LOC_ENTRY 8
PyCodeObject *
_Py_MakeShimCode(const _PyShimCodeDef *codedef)
{
PyObject *name = NULL;
PyObject *co_code = NULL;
PyObject *lines = NULL;
PyCodeObject *codeobj = NULL;
uint8_t *loc_table = NULL;
name = _PyUnicode_FromASCII(codedef->cname, strlen(codedef->cname));
if (name == NULL) {
goto cleanup;
}
co_code = PyBytes_FromStringAndSize(
(const char *)codedef->code, codedef->codelen);
if (co_code == NULL) {
goto cleanup;
}
int code_units = codedef->codelen / sizeof(_Py_CODEUNIT);
int loc_entries = (code_units + MAX_CODE_UNITS_PER_LOC_ENTRY - 1) /
MAX_CODE_UNITS_PER_LOC_ENTRY;
loc_table = PyMem_Malloc(loc_entries);
if (loc_table == NULL) {
PyErr_NoMemory();
goto cleanup;
}
for (int i = 0; i < loc_entries-1; i++) {
loc_table[i] = 0x80 | (PY_CODE_LOCATION_INFO_NONE << 3) | 7;
code_units -= MAX_CODE_UNITS_PER_LOC_ENTRY;
}
assert(loc_entries > 0);
assert(code_units > 0 && code_units <= MAX_CODE_UNITS_PER_LOC_ENTRY);
loc_table[loc_entries-1] = 0x80 |
(PY_CODE_LOCATION_INFO_NONE << 3) | (code_units-1);
lines = PyBytes_FromStringAndSize((const char *)loc_table, loc_entries);
PyMem_Free(loc_table);
if (lines == NULL) {
goto cleanup;
}
_Py_DECLARE_STR(shim_name, "<shim>");
struct _PyCodeConstructor con = {
.filename = &_Py_STR(shim_name),
.name = name,
.qualname = name,
.flags = CO_NEWLOCALS | CO_OPTIMIZED,
.code = co_code,
.firstlineno = 1,
.linetable = lines,
.consts = (PyObject *)&_Py_SINGLETON(tuple_empty),
.names = (PyObject *)&_Py_SINGLETON(tuple_empty),
.localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty),
.localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty),
.argcount = 0,
.posonlyargcount = 0,
.kwonlyargcount = 0,
.stacksize = codedef->stacksize,
.exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty),
};
codeobj = _PyCode_New(&con);
cleanup:
Py_XDECREF(name);
Py_XDECREF(co_code);
Py_XDECREF(lines);
return codeobj;
}

View File

@ -642,6 +642,7 @@ _PyFrame_GetState(PyFrameObject *frame)
static int static int
frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored)) frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored))
{ {
PyCodeObject *code = _PyFrame_GetCode(f->f_frame);
if (p_new_lineno == NULL) { if (p_new_lineno == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1; return -1;
@ -719,7 +720,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
} }
new_lineno = (int)l_new_lineno; new_lineno = (int)l_new_lineno;
if (new_lineno < f->f_frame->f_code->co_firstlineno) { if (new_lineno < code->co_firstlineno) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"line %d comes before the current code block", "line %d comes before the current code block",
new_lineno); new_lineno);
@ -728,8 +729,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this /* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
* should never overflow. */ * should never overflow. */
int len = (int)Py_SIZE(f->f_frame->f_code); int len = (int)Py_SIZE(code);
int *lines = marklines(f->f_frame->f_code, len); int *lines = marklines(code, len);
if (lines == NULL) { if (lines == NULL) {
return -1; return -1;
} }
@ -743,7 +744,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
return -1; return -1;
} }
int64_t *stacks = mark_stacks(f->f_frame->f_code, len); int64_t *stacks = mark_stacks(code, len);
if (stacks == NULL) { if (stacks == NULL) {
PyMem_Free(lines); PyMem_Free(lines);
return -1; return -1;
@ -788,7 +789,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
// in the new location. Rather than crashing or changing co_code, just bind // in the new location. Rather than crashing or changing co_code, just bind
// None instead: // None instead:
int unbound = 0; int unbound = 0;
for (int i = 0; i < f->f_frame->f_code->co_nlocalsplus; i++) { for (int i = 0; i < code->co_nlocalsplus; i++) {
// Counting every unbound local is overly-cautious, but a full flow // Counting every unbound local is overly-cautious, but a full flow
// analysis (like we do in the compiler) is probably too expensive: // analysis (like we do in the compiler) is probably too expensive:
unbound += f->f_frame->localsplus[i] == NULL; unbound += f->f_frame->localsplus[i] == NULL;
@ -801,7 +802,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
} }
// Do this in a second pass to avoid writing a bunch of Nones when // Do this in a second pass to avoid writing a bunch of Nones when
// warnings are being treated as errors and the previous bit raises: // warnings are being treated as errors and the previous bit raises:
for (int i = 0; i < f->f_frame->f_code->co_nlocalsplus; i++) { for (int i = 0; i < code->co_nlocalsplus; i++) {
if (f->f_frame->localsplus[i] == NULL) { if (f->f_frame->localsplus[i] == NULL) {
f->f_frame->localsplus[i] = Py_NewRef(Py_None); f->f_frame->localsplus[i] = Py_NewRef(Py_None);
unbound--; unbound--;
@ -832,7 +833,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
} }
/* Finally set the new lasti and return OK. */ /* Finally set the new lasti and return OK. */
f->f_lineno = 0; f->f_lineno = 0;
f->f_frame->prev_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr; f->f_frame->prev_instr = _PyCode_CODE(code) + best_addr;
return 0; return 0;
} }
@ -886,15 +887,15 @@ frame_dealloc(PyFrameObject *f)
} }
Py_TRASHCAN_BEGIN(f, frame_dealloc); Py_TRASHCAN_BEGIN(f, frame_dealloc);
PyCodeObject *co = NULL; PyObject *co = NULL;
/* Kill all local variables including specials, if we own them */ /* Kill all local variables including specials, if we own them */
if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) { if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data); assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data);
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data; _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data;
/* Don't clear code object until the end */ /* Don't clear code object until the end */
co = frame->f_code; co = frame->f_executable;
frame->f_code = NULL; frame->f_executable = NULL;
Py_CLEAR(frame->f_funcobj); Py_CLEAR(frame->f_funcobj);
Py_CLEAR(frame->f_locals); Py_CLEAR(frame->f_locals);
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
@ -968,7 +969,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
{ {
Py_ssize_t res; Py_ssize_t res;
res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus);
PyCodeObject *code = f->f_frame->f_code; PyCodeObject *code = _PyFrame_GetCode(f->f_frame);
res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *); res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *);
return PyLong_FromSsize_t(res); return PyLong_FromSsize_t(res);
} }
@ -980,7 +981,7 @@ static PyObject *
frame_repr(PyFrameObject *f) frame_repr(PyFrameObject *f)
{ {
int lineno = PyFrame_GetLineNumber(f); int lineno = PyFrame_GetLineNumber(f);
PyCodeObject *code = f->f_frame->f_code; PyCodeObject *code = _PyFrame_GetCode(f->f_frame);
return PyUnicode_FromFormat( return PyUnicode_FromFormat(
"<frame at %p, file %R, line %d, code %S>", "<frame at %p, file %R, line %d, code %S>",
f, code->co_filename, lineno, code->co_name); f, code->co_filename, lineno, code->co_name);
@ -1102,7 +1103,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
// This only works when opcode is a non-quickened form: // This only works when opcode is a non-quickened form:
assert(_PyOpcode_Deopt[opcode] == opcode); assert(_PyOpcode_Deopt[opcode] == opcode);
int check_oparg = 0; int check_oparg = 0;
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code); for (_Py_CODEUNIT *instruction = _PyCode_CODE(_PyFrame_GetCode(frame));
instruction < frame->prev_instr; instruction++) instruction < frame->prev_instr; instruction++)
{ {
int check_opcode = _PyOpcode_Deopt[instruction->op.code]; int check_opcode = _PyOpcode_Deopt[instruction->op.code];
@ -1128,7 +1129,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
{ {
// COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt // COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt
// here: // here:
PyCodeObject *co = frame->f_code; PyCodeObject *co = _PyFrame_GetCode(frame);
int lasti = _PyInterpreterFrame_LASTI(frame); int lasti = _PyInterpreterFrame_LASTI(frame);
if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS
&& PyFunction_Check(frame->f_funcobj))) && PyFunction_Check(frame->f_funcobj)))
@ -1145,7 +1146,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
frame->localsplus[offset + i] = Py_NewRef(o); frame->localsplus[offset + i] = Py_NewRef(o);
} }
// COPY_FREE_VARS doesn't have inline CACHEs, either: // COPY_FREE_VARS doesn't have inline CACHEs, either:
frame->prev_instr = _PyCode_CODE(frame->f_code); frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame));
} }
@ -1213,7 +1214,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame)
frame_init_get_vars(frame); frame_init_get_vars(frame);
PyCodeObject *co = frame->f_code; PyCodeObject *co = _PyFrame_GetCode(frame);
for (int i = 0; i < co->co_nlocalsplus; i++) { for (int i = 0; i < co->co_nlocalsplus; i++) {
PyObject *value; // borrowed reference PyObject *value; // borrowed reference
if (!frame_get_var(frame, co, i, &value)) { if (!frame_get_var(frame, co, i, &value)) {
@ -1257,7 +1258,7 @@ PyFrame_GetVar(PyFrameObject *frame_obj, PyObject *name)
_PyInterpreterFrame *frame = frame_obj->f_frame; _PyInterpreterFrame *frame = frame_obj->f_frame;
frame_init_get_vars(frame); frame_init_get_vars(frame);
PyCodeObject *co = frame->f_code; PyCodeObject *co = _PyFrame_GetCode(frame);
for (int i = 0; i < co->co_nlocalsplus; i++) { for (int i = 0; i < co->co_nlocalsplus; i++) {
PyObject *var_name = PyTuple_GET_ITEM(co->co_localsplusnames, i); PyObject *var_name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
if (!_PyUnicode_Equal(var_name, name)) { if (!_PyUnicode_Equal(var_name, name)) {
@ -1331,7 +1332,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
return; return;
} }
fast = _PyFrame_GetLocalsArray(frame); fast = _PyFrame_GetLocalsArray(frame);
co = frame->f_code; co = _PyFrame_GetCode(frame);
PyObject *exc = PyErr_GetRaisedException(); PyObject *exc = PyErr_GetRaisedException();
for (int i = 0; i < co->co_nlocalsplus; i++) { for (int i = 0; i < co->co_nlocalsplus; i++) {
@ -1417,7 +1418,7 @@ PyFrame_GetCode(PyFrameObject *frame)
{ {
assert(frame != NULL); assert(frame != NULL);
assert(!_PyFrame_IsIncomplete(frame->f_frame)); assert(!_PyFrame_IsIncomplete(frame->f_frame));
PyCodeObject *code = frame->f_frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame->f_frame);
assert(code != NULL); assert(code != NULL);
return (PyCodeObject*)Py_NewRef(code); return (PyCodeObject*)Py_NewRef(code);
} }

View File

@ -29,7 +29,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
static inline PyCodeObject * static inline PyCodeObject *
_PyGen_GetCode(PyGenObject *gen) { _PyGen_GetCode(PyGenObject *gen) {
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe);
return frame->f_code; return _PyFrame_GetCode(frame);
} }
PyCodeObject * PyCodeObject *
@ -957,7 +957,7 @@ static PyObject *
gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
PyObject *name, PyObject *qualname) PyObject *name, PyObject *qualname)
{ {
PyCodeObject *code = f->f_frame->f_code; PyCodeObject *code = _PyFrame_GetCode(f->f_frame);
int size = code->co_nlocalsplus + code->co_stacksize; int size = code->co_nlocalsplus + code->co_stacksize;
PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size);
if (gen == NULL) { if (gen == NULL) {
@ -1339,7 +1339,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame)
} }
frame = current_frame; frame = current_frame;
for (int i = 0; i < frame_count; ++i) { for (int i = 0; i < frame_count; ++i) {
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
int line = PyUnstable_InterpreterFrame_GetLine(frame); int line = PyUnstable_InterpreterFrame_GetLine(frame);
PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line,
code->co_name); code->co_name);

View File

@ -10405,7 +10405,7 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
return -1; return -1;
} }
assert(cframe->f_code->co_nlocalsplus > 0); assert(_PyFrame_GetCode(cframe)->co_nlocalsplus > 0);
PyObject *firstarg = _PyFrame_GetLocalsArray(cframe)[0]; PyObject *firstarg = _PyFrame_GetLocalsArray(cframe)[0];
// The first argument might be a cell. // The first argument might be a cell.
if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) { if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) {
@ -10498,7 +10498,7 @@ super_init_impl(PyObject *self, PyTypeObject *type, PyObject *obj) {
"super(): no current frame"); "super(): no current frame");
return -1; return -1;
} }
int res = super_init_without_args(frame, frame->f_code, &type, &obj); int res = super_init_without_args(frame, _PyFrame_GetCode(frame), &type, &obj);
if (res < 0) { if (res < 0) {
return -1; return -1;

View File

@ -898,7 +898,7 @@ setup_context(Py_ssize_t stack_level,
} }
else { else {
globals = f->f_frame->f_globals; globals = f->f_frame->f_globals;
*filename = Py_NewRef(f->f_frame->f_code->co_filename); *filename = Py_NewRef(_PyFrame_GetCode(f->f_frame)->co_filename);
*lineno = PyFrame_GetLineNumber(f); *lineno = PyFrame_GetLineNumber(f);
Py_DECREF(f); Py_DECREF(f);
} }

View File

@ -137,8 +137,8 @@ dummy_func(
assert(tstate->cframe == &cframe); assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame); assert(frame == cframe.current_frame);
/* Possibly combine this with eval breaker */ /* Possibly combine this with eval breaker */
if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) {
int err = _Py_Instrument(frame->f_code, tstate->interp); int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
ERROR_IF(err, error); ERROR_IF(err, error);
next_instr--; next_instr--;
} }
@ -152,8 +152,8 @@ dummy_func(
* We need to check the eval breaker anyway, can we * We need to check the eval breaker anyway, can we
* combine the instrument verison check and the eval breaker test? * combine the instrument verison check and the eval breaker test?
*/ */
if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) {
if (_Py_Instrument(frame->f_code, tstate->interp)) { if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) {
goto error; goto error;
} }
next_instr--; next_instr--;
@ -666,8 +666,6 @@ dummy_func(
inst(INTERPRETER_EXIT, (retval --)) { inst(INTERPRETER_EXIT, (retval --)) {
assert(frame == &entry_frame); assert(frame == &entry_frame);
assert(_PyFrame_IsIncomplete(frame)); assert(_PyFrame_IsIncomplete(frame));
STACK_SHRINK(1); // Since we're not going to DISPATCH()
assert(EMPTY());
/* Restore previous cframe and return. */ /* Restore previous cframe and return. */
tstate->cframe = cframe.previous; tstate->cframe = cframe.previous;
assert(tstate->cframe->current_frame == frame->previous); assert(tstate->cframe->current_frame == frame->previous);
@ -971,7 +969,7 @@ dummy_func(
if (oparg) { if (oparg) {
PyObject *lasti = values[0]; PyObject *lasti = values[0];
if (PyLong_Check(lasti)) { if (PyLong_Check(lasti)) {
frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
} }
else { else {
@ -1385,7 +1383,7 @@ dummy_func(
// Can't use ERROR_IF here. // Can't use ERROR_IF here.
// Fortunately we don't need its superpower. // Fortunately we don't need its superpower.
if (oldobj == NULL) { if (oldobj == NULL) {
format_exc_unbound(tstate, frame->f_code, oparg); format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg);
goto error; goto error;
} }
PyCell_SET(cell, NULL); PyCell_SET(cell, NULL);
@ -1395,8 +1393,8 @@ dummy_func(
inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) { inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) {
PyObject *name; PyObject *name;
assert(class_dict); assert(class_dict);
assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus);
name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg);
if (PyDict_CheckExact(class_dict)) { if (PyDict_CheckExact(class_dict)) {
value = PyDict_GetItemWithError(class_dict, name); value = PyDict_GetItemWithError(class_dict, name);
if (value != NULL) { if (value != NULL) {
@ -1422,7 +1420,7 @@ dummy_func(
PyObject *cell = GETLOCAL(oparg); PyObject *cell = GETLOCAL(oparg);
value = PyCell_GET(cell); value = PyCell_GET(cell);
if (value == NULL) { if (value == NULL) {
format_exc_unbound(tstate, frame->f_code, oparg); format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg);
goto error; goto error;
} }
Py_INCREF(value); Py_INCREF(value);
@ -1433,7 +1431,7 @@ dummy_func(
PyObject *cell = GETLOCAL(oparg); PyObject *cell = GETLOCAL(oparg);
value = PyCell_GET(cell); value = PyCell_GET(cell);
if (value == NULL) { if (value == NULL) {
format_exc_unbound(tstate, frame->f_code, oparg); format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg);
ERROR_IF(true, error); ERROR_IF(true, error);
} }
Py_INCREF(value); Py_INCREF(value);
@ -1448,7 +1446,7 @@ dummy_func(
inst(COPY_FREE_VARS, (--)) { inst(COPY_FREE_VARS, (--)) {
/* Copy closure variables to free variables */ /* Copy closure variables to free variables */
PyCodeObject *co = frame->f_code; PyCodeObject *co = _PyFrame_GetCode(frame);
assert(PyFunction_Check(frame->f_funcobj)); assert(PyFunction_Check(frame->f_funcobj));
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
assert(oparg == co->co_nfreevars); assert(oparg == co->co_nfreevars);
@ -2175,7 +2173,8 @@ dummy_func(
}; };
inst(ENTER_EXECUTOR, (--)) { inst(ENTER_EXECUTOR, (--)) {
_PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; PyCodeObject *code = _PyFrame_GetCode(frame);
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg];
Py_INCREF(executor); Py_INCREF(executor);
frame = executor->execute(executor, frame, stack_pointer); frame = executor->execute(executor, frame, stack_pointer);
if (frame == NULL) { if (frame == NULL) {
@ -2292,7 +2291,7 @@ dummy_func(
/* before: [obj]; after [getiter(obj)] */ /* before: [obj]; after [getiter(obj)] */
if (PyCoro_CheckExact(iterable)) { if (PyCoro_CheckExact(iterable)) {
/* `iterable` is a coroutine */ /* `iterable` is a coroutine */
if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
/* and it is used in a 'yield from' expression of a /* and it is used in a 'yield from' expression of a
regular generator. */ regular generator. */
_PyErr_SetString(tstate, PyExc_TypeError, _PyErr_SetString(tstate, PyExc_TypeError,

View File

@ -129,6 +129,9 @@ lltrace_instruction(_PyInterpreterFrame *frame,
PyObject **stack_pointer, PyObject **stack_pointer,
_Py_CODEUNIT *next_instr) _Py_CODEUNIT *next_instr)
{ {
if (frame->owner == FRAME_OWNED_BY_CSTACK) {
return;
}
/* This dump_stack() operation is risky, since the repr() of some /* This dump_stack() operation is risky, since the repr() of some
objects enters the interpreter recursively. It is also slow. objects enters the interpreter recursively. It is also slow.
So you might want to comment it out. */ So you might want to comment it out. */
@ -137,7 +140,7 @@ lltrace_instruction(_PyInterpreterFrame *frame,
int opcode = next_instr->op.code; int opcode = next_instr->op.code;
const char *opname = _PyOpcode_OpName[opcode]; const char *opname = _PyOpcode_OpName[opcode];
assert(opname != NULL); assert(opname != NULL);
int offset = (int)(next_instr - _PyCode_CODE(frame->f_code)); int offset = (int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame)));
if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) { if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
printf("%d: %s %d\n", offset * 2, opname, oparg); printf("%d: %s %d\n", offset * 2, opname, oparg);
} }
@ -150,7 +153,7 @@ static void
lltrace_resume_frame(_PyInterpreterFrame *frame) lltrace_resume_frame(_PyInterpreterFrame *frame)
{ {
PyObject *fobj = frame->f_funcobj; PyObject *fobj = frame->f_funcobj;
if (frame->owner == FRAME_OWNED_BY_CSTACK || if (!PyCode_Check(frame->f_executable) ||
fobj == NULL || fobj == NULL ||
!PyFunction_Check(fobj) !PyFunction_Check(fobj)
) { ) {
@ -621,6 +624,13 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) {
tstate->py_recursion_remaining++; tstate->py_recursion_remaining++;
} }
static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = {
/* Put a NOP at the start, so that the IP points into
* the code, rather than before it */
{ .op.code = NOP, .op.arg = 0 },
{ .op.code = INTERPRETER_EXIT, .op.arg = 0 },
{ .op.code = RESUME, .op.arg = 0 }
};
/* Disable unused label warnings. They are handy for debugging, even /* Disable unused label warnings. They are handy for debugging, even
if computed gotos aren't used. */ if computed gotos aren't used. */
@ -668,7 +678,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
cframe.previous = prev_cframe; cframe.previous = prev_cframe;
tstate->cframe = &cframe; tstate->cframe = &cframe;
assert(tstate->interp->interpreter_trampoline != NULL);
#ifdef Py_DEBUG #ifdef Py_DEBUG
/* Set these to invalid but identifiable values for debugging. */ /* Set these to invalid but identifiable values for debugging. */
entry_frame.f_funcobj = (PyObject*)0xaaa0; entry_frame.f_funcobj = (PyObject*)0xaaa0;
@ -677,9 +686,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
entry_frame.f_globals = (PyObject*)0xaaa3; entry_frame.f_globals = (PyObject*)0xaaa3;
entry_frame.f_builtins = (PyObject*)0xaaa4; entry_frame.f_builtins = (PyObject*)0xaaa4;
#endif #endif
entry_frame.f_code = tstate->interp->interpreter_trampoline; entry_frame.f_executable = Py_None;
entry_frame.prev_instr = entry_frame.prev_instr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS;
_PyCode_CODE(tstate->interp->interpreter_trampoline);
entry_frame.stacktop = 0; entry_frame.stacktop = 0;
entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.owner = FRAME_OWNED_BY_CSTACK;
entry_frame.return_offset = 0; entry_frame.return_offset = 0;
@ -701,7 +709,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
} }
/* Because this avoids the RESUME, /* Because this avoids the RESUME,
* we need to update instrumentation */ * we need to update instrumentation */
_Py_Instrument(frame->f_code, tstate->interp); _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
monitor_throw(tstate, frame, frame->prev_instr); monitor_throw(tstate, frame, frame->prev_instr);
/* TO DO -- Monitor throw entry. */ /* TO DO -- Monitor throw entry. */
goto resume_with_error; goto resume_with_error;
@ -715,7 +723,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
/* Sets the above local variables from the frame */ /* Sets the above local variables from the frame */
#define SET_LOCALS_FROM_FRAME() \ #define SET_LOCALS_FROM_FRAME() \
assert(_PyInterpreterFrame_LASTI(frame) >= -1); \
/* Jump back to the last instruction executed... */ \ /* Jump back to the last instruction executed... */ \
next_instr = frame->prev_instr + 1; \ next_instr = frame->prev_instr + 1; \
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
@ -874,7 +881,7 @@ handle_eval_breaker:
opcode = next_instr->op.code; opcode = next_instr->op.code;
_PyErr_Format(tstate, PyExc_SystemError, _PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d", "%U:%d: unknown opcode %d",
frame->f_code->co_filename, _PyFrame_GetCode(frame)->co_filename,
PyUnstable_InterpreterFrame_GetLine(frame), PyUnstable_InterpreterFrame_GetLine(frame),
opcode); opcode);
goto error; goto error;
@ -889,7 +896,7 @@ unbound_local_error:
{ {
format_exc_check_arg(tstate, PyExc_UnboundLocalError, format_exc_check_arg(tstate, PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG, UNBOUNDLOCAL_ERROR_MSG,
PyTuple_GetItem(frame->f_code->co_localsplusnames, oparg) PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg)
); );
goto error; goto error;
} }
@ -929,7 +936,7 @@ exception_unwind:
/* We can't use frame->f_lasti here, as RERAISE may have set it */ /* We can't use frame->f_lasti here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1; int offset = INSTR_OFFSET()-1;
int level, handler, lasti; int level, handler, lasti;
if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) { if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
// No handlers, so exit. // No handlers, so exit.
assert(_PyErr_Occurred(tstate)); assert(_PyErr_Occurred(tstate));
@ -1523,12 +1530,12 @@ clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
assert(frame->owner == FRAME_OWNED_BY_THREAD); assert(frame->owner == FRAME_OWNED_BY_THREAD);
// Make sure that this is, indeed, the top frame. We can't check this in // Make sure that this is, indeed, the top frame. We can't check this in
// _PyThreadState_PopFrame, since f_code is already cleared at that point: // _PyThreadState_PopFrame, since f_code is already cleared at that point:
assert((PyObject **)frame + frame->f_code->co_framesize == assert((PyObject **)frame + _PyFrame_GetCode(frame)->co_framesize ==
tstate->datastack_top); tstate->datastack_top);
tstate->c_recursion_remaining--; tstate->c_recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
_PyFrame_ClearExceptCode(frame); _PyFrame_ClearExceptCode(frame);
Py_DECREF(frame->f_code); Py_DECREF(frame->f_executable);
tstate->c_recursion_remaining++; tstate->c_recursion_remaining++;
_PyThreadState_PopFrame(tstate, frame); _PyThreadState_PopFrame(tstate, frame);
} }
@ -2013,7 +2020,7 @@ do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame,
static inline int static inline int
no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event)
{ {
_PyCoMonitoringData *data = frame->f_code->_co_monitoring; _PyCoMonitoringData *data = _PyFrame_GetCode(frame)->_co_monitoring;
if (data) { if (data) {
if (data->active_monitors.tools[event] == 0) { if (data->active_monitors.tools[event] == 0) {
return 1; return 1;
@ -2331,7 +2338,7 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
int result = cf->cf_flags != 0; int result = cf->cf_flags != 0;
if (current_frame != NULL) { if (current_frame != NULL) {
const int codeflags = current_frame->f_code->co_flags; const int codeflags = _PyFrame_GetCode(current_frame)->co_flags;
const int compilerflags = codeflags & PyCF_MASK; const int compilerflags = codeflags & PyCF_MASK;
if (compilerflags) { if (compilerflags) {
result = 1; result = 1;

View File

@ -138,13 +138,13 @@ GETITEM(PyObject *v, Py_ssize_t i) {
/* Code access macros */ /* Code access macros */
/* The integer overflow is checked by an assertion below. */ /* The integer overflow is checked by an assertion below. */
#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) #define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame))))
#define NEXTOPARG() do { \ #define NEXTOPARG() do { \
_Py_CODEUNIT word = *next_instr; \ _Py_CODEUNIT word = *next_instr; \
opcode = word.op.code; \ opcode = word.op.code; \
oparg = word.op.arg; \ oparg = word.op.arg; \
} while (0) } while (0)
#define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x)) #define JUMPTO(x) (next_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + (x))
#define JUMPBY(x) (next_instr += (x)) #define JUMPBY(x) (next_instr += (x))
/* OpCode prediction macros /* OpCode prediction macros
@ -182,7 +182,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
/* The stack can grow at most MAXINT deep, as co_nlocals and /* The stack can grow at most MAXINT deep, as co_nlocals and
co_stacksize are ints. */ co_stacksize are ints. */
#define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame)))
#define STACK_SIZE() (frame->f_code->co_stacksize) #define STACK_SIZE() (_PyFrame_GetCode(frame)->co_stacksize)
#define EMPTY() (STACK_LEVEL() == 0) #define EMPTY() (STACK_LEVEL() == 0)
#define TOP() (stack_pointer[-1]) #define TOP() (stack_pointer[-1])
#define SECOND() (stack_pointer[-2]) #define SECOND() (stack_pointer[-2])
@ -221,8 +221,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
/* Data access macros */ /* Data access macros */
#define FRAME_CO_CONSTS (frame->f_code->co_consts) #define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts)
#define FRAME_CO_NAMES (frame->f_code->co_names) #define FRAME_CO_NAMES (_PyFrame_GetCode(frame)->co_names)
/* Local variable macros */ /* Local variable macros */
@ -270,6 +270,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define GLOBALS() frame->f_globals #define GLOBALS() frame->f_globals
#define BUILTINS() frame->f_builtins #define BUILTINS() frame->f_builtins
#define LOCALS() frame->f_locals #define LOCALS() frame->f_locals
#define CONSTS() _PyFrame_GetCode(frame)->co_consts
#define NAMES() _PyFrame_GetCode(frame)->co_names
#define DTRACE_FUNCTION_ENTRY() \ #define DTRACE_FUNCTION_ENTRY() \
if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \

View File

@ -14,7 +14,7 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
Py_VISIT(frame->frame_obj); Py_VISIT(frame->frame_obj);
Py_VISIT(frame->f_locals); Py_VISIT(frame->f_locals);
Py_VISIT(frame->f_funcobj); Py_VISIT(frame->f_funcobj);
Py_VISIT(frame->f_code); Py_VISIT(_PyFrame_GetCode(frame));
/* locals */ /* locals */
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
int i = 0; int i = 0;
@ -31,7 +31,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
assert(frame->frame_obj == NULL); assert(frame->frame_obj == NULL);
PyObject *exc = PyErr_GetRaisedException(); PyObject *exc = PyErr_GetRaisedException();
PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code); PyFrameObject *f = _PyFrame_New_NoTrack(_PyFrame_GetCode(frame));
if (f == NULL) { if (f == NULL) {
Py_XDECREF(exc); Py_XDECREF(exc);
return NULL; return NULL;
@ -65,7 +65,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame)
void void
_PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest)
{ {
assert(src->stacktop >= src->f_code->co_nlocalsplus); assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus);
Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src;
memcpy(dest, src, size); memcpy(dest, src, size);
// Don't leave a dangling pointer to the old frame when creating generators // Don't leave a dangling pointer to the old frame when creating generators
@ -81,7 +81,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT);
assert(frame->owner != FRAME_CLEARED); assert(frame->owner != FRAME_CLEARED);
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
Py_INCREF(frame->f_code); Py_INCREF(_PyFrame_GetCode(frame));
memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size);
frame = (_PyInterpreterFrame *)f->_f_frame_data; frame = (_PyInterpreterFrame *)f->_f_frame_data;
f->f_frame = frame; f->f_frame = frame;
@ -89,7 +89,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
if (_PyFrame_IsIncomplete(frame)) { if (_PyFrame_IsIncomplete(frame)) {
// This may be a newly-created generator or coroutine frame. Since it's // This may be a newly-created generator or coroutine frame. Since it's
// dead anyways, just pretend that the first RESUME ran: // dead anyways, just pretend that the first RESUME ran:
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable;
} }
assert(!_PyFrame_IsIncomplete(frame)); assert(!_PyFrame_IsIncomplete(frame));
@ -149,7 +149,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
PyObject * PyObject *
PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)
{ {
PyObject *code = (PyObject *)frame->f_code; PyObject *code = frame->f_executable;
Py_INCREF(code); Py_INCREF(code);
return code; return code;
} }
@ -164,5 +164,13 @@ int
PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame) PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame)
{ {
int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
return PyCode_Addr2Line(frame->f_code, addr); return PyCode_Addr2Line(_PyFrame_GetCode(frame), addr);
} }
const PyTypeObject *const PyUnstable_ExecutableKinds[PY_EXECUTABLE_KINDS+1] = {
[PY_EXECUTABLE_KIND_SKIP] = &_PyNone_Type,
[PY_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type,
[PY_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type,
[PY_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type,
[PY_EXECUTABLE_KINDS] = NULL,
};

File diff suppressed because it is too large Load Diff

View File

@ -936,7 +936,7 @@ call_instrumentation_vector(
} }
assert(!_PyErr_Occurred(tstate)); assert(!_PyErr_Occurred(tstate));
assert(args[0] == NULL); assert(args[0] == NULL);
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); assert(code->_co_instrumentation_version == tstate->interp->monitoring_version);
assert(is_version_up_to_date(code, tstate->interp)); assert(is_version_up_to_date(code, tstate->interp));
assert(instrumentation_cross_checks(tstate->interp, code)); assert(instrumentation_cross_checks(tstate->interp, code));
@ -1017,7 +1017,7 @@ _Py_call_instrumentation_jump(
assert(frame->prev_instr == instr); assert(frame->prev_instr == instr);
/* Event should occur after the jump */ /* Event should occur after the jump */
frame->prev_instr = target; frame->prev_instr = target;
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
int to = (int)(target - _PyCode_CODE(code)); int to = (int)(target - _PyCode_CODE(code));
PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT));
if (to_obj == NULL) { if (to_obj == NULL) {
@ -1094,7 +1094,7 @@ int
_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
{ {
frame->prev_instr = instr; frame->prev_instr = instr;
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
assert(is_version_up_to_date(code, tstate->interp)); assert(is_version_up_to_date(code, tstate->interp));
assert(instrumentation_cross_checks(tstate->interp, code)); assert(instrumentation_cross_checks(tstate->interp, code));
int i = (int)(instr - _PyCode_CODE(code)); int i = (int)(instr - _PyCode_CODE(code));
@ -1162,7 +1162,7 @@ done:
int int
_Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr)
{ {
PyCodeObject *code = frame->f_code; PyCodeObject *code = _PyFrame_GetCode(frame);
assert(is_version_up_to_date(code, tstate->interp)); assert(is_version_up_to_date(code, tstate->interp));
assert(instrumentation_cross_checks(tstate->interp, code)); assert(instrumentation_cross_checks(tstate->interp, code));
int offset = (int)(instr - _PyCode_CODE(code)); int offset = (int)(instr - _PyCode_CODE(code));
@ -1632,7 +1632,7 @@ instrument_all_executing_code_objects(PyInterpreterState *interp) {
_PyInterpreterFrame *frame = ts->cframe->current_frame; _PyInterpreterFrame *frame = ts->cframe->current_frame;
while (frame) { while (frame) {
if (frame->owner != FRAME_OWNED_BY_CSTACK) { if (frame->owner != FRAME_OWNED_BY_CSTACK) {
if (_Py_Instrument(frame->f_code, interp)) { if (_Py_Instrument(_PyFrame_GetCode(frame), interp)) {
return -1; return -1;
} }
} }

View File

@ -148,14 +148,14 @@ stopiteration_error(PyThreadState* tstate, PyObject *exc)
const char *msg = NULL; const char *msg = NULL;
if (PyErr_GivenExceptionMatches(exc, PyExc_StopIteration)) { if (PyErr_GivenExceptionMatches(exc, PyExc_StopIteration)) {
msg = "generator raised StopIteration"; msg = "generator raised StopIteration";
if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) { if (_PyFrame_GetCode(frame)->co_flags & CO_ASYNC_GENERATOR) {
msg = "async generator raised StopIteration"; msg = "async generator raised StopIteration";
} }
else if (frame->f_code->co_flags & CO_COROUTINE) { else if (_PyFrame_GetCode(frame)->co_flags & CO_COROUTINE) {
msg = "coroutine raised StopIteration"; msg = "coroutine raised StopIteration";
} }
} }
else if ((frame->f_code->co_flags & CO_ASYNC_GENERATOR) && else if ((_PyFrame_GetCode(frame)->co_flags & CO_ASYNC_GENERATOR) &&
PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration))
{ {
/* code in `gen` raised a StopAsyncIteration error: /* code in `gen` raised a StopAsyncIteration error:

View File

@ -244,7 +244,7 @@ sys_trace_line_func(
"Missing frame when calling trace function."); "Missing frame when calling trace function.");
return NULL; return NULL;
} }
assert(args[0] == (PyObject *)frame->f_frame->f_code); assert(args[0] == (PyObject *)_PyFrame_GetCode(frame->f_frame));
return trace_line(tstate, self, frame, line); return trace_line(tstate, self, frame, line);
} }
@ -286,7 +286,6 @@ sys_trace_jump_func(
"Missing frame when calling trace function."); "Missing frame when calling trace function.");
return NULL; return NULL;
} }
assert(code == frame->f_frame->f_code);
if (!frame->f_trace_lines) { if (!frame->f_trace_lines) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }

View File

@ -148,15 +148,17 @@ PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer)
_PyInterpreterFrame * _PyInterpreterFrame *
_PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer) _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer)
{ {
PyCodeObject *code = (PyCodeObject *)frame->f_executable;
assert(PyCode_Check(code));
PyInterpreterState *interp = PyInterpreterState_Get(); PyInterpreterState *interp = PyInterpreterState_Get();
int index = get_executor_index(frame->f_code, src); int index = get_executor_index(code, src);
if (index < 0) { if (index < 0) {
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
return frame; return frame;
} }
_PyOptimizerObject *opt = interp->optimizer; _PyOptimizerObject *opt = interp->optimizer;
_PyExecutorObject *executor; _PyExecutorObject *executor;
int err = opt->optimize(opt, frame->f_code, dest, &executor); int err = opt->optimize(opt, code, dest, &executor);
if (err <= 0) { if (err <= 0) {
if (err < 0) { if (err < 0) {
return NULL; return NULL;
@ -164,7 +166,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
return frame; return frame;
} }
insert_executor(frame->f_code, src, index, executor); insert_executor(code, src, index, executor);
return executor->execute(executor, frame, stack_pointer); return executor->execute(executor, frame, stack_pointer);
} }

View File

@ -335,7 +335,7 @@ py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame,
perf_status == PERF_STATUS_NO_INIT) { perf_status == PERF_STATUS_NO_INIT) {
goto default_eval; goto default_eval;
} }
PyCodeObject *co = frame->f_code; PyCodeObject *co = _PyFrame_GetCode(frame);
py_trampoline f = NULL; py_trampoline f = NULL;
assert(extra_code_index != -1); assert(extra_code_index != -1);
int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f); int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f);

View File

@ -737,22 +737,6 @@ pycore_init_types(PyInterpreterState *interp)
return _PyStatus_OK(); return _PyStatus_OK();
} }
static const uint8_t INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = {
/* Put a NOP at the start, so that the IP points into
* the code, rather than before it */
NOP, 0,
INTERPRETER_EXIT, 0,
/* RESUME at end makes sure that the frame appears incomplete */
RESUME, 0
};
static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = {
INTERPRETER_TRAMPOLINE_INSTRUCTIONS,
sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS),
1,
"<interpreter trampoline>"
};
static PyStatus static PyStatus
pycore_init_builtins(PyThreadState *tstate) pycore_init_builtins(PyThreadState *tstate)
{ {
@ -786,10 +770,6 @@ pycore_init_builtins(PyThreadState *tstate)
PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__)); PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__));
assert(object__getattribute__); assert(object__getattribute__);
interp->callable_cache.object__getattribute__ = object__getattribute__; interp->callable_cache.object__getattribute__ = object__getattribute__;
interp->interpreter_trampoline = _Py_MakeShimCode(&INTERPRETER_TRAMPOLINE_CODEDEF);
if (interp->interpreter_trampoline == NULL) {
return _PyStatus_ERR("failed to create interpreter trampoline.");
}
if (_PyBuiltins_AddExceptions(bimod) < 0) { if (_PyBuiltins_AddExceptions(bimod) < 0) {
return _PyStatus_ERR("failed to add exceptions to builtins"); return _PyStatus_ERR("failed to add exceptions to builtins");
} }

View File

@ -892,7 +892,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
PyDict_Clear(interp->builtins); PyDict_Clear(interp->builtins);
Py_CLEAR(interp->sysdict); Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins); Py_CLEAR(interp->builtins);
Py_CLEAR(interp->interpreter_trampoline);
if (tstate->interp == interp) { if (tstate->interp == interp) {
/* We are now safe to fix tstate->_status.cleared. */ /* We are now safe to fix tstate->_status.cleared. */

View File

@ -785,7 +785,7 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen
} }
int code_offset = tb->tb_lasti; int code_offset = tb->tb_lasti;
PyCodeObject* code = frame->f_frame->f_code; PyCodeObject* code = _PyFrame_GetCode(frame->f_frame);
const Py_ssize_t source_line_len = PyUnicode_GET_LENGTH(source_line); const Py_ssize_t source_line_len = PyUnicode_GET_LENGTH(source_line);
int start_line; int start_line;
@ -1164,7 +1164,7 @@ done:
static void static void
dump_frame(int fd, _PyInterpreterFrame *frame) dump_frame(int fd, _PyInterpreterFrame *frame)
{ {
PyCodeObject *code = frame->f_code; PyCodeObject *code =_PyFrame_GetCode(frame);
PUTS(fd, " File "); PUTS(fd, " File ");
if (code->co_filename != NULL if (code->co_filename != NULL
&& PyUnicode_Check(code->co_filename)) && PyUnicode_Check(code->co_filename))

View File

@ -249,6 +249,7 @@ hashtable_compare_traceback(const void *key1, const void *key2)
static void static void
tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
{ {
assert(PyCode_Check(pyframe->f_executable));
frame->filename = &_Py_STR(anon_unknown); frame->filename = &_Py_STR(anon_unknown);
int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe);
if (lineno < 0) { if (lineno < 0) {
@ -256,7 +257,7 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
} }
frame->lineno = (unsigned int)lineno; frame->lineno = (unsigned int)lineno;
PyObject *filename = pyframe->f_code->co_filename; PyObject *filename = filename = ((PyCodeObject *)pyframe->f_executable)->co_filename;
if (filename == NULL) { if (filename == NULL) {
#ifdef TRACE_DEBUG #ifdef TRACE_DEBUG

View File

@ -327,6 +327,7 @@ Parser/parser.c - soft_keywords -
Parser/tokenizer.c - type_comment_prefix - Parser/tokenizer.c - type_comment_prefix -
Python/ast_opt.c fold_unaryop ops - Python/ast_opt.c fold_unaryop ops -
Python/ceval.c - binary_ops - Python/ceval.c - binary_ops -
Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS -
Python/codecs.c - Py_hexdigits - Python/codecs.c - Py_hexdigits -
Python/codecs.c - ucnhash_capi - Python/codecs.c - ucnhash_capi -
Python/codecs.c _PyCodecRegistry_Init methods - Python/codecs.c _PyCodecRegistry_Init methods -

Can't render this file because it has a wrong number of fields in line 4.

View File

@ -1009,14 +1009,18 @@ class PyFramePtr:
self._gdbval = gdbval self._gdbval = gdbval
if not self.is_optimized_out(): if not self.is_optimized_out():
self.co = self._f_code() try:
self.co_name = self.co.pyop_field('co_name') self.co = self._f_code()
self.co_filename = self.co.pyop_field('co_filename') self.co_name = self.co.pyop_field('co_name')
self.co_filename = self.co.pyop_field('co_filename')
self.f_lasti = self._f_lasti() self.f_lasti = self._f_lasti()
self.co_nlocals = int_from_int(self.co.field('co_nlocals')) self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
pnames = self.co.field('co_localsplusnames') pnames = self.co.field('co_localsplusnames')
self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames) self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames)
self._is_code = True
except:
self._is_code = False
def is_optimized_out(self): def is_optimized_out(self):
return self._gdbval.is_optimized_out return self._gdbval.is_optimized_out
@ -1051,7 +1055,10 @@ class PyFramePtr:
return self._f_special("f_builtins") return self._f_special("f_builtins")
def _f_code(self): def _f_code(self):
return self._f_special("f_code", PyCodeObjectPtr.from_pyobject_ptr) return self._f_special("f_executable", PyCodeObjectPtr.from_pyobject_ptr)
def _f_executable(self):
return self._f_special("f_executable")
def _f_nlocalsplus(self): def _f_nlocalsplus(self):
return self._f_special("nlocalsplus", int_from_int) return self._f_special("nlocalsplus", int_from_int)