summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c156
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