--- Python-2.5.4/Python/ceval.c.threaded 2008-12-10 18:23:20.000000000 +0100 +++ Python-2.5.4/Python/ceval.c 2009-01-21 13:36:28.000000000 +0100 @@ -569,6 +569,113 @@ 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 disable the optimization if 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(USE_COMPUTED_GOTOS) && defined(DYNAMIC_EXECUTION_PROFILE) +#undef 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; \ + } + +#ifdef LLTRACE +#define FAST_DISPATCH() \ + { \ + if (!lltrace && tstate->c_tracefunc == NULL) { \ + f->f_lasti = INSTR_OFFSET(); \ + goto *opcode_targets[*next_instr++]; \ + } \ + goto fast_next_opcode; \ + } +#else +#define FAST_DISPATCH() \ + { \ + if (tstate->c_tracefunc == NULL) { \ + f->f_lasti = INSTR_OFFSET(); \ + goto *opcode_targets[*next_instr++]; \ + } \ + goto fast_next_opcode; \ + } +#endif + +#else +#define TARGET(op) \ + case op: +#define TARGET_WITH_IMPL(op, impl) \ + /* silence compiler warnings about `impl` unused */ \ + if (0) goto impl; \ + case op: +#define DISPATCH() continue +#define FAST_DISPATCH() goto fast_next_opcode +#endif + + /* Tuple access macros */ #ifndef Py_DEBUG @@ -647,14 +754,16 @@ the opcode frequency counter updates). */ -#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 */ @@ -934,56 +1043,56 @@ /* 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(); @@ -992,15 +1101,15 @@ 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); @@ -1009,7 +1118,7 @@ STACKADJ(2); SET_TOP(x); SET_SECOND(w); - goto fast_next_opcode; + FAST_DISPATCH(); } else if (oparg == 3) { x = TOP(); Py_INCREF(x); @@ -1021,84 +1130,84 @@ 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(); @@ -1106,42 +1215,42 @@ 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)) { @@ -1168,10 +1277,10 @@ 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)) { @@ -1191,10 +1300,10 @@ 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)) { @@ -1215,60 +1324,60 @@ 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 = POP(); err = PyList_Append(v, w); @@ -1276,31 +1385,31 @@ 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(); @@ -1308,42 +1417,42 @@ 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)) { @@ -1370,10 +1479,10 @@ 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)) { @@ -1393,63 +1502,69 @@ 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: +#define SLICE_0 (SLICE+0) +#define SLICE_1 (SLICE+1) +#define SLICE_2 (SLICE+2) +#define SLICE_3 (SLICE+3) + + TARGET_WITH_IMPL(SLICE_0, _slice_3) + TARGET_WITH_IMPL(SLICE_1, _slice_3) + TARGET_WITH_IMPL(SLICE_2, _slice_3) + TARGET(SLICE_3) + _slice_3: if ((opcode-SLICE) & 2) w = POP(); else @@ -1464,13 +1579,19 @@ 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: +#define STORE_SLICE_0 (STORE_SLICE+0) +#define STORE_SLICE_1 (STORE_SLICE+1) +#define STORE_SLICE_2 (STORE_SLICE+2) +#define STORE_SLICE_3 (STORE_SLICE+3) + + TARGET_WITH_IMPL(STORE_SLICE_0, _store_slice_3) + TARGET_WITH_IMPL(STORE_SLICE_1, _store_slice_3) + TARGET_WITH_IMPL(STORE_SLICE_2, _store_slice_3) + TARGET(STORE_SLICE_3) + _store_slice_3: if ((opcode-STORE_SLICE) & 2) w = POP(); else @@ -1486,13 +1607,19 @@ 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: +#define DELETE_SLICE_0 (DELETE_SLICE+0) +#define DELETE_SLICE_1 (DELETE_SLICE+1) +#define DELETE_SLICE_2 (DELETE_SLICE+2) +#define DELETE_SLICE_3 (DELETE_SLICE+3) + + TARGET_WITH_IMPL(DELETE_SLICE_0, _delete_slice_3) + TARGET_WITH_IMPL(DELETE_SLICE_1, _delete_slice_3) + TARGET_WITH_IMPL(DELETE_SLICE_2, _delete_slice_3) + TARGET(DELETE_SLICE_3) + _delete_slice_3: if ((opcode-DELETE_SLICE) & 2) w = POP(); else @@ -1507,10 +1634,10 @@ 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(); @@ -1520,10 +1647,10 @@ 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); @@ -1531,10 +1658,10 @@ 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) { @@ -1558,11 +1685,11 @@ 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"); @@ -1609,14 +1736,14 @@ 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) { @@ -1640,7 +1767,7 @@ #ifdef CASE_TOO_BIG default: switch (opcode) { #endif - case RAISE_VARARGS: + TARGET(RAISE_VARARGS) u = v = w = NULL; switch (oparg) { case 3: @@ -1662,27 +1789,27 @@ } 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(); @@ -1695,7 +1822,7 @@ Py_DECREF(w); break; - case POP_BLOCK: + TARGET(POP_BLOCK) { PyTryBlock *b = PyFrame_BlockPop(f); while (STACK_LEVEL() > b->b_level) { @@ -1703,9 +1830,9 @@ Py_DECREF(v); } } - continue; + DISPATCH(); - case END_FINALLY: + TARGET(END_FINALLY) v = POP(); if (PyInt_Check(v)) { why = (enum why_code) PyInt_AS_LONG(v); @@ -1729,7 +1856,7 @@ Py_DECREF(v); break; - case BUILD_CLASS: + TARGET(BUILD_CLASS) u = TOP(); v = SECOND(); w = THIRD(); @@ -1741,7 +1868,7 @@ Py_DECREF(w); break; - case STORE_NAME: + TARGET(STORE_NAME) w = GETITEM(names, oparg); v = POP(); if ((x = f->f_locals) != NULL) { @@ -1750,7 +1877,7 @@ else err = PyObject_SetItem(x, w, v); Py_DECREF(v); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; } PyErr_Format(PyExc_SystemError, @@ -1758,7 +1885,7 @@ 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) @@ -1772,7 +1899,7 @@ break; PREDICTED_WITH_ARG(UNPACK_SEQUENCE); - case UNPACK_SEQUENCE: + TARGET(UNPACK_SEQUENCE) v = POP(); if (PyTuple_CheckExact(v) && PyTuple_GET_SIZE(v) == oparg) { PyObject **items = ((PyTupleObject *)v)->ob_item; @@ -1782,7 +1909,7 @@ PUSH(w); } Py_DECREF(v); - continue; + DISPATCH(); } else if (PyList_CheckExact(v) && PyList_GET_SIZE(v) == oparg) { PyObject **items = ((PyListObject *)v)->ob_item; while (oparg--) { @@ -1800,7 +1927,7 @@ Py_DECREF(v); break; - case STORE_ATTR: + TARGET(STORE_ATTR) w = GETITEM(names, oparg); v = TOP(); u = SECOND(); @@ -1808,10 +1935,10 @@ 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); @@ -1819,22 +1946,22 @@ 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, @@ -1869,9 +1996,9 @@ 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. @@ -1891,7 +2018,7 @@ if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } d = (PyDictObject *)(f->f_builtins); e = d->ma_lookup(d, w, hash); @@ -1903,7 +2030,7 @@ if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } goto load_global_error; } @@ -1922,13 +2049,13 @@ } 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, @@ -1937,19 +2064,19 @@ ); 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 */ @@ -1973,14 +2100,14 @@ } 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;) { @@ -1988,11 +2115,11 @@ 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;) { @@ -2000,26 +2127,26 @@ PyList_SET_ITEM(x, oparg, w); } PUSH(x); - continue; + DISPATCH(); } break; - case BUILD_MAP: + TARGET(BUILD_MAP) x = PyDict_New(); PUSH(x); - if (x != NULL) continue; + if (x != NULL) 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)) { @@ -2052,9 +2179,9 @@ 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) { @@ -2095,10 +2222,10 @@ 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) { @@ -2111,33 +2238,33 @@ 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) @@ -2146,18 +2273,18 @@ 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) { @@ -2168,14 +2295,14 @@ ; else break; - continue; + DISPATCH(); PREDICTED_WITH_ARG(JUMP_ABSOLUTE); - case JUMP_ABSOLUTE: + TARGET(JUMP_ABSOLUTE) JUMPTO(oparg); - continue; + DISPATCH(); - case GET_ITER: + TARGET(GET_ITER) /* before: [obj]; after [getiter(obj)] */ v = TOP(); x = PyObject_GetIter(v); @@ -2183,13 +2310,13 @@ 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); @@ -2197,7 +2324,7 @@ PUSH(x); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); - continue; + DISPATCH(); } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_StopIteration)) @@ -2208,13 +2335,13 @@ 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; @@ -2223,17 +2350,18 @@ 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. */ PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); - continue; + DISPATCH(); - case WITH_CLEANUP: + TARGET(WITH_CLEANUP) { /* TOP is the context.__exit__ bound method. Below that are 1-3 values indicating how/why @@ -2293,7 +2421,7 @@ break; } - case CALL_FUNCTION: + TARGET(CALL_FUNCTION) { PyObject **sp; PCALL(PCALL_ALL); @@ -2306,13 +2434,14 @@ 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; @@ -2352,11 +2481,11 @@ } 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); @@ -2378,7 +2507,7 @@ PUSH(x); break; - case MAKE_CLOSURE: + TARGET(MAKE_CLOSURE) { v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); @@ -2413,7 +2542,7 @@ break; } - case BUILD_SLICE: + TARGET(BUILD_SLICE) if (oparg == 3) w = POP(); else @@ -2425,14 +2554,17 @@ 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", --- /dev/null 2008-10-25 13:53:58.262220884 +0200 +++ Python-2.5.4/Python/makeopcodetargets.py 2009-01-21 13:35:37.000000000 +0100 @@ -0,0 +1,45 @@ +#! /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 + opname = opname.replace("+", "_") + 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() + --- /dev/null 2008-10-25 13:53:58.262220884 +0200 +++ Python-2.5.4/Python/opcode_targets.h 2009-01-21 13:35:37.000000000 +0100 @@ -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_0, + &&TARGET_SLICE_1, + &&TARGET_SLICE_2, + &&TARGET_SLICE_3, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&_unknown_opcode, + &&TARGET_STORE_SLICE_0, + &&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_0, + &&TARGET_DELETE_SLICE_1, + &&TARGET_DELETE_SLICE_2, + &&TARGET_DELETE_SLICE_3, + &&_unknown_opcode, + &&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, + &&_unknown_opcode, + &&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 +}; --- Python-2.5.4/configure.in.threaded 2008-12-13 15:13:52.000000000 +0100 +++ Python-2.5.4/configure.in 2009-01-21 13:35:51.000000000 +0100 @@ -3480,6 +3480,22 @@ #endif ]) +# Check for --with-computed-gotos +AC_MSG_CHECKING(for --with-computed-gotos) +AC_ARG_WITH(computed-gotos, + AC_HELP_STRING(--with-computed-gotos, + Use computed gotos / threaded dispatch in evaluation loop (not available on all compilers)), +[ +if test "$withval" != no +then + AC_DEFINE(USE_COMPUTED_GOTOS, 1, + [Define if you want to use computed gotos in ceval.c.]) + AC_MSG_RESULT(yes) +else AC_MSG_RESULT(no) +fi], +[AC_MSG_RESULT(no)]) + + AC_SUBST(THREADHEADERS) for h in `(cd $srcdir;echo Python/thread_*.h)`