diff options
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 156 |
1 files changed, 143 insertions, 13 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index bada365..6e156ab 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -202,15 +202,15 @@ maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, _PyInterpreterFrame *skip if (r < 0) { return -1; } - int lltrace = r; + int lltrace = r * 5; // Levels 1-4 only trace uops if (!lltrace) { - // When tracing executed uops, also trace bytecode - char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); - if (uop_debug != NULL && *uop_debug >= '0') { - lltrace = (*uop_debug - '0') >= 5; // TODO: Parse an int and all that + // Can also be controlled by environment variable + char *python_lltrace = Py_GETENV("PYTHON_LLTRACE"); + if (python_lltrace != NULL && *python_lltrace >= '0') { + lltrace = *python_lltrace - '0'; // TODO: Parse an int and all that } } - if (lltrace) { + if (lltrace >= 5) { lltrace_resume_frame(frame); } return lltrace; @@ -611,10 +611,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) return _PyEval_EvalFrame(tstate, f->f_frame, throwflag); } -#define TIER_ONE 1 #include "ceval_macros.h" - int _Py_CheckRecursiveCallPy( PyThreadState *tstate) { @@ -680,9 +678,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #ifdef Py_STATS int lastopcode = 0; #endif - // opcode is an 8-bit value to improve the code generated by MSVC - // for the big switch below (in combination with the EXTRA_CASES macro). - uint8_t opcode; /* Current opcode */ + int opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ #ifdef LLTRACE int lltrace = 0; @@ -730,6 +726,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto resume_with_error; } + /* State shared between Tier 1 and Tier 2 interpreter */ + _PyUOpExecutorObject *current_executor = NULL; + /* Local "register" variables. * These are cached values from the frame and code object. */ @@ -766,7 +765,9 @@ resume_frame: /* Start instructions */ #if !USE_COMPUTED_GOTOS dispatch_opcode: - switch (opcode) + // Cast to an 8-bit value to improve the code generated by MSVC + // (in combination with the EXTRA_CASES macro). + switch ((uint8_t)opcode) #endif { @@ -914,7 +915,7 @@ exception_unwind: } /* Resume normal execution */ #ifdef LLTRACE - if (lltrace) { + if (lltrace >= 5) { lltrace_resume_frame(frame); } #endif @@ -943,6 +944,135 @@ resume_with_error: stack_pointer = _PyFrame_GetStackPointer(frame); goto error; + + +// The Tier 2 interpreter is also here! +enter_tier_two: + +#undef LOAD_IP +#define LOAD_IP(UNUSED) (void)0 + +#undef GOTO_ERROR +#define GOTO_ERROR(LABEL) goto LABEL ## _tier_two + +#undef DEOPT_IF +#define DEOPT_IF(COND, INSTNAME) \ + if ((COND)) { \ + goto deoptimize;\ + } + +#ifdef Py_STATS +// Disable these macros that apply to Tier 1 stats when we are in Tier 2 +#undef STAT_INC +#define STAT_INC(opname, name) ((void)0) +#undef STAT_DEC +#define STAT_DEC(opname, name) ((void)0) +#undef CALL_STAT_INC +#define CALL_STAT_INC(name) ((void)0) +#endif + +#undef ENABLE_SPECIALIZATION +#define ENABLE_SPECIALIZATION 0 + +#ifdef Py_DEBUG + #define DPRINTF(level, ...) \ + if (lltrace >= (level)) { printf(__VA_ARGS__); } +#else + #define DPRINTF(level, ...) +#endif + + OPT_STAT_INC(traces_executed); + _PyUOpInstruction *next_uop = current_executor->trace; +#ifdef Py_DEBUG + uint64_t operand; // Used by several DPRINTF() calls +#endif +#ifdef Py_STATS + uint64_t trace_uop_execution_counter = 0; +#endif + + for (;;) { + opcode = next_uop->opcode; + oparg = next_uop->oparg; +#ifdef Py_DEBUG + operand = next_uop->operand; +#endif + DPRINTF(3, + "%4d: uop %s, oparg %d, operand %" PRIu64 ", stack_level %d\n", + (int)(next_uop - current_executor->trace), + opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode], + oparg, + operand, + (int)(stack_pointer - _PyFrame_Stackbase(frame))); + next_uop++; + OPT_STAT_INC(uops_executed); +#ifdef Py_STATS + trace_uop_execution_counter++; +#endif + + switch (opcode) { + +#include "executor_cases.c.h" + + default: +#ifdef Py_DEBUG + { + fprintf(stderr, "Unknown uop %d, oparg %d, operand %" PRIu64 "\n", + opcode, oparg, operand); + Py_FatalError("Unknown uop"); + } +#else + Py_UNREACHABLE(); +#endif + + } + } + +// Jump here from ERROR_IF(..., unbound_local_error) +unbound_local_error_tier_two: + _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + goto error_tier_two; + +// JUMP to any of these from ERROR_IF(..., error) +pop_4_error_tier_two: + STACK_SHRINK(1); +pop_3_error_tier_two: + STACK_SHRINK(1); +pop_2_error_tier_two: + STACK_SHRINK(1); +pop_1_error_tier_two: + STACK_SHRINK(1); +error_tier_two: + DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + frame->return_offset = 0; // Don't leave this random + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(current_executor); + goto resume_with_error; + +// Jump here from DEOPT_IF() +deoptimize: + // On DEOPT_IF we just repeat the last instruction. + // This presumes nothing was popped from the stack (nor pushed). + DPRINTF(2, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + frame->return_offset = 0; // Dispatch to frame->instr_ptr + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(current_executor); + // Fall through +// Jump here from ENTER_EXECUTOR +enter_tier_one: + next_instr = frame->instr_ptr; + goto resume_frame; + +// Jump here from _EXIT_TRACE +exit_trace: + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(current_executor); + OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); + goto enter_tier_one; } #if defined(__GNUC__) # pragma GCC diagnostic pop |