| #include "Python.h" |
| |
| #include "opcode.h" |
| |
| #include "pycore_bitutils.h" |
| #include "pycore_call.h" |
| #include "pycore_ceval.h" |
| #include "pycore_dict.h" |
| #include "pycore_emscripten_signal.h" |
| #include "pycore_intrinsics.h" |
| #include "pycore_long.h" |
| #include "pycore_object.h" |
| #include "pycore_opcode_metadata.h" |
| #include "pycore_opcode_utils.h" |
| #include "pycore_pyerrors.h" |
| #include "pycore_range.h" |
| #include "pycore_setobject.h" // _PySet_Update() |
| #include "pycore_sliceobject.h" |
| #include "pycore_uops.h" |
| |
| #define TIER_TWO 2 |
| #include "ceval_macros.h" |
| |
| |
| #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 |
| |
| |
| _PyInterpreterFrame * |
| _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer) |
| { |
| #ifdef Py_DEBUG |
| char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); |
| int lltrace = 0; |
| if (uop_debug != NULL && *uop_debug >= '0') { |
| lltrace = *uop_debug - '0'; // TODO: Parse an int and all that |
| } |
| #define DPRINTF(level, ...) \ |
| if (lltrace >= (level)) { printf(__VA_ARGS__); } |
| #else |
| #define DPRINTF(level, ...) |
| #endif |
| |
| DPRINTF(3, |
| "Entering _PyUopExecute for %s (%s:%d) at byte offset %ld\n", |
| PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname), |
| PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename), |
| _PyFrame_GetCode(frame)->co_firstlineno, |
| 2 * (long)(frame->prev_instr + 1 - |
| (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive)); |
| |
| PyThreadState *tstate = _PyThreadState_GET(); |
| _PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor; |
| |
| CHECK_EVAL_BREAKER(); |
| |
| OPT_STAT_INC(traces_executed); |
| _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; |
| int pc = 0; |
| int opcode; |
| int oparg; |
| uint64_t operand; |
| #ifdef Py_STATS |
| uint64_t trace_uop_execution_counter = 0; |
| #endif |
| |
| for (;;) { |
| opcode = self->trace[pc].opcode; |
| oparg = self->trace[pc].oparg; |
| operand = self->trace[pc].operand; |
| DPRINTF(3, |
| "%4d: uop %s, oparg %d, operand %" PRIu64 ", stack_level %d\n", |
| pc, |
| opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode], |
| oparg, |
| operand, |
| (int)(stack_pointer - _PyFrame_Stackbase(frame))); |
| pc++; |
| OPT_STAT_INC(uops_executed); |
| UOP_EXE_INC(opcode); |
| #ifdef Py_STATS |
| trace_uop_execution_counter++; |
| #endif |
| |
| switch (opcode) { |
| |
| #include "executor_cases.c.h" |
| |
| default: |
| { |
| fprintf(stderr, "Unknown uop %d, operand %" PRIu64 "\n", opcode, operand); |
| Py_FatalError("Unknown uop"); |
| } |
| |
| } |
| } |
| |
| unbound_local_error: |
| _PyEval_FormatExcCheckArg(tstate, PyExc_UnboundLocalError, |
| UNBOUNDLOCAL_ERROR_MSG, |
| PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) |
| ); |
| goto error; |
| |
| pop_4_error: |
| STACK_SHRINK(1); |
| pop_3_error: |
| STACK_SHRINK(1); |
| pop_2_error: |
| STACK_SHRINK(1); |
| pop_1_error: |
| STACK_SHRINK(1); |
| error: |
| // On ERROR_IF we return NULL as the frame. |
| // The caller recovers the frame from tstate->current_frame. |
| DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); |
| OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); |
| _PyFrame_SetStackPointer(frame, stack_pointer); |
| Py_DECREF(self); |
| return NULL; |
| |
| 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->prev_instr--; // Back up to just before destination |
| _PyFrame_SetStackPointer(frame, stack_pointer); |
| Py_DECREF(self); |
| return frame; |
| } |