From 2c992a0788536087bfd78da8f2c62b30a461d7e2 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Thu, 28 May 2015 12:45:31 -0500 Subject: [PATCH] backport computed gotos (#4753) --- Include/opcode.h | 9 + Makefile.pre.in | 15 + Misc/NEWS | 4 + Python/ceval.c | 779 +++++++++++++++++++++++++----------- Python/makeopcodetargets.py | 45 +++ Python/opcode_targets.h | 258 ++++++++++++ configure | 83 ++++ configure.ac | 51 +++ pyconfig.h.in | 6 + 9 files changed, 1021 insertions(+), 229 deletions(-) create mode 100755 Python/makeopcodetargets.py create mode 100644 Python/opcode_targets.h diff --git a/Include/opcode.h b/Include/opcode.h index 9764109adb2..9ed548729e6 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -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 diff --git a/Makefile.pre.in b/Makefile.pre.in index b3b2b3622f7..59891430f62 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -300,6 +300,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 \ @@ -671,6 +681,11 @@ Objects/bytearrayobject.o: $(srcdir)/Objects/bytearrayobject.c \ 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 --git a/Misc/NEWS b/Misc/NEWS index 01fd7639b6d..204b84434fd 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 2.7.11? Core and Builtins ----------------- +- Issue #4753: On compilers where it is supported, use "computed gotos" for + bytecode dispatch in the interpreter. This improves interpretation + performance. + - Issue #22939: Fixed integer overflow in iterator object. Original patch by Clement Rouault. diff --git a/Python/ceval.c b/Python/ceval.c index fa6bb60517b..c41cbb4bc32 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -688,6 +688,100 @@ PyEval_EvalFrame(PyFrameObject *f) { PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { +#ifdef DYNAMIC_EXECUTION_PROFILE + #undef USE_COMPUTED_GOTOS +#endif +#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 + + #ifdef DXPAIRS int lastopcode = 0; #endif @@ -805,14 +899,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 #endif -#define PREDICTED(op) PRED_##op: next_instr++ -#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 + /* Stack manipulation macros */ @@ -1108,55 +1211,70 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) /* case STOP_CODE: this is an error! */ - case NOP: - goto fast_next_opcode; + TARGET_NOARG(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(); + } - case POP_TOP: + TARGET_NOARG(POP_TOP) + { v = POP(); Py_DECREF(v); - goto fast_next_opcode; + FAST_DISPATCH(); + } - case ROT_TWO: + TARGET_NOARG(ROT_TWO) + { v = TOP(); w = SECOND(); SET_TOP(w); SET_SECOND(v); - goto fast_next_opcode; + FAST_DISPATCH(); + } - case ROT_THREE: + TARGET_NOARG(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_NOARG(ROT_FOUR) + { u = TOP(); v = SECOND(); w = THIRD(); @@ -1165,15 +1283,21 @@ 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_NOARG(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); @@ -1182,7 +1306,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); @@ -1194,84 +1318,100 @@ 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_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 +1419,37 @@ 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: + } + /* -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 +1459,12 @@ 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_ADD: + TARGET_NOARG(BINARY_ADD) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1346,10 +1493,12 @@ 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_NOARG(BINARY_SUBTRACT) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1371,10 +1520,12 @@ 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_NOARG(BINARY_SUBSCR) + { w = POP(); v = TOP(); if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1395,102 +1546,122 @@ 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_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 +1669,50 @@ 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_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 +1739,12 @@ 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_NOARG(INPLACE_SUBTRACT) + { w = POP(); v = TOP(); if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { @@ -1583,63 +1764,78 @@ 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_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 +1850,17 @@ 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_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 +1876,17 @@ 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_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 +1901,12 @@ 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_NOARG(STORE_SUBSCR) + { w = TOP(); v = SECOND(); u = THIRD(); @@ -1710,10 +1916,12 @@ 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_NOARG(DELETE_SUBSCR) + { w = TOP(); v = SECOND(); STACKADJ(-2); @@ -1721,10 +1929,12 @@ 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_NOARG(PRINT_EXPR) + { v = POP(); w = PySys_GetObject("displayhook"); if (w == NULL) { @@ -1747,12 +1957,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2012,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2045,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2073,37 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2115,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2126,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2155,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } Py_DECREF(v); break; + } - case BUILD_CLASS: + TARGET_NOARG(BUILD_CLASS) + { u = TOP(); v = SECOND(); w = THIRD(); @@ -1934,8 +2169,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2181,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; } t = PyObject_Repr(w); @@ -1955,8 +2192,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2212,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2228,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 = \ @@ -2006,8 +2247,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } Py_DECREF(v); break; + } - case STORE_ATTR: + + TARGET(STORE_ATTR) + { w = GETITEM(names, oparg); v = TOP(); u = SECOND(); @@ -2015,33 +2259,42 @@ 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); /* 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 +2334,11 @@ 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. @@ -2103,7 +2358,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); @@ -2115,7 +2370,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (x != NULL) { Py_INCREF(x); PUSH(x); - continue; + DISPATCH(); } goto load_global_error; } @@ -2134,13 +2389,15 @@ 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, @@ -2148,20 +2405,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2442,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) UNBOUNDFREE_ERROR_MSG, v); } 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;) { @@ -2197,11 +2462,13 @@ 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;) { @@ -2209,11 +2476,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2496,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2519,12 @@ 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 MAP_ADD: + TARGET(MAP_ADD) + { w = TOP(); /* key */ u = SECOND(); /* value */ STACKADJ(-2); @@ -2261,20 +2535,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2585,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (x == NULL) break; PREDICT(POP_JUMP_IF_FALSE); PREDICT(POP_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) { @@ -2350,10 +2630,12 @@ 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_NOARG(IMPORT_STAR) + { v = POP(); PyFrame_FastToLocals(f); if ((x = f->f_locals) == NULL) { @@ -2366,34 +2648,40 @@ 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(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 +2691,21 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +2717,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ; else break; - continue; + DISPATCH(); + } - case JUMP_IF_FALSE_OR_POP: + 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 +2742,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) JUMPTO(oparg); else break; - continue; + DISPATCH(); + } - case JUMP_IF_TRUE_OR_POP: + 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 +2768,12 @@ 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 @@ -2489,10 +2785,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) */ 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 +2798,15 @@ 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); @@ -2514,7 +2814,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) PUSH(x); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); - continue; + DISPATCH(); } if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches( @@ -2526,13 +2826,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) x = v = POP(); Py_DECREF(v); JUMPBY(oparg); - continue; + DISPATCH(); + } - case BREAK_LOOP: + 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 +2844,13 @@ 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. @@ -2551,9 +2858,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); - continue; + DISPATCH(); + } - case SETUP_WITH: + + + TARGET(SETUP_WITH) + { { static PyObject *exit, *enter; w = TOP(); @@ -2579,10 +2890,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) STACK_LEVEL()); PUSH(x); - continue; + DISPATCH(); + } } - case WITH_CLEANUP: + TARGET_NOARG(WITH_CLEANUP) { /* At the top of the stack are 1-3 values indicating how/why we entered the finally clause: @@ -2670,7 +2982,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) break; } - case CALL_FUNCTION: + TARGET(CALL_FUNCTION) { PyObject **sp; PCALL(PCALL_ALL); @@ -2682,14 +2994,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #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 +3039,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) 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 +3066,9 @@ 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); @@ -2789,7 +3103,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) break; } - case BUILD_SLICE: + TARGET(BUILD_SLICE) + { if (oparg == 3) w = POP(); else @@ -2801,14 +3116,20 @@ 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; + } +#if USE_COMPUTED_GOTOS + _unknown_opcode: +#endif default: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py new file mode 100755 index 00000000000..fcbf5ef7918 --- /dev/null +++ b/Python/makeopcodetargets.py @@ -0,0 +1,45 @@ +#! /usr/bin/env python +"""Generate C code for the jump table of the threaded code interpreter +(for compilers supporting computed gotos or "labels-as-values", such as gcc). +""" + +# This code should stay compatible with Python 2.3, at least while +# some of the buildbots have Python 2.3 as their system Python. + +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": + continue + targets[op] = "TARGET_%s" % opname.replace("+0", " ").replace("+", "_") + f.write("static void *opcode_targets[256] = {\n") + f.write(",\n".join([" &&%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 --git a/Python/opcode_targets.h b/Python/opcode_targets.h new file mode 100644 index 00000000000..95eb127a150 --- /dev/null +++ b/Python/opcode_targets.h @@ -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, + &&_unknown_opcode, + &&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_SET, + &&TARGET_BUILD_MAP, + &&TARGET_LOAD_ATTR, + &&TARGET_COMPARE_OP, + &&TARGET_IMPORT_NAME, + &&TARGET_IMPORT_FROM, + &&TARGET_JUMP_FORWARD, + &&TARGET_JUMP_IF_FALSE_OR_POP, + &&TARGET_JUMP_IF_TRUE_OR_POP, + &&TARGET_JUMP_ABSOLUTE, + &&TARGET_POP_JUMP_IF_FALSE, + &&TARGET_POP_JUMP_IF_TRUE, + &&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_SETUP_WITH, + &&_unknown_opcode, + &&TARGET_EXTENDED_ARG, + &&TARGET_SET_ADD, + &&TARGET_MAP_ADD, + &&_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 +}; diff --git a/configure b/configure index 8cf777e19b8..7ab0a468770 100755 --- a/configure +++ b/configure @@ -811,6 +811,7 @@ with_libm with_libc enable_big_digits enable_unicode +with_computed_gotos with_ensurepip ' ac_precious_vars='build_alias @@ -1494,6 +1495,9 @@ Optional Packages: --with-fpectl enable SIGFPE catching --with-libm=STRING math library --with-libc=STRING C library + --with(out)-computed-gotos + Use computed gotos in evaluation loop (enabled by + default on supported compilers) --with(out)-ensurepip=[=OPTION] "install" or "upgrade" using bundled pip, default is "no" @@ -14685,6 +14689,85 @@ for dir in $SRCDIRS; do mkdir $dir fi done + +# BEGIN_COMPUTED_GOTO +# Check for --with-computed-gotos +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-computed-gotos" >&5 +$as_echo_n "checking for --with-computed-gotos... " >&6; } + +# Check whether --with-computed-gotos was given. +if test "${with_computed_gotos+set}" = set; then : + withval=$with_computed_gotos; +if test "$withval" = yes +then + +$as_echo "#define USE_COMPUTED_GOTOS 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +if test "$withval" = no +then + +$as_echo "#define USE_COMPUTED_GOTOS 0" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no value specified" >&5 +$as_echo "no value specified" >&6; } +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports computed gotos" >&5 +$as_echo_n "checking whether $CC supports computed gotos... " >&6; } +if ${ac_cv_computed_gotos+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + 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 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int main(int argc, char **argv) +{ + static void *targets[1] = { &&LABEL1 }; + goto LABEL2; +LABEL1: + return 0; +LABEL2: + goto *targets[0]; + return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_computed_gotos=yes +else + ac_cv_computed_gotos=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_computed_gotos" >&5 +$as_echo "$ac_cv_computed_gotos" >&6; } +case "$ac_cv_computed_gotos" in yes*) + +$as_echo "#define HAVE_COMPUTED_GOTOS 1" >>confdefs.h + +esac +# END_COMPUTED_GOTO + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } diff --git a/configure.ac b/configure.ac index 78fe3c785fc..c2a183005bc 100644 --- a/configure.ac +++ b/configure.ac @@ -4557,6 +4557,57 @@ for dir in $SRCDIRS; do 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 --git a/pyconfig.h.in b/pyconfig.h.in index 8e810daf3e0..219bff34174 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -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