Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 68532) +++ Python/ceval.c (working copy) @@ -702,6 +702,102 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag char *filename; #endif +/* Computed GOTOs, or + the-optimization-commonly-but-improperly-known-as-"threaded code" + using gcc's labels-as-values extension + (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html). + + The traditional bytecode evaluation loop uses a "switch" statement, which + decent compilers will optimize as a single indirect branch instruction + combined with a lookup table of jump addresses. However, since the + indirect jump instruction is shared by all opcodes, the CPU will have a + hard time making the right prediction for where to jump next (actually, + it will be always wrong except in the uncommon case of a sequence of + several identical opcodes). + + "Threaded code" in contrast, uses an explicit jump table and an explicit + indirect jump instruction at the end of each opcode. Since the jump + instruction is at a different address for each opcode, the CPU will make a + separate prediction for each of these instructions, which is equivalent to + predicting the second opcode of each opcode pair. These predictions have + a much better chance to turn out valid, especially in small bytecode loops. + + A mispredicted branch on a modern CPU flushes the whole pipeline and + can cost several CPU cycles (depending on the pipeline depth), + and potentially many more instructions (depending on the pipeline width). + A correctly predicted branch, however, is nearly free. + + At the time of this writing, the "threaded code" version is up to 15-20% + faster than the normal "switch" version, depending on the compiler and the + CPU architecture. + + We enable the optimization on compilers that are known to support it, but + disable it if LLTRACE or DYNAMIC_EXECUTION_PROFILE is defined, because + it would render the measurements invalid. + + + NOTE: care must be taken that the compiler doesn't try to "optimize" the + indirect jumps by sharing them between all opcodes. If needed, gcc has a + dedicated flag for that, "-fno-crossjumping". +*/ + +#if (defined(__GNUC__) || defined (__SUNPRO_C)) \ + && !defined(DYNAMIC_EXECUTION_PROFILE) \ + && !defined(LLTRACE) +#define USE_COMPUTED_GOTOS +#endif + +#ifdef USE_COMPUTED_GOTOS +/* Import the static jump table */ +#include "opcode_targets.h" + +/* This macro is used when several opcodes defer to the same implementation + (e.g. SETUP_LOOP, SETUP_FINALLY) */ +#define TARGET_WITH_IMPL(op, impl) \ + TARGET_##op: \ + opcode = op; \ + if (HAS_ARG(op)) \ + oparg = NEXTARG(); \ + case op: \ + goto impl; \ + +#define TARGET(op) \ + TARGET_##op: \ + opcode = op; \ + if (HAS_ARG(op)) \ + oparg = NEXTARG(); \ + case op: + + +#define DISPATCH() \ + { \ + /* Avoid multiple loads from _Py_Ticker despite `volatile` */ \ + int _tick = _Py_Ticker - 1; \ + _Py_Ticker = _tick; \ + if (_tick >= 0) { \ + FAST_DISPATCH(); \ + } \ + continue; \ + } +#define FAST_DISPATCH() \ + { \ + if (!_Py_TracingPossible) { \ + f->f_lasti = INSTR_OFFSET(); \ + goto *opcode_targets[*next_instr++]; \ + } \ + goto fast_next_opcode; \ + } + +#else +#define TARGET(op) \ + case op: +#define TARGET_WITH_IMPL(op, impl) \ + case op: +#define DISPATCH() continue +#define FAST_DISPATCH() goto fast_next_opcode +#endif + + /* Tuple access macros */ #ifndef Py_DEBUG @@ -780,17 +876,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag predictions turned-on and interpret the results as if some opcodes had been combined or turn-off predictions so that the opcode frequency counter updates for both opcodes. + + Opcode prediction is disabled with threaded code, since the latter allows + the CPU to record separate branch prediction information for each + opcode. + */ -#ifdef DYNAMIC_EXECUTION_PROFILE +#if defined(DYNAMIC_EXECUTION_PROFILE) || defined(USE_COMPUTED_GOTOS) #define PREDICT(op) if (0) goto PRED_##op +#define PREDICTED(op) PRED_##op: +#define PREDICTED_WITH_ARG(op) PRED_##op: #else #define PREDICT(op) if (*next_instr == op) goto PRED_##op -#endif - #define PREDICTED(op) PRED_##op: next_instr++ #define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 +#endif + /* Stack manipulation macros */ /* The stack can grow at most MAXINT deep, as co_nlocals and @@ -1082,56 +1185,56 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag /* case STOP_CODE: this is an error! */ - case NOP: - goto fast_next_opcode; + TARGET(NOP) + FAST_DISPATCH(); - case LOAD_FAST: + TARGET(LOAD_FAST) x = GETLOCAL(oparg); if (x != NULL) { Py_INCREF(x); PUSH(x); - goto fast_next_opcode; + FAST_DISPATCH(); } format_exc_check_arg(PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(co->co_varnames, oparg)); break; - case LOAD_CONST: + TARGET(LOAD_CONST) x = GETITEM(consts, oparg); Py_INCREF(x); PUSH(x); - goto fast_next_opcode; + FAST_DISPATCH(); PREDICTED_WITH_ARG(STORE_FAST); - case STORE_FAST: + TARGET(STORE_FAST) v = POP(); SETLOCAL(oparg, v); - goto fast_next_opcode; + FAST_DISPATCH(); PREDICTED(POP_TOP); - case POP_TOP: + TARGET(POP_TOP) v = POP(); Py_DECREF(v); - goto fast_next_opcode; + FAST_DISPATCH(); - case ROT_TWO: + TARGET(ROT_TWO) v = TOP(); w = SECOND(); SET_TOP(w); SET_SECOND(v); - goto fast_next_opcode; + FAST_DISPATCH(); - case ROT_THREE: + TARGET(ROT_THREE) v = TOP(); w = SECOND(); x = THIRD(); SET_TOP(w); SET_SECOND(x); SET_THIRD(v); - goto fast_next_opcode; + FAST_DISPATCH(); - case ROT_FOUR: + TARGET(ROT_FOUR) u = TOP(); v = SECOND(); w = THIRD(); @@ -1140,15 +1243,15 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag SET_SECOND(w); SET_THIRD(x); SET_FOURTH(u); - goto fast_next_opcode; + FAST_DISPATCH(); - case DUP_TOP: + TARGET(DUP_TOP) v = TOP(); Py_INCREF(v); PUSH(v); - goto fast_next_opcode; + FAST_DISPATCH(); - case DUP_TOPX: + TARGET(DUP_TOPX) if (oparg == 2) { x = TOP(); Py_INCREF(x); @@ -1157,7 +1260,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag STACKADJ(2); SET_TOP(x); SET_SECOND(w); - goto fast_next_opcode; + FAST_DISPATCH(); } else if (oparg == 3) { x = TOP(); Py_INCREF(x); @@ -1169,84 +1272,84 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag SET_TOP(x); SET_SECOND(w); SET_THIRD(v); - goto fast_next_opcode; + FAST_DISPATCH(); } Py_FatalError("invalid argument to DUP_TOPX" " (bytecode corruption?)"); /* Never returns, so don't bother to set why. */ break; - case UNARY_POSITIVE: + TARGET(UNARY_POSITIVE) v = TOP(); x = PyNumber_Positive(v); Py_DECREF(v); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case UNARY_NEGATIVE: + TARGET(UNARY_NEGATIVE) v = TOP(); x = PyNumber_Negative(v); Py_DECREF(v); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case UNARY_NOT: + TARGET(UNARY_NOT) v = TOP(); err = PyObject_IsTrue(v); Py_DECREF(v); if (err == 0) { Py_INCREF(Py_True); SET_TOP(Py_True); - continue; + DISPATCH(); } else if (err > 0) { Py_INCREF(Py_False); SET_TOP(Py_False); err = 0; - continue; + DISPATCH(); } STACKADJ(-1); break; - case UNARY_CONVERT: + TARGET(UNARY_CONVERT) v = TOP(); x = PyObject_Repr(v); Py_DECREF(v); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case UNARY_INVERT: + TARGET(UNARY_INVERT) v = TOP(); x = PyNumber_Invert(v); Py_DECREF(v); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_POWER: + TARGET(BINARY_POWER) w = POP(); v = TOP(); x = PyNumber_Power(v, w, Py_None); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_MULTIPLY: + TARGET(BINARY_MULTIPLY) w = POP(); v = TOP(); x = PyNumber_Multiply(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_DIVIDE: + TARGET(BINARY_DIVIDE) if (!_Py_QnewFlag) { w = POP(); v = TOP(); @@ -1254,42 +1357,42 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; } /* -Qnew is in effect: fall through to BINARY_TRUE_DIVIDE */ - case BINARY_TRUE_DIVIDE: + TARGET(BINARY_TRUE_DIVIDE) w = POP(); v = TOP(); x = PyNumber_TrueDivide(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_FLOOR_DIVIDE: + TARGET(BINARY_FLOOR_DIVIDE) w = POP(); v = TOP(); x = PyNumber_FloorDivide(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_MODULO: + TARGET(BINARY_MODULO) w = POP(); v = TOP(); x = PyNumber_Remainder(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_ADD: + TARGET(BINARY_ADD) w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1316,10 +1419,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag skip_decref_vx: Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_SUBTRACT: + TARGET(BINARY_SUBTRACT) w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1339,10 +1442,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_SUBSCR: + TARGET(BINARY_SUBSCR) w = POP(); v = TOP(); if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1363,91 +1466,91 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_LSHIFT: + TARGET(BINARY_LSHIFT) w = POP(); v = TOP(); x = PyNumber_Lshift(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_RSHIFT: + TARGET(BINARY_RSHIFT) w = POP(); v = TOP(); x = PyNumber_Rshift(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_AND: + TARGET(BINARY_AND) w = POP(); v = TOP(); x = PyNumber_And(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_XOR: + TARGET(BINARY_XOR) w = POP(); v = TOP(); x = PyNumber_Xor(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case BINARY_OR: + TARGET(BINARY_OR) w = POP(); v = TOP(); x = PyNumber_Or(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case LIST_APPEND: + TARGET(LIST_APPEND) w = POP(); v = stack_pointer[-oparg]; err = PyList_Append(v, w); Py_DECREF(w); if (err == 0) { PREDICT(JUMP_ABSOLUTE); - continue; + DISPATCH(); } break; - case INPLACE_POWER: + TARGET(INPLACE_POWER) w = POP(); v = TOP(); x = PyNumber_InPlacePower(v, w, Py_None); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_MULTIPLY: + TARGET(INPLACE_MULTIPLY) w = POP(); v = TOP(); x = PyNumber_InPlaceMultiply(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_DIVIDE: + TARGET(INPLACE_DIVIDE) if (!_Py_QnewFlag) { w = POP(); v = TOP(); @@ -1455,42 +1558,42 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; } /* -Qnew is in effect: fall through to INPLACE_TRUE_DIVIDE */ - case INPLACE_TRUE_DIVIDE: + TARGET(INPLACE_TRUE_DIVIDE) w = POP(); v = TOP(); x = PyNumber_InPlaceTrueDivide(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_FLOOR_DIVIDE: + TARGET(INPLACE_FLOOR_DIVIDE) w = POP(); v = TOP(); x = PyNumber_InPlaceFloorDivide(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_MODULO: + TARGET(INPLACE_MODULO) w = POP(); v = TOP(); x = PyNumber_InPlaceRemainder(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_ADD: + TARGET(INPLACE_ADD) w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1517,10 +1620,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag skip_decref_v: Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_SUBTRACT: + TARGET(INPLACE_SUBTRACT) w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1540,63 +1643,64 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_LSHIFT: + TARGET(INPLACE_LSHIFT) w = POP(); v = TOP(); x = PyNumber_InPlaceLshift(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_RSHIFT: + TARGET(INPLACE_RSHIFT) w = POP(); v = TOP(); x = PyNumber_InPlaceRshift(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_AND: + TARGET(INPLACE_AND) w = POP(); v = TOP(); x = PyNumber_InPlaceAnd(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_XOR: + TARGET(INPLACE_XOR) w = POP(); v = TOP(); x = PyNumber_InPlaceXor(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case INPLACE_OR: + TARGET(INPLACE_OR) w = POP(); v = TOP(); x = PyNumber_InPlaceOr(v, w); Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case SLICE+0: - case SLICE+1: - case SLICE+2: - case SLICE+3: + TARGET_WITH_IMPL(SLICE, _slice) + TARGET_WITH_IMPL(SLICE_1, _slice) + TARGET_WITH_IMPL(SLICE_2, _slice) + TARGET_WITH_IMPL(SLICE_3, _slice) + _slice: if ((opcode-SLICE) & 2) w = POP(); else @@ -1611,13 +1715,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_XDECREF(v); Py_XDECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case STORE_SLICE+0: - case STORE_SLICE+1: - case STORE_SLICE+2: - case STORE_SLICE+3: + TARGET_WITH_IMPL(STORE_SLICE, _store_slice) + TARGET_WITH_IMPL(STORE_SLICE_1, _store_slice) + TARGET_WITH_IMPL(STORE_SLICE_2, _store_slice) + TARGET_WITH_IMPL(STORE_SLICE_3, _store_slice) + _store_slice: if ((opcode-STORE_SLICE) & 2) w = POP(); else @@ -1633,13 +1738,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(u); Py_XDECREF(v); Py_XDECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case DELETE_SLICE+0: - case DELETE_SLICE+1: - case DELETE_SLICE+2: - case DELETE_SLICE+3: + TARGET_WITH_IMPL(DELETE_SLICE, _delete_slice) + TARGET_WITH_IMPL(DELETE_SLICE_1, _delete_slice) + TARGET_WITH_IMPL(DELETE_SLICE_2, _delete_slice) + TARGET_WITH_IMPL(DELETE_SLICE_3, _delete_slice) + _delete_slice: if ((opcode-DELETE_SLICE) & 2) w = POP(); else @@ -1654,10 +1760,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(u); Py_XDECREF(v); Py_XDECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case STORE_SUBSCR: + TARGET(STORE_SUBSCR) w = TOP(); v = SECOND(); u = THIRD(); @@ -1667,10 +1773,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(u); Py_DECREF(v); Py_DECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case DELETE_SUBSCR: + TARGET(DELETE_SUBSCR) w = TOP(); v = SECOND(); STACKADJ(-2); @@ -1678,10 +1784,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag err = PyObject_DelItem(v, w); Py_DECREF(v); Py_DECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case PRINT_EXPR: + TARGET(PRINT_EXPR) v = POP(); w = PySys_GetObject("displayhook"); if (w == NULL) { @@ -1705,11 +1811,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_XDECREF(x); break; - case PRINT_ITEM_TO: + TARGET(PRINT_ITEM_TO) w = stream = POP(); /* fall through to PRINT_ITEM */ - case PRINT_ITEM: + TARGET(PRINT_ITEM) v = POP(); if (stream == NULL || stream == Py_None) { w = PySys_GetObject("stdout"); @@ -1756,14 +1862,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_XDECREF(stream); stream = NULL; if (err == 0) - continue; + DISPATCH(); break; - case PRINT_NEWLINE_TO: + TARGET(PRINT_NEWLINE_TO) w = stream = POP(); /* fall through to PRINT_NEWLINE */ - case PRINT_NEWLINE: + TARGET(PRINT_NEWLINE) if (stream == NULL || stream == Py_None) { w = PySys_GetObject("stdout"); if (w == NULL) { @@ -1789,7 +1895,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag #ifdef CASE_TOO_BIG default: switch (opcode) { #endif - case RAISE_VARARGS: + TARGET(RAISE_VARARGS) u = v = w = NULL; switch (oparg) { case 3: @@ -1811,27 +1917,27 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag } break; - case LOAD_LOCALS: + TARGET(LOAD_LOCALS) if ((x = f->f_locals) != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } PyErr_SetString(PyExc_SystemError, "no locals"); break; - case RETURN_VALUE: + TARGET(RETURN_VALUE) retval = POP(); why = WHY_RETURN; goto fast_block_end; - case YIELD_VALUE: + TARGET(YIELD_VALUE) retval = POP(); f->f_stacktop = stack_pointer; why = WHY_YIELD; goto fast_yield; - case EXEC_STMT: + TARGET(EXEC_STMT) w = TOP(); v = SECOND(); u = THIRD(); @@ -1844,7 +1950,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(w); break; - case POP_BLOCK: + TARGET(POP_BLOCK) { PyTryBlock *b = PyFrame_BlockPop(f); while (STACK_LEVEL() > b->b_level) { @@ -1852,10 +1958,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); } } - continue; + DISPATCH(); PREDICTED(END_FINALLY); - case END_FINALLY: + TARGET(END_FINALLY) v = POP(); if (PyInt_Check(v)) { why = (enum why_code) PyInt_AS_LONG(v); @@ -1880,7 +1986,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); break; - case BUILD_CLASS: + TARGET(BUILD_CLASS) u = TOP(); v = SECOND(); w = THIRD(); @@ -1892,7 +1998,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(w); break; - case STORE_NAME: + TARGET(STORE_NAME) w = GETITEM(names, oparg); v = POP(); if ((x = f->f_locals) != NULL) { @@ -1901,7 +2007,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag else err = PyObject_SetItem(x, w, v); Py_DECREF(v); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; } PyErr_Format(PyExc_SystemError, @@ -1909,7 +2015,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PyObject_REPR(w)); break; - case DELETE_NAME: + TARGET(DELETE_NAME) w = GETITEM(names, oparg); if ((x = f->f_locals) != NULL) { if ((err = PyObject_DelItem(x, w)) != 0) @@ -1924,7 +2030,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag break; PREDICTED_WITH_ARG(UNPACK_SEQUENCE); - case UNPACK_SEQUENCE: + TARGET(UNPACK_SEQUENCE) v = POP(); if (PyTuple_CheckExact(v) && PyTuple_GET_SIZE(v) == oparg) { @@ -1936,7 +2042,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PUSH(w); } Py_DECREF(v); - continue; + DISPATCH(); } else if (PyList_CheckExact(v) && PyList_GET_SIZE(v) == oparg) { PyObject **items = \ @@ -1956,7 +2062,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); break; - case STORE_ATTR: + TARGET(STORE_ATTR) w = GETITEM(names, oparg); v = TOP(); u = SECOND(); @@ -1964,10 +2070,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag err = PyObject_SetAttr(v, w, u); /* v.w = u */ Py_DECREF(v); Py_DECREF(u); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case DELETE_ATTR: + TARGET(DELETE_ATTR) w = GETITEM(names, oparg); v = POP(); err = PyObject_SetAttr(v, w, (PyObject *)NULL); @@ -1975,22 +2081,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); break; - case STORE_GLOBAL: + TARGET(STORE_GLOBAL) w = GETITEM(names, oparg); v = POP(); err = PyDict_SetItem(f->f_globals, w, v); Py_DECREF(v); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case DELETE_GLOBAL: + TARGET(DELETE_GLOBAL) w = GETITEM(names, oparg); if ((err = PyDict_DelItem(f->f_globals, w)) != 0) format_exc_check_arg( PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w); break; - case LOAD_NAME: + TARGET(LOAD_NAME) w = GETITEM(names, oparg); if ((v = f->f_locals) == NULL) { PyErr_Format(PyExc_SystemError, @@ -2026,9 +2132,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_INCREF(x); } PUSH(x); - continue; + DISPATCH(); - case LOAD_GLOBAL: + TARGET(LOAD_GLOBAL) w = GETITEM(names, oparg); if (PyString_CheckExact(w)) { /* Inline the PyDict_GetItem() calls. @@ -2048,7 +2154,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } d = (PyDictObject *)(f->f_builtins); e = d->ma_lookup(d, w, hash); @@ -2060,7 +2166,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } goto load_global_error; } @@ -2079,13 +2185,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag } Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); - case DELETE_FAST: + TARGET(DELETE_FAST) x = GETLOCAL(oparg); if (x != NULL) { SETLOCAL(oparg, NULL); - continue; + DISPATCH(); } format_exc_check_arg( PyExc_UnboundLocalError, @@ -2094,19 +2200,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag ); break; - case LOAD_CLOSURE: + TARGET(LOAD_CLOSURE) x = freevars[oparg]; Py_INCREF(x); PUSH(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case LOAD_DEREF: + TARGET(LOAD_DEREF) x = freevars[oparg]; w = PyCell_Get(x); if (w != NULL) { PUSH(w); - continue; + DISPATCH(); } err = -1; /* Don't stomp existing exception */ @@ -2127,14 +2233,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag } break; - case STORE_DEREF: + TARGET(STORE_DEREF) w = POP(); x = freevars[oparg]; PyCell_Set(x, w); Py_DECREF(w); - continue; + DISPATCH(); - case BUILD_TUPLE: + TARGET(BUILD_TUPLE) x = PyTuple_New(oparg); if (x != NULL) { for (; --oparg >= 0;) { @@ -2142,11 +2248,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PyTuple_SET_ITEM(x, oparg, w); } PUSH(x); - continue; + DISPATCH(); } break; - case BUILD_LIST: + TARGET(BUILD_LIST) x = PyList_New(oparg); if (x != NULL) { for (; --oparg >= 0;) { @@ -2154,17 +2260,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PyList_SET_ITEM(x, oparg, w); } PUSH(x); - continue; + DISPATCH(); } break; - case BUILD_MAP: + TARGET(BUILD_MAP) x = _PyDict_NewPresized((Py_ssize_t)oparg); PUSH(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case STORE_MAP: + TARGET(STORE_MAP) w = TOP(); /* key */ u = SECOND(); /* value */ v = THIRD(); /* dict */ @@ -2173,19 +2279,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag err = PyDict_SetItem(v, w, u); /* v[w] = u */ Py_DECREF(u); Py_DECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case LOAD_ATTR: + TARGET(LOAD_ATTR) w = GETITEM(names, oparg); v = TOP(); x = PyObject_GetAttr(v, w); Py_DECREF(v); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case COMPARE_OP: + TARGET(COMPARE_OP) w = POP(); v = TOP(); if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) { @@ -2218,9 +2324,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag if (x == NULL) break; PREDICT(JUMP_IF_FALSE); PREDICT(JUMP_IF_TRUE); - continue; + DISPATCH(); - case IMPORT_NAME: + TARGET(IMPORT_NAME) w = GETITEM(names, oparg); x = PyDict_GetItemString(f->f_builtins, "__import__"); if (x == NULL) { @@ -2261,10 +2367,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag READ_TIMESTAMP(intr1); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case IMPORT_STAR: + TARGET(IMPORT_STAR) v = POP(); PyFrame_FastToLocals(f); if ((x = f->f_locals) == NULL) { @@ -2277,33 +2383,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag READ_TIMESTAMP(intr1); PyFrame_LocalsToFast(f, 0); Py_DECREF(v); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - case IMPORT_FROM: + TARGET(IMPORT_FROM) w = GETITEM(names, oparg); v = TOP(); READ_TIMESTAMP(intr0); x = import_from(v, w); READ_TIMESTAMP(intr1); PUSH(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case JUMP_FORWARD: + TARGET(JUMP_FORWARD) JUMPBY(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); PREDICTED_WITH_ARG(JUMP_IF_FALSE); - case JUMP_IF_FALSE: + TARGET(JUMP_IF_FALSE) w = TOP(); if (w == Py_True) { PREDICT(POP_TOP); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_False) { JUMPBY(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); if (err > 0) @@ -2312,18 +2418,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag JUMPBY(oparg); else break; - continue; + DISPATCH(); PREDICTED_WITH_ARG(JUMP_IF_TRUE); - case JUMP_IF_TRUE: + TARGET(JUMP_IF_TRUE) w = TOP(); if (w == Py_False) { PREDICT(POP_TOP); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_True) { JUMPBY(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); if (err > 0) { @@ -2334,10 +2440,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag ; else break; - continue; + DISPATCH(); PREDICTED_WITH_ARG(JUMP_ABSOLUTE); - case JUMP_ABSOLUTE: + TARGET(JUMP_ABSOLUTE) JUMPTO(oparg); #if FAST_LOOPS /* Enabling this path speeds-up all while and for-loops by bypassing @@ -2345,14 +2451,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag because it prevents detection of a control-break in tight loops like "while 1: pass". Compile with this option turned-on when you need the speed-up and do not need break checking inside tight loops (ones - that contain only instructions ending with goto fast_next_opcode). + that contain only instructions ending with FAST_DISPATCH). */ - goto fast_next_opcode; + FAST_DISPATCH(); #else - continue; + DISPATCH(); #endif - case GET_ITER: + TARGET(GET_ITER) /* before: [obj]; after [getiter(obj)] */ v = TOP(); x = PyObject_GetIter(v); @@ -2360,13 +2466,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag if (x != NULL) { SET_TOP(x); PREDICT(FOR_ITER); - continue; + DISPATCH(); } STACKADJ(-1); break; PREDICTED_WITH_ARG(FOR_ITER); - case FOR_ITER: + TARGET(FOR_ITER) /* before: [iter]; after: [iter, iter()] *or* [] */ v = TOP(); x = (*v->ob_type->tp_iternext)(v); @@ -2374,7 +2480,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PUSH(x); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); - continue; + DISPATCH(); } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches( @@ -2386,13 +2492,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag x = v = POP(); Py_DECREF(v); JUMPBY(oparg); - continue; + DISPATCH(); - case BREAK_LOOP: + TARGET(BREAK_LOOP) why = WHY_BREAK; goto fast_block_end; - case CONTINUE_LOOP: + TARGET(CONTINUE_LOOP) retval = PyInt_FromLong(oparg); if (!retval) { x = NULL; @@ -2401,9 +2507,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag why = WHY_CONTINUE; goto fast_block_end; - case SETUP_LOOP: - case SETUP_EXCEPT: - case SETUP_FINALLY: + TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally) + TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally) + TARGET(SETUP_FINALLY) + _setup_finally: /* NOTE: If you add any new block-setup opcodes that are not try/except/finally handlers, you may need to update the PyGen_NeedsFinalizing() function. @@ -2411,9 +2518,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); - continue; + DISPATCH(); - case WITH_CLEANUP: + TARGET(WITH_CLEANUP) { /* At the top of the stack are 1-3 values indicating how/why we entered the finally clause: @@ -2501,7 +2608,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag break; } - case CALL_FUNCTION: + TARGET(CALL_FUNCTION) { PyObject **sp; PCALL(PCALL_ALL); @@ -2514,13 +2621,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag stack_pointer = sp; PUSH(x); if (x != NULL) - continue; + DISPATCH(); break; } - case CALL_FUNCTION_VAR: - case CALL_FUNCTION_KW: - case CALL_FUNCTION_VAR_KW: + TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw) + TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw) + TARGET(CALL_FUNCTION_VAR_KW) + _call_function_var_kw: { int na = oparg & 0xff; int nk = (oparg>>8) & 0xff; @@ -2560,11 +2668,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag } PUSH(x); if (x != NULL) - continue; + DISPATCH(); break; } - case MAKE_FUNCTION: + TARGET(MAKE_FUNCTION) v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); Py_DECREF(v); @@ -2586,7 +2694,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag PUSH(x); break; - case MAKE_CLOSURE: + TARGET(MAKE_CLOSURE) { v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); @@ -2621,7 +2729,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag break; } - case BUILD_SLICE: + TARGET(BUILD_SLICE) if (oparg == 3) w = POP(); else @@ -2633,14 +2741,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag Py_DECREF(v); Py_XDECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - case EXTENDED_ARG: + TARGET(EXTENDED_ARG) opcode = NEXTOP(); oparg = oparg<<16 | NEXTARG(); goto dispatch_opcode; +#ifdef USE_COMPUTED_GOTOS + _unknown_opcode: +#endif default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", Index: Python/makeopcodetargets.py =================================================================== --- Python/makeopcodetargets.py (revision 0) +++ Python/makeopcodetargets.py (revision 68407) @@ -0,0 +1,44 @@ +#! /usr/bin/env python +"""Generate C code for the jump table of the threaded code interpreter +(GCC only). +""" + +import imp +import os + + +def find_module(modname): + """Finds and returns a module in the local dist/checkout. + """ + modpath = os.path.join( + os.path.dirname(os.path.dirname(__file__)), "Lib") + return imp.load_module(modname, *imp.find_module(modname, [modpath])) + +def write_contents(f): + """Write C code contents to the target file object. + """ + opcode = find_module("opcode") + targets = ['_unknown_opcode'] * 256 + for opname, op in opcode.opmap.items(): + if opname == "STOP_CODE": + # XXX opcode not implemented + continue + targets[op] = "TARGET_%s" % opname + f.write("static void *opcode_targets[256] = {\n") + f.write(",\n".join("\t&&%s" % s for s in targets)) + f.write("\n};\n") + + +if __name__ == "__main__": + import sys + assert len(sys.argv) < 3, "Too many arguments" + if len(sys.argv) == 2: + target = sys.argv[1] + else: + target = "Python/opcode_targets.h" + f = open(target, "w") + try: + write_contents(f) + finally: + f.close() + Index: Python/opcode_targets.h =================================================================== --- Python/opcode_targets.h (revision 0) +++ Python/opcode_targets.h (revision 68407) @@ -0,0 +1,258 @@ +static void *opcode_targets[256] = { + &&_unknown_opcode, + &&TARGET_POP_TOP, + &&TARGET_ROT_TWO, + &&TARGET_ROT_THREE, + &&TARGET_DUP_TOP, + &&TARGET_ROT_FOUR, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_NOP, + &&TARGET_UNARY_POSITIVE, + &&TARGET_UNARY_NEGATIVE, + &&TARGET_UNARY_NOT, + &&TARGET_UNARY_CONVERT, + &&_unknown_opcode, + &&TARGET_UNARY_INVERT, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_LIST_APPEND, + &&TARGET_BINARY_POWER, + &&TARGET_BINARY_MULTIPLY, + &&TARGET_BINARY_DIVIDE, + &&TARGET_BINARY_MODULO, + &&TARGET_BINARY_ADD, + &&TARGET_BINARY_SUBTRACT, + &&TARGET_BINARY_SUBSCR, + &&TARGET_BINARY_FLOOR_DIVIDE, + &&TARGET_BINARY_TRUE_DIVIDE, + &&TARGET_INPLACE_FLOOR_DIVIDE, + &&TARGET_INPLACE_TRUE_DIVIDE, + &&TARGET_SLICE, + &&TARGET_SLICE_1, + &&TARGET_SLICE_2, + &&TARGET_SLICE_3, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_STORE_SLICE, + &&TARGET_STORE_SLICE_1, + &&TARGET_STORE_SLICE_2, + &&TARGET_STORE_SLICE_3, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_DELETE_SLICE, + &&TARGET_DELETE_SLICE_1, + &&TARGET_DELETE_SLICE_2, + &&TARGET_DELETE_SLICE_3, + &&TARGET_STORE_MAP, + &&TARGET_INPLACE_ADD, + &&TARGET_INPLACE_SUBTRACT, + &&TARGET_INPLACE_MULTIPLY, + &&TARGET_INPLACE_DIVIDE, + &&TARGET_INPLACE_MODULO, + &&TARGET_STORE_SUBSCR, + &&TARGET_DELETE_SUBSCR, + &&TARGET_BINARY_LSHIFT, + &&TARGET_BINARY_RSHIFT, + &&TARGET_BINARY_AND, + &&TARGET_BINARY_XOR, + &&TARGET_BINARY_OR, + &&TARGET_INPLACE_POWER, + &&TARGET_GET_ITER, + &&_unknown_opcode, + &&TARGET_PRINT_EXPR, + &&TARGET_PRINT_ITEM, + &&TARGET_PRINT_NEWLINE, + &&TARGET_PRINT_ITEM_TO, + &&TARGET_PRINT_NEWLINE_TO, + &&TARGET_INPLACE_LSHIFT, + &&TARGET_INPLACE_RSHIFT, + &&TARGET_INPLACE_AND, + &&TARGET_INPLACE_XOR, + &&TARGET_INPLACE_OR, + &&TARGET_BREAK_LOOP, + &&TARGET_WITH_CLEANUP, + &&TARGET_LOAD_LOCALS, + &&TARGET_RETURN_VALUE, + &&TARGET_IMPORT_STAR, + &&TARGET_EXEC_STMT, + &&TARGET_YIELD_VALUE, + &&TARGET_POP_BLOCK, + &&TARGET_END_FINALLY, + &&TARGET_BUILD_CLASS, + &&TARGET_STORE_NAME, + &&TARGET_DELETE_NAME, + &&TARGET_UNPACK_SEQUENCE, + &&TARGET_FOR_ITER, + &&TARGET_LIST_APPEND, + &&TARGET_STORE_ATTR, + &&TARGET_DELETE_ATTR, + &&TARGET_STORE_GLOBAL, + &&TARGET_DELETE_GLOBAL, + &&TARGET_DUP_TOPX, + &&TARGET_LOAD_CONST, + &&TARGET_LOAD_NAME, + &&TARGET_BUILD_TUPLE, + &&TARGET_BUILD_LIST, + &&TARGET_BUILD_MAP, + &&TARGET_LOAD_ATTR, + &&TARGET_COMPARE_OP, + &&TARGET_IMPORT_NAME, + &&TARGET_IMPORT_FROM, + &&_unknown_opcode, + &&TARGET_JUMP_FORWARD, + &&TARGET_JUMP_IF_FALSE, + &&TARGET_JUMP_IF_TRUE, + &&TARGET_JUMP_ABSOLUTE, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_LOAD_GLOBAL, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_CONTINUE_LOOP, + &&TARGET_SETUP_LOOP, + &&TARGET_SETUP_EXCEPT, + &&TARGET_SETUP_FINALLY, + &&_unknown_opcode, + &&TARGET_LOAD_FAST, + &&TARGET_STORE_FAST, + &&TARGET_DELETE_FAST, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_RAISE_VARARGS, + &&TARGET_CALL_FUNCTION, + &&TARGET_MAKE_FUNCTION, + &&TARGET_BUILD_SLICE, + &&TARGET_MAKE_CLOSURE, + &&TARGET_LOAD_CLOSURE, + &&TARGET_LOAD_DEREF, + &&TARGET_STORE_DEREF, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_CALL_FUNCTION_VAR, + &&TARGET_CALL_FUNCTION_KW, + &&TARGET_CALL_FUNCTION_VAR_KW, + &&TARGET_EXTENDED_ARG, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode +}; Index: Include/opcode.h =================================================================== --- Include/opcode.h (revision 68532) +++ Include/opcode.h (working copy) @@ -37,12 +37,21 @@ extern "C" { #define SLICE 30 /* Also uses 31-33 */ +#define SLICE_1 31 +#define SLICE_2 32 +#define SLICE_3 33 #define STORE_SLICE 40 /* Also uses 41-43 */ +#define STORE_SLICE_1 41 +#define STORE_SLICE_2 42 +#define STORE_SLICE_3 43 #define DELETE_SLICE 50 /* Also uses 51-53 */ +#define DELETE_SLICE_1 51 +#define DELETE_SLICE_2 52 +#define DELETE_SLICE_3 53 #define STORE_MAP 54 #define INPLACE_ADD 55 Index: Makefile.pre.in =================================================================== --- Makefile.pre.in (revision 68532) +++ Makefile.pre.in (working copy) @@ -248,6 +248,16 @@ ASDLGEN= $(srcdir)/Parser/asdl_c.py ########################################################################## # Python + +OPCODETARGETS_H= \ + $(srcdir)/Python/opcode_targets.h + +OPCODETARGETGEN= \ + $(srcdir)/Python/makeopcodetargets.py + +OPCODETARGETGEN_FILES= \ + $(OPCODETARGETGEN) $(srcdir)/Lib/opcode.py + PYTHON_OBJS= \ Python/_warnings.o \ Python/Python-ast.o \ @@ -567,6 +577,11 @@ Objects/unicodeobject.o: $(srcdir)/Objects/unicode Objects/stringobject.o: $(srcdir)/Objects/stringobject.c \ $(STRINGLIB_HEADERS) +$(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) + $(OPCODETARGETGEN) $(OPCODETARGETS_H) + +Python/ceval.o: $(OPCODETARGETS_H) + Python/formatter_unicode.o: $(srcdir)/Python/formatter_unicode.c \ $(STRINGLIB_HEADERS)