mirror of https://github.com/python/cpython
gh-123923: Defer refcounting for `f_funcobj` in `_PyInterpreterFrame` (#124026)
Use a `_PyStackRef` and defer the reference to `f_funcobj` when possible. This avoids some reference count contention in the common case of executing the same code object from multiple threads concurrently in the free-threaded build.
This commit is contained in:
parent
d3c76dff44
commit
f4997bb3ac
|
@ -62,7 +62,7 @@ enum _frameowner {
|
|||
typedef struct _PyInterpreterFrame {
|
||||
_PyStackRef f_executable; /* Deferred or strong reference (code object or None) */
|
||||
struct _PyInterpreterFrame *previous;
|
||||
PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */
|
||||
_PyStackRef f_funcobj; /* Deferred or strong reference. Only valid if not on C stack */
|
||||
PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */
|
||||
PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */
|
||||
PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */
|
||||
|
@ -84,6 +84,12 @@ static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) {
|
|||
return (PyCodeObject *)executable;
|
||||
}
|
||||
|
||||
static inline PyFunctionObject *_PyFrame_GetFunction(_PyInterpreterFrame *f) {
|
||||
PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj);
|
||||
assert(PyFunction_Check(func));
|
||||
return (PyFunctionObject *)func;
|
||||
}
|
||||
|
||||
static inline _PyStackRef *_PyFrame_Stackbase(_PyInterpreterFrame *f) {
|
||||
return (f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus);
|
||||
}
|
||||
|
@ -144,14 +150,15 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
|
|||
*/
|
||||
static inline void
|
||||
_PyFrame_Initialize(
|
||||
_PyInterpreterFrame *frame, PyFunctionObject *func,
|
||||
_PyInterpreterFrame *frame, _PyStackRef func,
|
||||
PyObject *locals, PyCodeObject *code, int null_locals_from, _PyInterpreterFrame *previous)
|
||||
{
|
||||
frame->previous = previous;
|
||||
frame->f_funcobj = (PyObject *)func;
|
||||
frame->f_funcobj = func;
|
||||
frame->f_executable = PyStackRef_FromPyObjectNew(code);
|
||||
frame->f_builtins = func->func_builtins;
|
||||
frame->f_globals = func->func_globals;
|
||||
PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func);
|
||||
frame->f_builtins = func_obj->func_builtins;
|
||||
frame->f_globals = func_obj->func_globals;
|
||||
frame->f_locals = locals;
|
||||
frame->stackpointer = frame->localsplus + code->co_nlocalsplus;
|
||||
frame->frame_obj = NULL;
|
||||
|
@ -300,10 +307,11 @@ PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFr
|
|||
* Must be guarded by _PyThreadState_HasStackSpace()
|
||||
* Consumes reference to func. */
|
||||
static inline _PyInterpreterFrame *
|
||||
_PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_locals_from, _PyInterpreterFrame * previous)
|
||||
_PyFrame_PushUnchecked(PyThreadState *tstate, _PyStackRef func, int null_locals_from, _PyInterpreterFrame * previous)
|
||||
{
|
||||
CALL_STAT_INC(frames_pushed);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func);
|
||||
PyCodeObject *code = (PyCodeObject *)func_obj->func_code;
|
||||
_PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top;
|
||||
tstate->datastack_top += code->co_framesize;
|
||||
assert(tstate->datastack_top < tstate->datastack_limit);
|
||||
|
@ -321,7 +329,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
|
|||
tstate->datastack_top += code->co_framesize;
|
||||
assert(tstate->datastack_top < tstate->datastack_limit);
|
||||
frame->previous = previous;
|
||||
frame->f_funcobj = Py_None;
|
||||
frame->f_funcobj = PyStackRef_None;
|
||||
frame->f_executable = PyStackRef_FromPyObjectNew(code);
|
||||
#ifdef Py_DEBUG
|
||||
frame->f_builtins = NULL;
|
||||
|
@ -345,7 +353,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
|
|||
}
|
||||
|
||||
PyAPI_FUNC(_PyInterpreterFrame *)
|
||||
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
|
||||
_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
|
||||
PyObject *locals, _PyStackRef const* args,
|
||||
size_t argcount, PyObject *kwnames,
|
||||
_PyInterpreterFrame *previous);
|
||||
|
|
|
@ -387,6 +387,17 @@ union _PyStackRef;
|
|||
extern int _PyGC_VisitFrameStack(struct _PyInterpreterFrame *frame, visitproc visit, void *arg);
|
||||
extern int _PyGC_VisitStackRef(union _PyStackRef *ref, visitproc visit, void *arg);
|
||||
|
||||
// Like Py_VISIT but for _PyStackRef fields
|
||||
#define _Py_VISIT_STACKREF(ref) \
|
||||
do { \
|
||||
if (!PyStackRef_IsNull(ref)) { \
|
||||
int vret = _PyGC_VisitStackRef(&(ref), visit, arg); \
|
||||
if (vret) \
|
||||
return vret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -681,13 +681,13 @@ set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
|
|||
static PyObject *
|
||||
record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
|
||||
{
|
||||
if (PyFunction_Check(f->f_funcobj)) {
|
||||
if (PyStackRef_FunctionCheck(f->f_funcobj)) {
|
||||
PyFunctionObject *func = _PyFrame_GetFunction(f);
|
||||
PyObject *module = _get_current_module();
|
||||
assert(module != NULL);
|
||||
module_state *state = get_module_state(module);
|
||||
Py_DECREF(module);
|
||||
int res = PyList_Append(state->record_list,
|
||||
((PyFunctionObject *)f->f_funcobj)->func_name);
|
||||
int res = PyList_Append(state->record_list, func->func_name);
|
||||
if (res < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1634,7 +1634,7 @@ frame_dealloc(PyFrameObject *f)
|
|||
/* Kill all local variables including specials, if we own them */
|
||||
if (f->f_frame == frame && frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) {
|
||||
PyStackRef_CLEAR(frame->f_executable);
|
||||
Py_CLEAR(frame->f_funcobj);
|
||||
PyStackRef_CLEAR(frame->f_funcobj);
|
||||
Py_CLEAR(frame->f_locals);
|
||||
_PyStackRef *locals = _PyFrame_GetLocalsArray(frame);
|
||||
_PyStackRef *sp = frame->stackpointer;
|
||||
|
@ -1790,7 +1790,7 @@ static void
|
|||
init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
|
||||
{
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
_PyFrame_Initialize(frame, (PyFunctionObject*)Py_NewRef(func),
|
||||
_PyFrame_Initialize(frame, PyStackRef_FromPyObjectNew(func),
|
||||
Py_XNewRef(locals), code, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -1861,14 +1861,15 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
|
|||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
int lasti = _PyInterpreterFrame_LASTI(frame);
|
||||
if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS
|
||||
&& PyFunction_Check(frame->f_funcobj)))
|
||||
&& PyStackRef_FunctionCheck(frame->f_funcobj)))
|
||||
{
|
||||
/* Free vars are initialized */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free vars have not been initialized -- Do that */
|
||||
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
|
||||
PyFunctionObject *func = _PyFrame_GetFunction(frame);
|
||||
PyObject *closure = func->func_closure;
|
||||
int offset = PyUnstable_Code_GetFirstFree(co);
|
||||
for (int i = 0; i < co->co_nfreevars; ++i) {
|
||||
PyObject *o = PyTuple_GET_ITEM(closure, i);
|
||||
|
|
|
@ -58,10 +58,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
|
|||
else {
|
||||
// We still need to visit the code object when the frame is cleared to
|
||||
// ensure that it's kept alive if the reference is deferred.
|
||||
int err = _PyGC_VisitStackRef(&gen->gi_iframe.f_executable, visit, arg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
_Py_VISIT_STACKREF(gen->gi_iframe.f_executable);
|
||||
}
|
||||
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
|
||||
participate in a reference cycle. */
|
||||
|
|
|
@ -372,10 +372,10 @@ caller(void)
|
|||
if (f == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
if (f == NULL || f->f_funcobj == NULL) {
|
||||
if (f == NULL || PyStackRef_IsNull(f->f_funcobj)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
PyObject *r = PyFunction_GetModule(f->f_funcobj);
|
||||
PyObject *r = PyFunction_GetModule(PyStackRef_AsPyObjectBorrow(f->f_funcobj));
|
||||
if (!r) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_NONE;
|
||||
|
|
|
@ -808,14 +808,13 @@ dummy_func(
|
|||
assert(code->co_argcount == 2);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize));
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
Py_INCREF(getitem);
|
||||
}
|
||||
|
||||
op(_BINARY_SUBSCR_INIT_CALL, (container, sub -- new_frame: _PyInterpreterFrame* )) {
|
||||
PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container));
|
||||
PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
|
||||
PyObject *getitem = ht->_spec_cache.getitem;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, (PyFunctionObject *)getitem, 2, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame);
|
||||
SYNC_SP();
|
||||
new_frame->localsplus[0] = container;
|
||||
new_frame->localsplus[1] = sub;
|
||||
|
@ -1666,8 +1665,9 @@ dummy_func(
|
|||
inst(COPY_FREE_VARS, (--)) {
|
||||
/* Copy closure variables to free variables */
|
||||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyObject *closure = func->func_closure;
|
||||
assert(oparg == co->co_nfreevars);
|
||||
int offset = co->co_nlocalsplus - oparg;
|
||||
for (int i = 0; i < oparg; ++i) {
|
||||
|
@ -2170,8 +2170,7 @@ dummy_func(
|
|||
DEOPT_IF(code->co_argcount != 1);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize));
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
Py_INCREF(fget);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, f, 1, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame);
|
||||
new_frame->localsplus[0] = owner;
|
||||
}
|
||||
|
||||
|
@ -2202,8 +2201,8 @@ dummy_func(
|
|||
STAT_INC(LOAD_ATTR, hit);
|
||||
|
||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
|
||||
Py_INCREF(f);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2, frame);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
|
||||
tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
|
||||
// Manipulate stack directly because we exit with DISPATCH_INLINED().
|
||||
STACK_SHRINK(1);
|
||||
new_frame->localsplus[0] = owner;
|
||||
|
@ -3251,7 +3250,7 @@ dummy_func(
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
|
@ -3340,7 +3339,7 @@ dummy_func(
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
@ -3475,11 +3474,9 @@ dummy_func(
|
|||
}
|
||||
|
||||
replicate(5) pure op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null[1], args[oparg] -- new_frame: _PyInterpreterFrame*)) {
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3601,10 +3598,9 @@ dummy_func(
|
|||
assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK);
|
||||
/* Push self onto stack of shim */
|
||||
shim->localsplus[0] = PyStackRef_DUP(self);
|
||||
PyFunctionObject *init_func = (PyFunctionObject *)PyStackRef_AsPyObjectSteal(init);
|
||||
args[-1] = self;
|
||||
init_frame = _PyEvalFramePushAndInit(
|
||||
tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
|
||||
tstate, init, NULL, args-1, oparg+1, NULL, shim);
|
||||
SYNC_SP();
|
||||
if (init_frame == NULL) {
|
||||
_PyEval_FrameClearAndPop(tstate, shim);
|
||||
|
@ -4080,7 +4076,7 @@ dummy_func(
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -4148,7 +4144,7 @@ dummy_func(
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -4332,9 +4328,9 @@ dummy_func(
|
|||
int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func));
|
||||
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
|
||||
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(
|
||||
tstate, func_st, locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
|
||||
STACK_SHRINK(oparg + 3);
|
||||
if (new_frame == NULL) {
|
||||
|
@ -4408,8 +4404,8 @@ dummy_func(
|
|||
}
|
||||
|
||||
inst(RETURN_GENERATOR, (-- res)) {
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
ERROR_NO_POP();
|
||||
|
@ -4771,8 +4767,9 @@ dummy_func(
|
|||
}
|
||||
|
||||
tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) {
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
DEOPT_IF(((PyFunctionObject *)frame->f_funcobj)->func_version != func_version);
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
DEOPT_IF(func->func_version != func_version);
|
||||
}
|
||||
|
||||
/* Internal -- for testing executors */
|
||||
|
|
|
@ -196,7 +196,7 @@ lltrace_instruction(_PyInterpreterFrame *frame,
|
|||
static void
|
||||
lltrace_resume_frame(_PyInterpreterFrame *frame)
|
||||
{
|
||||
PyObject *fobj = frame->f_funcobj;
|
||||
PyObject *fobj = PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
if (!PyStackRef_CodeCheck(frame->f_executable) ||
|
||||
fobj == NULL ||
|
||||
!PyFunction_Check(fobj)
|
||||
|
@ -277,7 +277,7 @@ static void monitor_throw(PyThreadState *tstate,
|
|||
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
|
||||
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
|
||||
static _PyInterpreterFrame *
|
||||
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
|
||||
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func,
|
||||
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs, _PyInterpreterFrame *previous);
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
|
@ -781,7 +781,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
|
||||
#ifdef Py_DEBUG
|
||||
/* Set these to invalid but identifiable values for debugging. */
|
||||
entry_frame.f_funcobj = (PyObject*)0xaaa0;
|
||||
entry_frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0};
|
||||
entry_frame.f_locals = (PyObject*)0xaaa1;
|
||||
entry_frame.frame_obj = (PyFrameObject*)0xaaa2;
|
||||
entry_frame.f_globals = (PyObject*)0xaaa3;
|
||||
|
@ -1719,18 +1719,19 @@ _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
|
|||
|
||||
/* Consumes references to func, locals and all the args */
|
||||
_PyInterpreterFrame *
|
||||
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
|
||||
_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
|
||||
PyObject *locals, _PyStackRef const* args,
|
||||
size_t argcount, PyObject *kwnames, _PyInterpreterFrame *previous)
|
||||
{
|
||||
PyCodeObject * code = (PyCodeObject *)func->func_code;
|
||||
PyFunctionObject *func_obj = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(func);
|
||||
PyCodeObject * code = (PyCodeObject *)func_obj->func_code;
|
||||
CALL_STAT_INC(frames_pushed);
|
||||
_PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize);
|
||||
if (frame == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
_PyFrame_Initialize(frame, func, locals, code, 0, previous);
|
||||
if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
|
||||
if (initialize_locals(tstate, func_obj, frame->localsplus, args, argcount, kwnames)) {
|
||||
assert(frame->owner == FRAME_OWNED_BY_THREAD);
|
||||
clear_thread_frame(tstate, frame);
|
||||
return NULL;
|
||||
|
@ -1738,7 +1739,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
|
|||
return frame;
|
||||
fail:
|
||||
/* Consume the references */
|
||||
Py_DECREF(func);
|
||||
PyStackRef_CLOSE(func);
|
||||
Py_XDECREF(locals);
|
||||
for (size_t i = 0; i < argcount; i++) {
|
||||
PyStackRef_CLOSE(args[i]);
|
||||
|
@ -1754,7 +1755,7 @@ fail:
|
|||
}
|
||||
|
||||
static _PyInterpreterFrame *
|
||||
_PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, PyFunctionObject *func,
|
||||
_PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, _PyStackRef func,
|
||||
PyObject *locals, PyObject *const* args,
|
||||
size_t argcount, PyObject *kwnames, _PyInterpreterFrame *previous)
|
||||
{
|
||||
|
@ -1784,7 +1785,7 @@ _PyEvalFramePushAndInit_UnTagged(PyThreadState *tstate, PyFunctionObject *func,
|
|||
Steals references to func, callargs and kwargs.
|
||||
*/
|
||||
static _PyInterpreterFrame *
|
||||
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
|
||||
_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func,
|
||||
PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs, _PyInterpreterFrame *previous)
|
||||
{
|
||||
bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0);
|
||||
|
@ -1793,7 +1794,7 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
|
|||
if (has_dict) {
|
||||
newargs = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames);
|
||||
if (newargs == NULL) {
|
||||
Py_DECREF(func);
|
||||
PyStackRef_CLOSE(func);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
@ -1805,7 +1806,7 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
|
|||
}
|
||||
}
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_UnTagged(
|
||||
tstate, (PyFunctionObject *)func, locals,
|
||||
tstate, func, locals,
|
||||
newargs, nargs, kwnames, previous
|
||||
);
|
||||
if (has_dict) {
|
||||
|
@ -1831,7 +1832,6 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
|
|||
{
|
||||
/* _PyEvalFramePushAndInit consumes the references
|
||||
* to func, locals and all its arguments */
|
||||
Py_INCREF(func);
|
||||
Py_XINCREF(locals);
|
||||
for (size_t i = 0; i < argcount; i++) {
|
||||
Py_INCREF(args[i]);
|
||||
|
@ -1843,7 +1843,8 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
|
|||
}
|
||||
}
|
||||
_PyInterpreterFrame *frame = _PyEvalFramePushAndInit_UnTagged(
|
||||
tstate, func, locals, args, argcount, kwnames, NULL);
|
||||
tstate, PyStackRef_FromPyObjectNew(func), locals,
|
||||
args, argcount, kwnames, NULL);
|
||||
if (frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1018,7 +1018,6 @@
|
|||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
Py_INCREF(getitem);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1031,7 +1030,7 @@
|
|||
PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container));
|
||||
PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
|
||||
PyObject *getitem = ht->_spec_cache.getitem;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, (PyFunctionObject *)getitem, 2, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame);
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
new_frame->localsplus[0] = container;
|
||||
|
@ -1852,8 +1851,9 @@
|
|||
oparg = CURRENT_OPARG();
|
||||
/* Copy closure variables to free variables */
|
||||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyObject *closure = func->func_closure;
|
||||
assert(oparg == co->co_nfreevars);
|
||||
int offset = co->co_nlocalsplus - oparg;
|
||||
for (int i = 0; i < oparg; ++i) {
|
||||
|
@ -2553,8 +2553,7 @@
|
|||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
Py_INCREF(fget);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, f, 1, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame);
|
||||
new_frame->localsplus[0] = owner;
|
||||
stack_pointer[-1].bits = (uintptr_t)new_frame;
|
||||
break;
|
||||
|
@ -3603,7 +3602,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
@ -3833,11 +3832,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3859,11 +3856,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3885,11 +3880,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3911,11 +3904,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3937,11 +3928,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -3962,11 +3951,9 @@
|
|||
args = &stack_pointer[-oparg];
|
||||
self_or_null = &stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -4145,10 +4132,9 @@
|
|||
assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK);
|
||||
/* Push self onto stack of shim */
|
||||
shim->localsplus[0] = PyStackRef_DUP(self);
|
||||
PyFunctionObject *init_func = (PyFunctionObject *)PyStackRef_AsPyObjectSteal(init);
|
||||
args[-1] = self;
|
||||
init_frame = _PyEvalFramePushAndInit(
|
||||
tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
|
||||
tstate, init, NULL, args-1, oparg+1, NULL, shim);
|
||||
stack_pointer += -2 - oparg;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
if (init_frame == NULL) {
|
||||
|
@ -4780,7 +4766,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -5001,8 +4987,8 @@
|
|||
|
||||
case _RETURN_GENERATOR: {
|
||||
_PyStackRef res;
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
JUMP_TO_ERROR();
|
||||
|
@ -5376,8 +5362,9 @@
|
|||
|
||||
case _CHECK_FUNCTION: {
|
||||
uint32_t func_version = (uint32_t)CURRENT_OPERAND();
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
if (((PyFunctionObject *)frame->f_funcobj)->func_version != func_version) {
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
if (func->func_version != func_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
|
|
|
@ -13,11 +13,8 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg)
|
|||
{
|
||||
Py_VISIT(frame->frame_obj);
|
||||
Py_VISIT(frame->f_locals);
|
||||
Py_VISIT(frame->f_funcobj);
|
||||
int err = _PyGC_VisitStackRef(&frame->f_executable, visit, arg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
_Py_VISIT_STACKREF(frame->f_funcobj);
|
||||
_Py_VISIT_STACKREF(frame->f_executable);
|
||||
return _PyGC_VisitFrameStack(frame, visit, arg);
|
||||
}
|
||||
|
||||
|
@ -126,7 +123,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
|
|||
Py_DECREF(f);
|
||||
}
|
||||
_PyFrame_ClearLocals(frame);
|
||||
Py_DECREF(frame->f_funcobj);
|
||||
PyStackRef_CLEAR(frame->f_funcobj);
|
||||
}
|
||||
|
||||
/* Unstable API functions */
|
||||
|
|
|
@ -200,6 +200,7 @@ frame_disable_deferred_refcounting(_PyInterpreterFrame *frame)
|
|||
}
|
||||
}
|
||||
|
||||
frame->f_funcobj = PyStackRef_AsStrongReference(frame->f_funcobj);
|
||||
for (_PyStackRef *ref = frame->localsplus; ref < frame->stackpointer; ref++) {
|
||||
if (!PyStackRef_IsNull(*ref) && PyStackRef_IsDeferred(*ref)) {
|
||||
*ref = PyStackRef_AsStrongReference(*ref);
|
||||
|
@ -994,9 +995,7 @@ _PyGC_VisitFrameStack(_PyInterpreterFrame *frame, visitproc visit, void *arg)
|
|||
_PyStackRef *ref = _PyFrame_GetLocalsArray(frame);
|
||||
/* locals and stack */
|
||||
for (; ref < frame->stackpointer; ref++) {
|
||||
if (_PyGC_VisitStackRef(ref, visit, arg) < 0) {
|
||||
return -1;
|
||||
}
|
||||
_Py_VISIT_STACKREF(*ref);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -506,7 +506,6 @@
|
|||
assert(code->co_argcount == 2);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR);
|
||||
STAT_INC(BINARY_SUBSCR, hit);
|
||||
Py_INCREF(getitem);
|
||||
}
|
||||
// _BINARY_SUBSCR_INIT_CALL
|
||||
sub = stack_pointer[-1];
|
||||
|
@ -514,7 +513,7 @@
|
|||
PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(container));
|
||||
PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
|
||||
PyObject *getitem = ht->_spec_cache.getitem;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, (PyFunctionObject *)getitem, 2, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(getitem), 2, frame);
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
new_frame->localsplus[0] = container;
|
||||
|
@ -892,7 +891,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
|
@ -1021,10 +1020,9 @@
|
|||
assert(_PyCode_CODE(_PyFrame_GetCode(shim))[0].op.code == EXIT_INIT_CHECK);
|
||||
/* Push self onto stack of shim */
|
||||
shim->localsplus[0] = PyStackRef_DUP(self);
|
||||
PyFunctionObject *init_func = (PyFunctionObject *)PyStackRef_AsPyObjectSteal(init);
|
||||
args[-1] = self;
|
||||
init_frame = _PyEvalFramePushAndInit(
|
||||
tstate, init_func, NULL, args-1, oparg+1, NULL, shim);
|
||||
tstate, init, NULL, args-1, oparg+1, NULL, shim);
|
||||
stack_pointer += -2 - oparg;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
if (init_frame == NULL) {
|
||||
|
@ -1119,11 +1117,9 @@
|
|||
// _INIT_CALL_PY_EXACT_ARGS
|
||||
args = &stack_pointer[-oparg];
|
||||
{
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -1216,7 +1212,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
@ -1616,8 +1612,8 @@
|
|||
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
|
||||
int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
|
||||
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(
|
||||
tstate, func_st, locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
|
||||
STACK_SHRINK(oparg + 3);
|
||||
|
@ -1802,7 +1798,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -1936,7 +1932,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -2104,7 +2100,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, positional_args, kwnames_o, frame
|
||||
);
|
||||
PyStackRef_CLOSE(kwnames);
|
||||
|
@ -2649,11 +2645,9 @@
|
|||
// _INIT_CALL_PY_EXACT_ARGS
|
||||
args = &stack_pointer[-oparg];
|
||||
{
|
||||
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
|
||||
int has_self = !PyStackRef_IsNull(self_or_null[0]);
|
||||
STAT_INC(CALL, hit);
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable_o;
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, func, oparg + has_self, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, callable, oparg + has_self, frame);
|
||||
_PyStackRef *first_non_self_local = new_frame->localsplus + has_self;
|
||||
new_frame->localsplus[0] = self_or_null[0];
|
||||
for (int i = 0; i < oparg; i++) {
|
||||
|
@ -2726,7 +2720,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// The frame has stolen all the arguments from the stack,
|
||||
|
@ -3274,8 +3268,9 @@
|
|||
INSTRUCTION_STATS(COPY_FREE_VARS);
|
||||
/* Copy closure variables to free variables */
|
||||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyObject *closure = func->func_closure;
|
||||
assert(oparg == co->co_nfreevars);
|
||||
int offset = co->co_nlocalsplus - oparg;
|
||||
for (int i = 0; i < oparg; ++i) {
|
||||
|
@ -4102,7 +4097,7 @@
|
|||
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
|
||||
tstate, (PyFunctionObject *)PyStackRef_AsPyObjectSteal(callable), locals,
|
||||
tstate, callable, locals,
|
||||
args, total_args, NULL, frame
|
||||
);
|
||||
// Manipulate stack directly since we leave using DISPATCH_INLINED().
|
||||
|
@ -4997,8 +4992,8 @@
|
|||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1);
|
||||
Py_INCREF(f);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2, frame);
|
||||
_PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(
|
||||
tstate, PyStackRef_FromPyObjectNew(f), 2, frame);
|
||||
// Manipulate stack directly because we exit with DISPATCH_INLINED().
|
||||
STACK_SHRINK(1);
|
||||
new_frame->localsplus[0] = owner;
|
||||
|
@ -5328,8 +5323,7 @@
|
|||
DEOPT_IF(code->co_argcount != 1, LOAD_ATTR);
|
||||
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
Py_INCREF(fget);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, f, 1, frame);
|
||||
new_frame = _PyFrame_PushUnchecked(tstate, PyStackRef_FromPyObjectNew(fget), 1, frame);
|
||||
new_frame->localsplus[0] = owner;
|
||||
}
|
||||
// _SAVE_RETURN_OFFSET
|
||||
|
@ -6504,8 +6498,8 @@
|
|||
next_instr += 1;
|
||||
INSTRUCTION_STATS(RETURN_GENERATOR);
|
||||
_PyStackRef res;
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
goto error;
|
||||
|
@ -7718,8 +7712,8 @@
|
|||
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
|
||||
int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags;
|
||||
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func));
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate,
|
||||
(PyFunctionObject *)PyStackRef_AsPyObjectSteal(func_st), locals,
|
||||
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(
|
||||
tstate, func_st, locals,
|
||||
nargs, callargs, kwargs, frame);
|
||||
// Need to manually shrink the stack since we exit with DISPATCH_INLINED.
|
||||
STACK_SHRINK(oparg + 3);
|
||||
|
|
|
@ -533,7 +533,7 @@ translate_bytecode_to_trace(
|
|||
{
|
||||
bool first = true;
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyFunctionObject *func = _PyFrame_GetFunction(frame);
|
||||
assert(PyFunction_Check(func));
|
||||
PyCodeObject *initial_code = code;
|
||||
_Py_BloomFilter_Add(dependencies, initial_code);
|
||||
|
|
|
@ -145,7 +145,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
|||
return 1;
|
||||
}
|
||||
PyObject *globals = frame->f_globals;
|
||||
PyFunctionObject *function = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyFunctionObject *function = _PyFrame_GetFunction(frame);
|
||||
assert(PyFunction_Check(function));
|
||||
assert(function->func_builtins == builtins);
|
||||
assert(function->func_globals == globals);
|
||||
|
|
|
@ -2384,10 +2384,11 @@ sys__getframemodulename_impl(PyObject *module, int depth)
|
|||
while (f && (_PyFrame_IsIncomplete(f) || depth-- > 0)) {
|
||||
f = f->previous;
|
||||
}
|
||||
if (f == NULL || f->f_funcobj == NULL) {
|
||||
if (f == NULL || PyStackRef_IsNull(f->f_funcobj)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
PyObject *r = PyFunction_GetModule(f->f_funcobj);
|
||||
PyObject *func = PyStackRef_AsPyObjectBorrow(f->f_funcobj);
|
||||
PyObject *r = PyFunction_GetModule(func);
|
||||
if (!r) {
|
||||
PyErr_Clear();
|
||||
r = Py_None;
|
||||
|
|
|
@ -365,12 +365,24 @@ def analyze_deferred_refs(node: parser.InstDef) -> dict[lexer.Token, str | None]
|
|||
offset += 1
|
||||
return []
|
||||
|
||||
def in_frame_push(idx: int) -> bool:
|
||||
for tkn in reversed(node.block.tokens[: idx - 1]):
|
||||
if tkn.kind == "SEMI" or tkn.kind == "LBRACE" or tkn.kind == "RBRACE":
|
||||
return False
|
||||
if tkn.kind == "IDENTIFIER" and tkn.text == "_PyFrame_PushUnchecked":
|
||||
return True
|
||||
return False
|
||||
|
||||
refs: dict[lexer.Token, str | None] = {}
|
||||
for idx, tkn in enumerate(node.block.tokens):
|
||||
if tkn.kind != "IDENTIFIER" or tkn.text != "PyStackRef_FromPyObjectNew":
|
||||
continue
|
||||
|
||||
if idx == 0 or node.block.tokens[idx - 1].kind != "EQUALS":
|
||||
if in_frame_push(idx):
|
||||
# PyStackRef_FromPyObjectNew() is called in _PyFrame_PushUnchecked()
|
||||
refs[tkn] = None
|
||||
continue
|
||||
raise analysis_error("Expected '=' before PyStackRef_FromPyObjectNew", tkn)
|
||||
|
||||
lhs = find_assignment_target(idx)
|
||||
|
|
|
@ -200,15 +200,16 @@ class Emitter:
|
|||
stack: Stack,
|
||||
inst: Instruction | None,
|
||||
) -> None:
|
||||
self.out.emit(tkn)
|
||||
emit_to(self.out, tkn_iter, "SEMI")
|
||||
self.out.emit(";\n")
|
||||
|
||||
target = uop.deferred_refs[tkn]
|
||||
if target is None:
|
||||
# An assignment we don't handle, such as to a pointer or array.
|
||||
self.out.emit(tkn)
|
||||
return
|
||||
|
||||
self.out.emit(tkn)
|
||||
emit_to(self.out, tkn_iter, "SEMI")
|
||||
self.out.emit(";\n")
|
||||
|
||||
# Flush the assignment to the stack. Note that we don't flush the
|
||||
# stack pointer here, and instead are currently relying on initializing
|
||||
# unused portions of the stack to NULL.
|
||||
|
|
Loading…
Reference in New Issue