diff -r 9213c70c67d2 Include/opcode.h --- a/Include/opcode.h Tue May 26 01:35:54 2015 -0700 +++ b/Include/opcode.h Tue May 26 16:53:01 2015 -0700 @@ -37,12 +37,21 @@ #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 diff -r 9213c70c67d2 Makefile.pre.in --- a/Makefile.pre.in Tue May 26 01:35:54 2015 -0700 +++ b/Makefile.pre.in Tue May 26 16:53:01 2015 -0700 @@ -300,6 +300,16 @@ ########################################################################## # 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 \ @@ -671,6 +681,11 @@ 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) diff -r 9213c70c67d2 Python/ceval.c --- a/Python/ceval.c Tue May 26 01:35:54 2015 -0700 +++ b/Python/ceval.c Tue May 26 16:53:01 2015 -0700 @@ -688,6 +688,106 @@ PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { +#ifdef DYNAMIC_EXECUTION_PROFILE + #undef USE_COMPUTED_GOTOS +#endif +// Computed goto not enabled by default in this patch +/* +#ifdef HAVE_COMPUTED_GOTOS + #ifndef USE_COMPUTED_GOTOS + #define USE_COMPUTED_GOTOS 1 + #endif +#else + #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS + #error "Computed gotos are not supported on this compiler." + #endif + #undef USE_COMPUTED_GOTOS + #define USE_COMPUTED_GOTOS 0 +#endif +*/ +#if 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; \ + oparg = NEXTARG(); \ + case op: \ + goto impl; \ + +#define TARGET_WITH_IMPL_NOARG(op, impl) \ + TARGET_##op: \ + opcode = op; \ + case op: \ + goto impl; \ + +#define TARGET_NOARG(op) \ + TARGET_##op: \ + opcode = op; \ + case op:\ + +#define TARGET(op) \ + TARGET_##op: \ + opcode = op; \ + oparg = NEXTARG(); \ + case op:\ + + +#define DISPATCH() \ + { \ + int _tick = _Py_Ticker - 1; \ + _Py_Ticker = _tick; \ + if (_tick >= 0) { \ + FAST_DISPATCH(); \ + } \ + continue; \ + } + +#ifdef LLTRACE +#define FAST_DISPATCH() \ + { \ + if (!lltrace && !_Py_TracingPossible) { \ + f->f_lasti = INSTR_OFFSET(); \ + goto *opcode_targets[*next_instr++]; \ + } \ + goto fast_next_opcode; \ + } +#else +#define FAST_DISPATCH() { \ + if (!_Py_TracingPossible) { \ + 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 TARGET_NOARG(op) \ + case op:\ + +#define TARGET_WITH_IMPL_NOARG(op, impl) \ + if (0) goto impl; \ + case op:\ + +#define DISPATCH() continue +#define FAST_DISPATCH() goto fast_next_opcode +#endif + +// *********** END OF COMPUTED GOTOS ********************* + + + #ifdef DXPAIRS int lastopcode = 0; #endif @@ -805,14 +905,23 @@ counter updates for both opcodes. */ + +// Next opcode prediction is also enabled for Computed Gotos as well. #ifdef DYNAMIC_EXECUTION_PROFILE -#define PREDICT(op) if (0) goto PRED_##op +#define PREDICT(op) //if (0) goto PRED_##op +#define PREDICTED(op) +#define PREDICTED_WITH_ARG(op) #else #define PREDICT(op) if (*next_instr == op) goto PRED_##op +#define PREDICTED(op) PRED_##op: next_instr++ +#ifdef USE_COMPUTED_GOTOS +#define PREDICTED_WITH_ARG(op) PRED_##op: next_instr++ +#else +#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 #endif - -#define PREDICTED(op) PRED_##op: next_instr++ -#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 +#endif + + /* Stack manipulation macros */ @@ -1108,55 +1217,70 @@ /* case STOP_CODE: this is an error! */ - case NOP: - goto fast_next_opcode; - - case LOAD_FAST: + TARGET_NOARG(NOP) + { + FAST_DISPATCH(); + } + + 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; - - case POP_TOP: + FAST_DISPATCH(); + } + + TARGET_NOARG(POP_TOP) + { v = POP(); Py_DECREF(v); - goto fast_next_opcode; - - case ROT_TWO: + FAST_DISPATCH(); + } + + TARGET_NOARG(ROT_TWO) + { v = TOP(); w = SECOND(); SET_TOP(w); SET_SECOND(v); - goto fast_next_opcode; - - case ROT_THREE: + FAST_DISPATCH(); + } + + TARGET_NOARG(ROT_THREE) + { v = TOP(); w = SECOND(); x = THIRD(); SET_TOP(w); SET_SECOND(x); SET_THIRD(v); - goto fast_next_opcode; - - case ROT_FOUR: + FAST_DISPATCH(); + } + + TARGET_NOARG(ROT_FOUR) + { u = TOP(); v = SECOND(); w = THIRD(); @@ -1165,15 +1289,21 @@ SET_SECOND(w); SET_THIRD(x); SET_FOURTH(u); - goto fast_next_opcode; - - case DUP_TOP: + FAST_DISPATCH(); + } + + + TARGET_NOARG(DUP_TOP) + { v = TOP(); Py_INCREF(v); PUSH(v); - goto fast_next_opcode; - - case DUP_TOPX: + FAST_DISPATCH(); + } + + + TARGET(DUP_TOPX) + { if (oparg == 2) { x = TOP(); Py_INCREF(x); @@ -1182,7 +1312,7 @@ STACKADJ(2); SET_TOP(x); SET_SECOND(w); - goto fast_next_opcode; + FAST_DISPATCH(); } else if (oparg == 3) { x = TOP(); Py_INCREF(x); @@ -1194,84 +1324,100 @@ 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_NOARG(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_NOARG( 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_NOARG(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_NOARG(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_NOARG(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_NOARG(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_NOARG(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_NOARG(BINARY_DIVIDE) + { if (!_Py_QnewFlag) { w = POP(); v = TOP(); @@ -1279,32 +1425,37 @@ 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: + } + /* -Qnew is in effect: fall through to BINARY_TRUE_DIVIDE */ + TARGET_NOARG(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_NOARG(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_NOARG(BINARY_MODULO) + { w = POP(); v = TOP(); if (PyString_CheckExact(v)) @@ -1314,10 +1465,12 @@ Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case BINARY_ADD: + } + + TARGET_NOARG(BINARY_ADD) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1346,10 +1499,12 @@ skip_decref_vx: Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case BINARY_SUBTRACT: + } + + TARGET_NOARG(BINARY_SUBTRACT) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1371,10 +1526,12 @@ Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case BINARY_SUBSCR: + } + + TARGET_NOARG(BINARY_SUBSCR) + { w = POP(); v = TOP(); if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1395,102 +1552,122 @@ Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case BINARY_LSHIFT: + } + + TARGET_NOARG(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_NOARG(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_NOARG(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_NOARG(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_NOARG(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 = PEEK(oparg); err = PyList_Append(v, w); Py_DECREF(w); if (err == 0) { PREDICT(JUMP_ABSOLUTE); - continue; + DISPATCH(); } break; - - case SET_ADD: + } + + TARGET(SET_ADD) + { w = POP(); v = stack_pointer[-oparg]; err = PySet_Add(v, w); Py_DECREF(w); if (err == 0) { PREDICT(JUMP_ABSOLUTE); - continue; + DISPATCH(); } break; - - case INPLACE_POWER: + } + + TARGET_NOARG(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_NOARG(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_NOARG(INPLACE_DIVIDE) + { if (!_Py_QnewFlag) { w = POP(); v = TOP(); @@ -1498,42 +1675,50 @@ 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_NOARG(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_NOARG(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_NOARG(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_NOARG(INPLACE_ADD) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1560,10 +1745,12 @@ skip_decref_v: Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case INPLACE_SUBTRACT: + } + + TARGET_NOARG(INPLACE_SUBTRACT) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1583,63 +1770,78 @@ Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case INPLACE_LSHIFT: + } + + TARGET_NOARG(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_NOARG(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_NOARG(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_NOARG(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_NOARG(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_NOARG(SLICE, _slice) + TARGET_WITH_IMPL_NOARG(SLICE_1, _slice) + TARGET_WITH_IMPL_NOARG(SLICE_2, _slice) + TARGET_WITH_IMPL_NOARG(SLICE_3, _slice) + _slice: + { if ((opcode-SLICE) & 2) w = POP(); else @@ -1654,13 +1856,17 @@ 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_NOARG(STORE_SLICE, _store_slice) + TARGET_WITH_IMPL_NOARG(STORE_SLICE_1, _store_slice) + TARGET_WITH_IMPL_NOARG(STORE_SLICE_2, _store_slice) + TARGET_WITH_IMPL_NOARG(STORE_SLICE_3, _store_slice) + _store_slice: + { if ((opcode-STORE_SLICE) & 2) w = POP(); else @@ -1676,13 +1882,17 @@ 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_NOARG(DELETE_SLICE, _delete_slice) + TARGET_WITH_IMPL_NOARG(DELETE_SLICE_1, _delete_slice) + TARGET_WITH_IMPL_NOARG(DELETE_SLICE_2, _delete_slice) + TARGET_WITH_IMPL_NOARG(DELETE_SLICE_3, _delete_slice) + _delete_slice: + { if ((opcode-DELETE_SLICE) & 2) w = POP(); else @@ -1697,10 +1907,12 @@ Py_DECREF(u); Py_XDECREF(v); Py_XDECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - - case STORE_SUBSCR: + } + + TARGET_NOARG(STORE_SUBSCR) + { w = TOP(); v = SECOND(); u = THIRD(); @@ -1710,10 +1922,12 @@ Py_DECREF(u); Py_DECREF(v); Py_DECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - - case DELETE_SUBSCR: + } + + TARGET_NOARG(DELETE_SUBSCR) + { w = TOP(); v = SECOND(); STACKADJ(-2); @@ -1721,10 +1935,12 @@ err = PyObject_DelItem(v, w); Py_DECREF(v); Py_DECREF(w); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; - - case PRINT_EXPR: + } + + TARGET_NOARG(PRINT_EXPR) + { v = POP(); w = PySys_GetObject("displayhook"); if (w == NULL) { @@ -1747,12 +1963,16 @@ Py_DECREF(v); Py_XDECREF(x); break; - - case PRINT_ITEM_TO: + } + + TARGET_NOARG(PRINT_ITEM_TO) + { w = stream = POP(); /* fall through to PRINT_ITEM */ - - case PRINT_ITEM: + } + + TARGET_NOARG(PRINT_ITEM) + { v = POP(); if (stream == NULL || stream == Py_None) { w = PySys_GetObject("stdout"); @@ -1798,16 +2018,20 @@ Py_DECREF(v); Py_XDECREF(stream); stream = NULL; - if (err == 0) - continue; + if (err == 0) DISPATCH(); break; - - case PRINT_NEWLINE_TO: + } + + TARGET_NOARG(PRINT_NEWLINE_TO) + { w = stream = POP(); /* fall through to PRINT_NEWLINE */ - - case PRINT_NEWLINE: - if (stream == NULL || stream == Py_None) { + } + + TARGET_NOARG(PRINT_NEWLINE) + { + if (stream == NULL || stream == Py_None) + { w = PySys_GetObject("stdout"); if (w == NULL) { PyErr_SetString(PyExc_RuntimeError, @@ -1827,12 +2051,14 @@ Py_XDECREF(stream); stream = NULL; break; - + } #ifdef CASE_TOO_BIG default: switch (opcode) { #endif - case RAISE_VARARGS: + + TARGET(RAISE_VARARGS) + { u = v = w = NULL; switch (oparg) { case 3: @@ -1853,28 +2079,37 @@ break; } break; - - case LOAD_LOCALS: - if ((x = f->f_locals) != NULL) { + } + + TARGET_NOARG(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_NOARG(RETURN_VALUE) + { retval = POP(); why = WHY_RETURN; goto fast_block_end; - - case YIELD_VALUE: + } + + TARGET_NOARG(YIELD_VALUE) + { retval = POP(); f->f_stacktop = stack_pointer; why = WHY_YIELD; goto fast_yield; - - case EXEC_STMT: + } + + TARGET_NOARG(EXEC_STMT) + { w = TOP(); v = SECOND(); u = THIRD(); @@ -1886,8 +2121,10 @@ Py_DECREF(v); Py_DECREF(w); break; - - case POP_BLOCK: + } + + TARGET_NOARG(POP_BLOCK) + { { PyTryBlock *b = PyFrame_BlockPop(f); while (STACK_LEVEL() > b->b_level) { @@ -1895,10 +2132,12 @@ Py_DECREF(v); } } - continue; + DISPATCH(); + } PREDICTED(END_FINALLY); - case END_FINALLY: + TARGET_NOARG(END_FINALLY) + { v = POP(); if (PyInt_Check(v)) { why = (enum why_code) PyInt_AS_LONG(v); @@ -1922,8 +2161,10 @@ } Py_DECREF(v); break; - - case BUILD_CLASS: + } + + TARGET_NOARG(BUILD_CLASS) + { u = TOP(); v = SECOND(); w = THIRD(); @@ -1934,8 +2175,10 @@ Py_DECREF(v); Py_DECREF(w); break; - - case STORE_NAME: + } + + TARGET(STORE_NAME) + { w = GETITEM(names, oparg); v = POP(); if ((x = f->f_locals) != NULL) { @@ -1944,7 +2187,7 @@ else err = PyObject_SetItem(x, w, v); Py_DECREF(v); - if (err == 0) continue; + if (err == 0) DISPATCH(); break; } t = PyObject_Repr(w); @@ -1955,8 +2198,10 @@ PyString_AS_STRING(t)); Py_DECREF(t); break; - - case DELETE_NAME: + } + + TARGET(DELETE_NAME) + { w = GETITEM(names, oparg); if ((x = f->f_locals) != NULL) { if ((err = PyObject_DelItem(x, w)) != 0) @@ -1973,9 +2218,11 @@ PyString_AS_STRING(w)); Py_DECREF(t); break; + } PREDICTED_WITH_ARG(UNPACK_SEQUENCE); - case UNPACK_SEQUENCE: + TARGET(UNPACK_SEQUENCE) + { v = POP(); if (PyTuple_CheckExact(v) && PyTuple_GET_SIZE(v) == oparg) { @@ -1987,7 +2234,7 @@ PUSH(w); } Py_DECREF(v); - continue; + DISPATCH(); } else if (PyList_CheckExact(v) && PyList_GET_SIZE(v) == oparg) { PyObject **items = \ @@ -2006,8 +2253,11 @@ } Py_DECREF(v); break; - - case STORE_ATTR: + } + + + TARGET(STORE_ATTR) + { w = GETITEM(names, oparg); v = TOP(); u = SECOND(); @@ -2015,33 +2265,42 @@ 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); /* del v.w */ 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) { why = WHY_EXCEPTION; @@ -2081,9 +2340,11 @@ Py_INCREF(x); } PUSH(x); - continue; - - case LOAD_GLOBAL: + DISPATCH(); + } + + TARGET(LOAD_GLOBAL) + { w = GETITEM(names, oparg); if (PyString_CheckExact(w)) { /* Inline the PyDict_GetItem() calls. @@ -2103,7 +2364,7 @@ if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } d = (PyDictObject *)(f->f_builtins); e = d->ma_lookup(d, w, hash); @@ -2115,7 +2376,7 @@ if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } goto load_global_error; } @@ -2134,13 +2395,15 @@ } Py_INCREF(x); PUSH(x); - continue; - - case DELETE_FAST: + DISPATCH(); + } + + TARGET(DELETE_FAST) + { x = GETLOCAL(oparg); if (x != NULL) { SETLOCAL(oparg, NULL); - continue; + DISPATCH(); } format_exc_check_arg( PyExc_UnboundLocalError, @@ -2148,20 +2411,24 @@ PyTuple_GetItem(co->co_varnames, oparg) ); 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 */ @@ -2181,15 +2448,19 @@ UNBOUNDFREE_ERROR_MSG, v); } break; - - case STORE_DEREF: + } + + TARGET(STORE_DEREF) + { w = POP(); x = freevars[oparg]; PyCell_Set(x, w); Py_DECREF(w); - continue; - - case BUILD_TUPLE: + DISPATCH(); + } + + TARGET(BUILD_TUPLE) + { x = PyTuple_New(oparg); if (x != NULL) { for (; --oparg >= 0;) { @@ -2197,11 +2468,13 @@ 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;) { @@ -2209,11 +2482,13 @@ PyList_SET_ITEM(x, oparg, w); } PUSH(x); - continue; + DISPATCH(); } break; - - case BUILD_SET: + } + + TARGET(BUILD_SET) + { x = PySet_New(NULL); if (x != NULL) { for (; --oparg >= 0;) { @@ -2227,18 +2502,21 @@ break; } 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_NOARG(STORE_MAP) + { w = TOP(); /* key */ u = SECOND(); /* value */ v = THIRD(); /* dict */ @@ -2247,10 +2525,12 @@ 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 MAP_ADD: + } + + TARGET(MAP_ADD) + { w = TOP(); /* key */ u = SECOND(); /* value */ STACKADJ(-2); @@ -2261,20 +2541,24 @@ Py_DECREF(w); if (err == 0) { PREDICT(JUMP_ABSOLUTE); - continue; + 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)) { @@ -2307,9 +2591,11 @@ if (x == NULL) break; PREDICT(POP_JUMP_IF_FALSE); PREDICT(POP_JUMP_IF_TRUE); - continue; - - case IMPORT_NAME: + DISPATCH(); + } + + TARGET(IMPORT_NAME) + { w = GETITEM(names, oparg); x = PyDict_GetItemString(f->f_builtins, "__import__"); if (x == NULL) { @@ -2350,10 +2636,12 @@ READ_TIMESTAMP(intr1); Py_DECREF(w); SET_TOP(x); - if (x != NULL) continue; + if (x != NULL) DISPATCH(); break; - - case IMPORT_STAR: + } + + TARGET_NOARG(IMPORT_STAR) + { v = POP(); PyFrame_FastToLocals(f); if ((x = f->f_locals) == NULL) { @@ -2366,34 +2654,40 @@ 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(POP_JUMP_IF_FALSE); - case POP_JUMP_IF_FALSE: + TARGET(POP_JUMP_IF_FALSE) + { w = POP(); if (w == Py_True) { Py_DECREF(w); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_False) { Py_DECREF(w); JUMPTO(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); Py_DECREF(w); @@ -2403,19 +2697,21 @@ JUMPTO(oparg); else break; - continue; + DISPATCH(); + } PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE); - case POP_JUMP_IF_TRUE: + TARGET(POP_JUMP_IF_TRUE) + { w = POP(); if (w == Py_False) { Py_DECREF(w); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_True) { Py_DECREF(w); JUMPTO(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); Py_DECREF(w); @@ -2427,18 +2723,20 @@ ; else break; - continue; - - case JUMP_IF_FALSE_OR_POP: + DISPATCH(); + } + + TARGET(JUMP_IF_FALSE_OR_POP) + { w = TOP(); if (w == Py_True) { STACKADJ(-1); Py_DECREF(w); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_False) { JUMPTO(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); if (err > 0) { @@ -2450,18 +2748,20 @@ JUMPTO(oparg); else break; - continue; - - case JUMP_IF_TRUE_OR_POP: + DISPATCH(); + } + + TARGET(JUMP_IF_TRUE_OR_POP) + { w = TOP(); if (w == Py_False) { STACKADJ(-1); Py_DECREF(w); - goto fast_next_opcode; + FAST_DISPATCH(); } if (w == Py_True) { JUMPTO(oparg); - goto fast_next_opcode; + FAST_DISPATCH(); } err = PyObject_IsTrue(w); if (err > 0) { @@ -2474,10 +2774,12 @@ } 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 @@ -2489,10 +2791,12 @@ */ goto fast_next_opcode; #else - continue; + DISPATCH(); #endif - - case GET_ITER: + } + + TARGET_NOARG(GET_ITER) + { /* before: [obj]; after [getiter(obj)] */ v = TOP(); x = PyObject_GetIter(v); @@ -2500,13 +2804,15 @@ 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); @@ -2514,7 +2820,7 @@ PUSH(x); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); - continue; + DISPATCH(); } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches( @@ -2526,13 +2832,17 @@ x = v = POP(); Py_DECREF(v); JUMPBY(oparg); - continue; - - case BREAK_LOOP: + DISPATCH(); + } + + TARGET_NOARG(BREAK_LOOP) + { why = WHY_BREAK; goto fast_block_end; - - case CONTINUE_LOOP: + } + + TARGET(CONTINUE_LOOP) + { retval = PyInt_FromLong(oparg); if (!retval) { x = NULL; @@ -2540,10 +2850,13 @@ } 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. @@ -2551,9 +2864,13 @@ PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); - continue; - - case SETUP_WITH: + DISPATCH(); + } + + + + TARGET(SETUP_WITH) + { { static PyObject *exit, *enter; w = TOP(); @@ -2579,10 +2896,11 @@ STACK_LEVEL()); PUSH(x); - continue; - } - - case WITH_CLEANUP: + DISPATCH(); + } + } + + TARGET_NOARG(WITH_CLEANUP) { /* At the top of the stack are 1-3 values indicating how/why we entered the finally clause: @@ -2670,7 +2988,7 @@ break; } - case CALL_FUNCTION: + TARGET(CALL_FUNCTION) { PyObject **sp; PCALL(PCALL_ALL); @@ -2682,14 +3000,14 @@ #endif stack_pointer = sp; PUSH(x); - if (x != NULL) - continue; + if (x != NULL) 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; @@ -2727,12 +3045,13 @@ Py_DECREF(w); } PUSH(x); - if (x != NULL) - continue; + if (x != NULL) DISPATCH(); break; } - case MAKE_FUNCTION: + + TARGET(MAKE_FUNCTION) + { v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); Py_DECREF(v); @@ -2753,8 +3072,9 @@ } PUSH(x); break; - - case MAKE_CLOSURE: + } + + TARGET(MAKE_CLOSURE) { v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); @@ -2789,7 +3109,8 @@ break; } - case BUILD_SLICE: + TARGET(BUILD_SLICE) + { if (oparg == 3) w = POP(); else @@ -2801,14 +3122,20 @@ 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; - + } + +#if USE_COMPUTED_GOTOS + _unknown_opcode: +#endif default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", diff -r 9213c70c67d2 Python/makeopcodetargets.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Python/makeopcodetargets.py Tue May 26 16:53:01 2015 -0700 @@ -0,0 +1,51 @@ +#! /usr/bin/env python +"""Generate C code for the jump table of the threaded code interpreter +(GCC only). +""" + +import imp +import os +import string + + +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 + """Deal with opcodes like SLICE+0, SLICE+1, etc., + """ + opname = string.replace(opname, '+0', ' ') + opname = string.replace(opname, '+1', '_1') + opname = string.replace(opname, '+2', '_2') + opname = string.replace(opname, '+3', '_3') + 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() + diff -r 9213c70c67d2 configure.ac --- a/configure.ac Tue May 26 01:35:54 2015 -0700 +++ b/configure.ac Tue May 26 16:53:01 2015 -0700 @@ -4557,6 +4557,57 @@ mkdir $dir fi done + +# BEGIN_COMPUTED_GOTO +# Check for --with-computed-gotos +AC_MSG_CHECKING(for --with-computed-gotos) +AC_ARG_WITH(computed-gotos, + AS_HELP_STRING([--with(out)-computed-gotos], + [Use computed gotos in evaluation loop (enabled by default on supported compilers)]), +[ +if test "$withval" = yes +then + AC_DEFINE(USE_COMPUTED_GOTOS, 1, + [Define if you want to use computed gotos in ceval.c.]) + AC_MSG_RESULT(yes) +fi +if test "$withval" = no +then + AC_DEFINE(USE_COMPUTED_GOTOS, 0, + [Define if you want to use computed gotos in ceval.c.]) + AC_MSG_RESULT(no) +fi +], +[AC_MSG_RESULT(no value specified)]) + +AC_MSG_CHECKING(whether $CC supports computed gotos) +AC_CACHE_VAL(ac_cv_computed_gotos, +AC_RUN_IFELSE([AC_LANG_SOURCE([[[ +int main(int argc, char **argv) +{ + static void *targets[1] = { &&LABEL1 }; + goto LABEL2; +LABEL1: + return 0; +LABEL2: + goto *targets[0]; + return 1; +} +]]])], +[ac_cv_computed_gotos=yes], +[ac_cv_computed_gotos=no], +[if test "${with_computed_gotos+set}" = set; then + ac_cv_computed_gotos="$with_computed_gotos -- configured --with(out)-computed-gotos" + else + ac_cv_computed_gotos=no + fi])) +AC_MSG_RESULT($ac_cv_computed_gotos) +case "$ac_cv_computed_gotos" in yes*) + AC_DEFINE(HAVE_COMPUTED_GOTOS, 1, + [Define if the C compiler supports computed gotos.]) +esac +# END_COMPUTED_GOTO + AC_MSG_RESULT(done) # ensurepip option diff -r 9213c70c67d2 pyconfig.h.in --- a/pyconfig.h.in Tue May 26 01:35:54 2015 -0700 +++ b/pyconfig.h.in Tue May 26 16:53:01 2015 -0700 @@ -118,6 +118,9 @@ /* Define to 1 if you have the `clock' function. */ #undef HAVE_CLOCK +/* Define if the C compiler supports computed gotos. */ +#undef HAVE_COMPUTED_GOTOS + /* Define to 1 if you have the `confstr' function. */ #undef HAVE_CONFSTR @@ -1069,6 +1072,9 @@ /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME +/* Define if you want to use computed gotos in ceval.c. */ +#undef USE_COMPUTED_GOTOS + /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE