diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/_warnings.c | 6 | ||||
-rw-r--r-- | Python/ceval.c | 431 | ||||
-rw-r--r-- | Python/errors.c | 3 | ||||
-rw-r--r-- | Python/frame.c | 135 | ||||
-rw-r--r-- | Python/pystate.c | 81 | ||||
-rw-r--r-- | Python/suggestions.c | 4 | ||||
-rw-r--r-- | Python/sysmodule.c | 16 | ||||
-rw-r--r-- | Python/traceback.c | 29 |
8 files changed, 433 insertions, 272 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c index 9f68da2087..cf2110d31c 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -854,10 +854,8 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, *lineno = 1; } else { - globals = _PyFrame_GetGlobals(f); - PyCodeObject *code = PyFrame_GetCode(f); - *filename = code->co_filename; - Py_DECREF(code); + globals = f->f_frame->f_globals; + *filename = f->f_frame->f_code->co_filename; Py_INCREF(*filename); *lineno = PyFrame_GetLineNumber(f); Py_DECREF(f); diff --git a/Python/ceval.c b/Python/ceval.c index 90112aa3f9..02eef9bc1c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -62,27 +62,27 @@ static int lltrace; static int prtrace(PyThreadState *, PyObject *, const char *); #endif static int call_trace(Py_tracefunc, PyObject *, - PyThreadState *, PyFrameObject *, + PyThreadState *, InterpreterFrame *, int, PyObject *); static int call_trace_protected(Py_tracefunc, PyObject *, - PyThreadState *, PyFrameObject *, + PyThreadState *, InterpreterFrame *, int, PyObject *); static void call_exc_trace(Py_tracefunc, PyObject *, - PyThreadState *, PyFrameObject *); + PyThreadState *, InterpreterFrame *); static int maybe_call_line_trace(Py_tracefunc, PyObject *, - PyThreadState *, PyFrameObject *, int); -static void maybe_dtrace_line(PyFrameObject *, PyTraceInfo *, int); -static void dtrace_function_entry(PyFrameObject *); -static void dtrace_function_return(PyFrameObject *); + PyThreadState *, InterpreterFrame *, int); +static void maybe_dtrace_line(InterpreterFrame *, PyTraceInfo *, int); +static void dtrace_function_entry(InterpreterFrame *); +static void dtrace_function_return(InterpreterFrame *); -static PyObject * import_name(PyThreadState *, PyFrameObject *, +static PyObject * import_name(PyThreadState *, InterpreterFrame *, PyObject *, PyObject *, PyObject *); static PyObject * import_from(PyThreadState *, PyObject *, PyObject *); static int import_all_from(PyThreadState *, PyObject *, PyObject *); static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *); static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg); static PyObject * unicode_concatenate(PyThreadState *, PyObject *, PyObject *, - PyFrameObject *, const _Py_CODEUNIT *); + InterpreterFrame *, const _Py_CODEUNIT *); static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs); static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int); @@ -1065,14 +1065,14 @@ PyEval_EvalFrame(PyFrameObject *f) { /* Function kept for backward compatibility */ PyThreadState *tstate = _PyThreadState_GET(); - return _PyEval_EvalFrame(tstate, f, 0); + return _PyEval_EvalFrame(tstate, f->f_frame, 0); } PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { PyThreadState *tstate = _PyThreadState_GET(); - return _PyEval_EvalFrame(tstate, f, throwflag); + return _PyEval_EvalFrame(tstate, f->f_frame, throwflag); } @@ -1231,7 +1231,7 @@ eval_frame_handle_pending(PyThreadState *tstate) if (cframe.use_tracing OR_DTRACE_LINE OR_LLTRACE) { \ goto tracing_dispatch; \ } \ - f->f_lasti = INSTR_OFFSET(); \ + frame->f_lasti = INSTR_OFFSET(); \ NEXTOPARG(); \ DISPATCH_GOTO(); \ } @@ -1320,7 +1320,7 @@ eval_frame_handle_pending(PyThreadState *tstate) /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ -#define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack)) +#define STACK_LEVEL() ((int)(stack_pointer - frame->stack)) #define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) @@ -1388,12 +1388,12 @@ eval_frame_handle_pending(PyThreadState *tstate) #define UPDATE_PREV_INSTR_OPARG(instr, oparg) ((uint8_t*)(instr))[-1] = (oparg) -#define GLOBALS() specials[FRAME_SPECIALS_GLOBALS_OFFSET] -#define BUILTINS() specials[FRAME_SPECIALS_BUILTINS_OFFSET] -#define LOCALS() specials[FRAME_SPECIALS_LOCALS_OFFSET] +#define GLOBALS() frame->f_globals +#define BUILTINS() frame->f_builtins +#define LOCALS() frame->f_locals PyObject* _Py_HOT_FUNCTION -_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) +_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag) { _Py_EnsureTstateNotNULL(tstate); @@ -1409,7 +1409,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _Py_CODEUNIT *next_instr; int opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ - PyObject **localsplus, **specials; + PyObject **localsplus; PyObject *retval = NULL; /* Return value */ _Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker; PyCodeObject *co; @@ -1438,9 +1438,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) tstate->cframe = &cframe; /* push frame */ - tstate->frame = f; - specials = f->f_valuestack - FRAME_SPECIALS_SIZE; - co = (PyCodeObject *)specials[FRAME_SPECIALS_CODE_OFFSET]; + tstate->frame = frame; + co = frame->f_code; if (cframe.use_tracing) { if (tstate->c_tracefunc != NULL) { @@ -1459,7 +1458,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) whenever an exception is detected. */ if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj, - tstate, f, + tstate, frame, PyTrace_CALL, Py_None)) { /* Trace function raised an error */ goto exit_eval_frame; @@ -1470,7 +1469,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) return itself and isn't called for "line" events */ if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj, - tstate, f, + tstate, frame, PyTrace_CALL, Py_None)) { /* Profile function raised an error */ goto exit_eval_frame; @@ -1479,7 +1478,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } if (PyDTrace_FUNCTION_ENTRY_ENABLED()) - dtrace_function_entry(f); + dtrace_function_entry(frame); /* Increment the warmup counter and quicken if warm enough * _Py_Quicken is idempotent so we don't worry about overflow */ @@ -1495,34 +1494,34 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) names = co->co_names; consts = co->co_consts; - localsplus = f->f_localsptr; + localsplus = _PyFrame_GetLocalsArray(frame); first_instr = co->co_firstinstr; /* - f->f_lasti refers to the index of the last instruction, + frame->f_lasti refers to the index of the last instruction, unless it's -1 in which case next_instr should be first_instr. - YIELD_FROM sets f_lasti to itself, in order to repeatedly yield + YIELD_FROM sets frame->f_lasti to itself, in order to repeatedly yield multiple values. When the PREDICT() macros are enabled, some opcode pairs follow in - direct succession without updating f->f_lasti. A successful + direct succession without updating frame->f_lasti. A successful prediction effectively links the two codes together as if they - were a single new opcode; accordingly,f->f_lasti will point to + were a single new opcode; accordingly,frame->f_lasti will point to the first code in the pair (for instance, GET_ITER followed by - FOR_ITER is effectively a single opcode and f->f_lasti will point + FOR_ITER is effectively a single opcode and frame->f_lasti will point to the beginning of the combined pair.) */ - assert(f->f_lasti >= -1); - next_instr = first_instr + f->f_lasti + 1; - stack_pointer = f->f_valuestack + f->f_stackdepth; - /* Set f->f_stackdepth to -1. + assert(frame->f_lasti >= -1); + next_instr = first_instr + frame->f_lasti + 1; + stack_pointer = frame->stack + frame->stackdepth; + /* Set stackdepth to -1. * Update when returning or calling trace function. Having f_stackdepth <= 0 ensures that invalid values are not visible to the cycle GC. We choose -1 rather than 0 to assist debugging. */ - f->f_stackdepth = -1; - f->f_state = FRAME_EXECUTING; + frame->stackdepth = -1; + frame->f_state = FRAME_EXECUTING; #ifdef LLTRACE { @@ -1546,7 +1545,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) #endif for (;;) { - assert(stack_pointer >= f->f_valuestack); /* else underflow */ + assert(STACK_LEVEL() >= 0); /* else underflow */ assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ assert(!_PyErr_Occurred(tstate)); @@ -1586,12 +1585,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) tracing_dispatch: { - int instr_prev = f->f_lasti; - f->f_lasti = INSTR_OFFSET(); + int instr_prev = frame->f_lasti; + frame->f_lasti = INSTR_OFFSET(); TRACING_NEXTOPARG(); if (PyDTrace_LINE_ENABLED()) - maybe_dtrace_line(f, &tstate->trace_info, instr_prev); + maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); /* line-by-line tracing support */ @@ -1600,19 +1599,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) int err; /* see maybe_call_line_trace() for expository comments */ - f->f_stackdepth = (int)(stack_pointer - f->f_valuestack); + frame->stackdepth = (int)(stack_pointer - frame->stack); err = maybe_call_line_trace(tstate->c_tracefunc, tstate->c_traceobj, - tstate, f, instr_prev); + tstate, frame, instr_prev); if (err) { /* trace function raised an exception */ goto error; } /* Reload possibly changed frame fields */ - JUMPTO(f->f_lasti); - stack_pointer = f->f_valuestack+f->f_stackdepth; - f->f_stackdepth = -1; + JUMPTO(frame->f_lasti); + stack_pointer = frame->stack+frame->stackdepth; + frame->stackdepth = -1; TRACING_NEXTOPARG(); } } @@ -1623,11 +1622,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (lltrace) { if (HAS_ARG(opcode)) { printf("%d: %d, %d\n", - f->f_lasti, opcode, oparg); + frame->f_lasti, opcode, oparg); } else { printf("%d: %d\n", - f->f_lasti, opcode); + frame->f_lasti, opcode); } } #endif @@ -1876,7 +1875,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) speedup on microbenchmarks. */ if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) { - sum = unicode_concatenate(tstate, left, right, f, next_instr); + sum = unicode_concatenate(tstate, left, right, frame, next_instr); /* unicode_concatenate consumed the ref to left */ } else { @@ -2162,7 +2161,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *left = TOP(); PyObject *sum; if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) { - sum = unicode_concatenate(tstate, left, right, f, next_instr); + sum = unicode_concatenate(tstate, left, right, frame, next_instr); /* unicode_concatenate consumed the ref to left */ } else { @@ -2322,8 +2321,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(RETURN_VALUE): { retval = POP(); assert(EMPTY()); - f->f_state = FRAME_RETURNED; - f->f_stackdepth = 0; + frame->f_state = FRAME_RETURNED; + frame->stackdepth = 0; goto exiting; } @@ -2480,7 +2479,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (retval == NULL) { if (tstate->c_tracefunc != NULL && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f); + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); if (_PyGen_FetchStopIterationValue(&retval) == 0) { gen_status = PYGEN_RETURN; } @@ -2508,10 +2507,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) assert (gen_status == PYGEN_NEXT); /* receiver remains on stack, retval is value to be yielded */ /* and repeat... */ - assert(f->f_lasti > 0); - f->f_lasti -= 1; - f->f_state = FRAME_SUSPENDED; - f->f_stackdepth = (int)(stack_pointer - f->f_valuestack); + assert(frame->f_lasti > 0); + frame->f_lasti -= 1; + frame->f_state = FRAME_SUSPENDED; + frame->stackdepth = (int)(stack_pointer - frame->stack); goto exiting; } @@ -2527,8 +2526,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } retval = w; } - f->f_state = FRAME_SUSPENDED; - f->f_stackdepth = (int)(stack_pointer - f->f_valuestack); + frame->f_state = FRAME_SUSPENDED; + frame->stackdepth = (int)(stack_pointer - frame->stack); goto exiting; } @@ -2575,7 +2574,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(POP_EXCEPT_AND_RERAISE): { PyObject *lasti = PEEK(4); if (PyLong_Check(lasti)) { - f->f_lasti = PyLong_AsLong(lasti); + frame->f_lasti = PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { @@ -2606,7 +2605,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) if (oparg) { PyObject *lasti = PEEK(oparg+3); if (PyLong_Check(lasti)) { - f->f_lasti = PyLong_AsLong(lasti); + frame->f_lasti = PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { @@ -3579,7 +3578,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *fromlist = POP(); PyObject *level = TOP(); PyObject *res; - res = import_name(tstate, f, name, fromlist, level); + res = import_name(tstate, frame, name, fromlist, level); Py_DECREF(level); Py_DECREF(fromlist); SET_TOP(res); @@ -3591,7 +3590,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(IMPORT_STAR): { PyObject *from = POP(), *locals; int err; - if (PyFrame_FastToLocalsWithError(f) < 0) { + if (_PyFrame_FastToLocalsWithError(frame) < 0) { Py_DECREF(from); goto error; } @@ -3604,7 +3603,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) goto error; } err = import_all_from(tstate, locals, from); - PyFrame_LocalsToFast(f, 0); + _PyFrame_LocalsToFast(frame, 0); Py_DECREF(from); if (err != 0) goto error; @@ -3918,7 +3917,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) goto error; } else if (tstate->c_tracefunc != NULL) { - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f); + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); } _PyErr_Clear(tstate); } @@ -4381,7 +4380,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", - PyFrame_GetLineNumber(f), + PyCode_Addr2Line(frame->f_code, frame->f_lasti*2), opcode); _PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode"); goto error; @@ -4450,19 +4449,22 @@ error: #endif /* Log traceback info. */ - PyTraceBack_Here(f); + PyFrameObject *f = _PyFrame_GetFrameObject(frame); + if (f != NULL) { + PyTraceBack_Here(f); + } if (tstate->c_tracefunc != NULL) { /* Make sure state is set to FRAME_EXECUTING for tracing */ - assert(f->f_state == FRAME_EXECUTING); - f->f_state = FRAME_UNWINDING; + assert(frame->f_state == FRAME_EXECUTING); + frame->f_state = FRAME_UNWINDING; call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, - tstate, f); + tstate, frame); } exception_unwind: - f->f_state = FRAME_UNWINDING; - /* We can't use f->f_lasti here, as RERAISE may have set it */ + frame->f_state = FRAME_UNWINDING; + /* We can't use frame->f_lasti here, as RERAISE may have set it */ int offset = INSTR_OFFSET()-1; int level, handler, lasti; if (get_exception_handler(co, offset, &level, &handler, &lasti) == 0) { @@ -4477,7 +4479,7 @@ exception_unwind: } PyObject *exc, *val, *tb; if (lasti) { - PyObject *lasti = PyLong_FromLong(f->f_lasti); + PyObject *lasti = PyLong_FromLong(frame->f_lasti); if (lasti == NULL) { goto exception_unwind; } @@ -4502,8 +4504,8 @@ exception_unwind: PUSH(exc); JUMPTO(handler); /* Resume normal execution */ - f->f_state = FRAME_EXECUTING; - f->f_lasti = handler; + frame->f_state = FRAME_EXECUTING; + frame->f_lasti = handler; NEXTOPARG(); goto dispatch_opcode; } /* main loop */ @@ -4516,19 +4518,19 @@ exception_unwind: PyObject *o = POP(); Py_XDECREF(o); } - f->f_stackdepth = 0; - f->f_state = FRAME_RAISED; + frame->stackdepth = 0; + frame->f_state = FRAME_RAISED; exiting: if (cframe.use_tracing) { if (tstate->c_tracefunc) { if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj, - tstate, f, PyTrace_RETURN, retval)) { + tstate, frame, PyTrace_RETURN, retval)) { Py_CLEAR(retval); } } if (tstate->c_profilefunc) { if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj, - tstate, f, PyTrace_RETURN, retval)) { + tstate, frame, PyTrace_RETURN, retval)) { Py_CLEAR(retval); } } @@ -4541,10 +4543,9 @@ exit_eval_frame: tstate->cframe->use_tracing = cframe.use_tracing; if (PyDTrace_FUNCTION_RETURN_ENABLED()) - dtrace_function_return(f); + dtrace_function_return(frame); _Py_LeaveRecursiveCall(tstate); - tstate->frame = f->f_back; - + tstate->frame = frame->previous; return _Py_CheckFunctionResult(tstate, NULL, retval, __func__); } @@ -5051,116 +5052,110 @@ fail: /* Jump here from prelude on failure */ } - -PyFrameObject * -_PyEval_MakeFrameVector(PyThreadState *tstate, +static InterpreterFrame * +make_coro_frame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals, PyObject *const *args, Py_ssize_t argcount, - PyObject *kwnames, PyObject** localsarray) + PyObject *kwnames) { assert(is_tstate_valid(tstate)); assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); - - /* Create the frame */ - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, con, locals, localsarray); - if (f == NULL) { + PyCodeObject *code = (PyCodeObject *)con->fc_code; + int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; + PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size); + if (localsarray == NULL) { + PyErr_NoMemory(); return NULL; } - if (initialize_locals(tstate, con, f->f_localsptr, args, argcount, kwnames)) { - Py_DECREF(f); + for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) { + localsarray[i] = NULL; + } + InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus); + _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); + assert(frame->frame_obj == NULL); + if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) { + _PyFrame_Clear(frame, 1); return NULL; } - return f; + return frame; } static PyObject * -make_coro(PyFrameConstructor *con, PyFrameObject *f) +make_coro(PyThreadState *tstate, PyFrameConstructor *con, + PyObject *locals, + PyObject* const* args, size_t argcount, + PyObject *kwnames) { assert (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)); - PyObject *gen; - int is_coro = ((PyCodeObject *)con->fc_code)->co_flags & CO_COROUTINE; - - /* Don't need to keep the reference to f_back, it will be set - * when the generator is resumed. */ - Py_CLEAR(f->f_back); - - /* Create a new generator that owns the ready to run frame - * and return that as the value. */ - if (is_coro) { - gen = PyCoro_New(f, con->fc_name, con->fc_qualname); - } else if (((PyCodeObject *)con->fc_code)->co_flags & CO_ASYNC_GENERATOR) { - gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname); - } else { - gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname); + InterpreterFrame *frame = make_coro_frame(tstate, con, locals, args, argcount, kwnames); + if (frame == NULL) { + return NULL; } + PyObject *gen = _Py_MakeCoro(con, frame); if (gen == NULL) { return NULL; } - _PyObject_GC_TRACK(f); - return gen; } +static InterpreterFrame * +_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con, + PyObject *locals, PyObject* const* args, + size_t argcount, PyObject *kwnames) +{ + InterpreterFrame * frame = _PyThreadState_PushFrame(tstate, con, locals); + if (frame == NULL) { + return NULL; + } + PyObject **localsarray = _PyFrame_GetLocalsArray(frame); + if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) { + _PyFrame_Clear(frame, 0); + return NULL; + } + frame->previous = tstate->frame; + tstate->frame = frame; + return frame; +} + +static int +_PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame) +{ + ++tstate->recursion_depth; + assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0); + if (_PyFrame_Clear(frame, 0)) { + return -1; + } + assert(frame->frame_obj == NULL); + --tstate->recursion_depth; + tstate->frame = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + return 0; +} + PyObject * _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals, PyObject* const* args, size_t argcount, PyObject *kwnames) { - PyObject **localsarray; PyCodeObject *code = (PyCodeObject *)con->fc_code; int is_coro = code->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); if (is_coro) { - localsarray = NULL; - } - else { - int size = code->co_nlocalsplus + code->co_stacksize + - FRAME_SPECIALS_SIZE; - localsarray = _PyThreadState_PushLocals(tstate, size); - if (localsarray == NULL) { - return NULL; - } + return make_coro(tstate, con, locals, args, argcount, kwnames); } - PyFrameObject *f = _PyEval_MakeFrameVector( - tstate, con, locals, args, argcount, kwnames, localsarray); - if (f == NULL) { - if (!is_coro) { - _PyThreadState_PopLocals(tstate, localsarray); - } + InterpreterFrame *frame = _PyEvalFramePushAndInit( + tstate, con, locals, args, argcount, kwnames); + if (frame == NULL) { return NULL; } - if (is_coro) { - return make_coro(con, f); - } - PyObject *retval = _PyEval_EvalFrame(tstate, f, 0); - assert(f->f_stackdepth == 0); - - /* decref'ing the frame can cause __del__ methods to get invoked, - which can call back into Python. While we're done with the - current Python frame (f), the associated C stack is still in use, - so recursion_depth must be boosted for the duration. - */ - assert (!is_coro); - assert(f->f_own_locals_memory == 0); - if (Py_REFCNT(f) > 1) { - Py_DECREF(f); - _PyObject_GC_TRACK(f); - if (_PyFrame_TakeLocals(f)) { - Py_CLEAR(retval); - } - } - else { - ++tstate->recursion_depth; - f->f_localsptr = NULL; - for (int i = 0; i < code->co_nlocalsplus + FRAME_SPECIALS_SIZE; i++) { - Py_XDECREF(localsarray[i]); - } - Py_DECREF(f); - --tstate->recursion_depth; + assert (tstate->interp->eval_frame != NULL); + PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0); + assert(frame->stackdepth == 0); + if (_PyEvalFrameClearAndPop(tstate, frame)) { + retval = NULL; } - _PyThreadState_PopLocals(tstate, localsarray); return retval; } @@ -5467,7 +5462,7 @@ prtrace(PyThreadState *tstate, PyObject *v, const char *str) static void call_exc_trace(Py_tracefunc func, PyObject *self, PyThreadState *tstate, - PyFrameObject *f) + InterpreterFrame *f) { PyObject *type, *value, *traceback, *orig_traceback, *arg; int err; @@ -5497,7 +5492,7 @@ call_exc_trace(Py_tracefunc func, PyObject *self, static int call_trace_protected(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, PyFrameObject *frame, + PyThreadState *tstate, InterpreterFrame *frame, int what, PyObject *arg) { PyObject *type, *value, *traceback; @@ -5518,9 +5513,9 @@ call_trace_protected(Py_tracefunc func, PyObject *obj, } static void -initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame) +initialize_trace_info(PyTraceInfo *trace_info, InterpreterFrame *frame) { - PyCodeObject *code = _PyFrame_GetCode(frame); + PyCodeObject *code = frame->f_code; if (trace_info->code != code) { trace_info->code = code; _PyCode_InitAddressRange(code, &trace_info->bounds); @@ -5529,7 +5524,7 @@ initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame) static int call_trace(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, PyFrameObject *frame, + PyThreadState *tstate, InterpreterFrame *frame, int what, PyObject *arg) { int result; @@ -5537,15 +5532,19 @@ call_trace(Py_tracefunc func, PyObject *obj, return 0; tstate->tracing++; tstate->cframe->use_tracing = 0; + PyFrameObject *f = _PyFrame_GetFrameObject(frame); + if (f == NULL) { + return -1; + } if (frame->f_lasti < 0) { - frame->f_lineno = _PyFrame_GetCode(frame)->co_firstlineno; + f->f_lineno = frame->f_code->co_firstlineno; } else { initialize_trace_info(&tstate->trace_info, frame); - frame->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds); + f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds); } - result = func(obj, frame, what, arg); - frame->f_lineno = 0; + result = func(obj, f, what, arg); + f->f_lineno = 0; tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL) || (tstate->c_profilefunc != NULL)); tstate->tracing--; @@ -5572,7 +5571,7 @@ _PyEval_CallTracing(PyObject *func, PyObject *args) /* See Objects/lnotab_notes.txt for a description of how tracing works. */ static int maybe_call_line_trace(Py_tracefunc func, PyObject *obj, - PyThreadState *tstate, PyFrameObject *frame, int instr_prev) + PyThreadState *tstate, InterpreterFrame *frame, int instr_prev) { int result = 0; @@ -5583,14 +5582,18 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, initialize_trace_info(&tstate->trace_info, frame); int lastline = _PyCode_CheckLineNumber(instr_prev*2, &tstate->trace_info.bounds); int line = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds); - if (line != -1 && frame->f_trace_lines) { + PyFrameObject *f = _PyFrame_GetFrameObject(frame); + if (f == NULL) { + return -1; + } + if (line != -1 && f->f_trace_lines) { /* Trace backward edges or if line number has changed */ if (frame->f_lasti < instr_prev || line != lastline) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } } /* Always emit an opcode event if we're tracing all opcodes. */ - if (frame->f_trace_opcodes) { + if (f->f_trace_opcodes) { result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None); } return result; @@ -5737,19 +5740,33 @@ _PyEval_GetAsyncGenFinalizer(void) return tstate->async_gen_finalizer; } +InterpreterFrame * +_PyEval_GetFrame(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + return tstate->frame; +} + PyFrameObject * PyEval_GetFrame(void) { PyThreadState *tstate = _PyThreadState_GET(); - return tstate->frame; + if (tstate->frame == NULL) { + return NULL; + } + PyFrameObject *f = _PyFrame_GetFrameObject(tstate->frame); + if (f == NULL) { + PyErr_Clear(); + } + return f; } PyObject * _PyEval_GetBuiltins(PyThreadState *tstate) { - PyFrameObject *frame = tstate->frame; + InterpreterFrame *frame = tstate->frame; if (frame != NULL) { - return _PyFrame_GetBuiltins(frame); + return frame->f_builtins; } return tstate->interp->builtins; } @@ -5780,18 +5797,17 @@ PyObject * PyEval_GetLocals(void) { PyThreadState *tstate = _PyThreadState_GET(); - PyFrameObject *current_frame = tstate->frame; + InterpreterFrame *current_frame = tstate->frame; if (current_frame == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist"); return NULL; } - if (PyFrame_FastToLocalsWithError(current_frame) < 0) { + if (_PyFrame_FastToLocalsWithError(current_frame) < 0) { return NULL; } - PyObject *locals = current_frame->f_valuestack[ - FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; + PyObject *locals = current_frame->f_locals; assert(locals != NULL); return locals; } @@ -5800,22 +5816,22 @@ PyObject * PyEval_GetGlobals(void) { PyThreadState *tstate = _PyThreadState_GET(); - PyFrameObject *current_frame = tstate->frame; + InterpreterFrame *current_frame = tstate->frame; if (current_frame == NULL) { return NULL; } - return _PyFrame_GetGlobals(current_frame); + return current_frame->f_globals; } int PyEval_MergeCompilerFlags(PyCompilerFlags *cf) { PyThreadState *tstate = _PyThreadState_GET(); - PyFrameObject *current_frame = tstate->frame; + InterpreterFrame *current_frame = tstate->frame; int result = cf->cf_flags != 0; if (current_frame != NULL) { - const int codeflags = _PyFrame_GetCode(current_frame)->co_flags; + const int codeflags = current_frame->f_code->co_flags; const int compilerflags = codeflags & PyCF_MASK; if (compilerflags) { result = 1; @@ -6049,22 +6065,21 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi) } static PyObject * -import_name(PyThreadState *tstate, PyFrameObject *f, +import_name(PyThreadState *tstate, InterpreterFrame *frame, PyObject *name, PyObject *fromlist, PyObject *level) { _Py_IDENTIFIER(__import__); PyObject *import_func, *res; PyObject* stack[5]; - import_func = _PyDict_GetItemIdWithError(_PyFrame_GetBuiltins(f), &PyId___import__); + import_func = _PyDict_GetItemIdWithError(frame->f_builtins, &PyId___import__); if (import_func == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found"); } return NULL; } - PyObject *locals = f->f_valuestack[ - FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; + PyObject *locals = frame->f_locals; /* Fast path for not overloaded __import__. */ if (import_func == tstate->interp->import_func) { int ilevel = _PyLong_AsInt(level); @@ -6073,7 +6088,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f, } res = PyImport_ImportModuleLevelObject( name, - _PyFrame_GetGlobals(f), + frame->f_globals, locals == NULL ? Py_None :locals, fromlist, ilevel); @@ -6083,7 +6098,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f, Py_INCREF(import_func); stack[0] = name; - stack[1] = _PyFrame_GetGlobals(f); + stack[1] = frame->f_globals; stack[2] = locals == NULL ? Py_None : locals; stack[3] = fromlist; stack[4] = level; @@ -6389,7 +6404,7 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int prevprevop static PyObject * unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, - PyFrameObject *f, const _Py_CODEUNIT *next_instr) + InterpreterFrame *frame, const _Py_CODEUNIT *next_instr) { PyObject *res; if (Py_REFCNT(v) == 2) { @@ -6404,14 +6419,14 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, switch (opcode) { case STORE_FAST: { - PyObject **localsplus = f->f_localsptr; + PyObject **localsplus = _PyFrame_GetLocalsArray(frame); if (GETLOCAL(oparg) == v) SETLOCAL(oparg, NULL); break; } case STORE_DEREF: { - PyObject *c = f->f_localsptr[oparg]; + PyObject *c = _PyFrame_GetLocalsArray(frame)[oparg]; if (PyCell_GET(c) == v) { PyCell_SET(c, NULL); Py_DECREF(v); @@ -6420,10 +6435,9 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w, } case STORE_NAME: { - PyObject *names = _PyFrame_GetCode(f)->co_names; + PyObject *names = frame->f_code->co_names; PyObject *name = GETITEM(names, oparg); - PyObject *locals = f->f_valuestack[ - FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE]; + PyObject *locals = frame->f_locals; if (locals && PyDict_CheckExact(locals)) { PyObject *w = PyDict_GetItemWithError(locals, name); if ((w == v && PyDict_DelItem(locals, name) != 0) || @@ -6501,38 +6515,38 @@ _PyEval_RequestCodeExtraIndex(freefunc free) } static void -dtrace_function_entry(PyFrameObject *f) +dtrace_function_entry(InterpreterFrame *frame) { const char *filename; const char *funcname; int lineno; - PyCodeObject *code = _PyFrame_GetCode(f); + PyCodeObject *code = frame->f_code; filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); - lineno = PyFrame_GetLineNumber(f); + lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*2); PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); } static void -dtrace_function_return(PyFrameObject *f) +dtrace_function_return(InterpreterFrame *frame) { const char *filename; const char *funcname; int lineno; - PyCodeObject *code = _PyFrame_GetCode(f); + PyCodeObject *code = frame->f_code; filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); - lineno = PyFrame_GetLineNumber(f); + lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*2); PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); } /* DTrace equivalent of maybe_call_line_trace. */ static void -maybe_dtrace_line(PyFrameObject *frame, +maybe_dtrace_line(InterpreterFrame *frame, PyTraceInfo *trace_info, int instr_prev) { @@ -6542,25 +6556,26 @@ maybe_dtrace_line(PyFrameObject *frame, instruction window, reset the window. */ initialize_trace_info(trace_info, frame); + int lastline = _PyCode_CheckLineNumber(instr_prev*2, &trace_info->bounds); int line = _PyCode_CheckLineNumber(frame->f_lasti*2, &trace_info->bounds); - /* If the last instruction falls at the start of a line or if - it represents a jump backwards, update the frame's line - number and call the trace function. */ - if (line != frame->f_lineno || frame->f_lasti < instr_prev) { - if (line != -1) { - frame->f_lineno = line; - co_filename = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename); - if (!co_filename) + if (line != -1) { + /* Trace backward edges or first instruction of a new line */ + if (frame->f_lasti < instr_prev || + (line != lastline && frame->f_lasti*2 == trace_info->bounds.ar_start)) + { + co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); + if (!co_filename) { co_filename = "?"; - co_name = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_name); - if (!co_name) + } + co_name = PyUnicode_AsUTF8(frame->f_code->co_name); + if (!co_name) { co_name = "?"; + } PyDTrace_LINE(co_filename, co_name, line); } } } - /* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions for the limited API. */ diff --git a/Python/errors.c b/Python/errors.c index 118118ffe9..1f84215a13 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1406,12 +1406,13 @@ _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj) } if (exc_tb == NULL) { - PyFrameObject *frame = tstate->frame; + PyFrameObject *frame = PyThreadState_GetFrame(tstate); if (frame != NULL) { exc_tb = _PyTraceBack_FromFrame(NULL, frame); if (exc_tb == NULL) { _PyErr_Clear(tstate); } + Py_DECREF(frame); } } diff --git a/Python/frame.c b/Python/frame.c new file mode 100644 index 0000000000..ae4284346e --- /dev/null +++ b/Python/frame.c @@ -0,0 +1,135 @@ + +#include "Python.h" +#include "frameobject.h" +#include "pycore_frame.h" +#include "pycore_object.h" // _PyObject_GC_UNTRACK() + +int +_PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg) +{ + Py_VISIT(frame->frame_obj); + Py_VISIT(frame->f_globals); + Py_VISIT(frame->f_builtins); + Py_VISIT(frame->f_locals); + Py_VISIT(frame->f_code); + /* locals */ + PyObject **locals = _PyFrame_GetLocalsArray(frame); + for (int i = 0; i < frame->nlocalsplus; i++) { + Py_VISIT(locals[i]); + } + /* stack */ + for (int i = 0; i <frame->stackdepth; i++) { + Py_VISIT(frame->stack[i]); + } + return 0; +} + +PyFrameObject * +_PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame) +{ + assert(frame->frame_obj == NULL); + PyObject *error_type, *error_value, *error_traceback; + PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyFrameObject *f = _PyFrame_New_NoTrack(frame, 0); + if (f == NULL) { + Py_XDECREF(error_type); + Py_XDECREF(error_value); + Py_XDECREF(error_traceback); + } + else { + PyErr_Restore(error_type, error_value, error_traceback); + } + frame->frame_obj = f; + return f; +} + + +static InterpreterFrame * +copy_frame_to_heap(InterpreterFrame *frame) +{ + + Py_ssize_t size = ((char*)&frame->stack[frame->stackdepth]) - (char *)_PyFrame_GetLocalsArray(frame); + PyObject **copy = PyMem_Malloc(size); + if (copy == NULL) { + PyErr_NoMemory(); + return NULL; + } + PyObject **locals = _PyFrame_GetLocalsArray(frame); + memcpy(copy, locals, size); + InterpreterFrame *res = (InterpreterFrame *)(copy + frame->nlocalsplus); + return res; +} + +static inline void +clear_specials(InterpreterFrame *frame) +{ + frame->generator = NULL; + Py_XDECREF(frame->frame_obj); + Py_XDECREF(frame->f_locals); + Py_DECREF(frame->f_globals); + Py_DECREF(frame->f_builtins); + Py_DECREF(frame->f_code); +} + +static void +take_ownership(PyFrameObject *f, InterpreterFrame *frame) +{ + assert(f->f_own_locals_memory == 0); + assert(frame->frame_obj == NULL); + + f->f_own_locals_memory = 1; + f->f_frame = frame; + assert(f->f_back == NULL); + if (frame->previous != NULL) { + /* Link PyFrameObjects.f_back and remove link through InterpreterFrame.previous */ + PyFrameObject *back = _PyFrame_GetFrameObject(frame->previous); + if (back == NULL) { + /* Memory error here. */ + assert(PyErr_ExceptionMatches(PyExc_MemoryError)); + /* Nothing we can do about it */ + PyErr_Clear(); + _PyErr_WriteUnraisableMsg("Out of memory lazily allocating frame->f_back", NULL); + } + else { + f->f_back = (PyFrameObject *)Py_NewRef(back); + } + frame->previous = NULL; + } + if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) { + _PyObject_GC_TRACK((PyObject *)f); + } +} + +int +_PyFrame_Clear(InterpreterFrame * frame, int take) +{ + PyObject **localsarray = ((PyObject **)frame)-frame->nlocalsplus; + if (frame->frame_obj) { + PyFrameObject *f = frame->frame_obj; + frame->frame_obj = NULL; + if (Py_REFCNT(f) > 1) { + if (!take) { + frame = copy_frame_to_heap(frame); + if (frame == NULL) { + return -1; + } + } + take_ownership(f, frame); + Py_DECREF(f); + return 0; + } + Py_DECREF(f); + } + for (int i = 0; i < frame->nlocalsplus; i++) { + Py_XDECREF(localsarray[i]); + } + assert(frame->stackdepth >= 0); + for (int i = 0; i < frame->stackdepth; i++) { + Py_DECREF(frame->stack[i]); + } + clear_specials(frame); + if (take) { + PyMem_Free(_PyFrame_GetLocalsArray(frame)); + } + return 0; +} diff --git a/Python/pystate.c b/Python/pystate.c index a94a615f39..6a15b54d1d 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_ceval.h" +#include "pycore_frame.h" #include "pycore_initconfig.h" #include "pycore_object.h" // _PyType_InitCache() #include "pycore_pyerrors.h" @@ -685,7 +686,7 @@ new_threadstate(PyInterpreterState *interp, int init) PyMem_RawFree(tstate); return NULL; } - /* If top points to entry 0, then _PyThreadState_PopLocals will try to pop this chunk */ + /* If top points to entry 0, then _PyThreadState_PopFrame will try to pop this chunk */ tstate->datastack_top = &tstate->datastack_chunk->data[1]; tstate->datastack_limit = (PyObject **)(((char *)tstate->datastack_chunk) + DATA_STACK_CHUNK_SIZE); /* Mark trace_info as uninitialized */ @@ -872,7 +873,7 @@ PyThreadState_Clear(PyThreadState *tstate) "PyThreadState_Clear: warning: thread still has a frame\n"); } - /* Don't clear tstate->frame: it is a borrowed reference */ + /* Don't clear tstate->pyframe: it is a borrowed reference */ Py_CLEAR(tstate->dict); Py_CLEAR(tstate->async_exc); @@ -1133,7 +1134,13 @@ PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) { assert(tstate != NULL); - PyFrameObject *frame = tstate->frame; + if (tstate->frame == NULL) { + return NULL; + } + PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->frame); + if (frame == NULL) { + PyErr_Clear(); + } Py_XINCREF(frame); return frame; } @@ -1254,7 +1261,7 @@ _PyThread_CurrentFrames(void) for (i = runtime->interpreters.head; i != NULL; i = i->next) { PyThreadState *t; for (t = i->tstate_head; t != NULL; t = t->next) { - PyFrameObject *frame = t->frame; + InterpreterFrame *frame = t->frame; if (frame == NULL) { continue; } @@ -1262,7 +1269,7 @@ _PyThread_CurrentFrames(void) if (id == NULL) { goto fail; } - int stat = PyDict_SetItem(result, id, (PyObject *)frame); + int stat = PyDict_SetItem(result, id, (PyObject *)_PyFrame_GetFrameObject(frame)); Py_DECREF(id); if (stat < 0) { goto fail; @@ -2009,42 +2016,58 @@ _Py_GetConfig(void) #define MINIMUM_OVERHEAD 1000 -PyObject ** -_PyThreadState_PushLocals(PyThreadState *tstate, int size) +static PyObject ** +push_chunk(PyThreadState *tstate, int size) +{ + assert(tstate->datastack_top + size >= tstate->datastack_limit); + + int allocate_size = DATA_STACK_CHUNK_SIZE; + while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) { + allocate_size *= 2; + } + _PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk); + if (new == NULL) { + return NULL; + } + tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0]; + tstate->datastack_chunk = new; + tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size); + PyObject **res = &new->data[0]; + tstate->datastack_top = res + size; + return res; +} + +InterpreterFrame * +_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals) { - assert(((unsigned)size) < INT_MAX/sizeof(PyObject*)/2); - PyObject **res = tstate->datastack_top; - PyObject **top = res + size; + PyCodeObject *code = (PyCodeObject *)con->fc_code; + int nlocalsplus = code->co_nlocalsplus; + size_t size = nlocalsplus + code->co_stacksize + + FRAME_SPECIALS_SIZE; + assert(size < INT_MAX/sizeof(PyObject *)); + PyObject **localsarray = tstate->datastack_top; + PyObject **top = localsarray + size; if (top >= tstate->datastack_limit) { - int allocate_size = DATA_STACK_CHUNK_SIZE; - while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) { - allocate_size *= 2; - } - _PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk); - if (new == NULL) { - goto error; + localsarray = push_chunk(tstate, (int)size); + if (localsarray == NULL) { + return NULL; } - tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0]; - tstate->datastack_chunk = new; - tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size); - res = &new->data[0]; - tstate->datastack_top = res + size; } else { tstate->datastack_top = top; } - for (int i=0; i < size; i++) { - res[i] = NULL; + InterpreterFrame * frame = (InterpreterFrame *)(localsarray + nlocalsplus); + _PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus); + for (int i=0; i < nlocalsplus; i++) { + localsarray[i] = NULL; } - return res; -error: - _PyErr_SetString(tstate, PyExc_MemoryError, "Out of memory"); - return NULL; + return frame; } void -_PyThreadState_PopLocals(PyThreadState *tstate, PyObject **locals) +_PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) { + PyObject **locals = _PyFrame_GetLocalsArray(frame); if (locals == &tstate->datastack_chunk->data[0]) { _PyStackChunk *chunk = tstate->datastack_chunk; _PyStackChunk *previous = chunk->previous; diff --git a/Python/suggestions.c b/Python/suggestions.c index 77bdb6c165..81976ff4f2 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -232,7 +232,7 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) return suggestions; } - dir = PySequence_List(_PyFrame_GetGlobals(frame)); + dir = PySequence_List(frame->f_frame->f_globals); if (dir == NULL) { return NULL; } @@ -242,7 +242,7 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) return suggestions; } - dir = PySequence_List(_PyFrame_GetBuiltins(frame)); + dir = PySequence_List(frame->f_frame->f_builtins); if (dir == NULL) { return NULL; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f809e2fda5..5dfa917e8f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -29,6 +29,7 @@ Data members: #include "code.h" #include "frameobject.h" // PyFrame_GetBack() +#include "pycore_frame.h" #include "pydtrace.h" #include "osdefs.h" // DELIM #include "stdlib_module_names.h" // _Py_stdlib_module_names @@ -1814,25 +1815,22 @@ sys__getframe_impl(PyObject *module, int depth) /*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/ { PyThreadState *tstate = _PyThreadState_GET(); - PyFrameObject *f = PyThreadState_GetFrame(tstate); + InterpreterFrame *frame = tstate->frame; - if (_PySys_Audit(tstate, "sys._getframe", "O", f) < 0) { - Py_DECREF(f); + if (_PySys_Audit(tstate, "sys._getframe", NULL) < 0) { return NULL; } - while (depth > 0 && f != NULL) { - PyFrameObject *back = PyFrame_GetBack(f); - Py_DECREF(f); - f = back; + while (depth > 0 && frame != NULL) { + frame = frame->previous; --depth; } - if (f == NULL) { + if (frame == NULL) { _PyErr_SetString(tstate, PyExc_ValueError, "call stack is not deep enough"); return NULL; } - return (PyObject*)f; + return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(frame)); } /*[clinic input] diff --git a/Python/traceback.c b/Python/traceback.c index 6d230138a3..204121ba66 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -240,7 +240,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) assert(tb_next == NULL || PyTraceBack_Check(tb_next)); assert(frame != NULL); - return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti*2, + return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_frame->f_lasti*2, PyFrame_GetLineNumber(frame)); } @@ -521,7 +521,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent, i * When displaying a new traceback line, for certain syntactical constructs * (e.g a subscript, an arithmetic operation) we try to create a representation * that separates the primary source of error from the rest. - * + * * Example specialization of BinOp nodes: * Traceback (most recent call last): * File "/home/isidentical/cpython/cpython/t.py", line 10, in <module> @@ -710,7 +710,7 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen } int code_offset = tb->tb_lasti; - PyCodeObject* code = _PyFrame_GetCode(frame); + PyCodeObject* code = frame->f_frame->f_code; int start_line; int end_line; @@ -1024,9 +1024,9 @@ _Py_DumpASCII(int fd, PyObject *text) This function is signal safe. */ static void -dump_frame(int fd, PyFrameObject *frame) +dump_frame(int fd, InterpreterFrame *frame) { - PyCodeObject *code = PyFrame_GetCode(frame); + PyCodeObject *code = frame->f_code; PUTS(fd, " File "); if (code->co_filename != NULL && PyUnicode_Check(code->co_filename)) @@ -1038,7 +1038,7 @@ dump_frame(int fd, PyFrameObject *frame) PUTS(fd, "???"); } - int lineno = PyFrame_GetLineNumber(frame); + int lineno = PyCode_Addr2Line(code, frame->f_lasti*2); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); @@ -1057,20 +1057,19 @@ dump_frame(int fd, PyFrameObject *frame) } PUTS(fd, "\n"); - Py_DECREF(code); } static void dump_traceback(int fd, PyThreadState *tstate, int write_header) { - PyFrameObject *frame; + InterpreterFrame *frame; unsigned int depth; if (write_header) { PUTS(fd, "Stack (most recent call first):\n"); } - frame = PyThreadState_GetFrame(tstate); + frame = tstate->frame; if (frame == NULL) { PUTS(fd, "<no Python frame>\n"); return; @@ -1079,22 +1078,14 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) depth = 0; while (1) { if (MAX_FRAME_DEPTH <= depth) { - Py_DECREF(frame); PUTS(fd, " ...\n"); break; } - if (!PyFrame_Check(frame)) { - Py_DECREF(frame); - break; - } dump_frame(fd, frame); - PyFrameObject *back = PyFrame_GetBack(frame); - Py_DECREF(frame); - - if (back == NULL) { + frame = frame->previous; + if (frame == NULL) { break; } - frame = back; depth++; } } |