# HG changeset patch # User Alexandre Vassalotti # Date 1231096876 18000 # Branch py3k # Node ID 14a1090bc0b8b470a245d9df7bb3749342783f2a # Parent 252c29c9bfcc968ac3e70aef4de42414011a48a5 Abstracted the control-flow of the switch-case. This allows the switch to be removed when using the computed gotos optimization. The resulting code is slower on x86-64 because opcode and argument fetching was moved. diff -r 252c29c9bfcc -r 14a1090bc0b8 Python/ceval.c --- a/Python/ceval.c Thu Jan 01 23:54:01 2009 +0100 +++ b/Python/ceval.c Sun Jan 04 14:21:16 2009 -0500 @@ -633,20 +633,9 @@ /* 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: - + TARGET_##op: goto impl; + +#define TARGET(op) TARGET_##op: #define DISPATCH() \ { \ @@ -661,20 +650,40 @@ #define FAST_DISPATCH() \ { \ if (!_Py_TracingPossible) { \ - f->f_lasti = INSTR_OFFSET(); \ - goto *opcode_targets[*next_instr++]; \ + FETCH_NEXT_OPCODE(); \ + goto *opcode_targets[opcode]; \ } \ goto fast_next_opcode; \ } -#else -#define TARGET(op) \ +#define SWITCH(op) goto *opcode_targets[op]; +#define DEFAULT_TARGET _unknown_opcode +#define BREAK() goto on_error + +#else +#define TARGET(op) case op: +#define TARGET_WITH_IMPL(op, impl) \ + if (0) goto impl; /* avoid warnings */ \ case op: -#define TARGET_WITH_IMPL(op, impl) \ - case op: + #define DISPATCH() continue #define FAST_DISPATCH() goto fast_next_opcode -#endif + +#define SWITCH(op) switch(op) +#define DEFAULT_TARGET default +#define BREAK() break +#endif + + +/* Extract next opcode and argument. */ +#define FETCH_NEXT_OPCODE() \ + { \ + f->f_lasti = INSTR_OFFSET(); \ + opcode = NEXTOP(); \ + oparg = 0; /* allows oparg to be stored in a register. */ \ + if (HAS_ARG(opcode)) \ + oparg = NEXTARG(); \ + } /* Tuple access macros */ @@ -1063,12 +1072,12 @@ } fast_next_opcode: - f->f_lasti = INSTR_OFFSET(); /* line-by-line tracing support */ if (_Py_TracingPossible && tstate->c_tracefunc != NULL && !tstate->tracing) { + f->f_lasti = INSTR_OFFSET(); /* see maybe_call_line_trace for expository comments */ f->f_stacktop = stack_pointer; @@ -1089,13 +1098,8 @@ } } - /* Extract opcode and argument */ - - opcode = NEXTOP(); - oparg = 0; /* allows oparg to be stored in a register because - it doesn't have to be remembered across a full loop */ - if (HAS_ARG(opcode)) - oparg = NEXTARG(); + FETCH_NEXT_OPCODE(); + dispatch_opcode: #ifdef DYNAMIC_EXECUTION_PROFILE #ifdef DXPAIRS @@ -1123,8 +1127,8 @@ /* Main switch on opcode */ READ_TIMESTAMP(inst0); - switch (opcode) { - + + SWITCH(opcode) { /* BEWARE! It is essential that any operation that fails sets either x to NULL, err to nonzero, or why to anything but WHY_NOT, @@ -1145,7 +1149,7 @@ format_exc_check_arg(PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(co->co_varnames, oparg)); - break; + BREAK(); TARGET(LOAD_CONST) x = GETITEM(consts, oparg); @@ -1224,7 +1228,7 @@ Py_FatalError("invalid argument to DUP_TOPX" " (bytecode corruption?)"); /* Never returns, so don't bother to set why. */ - break; + BREAK(); TARGET(UNARY_POSITIVE) v = TOP(); @@ -1232,7 +1236,7 @@ Py_DECREF(v); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(UNARY_NEGATIVE) v = TOP(); @@ -1240,7 +1244,7 @@ Py_DECREF(v); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(UNARY_NOT) v = TOP(); @@ -1258,7 +1262,7 @@ DISPATCH(); } STACKADJ(-1); - break; + BREAK(); TARGET(UNARY_INVERT) v = TOP(); @@ -1266,7 +1270,7 @@ Py_DECREF(v); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_POWER) w = POP(); @@ -1276,7 +1280,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_MULTIPLY) w = POP(); @@ -1286,7 +1290,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_TRUE_DIVIDE) w = POP(); @@ -1296,7 +1300,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_FLOOR_DIVIDE) w = POP(); @@ -1306,7 +1310,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_MODULO) w = POP(); @@ -1316,7 +1320,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_ADD) w = POP(); @@ -1335,7 +1339,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_SUBTRACT) w = POP(); @@ -1345,7 +1349,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_SUBSCR) w = POP(); @@ -1355,7 +1359,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_LSHIFT) w = POP(); @@ -1365,7 +1369,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_RSHIFT) w = POP(); @@ -1375,7 +1379,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_AND) w = POP(); @@ -1385,7 +1389,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_XOR) w = POP(); @@ -1395,7 +1399,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(BINARY_OR) w = POP(); @@ -1405,7 +1409,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(LIST_APPEND) w = POP(); @@ -1416,7 +1420,7 @@ PREDICT(JUMP_ABSOLUTE); DISPATCH(); } - break; + BREAK(); TARGET(SET_ADD) w = POP(); @@ -1427,7 +1431,7 @@ PREDICT(JUMP_ABSOLUTE); DISPATCH(); } - break; + BREAK(); TARGET(INPLACE_POWER) w = POP(); @@ -1437,7 +1441,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_MULTIPLY) w = POP(); @@ -1447,7 +1451,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_TRUE_DIVIDE) w = POP(); @@ -1457,7 +1461,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_FLOOR_DIVIDE) w = POP(); @@ -1467,7 +1471,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_MODULO) w = POP(); @@ -1477,7 +1481,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_ADD) w = POP(); @@ -1496,7 +1500,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_SUBTRACT) w = POP(); @@ -1506,7 +1510,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_LSHIFT) w = POP(); @@ -1516,7 +1520,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_RSHIFT) w = POP(); @@ -1526,7 +1530,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_AND) w = POP(); @@ -1536,7 +1540,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_XOR) w = POP(); @@ -1546,7 +1550,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(INPLACE_OR) w = POP(); @@ -1556,7 +1560,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(STORE_SUBSCR) w = TOP(); @@ -1569,7 +1573,7 @@ Py_DECREF(v); Py_DECREF(w); if (err == 0) DISPATCH(); - break; + BREAK(); TARGET(DELETE_SUBSCR) w = TOP(); @@ -1580,7 +1584,7 @@ Py_DECREF(v); Py_DECREF(w); if (err == 0) DISPATCH(); - break; + BREAK(); TARGET(PRINT_EXPR) v = POP(); @@ -1604,9 +1608,9 @@ } Py_DECREF(v); Py_XDECREF(x); - break; - -#ifdef CASE_TOO_BIG + BREAK(); + +#if defined(CASE_TOO_BIG) && !defined(USE_COMPUTED_GOTOS) default: switch (opcode) { #endif TARGET(RAISE_VARARGS) @@ -1625,7 +1629,7 @@ why = WHY_EXCEPTION; break; } - break; + BREAK(); TARGET(STORE_LOCALS) x = POP(); @@ -1656,7 +1660,7 @@ PyErr_SetString(PyExc_SystemError, "popped block is not an except handler"); why = WHY_EXCEPTION; - break; + BREAK(); } UNWIND_EXCEPT_HANDLER(b); } @@ -1700,7 +1704,7 @@ u = POP(); PyErr_Restore(v, w, u); why = WHY_RERAISE; - break; + BREAK(); } else if (v != Py_None) { PyErr_SetString(PyExc_SystemError, @@ -1708,7 +1712,7 @@ why = WHY_EXCEPTION; } Py_DECREF(v); - break; + BREAK(); TARGET(LOAD_BUILD_CLASS) x = PyDict_GetItemString(f->f_builtins, @@ -1716,11 +1720,11 @@ if (x == NULL) { PyErr_SetString(PyExc_ImportError, "__build_class__ not found"); - break; - } - Py_INCREF(x); - PUSH(x); - break; + BREAK(); + } + Py_INCREF(x); + PUSH(x); + BREAK(); TARGET(STORE_NAME) w = GETITEM(names, oparg); @@ -1732,11 +1736,11 @@ err = PyObject_SetItem(x, w, v); Py_DECREF(v); if (err == 0) DISPATCH(); - break; + BREAK(); } PyErr_Format(PyExc_SystemError, "no locals found when storing %R", w); - break; + BREAK(); TARGET(DELETE_NAME) w = GETITEM(names, oparg); @@ -1745,11 +1749,11 @@ format_exc_check_arg(PyExc_NameError, NAME_ERROR_MSG, w); - break; + BREAK(); } PyErr_Format(PyExc_SystemError, "no locals when deleting %R", w); - break; + BREAK(); PREDICTED_WITH_ARG(UNPACK_SEQUENCE); TARGET(UNPACK_SEQUENCE) @@ -1782,7 +1786,7 @@ why = WHY_EXCEPTION; } Py_DECREF(v); - break; + BREAK(); TARGET(UNPACK_EX) { @@ -1796,7 +1800,7 @@ why = WHY_EXCEPTION; } Py_DECREF(v); - break; + BREAK(); } TARGET(STORE_ATTR) @@ -1808,7 +1812,7 @@ Py_DECREF(v); Py_DECREF(u); if (err == 0) DISPATCH(); - break; + BREAK(); TARGET(DELETE_ATTR) w = GETITEM(names, oparg); @@ -1816,7 +1820,7 @@ err = PyObject_SetAttr(v, w, (PyObject *)NULL); /* del v.w */ Py_DECREF(v); - break; + BREAK(); TARGET(STORE_GLOBAL) w = GETITEM(names, oparg); @@ -1824,14 +1828,14 @@ err = PyDict_SetItem(f->f_globals, w, v); Py_DECREF(v); if (err == 0) DISPATCH(); - break; + BREAK(); 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; + BREAK(); TARGET(LOAD_NAME) w = GETITEM(names, oparg); @@ -1839,7 +1843,7 @@ PyErr_Format(PyExc_SystemError, "no locals when loading %R", w); why = WHY_EXCEPTION; - break; + BREAK(); } if (PyDict_CheckExact(v)) { x = PyDict_GetItem(v, w); @@ -1850,7 +1854,7 @@ if (x == NULL && PyErr_Occurred()) { if (!PyErr_ExceptionMatches( PyExc_KeyError)) - break; + BREAK(); PyErr_Clear(); } } @@ -1862,7 +1866,7 @@ format_exc_check_arg( PyExc_NameError, NAME_ERROR_MSG, w); - break; + BREAK(); } } Py_INCREF(x); @@ -1884,7 +1888,7 @@ e = d->ma_lookup(d, w, hash); if (e == NULL) { x = NULL; - break; + BREAK(); } x = e->me_value; if (x != NULL) { @@ -1896,7 +1900,7 @@ e = d->ma_lookup(d, w, hash); if (e == NULL) { x = NULL; - break; + BREAK(); } x = e->me_value; if (x != NULL) { @@ -1916,7 +1920,7 @@ format_exc_check_arg( PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w); - break; + BREAK(); } } Py_INCREF(x); @@ -1934,14 +1938,14 @@ UNBOUNDLOCAL_ERROR_MSG, PyTuple_GetItem(co->co_varnames, oparg) ); - break; + BREAK(); TARGET(LOAD_CLOSURE) x = freevars[oparg]; Py_INCREF(x); PUSH(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(LOAD_DEREF) x = freevars[oparg]; @@ -1953,7 +1957,7 @@ err = -1; /* Don't stomp existing exception */ if (PyErr_Occurred()) - break; + BREAK(); if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) { v = PyTuple_GET_ITEM(co->co_cellvars, oparg); @@ -1967,7 +1971,7 @@ format_exc_check_arg(PyExc_NameError, UNBOUNDFREE_ERROR_MSG, v); } - break; + BREAK(); TARGET(STORE_DEREF) w = POP(); @@ -1986,7 +1990,7 @@ PUSH(x); DISPATCH(); } - break; + BREAK(); TARGET(BUILD_LIST) x = PyList_New(oparg); @@ -1998,7 +2002,7 @@ PUSH(x); DISPATCH(); } - break; + BREAK(); TARGET(BUILD_SET) x = PySet_New(NULL); @@ -2011,18 +2015,18 @@ } if (err != 0) { Py_DECREF(x); - break; - } - PUSH(x); - DISPATCH(); - } - break; + BREAK(); + } + PUSH(x); + DISPATCH(); + } + BREAK(); TARGET(BUILD_MAP) x = _PyDict_NewPresized((Py_ssize_t)oparg); PUSH(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(STORE_MAP) w = TOP(); /* key */ @@ -2034,7 +2038,7 @@ Py_DECREF(u); Py_DECREF(w); if (err == 0) DISPATCH(); - break; + BREAK(); TARGET(MAP_ADD) w = TOP(); /* key */ @@ -2049,7 +2053,7 @@ PREDICT(JUMP_ABSOLUTE); DISPATCH(); } - break; + BREAK(); TARGET(LOAD_ATTR) w = GETITEM(names, oparg); @@ -2058,7 +2062,7 @@ Py_DECREF(v); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(COMPARE_OP) w = POP(); @@ -2067,7 +2071,7 @@ Py_DECREF(v); Py_DECREF(w); SET_TOP(x); - if (x == NULL) break; + if (x == NULL) BREAK(); PREDICT(JUMP_IF_FALSE); PREDICT(JUMP_IF_TRUE); DISPATCH(); @@ -2078,7 +2082,7 @@ if (x == NULL) { PyErr_SetString(PyExc_ImportError, "__import__ not found"); - break; + BREAK(); } Py_INCREF(x); v = POP(); @@ -2104,7 +2108,7 @@ u = POP(); Py_DECREF(x); x = NULL; - break; + BREAK(); } READ_TIMESTAMP(intr0); v = x; @@ -2114,7 +2118,7 @@ Py_DECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(IMPORT_STAR) v = POP(); @@ -2122,7 +2126,7 @@ if ((x = f->f_locals) == NULL) { PyErr_SetString(PyExc_SystemError, "no locals found during 'import *'"); - break; + BREAK(); } READ_TIMESTAMP(intr0); err = import_all_from(x, v); @@ -2130,7 +2134,7 @@ PyFrame_LocalsToFast(f, 0); Py_DECREF(v); if (err == 0) DISPATCH(); - break; + BREAK(); TARGET(IMPORT_FROM) w = GETITEM(names, oparg); @@ -2140,7 +2144,7 @@ READ_TIMESTAMP(intr1); PUSH(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(JUMP_FORWARD) JUMPBY(oparg); @@ -2163,7 +2167,7 @@ else if (err == 0) JUMPBY(oparg); else - break; + BREAK(); DISPATCH(); PREDICTED_WITH_ARG(JUMP_IF_TRUE); @@ -2185,7 +2189,7 @@ else if (err == 0) ; else - break; + BREAK(); DISPATCH(); PREDICTED_WITH_ARG(JUMP_ABSOLUTE); @@ -2215,7 +2219,7 @@ DISPATCH(); } STACKADJ(-1); - break; + BREAK(); PREDICTED_WITH_ARG(FOR_ITER); TARGET(FOR_ITER) @@ -2231,7 +2235,7 @@ if (PyErr_Occurred()) { if (!PyErr_ExceptionMatches( PyExc_StopIteration)) - break; + BREAK(); PyErr_Clear(); } /* iterator ended normally */ @@ -2248,7 +2252,7 @@ retval = PyLong_FromLong(oparg); if (!retval) { x = NULL; - break; + BREAK(); } why = WHY_CONTINUE; goto fast_block_end; @@ -2307,7 +2311,7 @@ NULL); Py_DECREF(exit_func); if (x == NULL) - break; /* Go to error exit */ + BREAK(); /* Go to error exit */ if (u != Py_None) err = PyObject_IsTrue(x); @@ -2316,7 +2320,7 @@ Py_DECREF(x); if (err < 0) - break; /* Go to error exit */ + BREAK(); /* Go to error exit */ else if (err > 0) { err = 0; /* There was an exception and a True return */ @@ -2327,7 +2331,7 @@ Py_DECREF(w); } PREDICT(END_FINALLY); - break; + BREAK(); } TARGET(CALL_FUNCTION) @@ -2344,7 +2348,7 @@ PUSH(x); if (x != NULL) DISPATCH(); - break; + BREAK(); } TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw) @@ -2391,7 +2395,7 @@ PUSH(x); if (x != NULL) DISPATCH(); - break; + BREAK(); } TARGET_WITH_IMPL(MAKE_CLOSURE, _make_function) @@ -2422,7 +2426,7 @@ if (v == NULL) { Py_DECREF(x); x = NULL; - break; + BREAK(); } name_ix = PyTuple_Size(u); assert(num_annotations == name_ix+1); @@ -2450,7 +2454,7 @@ if (v == NULL) { Py_DECREF(x); x = NULL; - break; + BREAK(); } while (--posdefaults >= 0) { w = POP(); @@ -2468,7 +2472,7 @@ if (v == NULL) { Py_DECREF(x); x = NULL; - break; + BREAK(); } while (--kwdefaults >= 0) { w = POP(); /* default value */ @@ -2486,7 +2490,7 @@ Py_DECREF(v); } PUSH(x); - break; + BREAK(); } TARGET(BUILD_SLICE) @@ -2502,30 +2506,28 @@ Py_XDECREF(w); SET_TOP(x); if (x != NULL) DISPATCH(); - break; + BREAK(); TARGET(EXTENDED_ARG) opcode = NEXTOP(); oparg = oparg<<16 | NEXTARG(); goto dispatch_opcode; -#ifdef USE_COMPUTED_GOTOS - _unknown_opcode: -#endif - default: + + DEFAULT_TARGET: fprintf(stderr, "XXX lineno: %d, opcode: %d\n", PyCode_Addr2Line(f->f_code, f->f_lasti), opcode); PyErr_SetString(PyExc_SystemError, "unknown opcode"); why = WHY_EXCEPTION; - break; - -#ifdef CASE_TOO_BIG - } -#endif - - } /* switch */ + BREAK(); + +#if defined(CASE_TOO_BIG) && !defined(USE_COMPUTED_GOTOS) + } +#endif + + } /* switch */ on_error: