diff --git a/Include/opcode.h b/Include/opcode.h index 171aae7..8e76d63 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -106,9 +106,8 @@ extern "C" { #define LOAD_DEREF 136 #define STORE_DEREF 137 #define DELETE_DEREF 138 -#define CALL_FUNCTION_VAR 140 #define CALL_FUNCTION_KW 141 -#define CALL_FUNCTION_VAR_KW 142 +#define CALL_FUNCTION_EX 142 #define SETUP_WITH 143 #define EXTENDED_ARG 144 #define LIST_APPEND 145 diff --git a/Lib/dis.py b/Lib/dis.py index 59886f1..386d86d 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -313,7 +313,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None, argrepr = argval elif op in hasfree: argval, argrepr = _get_name_info(arg, cells) - elif op in hasnargs: + elif op in hasnargs: # unused argrepr = "%d positional, %d keyword pair" % (arg%256, arg//256) yield Instruction(opname[op], op, arg, argval, argrepr, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 30e8330..967fc61 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -226,6 +226,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.6a1 3371 (add BUILD_CONST_KEY_MAP opcode #27140) # Python 3.6a1 3372 (MAKE_FUNCTION simplification, remove MAKE_CLOSURE #27095) +# Python 3.6a1 3373 (CALL_FUNCTIONs simplification) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually @@ -234,7 +235,7 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3372).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3373).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 0640819..109a6bd 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -31,7 +31,7 @@ hasjabs = [] haslocal = [] hascompare = [] hasfree = [] -hasnargs = [] +hasnargs = [] # unused opmap = {} opname = ['<%r>' % (op,) for op in range(256)] @@ -171,8 +171,7 @@ def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) -def_op('CALL_FUNCTION', 131) # #args + (#kwargs << 8) -hasnargs.append(131) +def_op('CALL_FUNCTION', 131) # #args def_op('MAKE_FUNCTION', 132) # Flags def_op('BUILD_SLICE', 133) # Number of items def_op('LOAD_CLOSURE', 135) @@ -184,12 +183,8 @@ hasfree.append(137) def_op('DELETE_DEREF', 138) hasfree.append(138) -def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8) -hasnargs.append(140) -def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8) -hasnargs.append(141) -def_op('CALL_FUNCTION_VAR_KW', 142) # #args + (#kwargs << 8) -hasnargs.append(142) +def_op('CALL_FUNCTION_KW', 141) # #args + #kwargs +def_op('CALL_FUNCTION_EX', 142) # Flags jrel_op('SETUP_WITH', 143) diff --git a/Python/ceval.c b/Python/ceval.c index 38ac509..4d43eb5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -109,19 +109,17 @@ typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *); /* Forward declarations */ #ifdef WITH_TSC -static PyObject * call_function(PyObject ***, int, uint64*, uint64*); +static PyObject * call_function(PyObject ***, Py_ssize_t, uint64*, uint64*); +static PyObject * call_function_kw(PyObject ***, Py_ssize_t, uint64*, uint64*); #else -static PyObject * call_function(PyObject ***, int); +static PyObject * call_function(PyObject ***, Py_ssize_t); +static PyObject * call_function_kw(PyObject ***, Py_ssize_t); #endif -static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); -static PyObject * do_call(PyObject *, PyObject ***, int, int); -static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); -static PyObject * update_keyword_args(PyObject *, int, PyObject ***, - PyObject *); -static PyObject * update_star_args(int, int, PyObject *, PyObject ***); -static PyObject * load_args(PyObject ***, int); -#define CALL_FLAG_VAR 1 -#define CALL_FLAG_KW 2 +static PyObject * fast_function(PyObject *, PyObject ***, int); +static PyObject * do_call(PyObject *, PyObject ***, Py_ssize_t, PyObject *); +static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); +static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *); +static PyObject * load_args(PyObject ***, Py_ssize_t); #ifdef LLTRACE static int lltrace; @@ -2690,8 +2688,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (sum == NULL) goto error; if (with_call) { - num_maps = oparg & 0xff; - function_location = (oparg>>8) & 0xff; + num_maps = oparg & 0x7FFF; + function_location = !(oparg>>15); } else { num_maps = oparg; @@ -3266,60 +3264,87 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } TARGET(CALL_FUNCTION) { - PyObject **sp, *res; + PyObject *res; PCALL(PCALL_ALL); - sp = stack_pointer; #ifdef WITH_TSC - res = call_function(&sp, oparg, &intr0, &intr1); + res = call_function(&stack_pointer, oparg, &intr0, &intr1); #else - res = call_function(&sp, oparg); + res = call_function(&stack_pointer, oparg); #endif - stack_pointer = sp; PUSH(res); - if (res == NULL) + if (res == NULL) { goto error; + } DISPATCH(); } - TARGET(CALL_FUNCTION_VAR) - TARGET(CALL_FUNCTION_KW) - TARGET(CALL_FUNCTION_VAR_KW) { - int na = oparg & 0xff; - int nk = (oparg>>8) & 0xff; - int flags = (opcode - CALL_FUNCTION) & 3; - int n = na + 2 * nk; - PyObject **pfunc, *func, **sp, *res; + TARGET(CALL_FUNCTION_KW) { + PyObject *res; + assert(PyTuple_CheckExact(TOP()) && PyTuple_GET_SIZE(TOP()) <= oparg); PCALL(PCALL_ALL); - if (flags & CALL_FLAG_VAR) - n++; - if (flags & CALL_FLAG_KW) - n++; - pfunc = stack_pointer - n - 1; - func = *pfunc; +#ifdef WITH_TSC + res = call_function_kw(&stack_pointer, oparg, &intr0, &intr1); +#else + res = call_function_kw(&stack_pointer, oparg); +#endif + PUSH(res); + if (res == NULL) { + goto error; + } + DISPATCH(); + } + + TARGET(CALL_FUNCTION_EX) { + PyObject *func, *callargs, *kwargs = NULL, *res; + PCALL(PCALL_ALL); + if (oparg & 0x02) { + kwargs = POP(); + } + if (oparg & 0x01) { + callargs = POP(); + assert(PyTuple_CheckExact(callargs)); + } else { + callargs = PyTuple_New(0); + if (callargs == NULL) { + goto error; + } + } + func = TOP(); if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { - PyObject *self = PyMethod_GET_SELF(func); + Py_ssize_t calllen = PyTuple_GET_SIZE(callargs); + PyObject *newcallargs = PyTuple_New(calllen + 1); + PyObject *self; + if (newcallargs == NULL) { + goto error; + } + + self = PyMethod_GET_SELF(func); Py_INCREF(self); + PyTuple_SET_ITEM(newcallargs, 0, self); + for (Py_ssize_t i = 0; i < calllen; i++) { + PyObject *item = PyTuple_GET_ITEM(callargs, i); + Py_INCREF(item); + PyTuple_SET_ITEM(newcallargs, i+1, item); + } + Py_DECREF(callargs); + callargs = newcallargs; func = PyMethod_GET_FUNCTION(func); + Py_DECREF(TOP()); Py_INCREF(func); - Py_SETREF(*pfunc, self); - na++; - /* n++; */ - } else + + } else { Py_INCREF(func); - sp = stack_pointer; + } READ_TIMESTAMP(intr0); - res = ext_do_call(func, &sp, flags, na, nk); + res = do_call_core(func, callargs, kwargs); READ_TIMESTAMP(intr1); - stack_pointer = sp; Py_DECREF(func); + Py_XDECREF(callargs); + Py_XDECREF(kwargs); - while (stack_pointer > pfunc) { - PyObject *o = POP(); - Py_DECREF(o); - } - PUSH(res); + SET_TOP(res); if (res == NULL) goto error; DISPATCH(); @@ -4670,25 +4695,21 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \ } else { \ x = call; \ } - static PyObject * -call_function(PyObject ***pp_stack, int oparg +call_function(PyObject ***pp_stack, Py_ssize_t oparg #ifdef WITH_TSC , uint64* pintr0, uint64* pintr1 #endif ) { - int na = oparg & 0xff; - int nk = (oparg>>8) & 0xff; - int n = na + 2 * nk; - PyObject **pfunc = (*pp_stack) - n - 1; + PyObject **pfunc = (*pp_stack) - oparg - 1; PyObject *func = *pfunc; PyObject *x, *w; /* Always dispatch PyCFunction first, because these are presumed to be the most frequent callable object. */ - if (PyCFunction_Check(func) && nk == 0) { + if (PyCFunction_Check(func)) { int flags = PyCFunction_GET_FLAGS(func); PyThreadState *tstate = PyThreadState_GET(); @@ -4696,12 +4717,12 @@ call_function(PyObject ***pp_stack, int oparg if (flags & (METH_NOARGS | METH_O)) { PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); - if (flags & METH_NOARGS && na == 0) { + if (flags & METH_NOARGS && oparg == 0) { C_TRACE(x, (*meth)(self,NULL)); x = _Py_CheckFunctionResult(func, x, NULL); } - else if (flags & METH_O && na == 1) { + else if (flags & METH_O && oparg == 1) { PyObject *arg = EXT_POP(*pp_stack); C_TRACE(x, (*meth)(self,arg)); Py_DECREF(arg); @@ -4709,18 +4730,18 @@ call_function(PyObject ***pp_stack, int oparg x = _Py_CheckFunctionResult(func, x, NULL); } else { - err_args(func, flags, na); + err_args(func, flags, oparg); x = NULL; } } else { PyObject *callargs; - callargs = load_args(pp_stack, na); + callargs = load_args(pp_stack, oparg); if (callargs != NULL) { READ_TIMESTAMP(*pintr0); - C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); + C_TRACE(x, PyCFunction_Call(func, callargs, NULL)); READ_TIMESTAMP(*pintr1); - Py_XDECREF(callargs); + Py_DECREF(callargs); } else { x = NULL; @@ -4728,30 +4749,81 @@ call_function(PyObject ***pp_stack, int oparg } } else { - if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { - /* optimize access to bound methods */ - PyObject *self = PyMethod_GET_SELF(func); - PCALL(PCALL_METHOD); - PCALL(PCALL_BOUND_METHOD); - Py_INCREF(self); - func = PyMethod_GET_FUNCTION(func); - Py_INCREF(func); - Py_SETREF(*pfunc, self); - na++; - n++; - } else - Py_INCREF(func); - READ_TIMESTAMP(*pintr0); - if (PyFunction_Check(func)) - x = fast_function(func, pp_stack, n, na, nk); - else - x = do_call(func, pp_stack, na, nk); - READ_TIMESTAMP(*pintr1); - Py_DECREF(func); + if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { + /* optimize access to bound methods */ + PyObject *self = PyMethod_GET_SELF(func); + PCALL(PCALL_METHOD); + PCALL(PCALL_BOUND_METHOD); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_SETREF(*pfunc, self); + oparg++; + } else { + Py_INCREF(func); + } + READ_TIMESTAMP(*pintr0); + if (PyFunction_Check(func)) { + x = fast_function(func, pp_stack, oparg); + } else { + x = do_call(func, pp_stack, oparg, 0); + } + READ_TIMESTAMP(*pintr1); + Py_DECREF(func); + } + + assert((x != NULL) ^ (PyErr_Occurred() != NULL)); - assert((x != NULL) ^ (PyErr_Occurred() != NULL)); + /* Clear the stack of the function object. Also removes + the arguments in case they weren't consumed already + (fast_function() and err_args() leave them on the stack). + */ + while ((*pp_stack) > pfunc) { + w = EXT_POP(*pp_stack); + Py_DECREF(w); + PCALL(PCALL_POP); } + return x; +} + +static PyObject * +call_function_kw(PyObject ***pp_stack, Py_ssize_t oparg +#ifdef WITH_TSC + , uint64* pintr0, uint64* pintr1 +#endif + ) +{ + PyObject *names = EXT_POP(*pp_stack); + PyObject **pfunc = (*pp_stack) - oparg - 1; + PyObject *func = *pfunc; + PyObject *x, *w; + Py_ssize_t nk = PyTuple_GET_SIZE(names); + Py_ssize_t na = oparg - nk; + + /* Always dispatch PyCFunction first, because these are + presumed to be the most frequent callable object. + */ + if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { + /* optimize access to bound methods */ + PyObject *self = PyMethod_GET_SELF(func); + PCALL(PCALL_METHOD); + PCALL(PCALL_BOUND_METHOD); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_SETREF(*pfunc, self); + na++; + } else { + Py_INCREF(func); + } + READ_TIMESTAMP(*pintr0); + x = do_call(func, pp_stack, na, names); + READ_TIMESTAMP(*pintr1); + Py_DECREF(func); + + assert((x != NULL) ^ (PyErr_Occurred() != NULL)); + /* Clear the stack of the function object. Also removes the arguments in case they weren't consumed already (fast_function() and err_args() leave them on the stack). @@ -4776,7 +4848,7 @@ call_function(PyObject ***pp_stack, int oparg */ static PyObject * -fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) +fast_function(PyObject *func, PyObject ***pp_stack, int na) { PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); PyObject *globals = PyFunction_GET_GLOBALS(func); @@ -4789,8 +4861,8 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) PCALL(PCALL_FUNCTION); PCALL(PCALL_FAST_FUNCTION); - if (argdefs == NULL && co->co_argcount == n && - co->co_kwonlyargcount == 0 && nk==0 && + if (argdefs == NULL && co->co_argcount == na && + co->co_kwonlyargcount == 0 && co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { PyFrameObject *f; PyObject *retval = NULL; @@ -4810,9 +4882,9 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) return NULL; fastlocals = f->f_localsplus; - stack = (*pp_stack) - n; + stack = (*pp_stack) - na; - for (i = 0; i < n; i++) { + for (i = 0; i < na; i++) { Py_INCREF(*stack); fastlocals[i] = *stack++; } @@ -4827,29 +4899,24 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) nd = Py_SIZE(argdefs); } return _PyEval_EvalCodeWithName((PyObject*)co, globals, - (PyObject *)NULL, (*pp_stack)-n, na, - (*pp_stack)-2*nk, nk, d, nd, kwdefs, + (PyObject *)NULL, (*pp_stack)-na, na, + NULL, 0, d, nd, kwdefs, PyFunction_GET_CLOSURE(func), name, qualname); } static PyObject * -update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, +create_keyword_args(PyObject *names, PyObject ***pp_stack, PyObject *func) { - PyObject *kwdict = NULL; - if (orig_kwdict == NULL) - kwdict = PyDict_New(); - else { - kwdict = PyDict_Copy(orig_kwdict); - Py_DECREF(orig_kwdict); - } + Py_ssize_t nk = PyTuple_GET_SIZE(names); + PyObject *kwdict = _PyDict_NewPresized(nk); if (kwdict == NULL) return NULL; while (--nk >= 0) { int err; PyObject *value = EXT_POP(*pp_stack); - PyObject *key = EXT_POP(*pp_stack); + PyObject *key = PyTuple_GET_ITEM(names, nk); if (PyDict_GetItem(kwdict, key) != NULL) { PyErr_Format(PyExc_TypeError, "%.200s%s got multiple values " @@ -4857,13 +4924,11 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, PyEval_GetFuncName(func), PyEval_GetFuncDesc(func), key); - Py_DECREF(key); Py_DECREF(value); Py_DECREF(kwdict); return NULL; } err = PyDict_SetItem(kwdict, key, value); - Py_DECREF(key); Py_DECREF(value); if (err) { Py_DECREF(kwdict); @@ -4874,47 +4939,7 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, } static PyObject * -update_star_args(int nstack, int nstar, PyObject *stararg, - PyObject ***pp_stack) -{ - PyObject *callargs, *w; - - if (!nstack) { - if (!stararg) { - /* There are no positional arguments on the stack and there is no - sequence to be unpacked. */ - return PyTuple_New(0); - } - if (PyTuple_CheckExact(stararg)) { - /* No arguments are passed on the stack and the sequence is not a - tuple subclass so we can just pass the stararg tuple directly - to the function. */ - Py_INCREF(stararg); - return stararg; - } - } - - callargs = PyTuple_New(nstack + nstar); - if (callargs == NULL) { - return NULL; - } - if (nstar) { - int i; - for (i = 0; i < nstar; i++) { - PyObject *a = PyTuple_GET_ITEM(stararg, i); - Py_INCREF(a); - PyTuple_SET_ITEM(callargs, nstack + i, a); - } - } - while (--nstack >= 0) { - w = EXT_POP(*pp_stack); - PyTuple_SET_ITEM(callargs, nstack, w); - } - return callargs; -} - -static PyObject * -load_args(PyObject ***pp_stack, int na) +load_args(PyObject ***pp_stack, Py_ssize_t na) { PyObject *args = PyTuple_New(na); PyObject *w; @@ -4929,42 +4954,22 @@ load_args(PyObject ***pp_stack, int na) } static PyObject * -do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) +do_call(PyObject *func, PyObject ***pp_stack, Py_ssize_t na, PyObject *names) { PyObject *callargs = NULL; PyObject *kwdict = NULL; PyObject *result = NULL; - if (nk > 0) { - kwdict = update_keyword_args(NULL, nk, pp_stack, func); + if (names != NULL) { + kwdict = create_keyword_args(names, pp_stack, func); if (kwdict == NULL) goto call_fail; } callargs = load_args(pp_stack, na); if (callargs == NULL) goto call_fail; -#ifdef CALL_PROFILE - /* At this point, we have to look at the type of func to - update the call stats properly. Do it here so as to avoid - exposing the call stats machinery outside ceval.c - */ - if (PyFunction_Check(func)) - PCALL(PCALL_FUNCTION); - else if (PyMethod_Check(func)) - PCALL(PCALL_METHOD); - else if (PyType_Check(func)) - PCALL(PCALL_TYPE); - else if (PyCFunction_Check(func)) - PCALL(PCALL_CFUNCTION); - else - PCALL(PCALL_OTHER); -#endif - if (PyCFunction_Check(func)) { - PyThreadState *tstate = PyThreadState_GET(); - C_TRACE(result, PyCFunction_Call(func, callargs, kwdict)); - } - else - result = PyObject_Call(func, callargs, kwdict); + + result = do_call_core(func, callargs, kwdict); call_fail: Py_XDECREF(callargs); Py_XDECREF(kwdict); @@ -4972,75 +4977,8 @@ call_fail: } static PyObject * -ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) +do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) { - int nstar = 0; - PyObject *callargs = NULL; - PyObject *stararg = NULL; - PyObject *kwdict = NULL; - PyObject *result = NULL; - - if (flags & CALL_FLAG_KW) { - kwdict = EXT_POP(*pp_stack); - if (!PyDict_CheckExact(kwdict)) { - PyObject *d; - d = PyDict_New(); - if (d == NULL) - goto ext_call_fail; - if (PyDict_Update(d, kwdict) != 0) { - Py_DECREF(d); - /* PyDict_Update raises attribute - * error (percolated from an attempt - * to get 'keys' attribute) instead of - * a type error if its second argument - * is not a mapping. - */ - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after ** " - "must be a mapping, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - kwdict->ob_type->tp_name); - } - goto ext_call_fail; - } - Py_DECREF(kwdict); - kwdict = d; - } - } - if (nk > 0) { - kwdict = update_keyword_args(kwdict, nk, pp_stack, func); - if (kwdict == NULL) - goto ext_call_fail; - } - - if (flags & CALL_FLAG_VAR) { - stararg = EXT_POP(*pp_stack); - if (!PyTuple_Check(stararg)) { - PyObject *t = NULL; - if (Py_TYPE(stararg)->tp_iter == NULL && - !PySequence_Check(stararg)) { - PyErr_Format(PyExc_TypeError, - "%.200s%.200s argument after * " - "must be an iterable, not %.200s", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - stararg->ob_type->tp_name); - goto ext_call_fail; - } - t = PySequence_Tuple(stararg); - if (t == NULL) { - goto ext_call_fail; - } - Py_DECREF(stararg); - stararg = t; - } - nstar = PyTuple_GET_SIZE(stararg); - } - callargs = update_star_args(na, nstar, stararg, pp_stack); - if (callargs == NULL) - goto ext_call_fail; #ifdef CALL_PROFILE /* At this point, we have to look at the type of func to update the call stats properly. Do it here so as to avoid @@ -5058,16 +4996,14 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) PCALL(PCALL_OTHER); #endif if (PyCFunction_Check(func)) { + PyObject *result; PyThreadState *tstate = PyThreadState_GET(); C_TRACE(result, PyCFunction_Call(func, callargs, kwdict)); + return result; + } + else { + return PyObject_Call(func, callargs, kwdict); } - else - result = PyObject_Call(func, callargs, kwdict); -ext_call_fail: - Py_XDECREF(callargs); - Py_XDECREF(kwdict); - Py_XDECREF(stararg); - return result; } /* Extract a slice index from a PyLong or an object with the diff --git a/Python/compile.c b/Python/compile.c index 687b750..47d10b4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -977,7 +977,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) case BUILD_MAP_UNPACK: return 1 - oparg; case BUILD_MAP_UNPACK_WITH_CALL: - return 1 - (oparg & 0xFF); + return 1 - (oparg & 0x7FFF); case BUILD_MAP: return 1 - 2*oparg; case BUILD_CONST_KEY_MAP: @@ -1022,15 +1022,12 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) case RAISE_VARARGS: return -oparg; -#define NARGS(o) (((o) % 256) + 2*(((o) / 256) % 256)) case CALL_FUNCTION: - return -NARGS(oparg); - case CALL_FUNCTION_VAR: + return -oparg; case CALL_FUNCTION_KW: - return -NARGS(oparg)-1; - case CALL_FUNCTION_VAR_KW: - return -NARGS(oparg)-2; -#undef NARGS + return -oparg-1; + case CALL_FUNCTION_EX: + return - ((oparg & 0x01) != 0) - ((oparg & 0x02) != 0); case MAKE_FUNCTION: return -1 - ((oparg & 0x01) != 0) - ((oparg & 0x02) != 0) - ((oparg & 0x04) != 0) - ((oparg & 0x08) != 0); @@ -3394,32 +3391,21 @@ compiler_subkwargs(struct compiler *c, asdl_seq *keywords, Py_ssize_t begin, Py_ keyword_ty kw; PyObject *keys, *key; assert(n > 0); - if (n > 1) { - for (i = begin; i < end; i++) { - kw = asdl_seq_GET(keywords, i); - VISIT(c, expr, kw->value); - } - keys = PyTuple_New(n); - if (keys == NULL) { - return 0; - } - for (i = begin; i < end; i++) { - key = ((keyword_ty) asdl_seq_GET(keywords, i))->arg; - Py_INCREF(key); - PyTuple_SET_ITEM(keys, i - begin, key); - } - ADDOP_N(c, LOAD_CONST, keys, consts); - ADDOP_I(c, BUILD_CONST_KEY_MAP, n); + for (i = begin; i < end; i++) { + kw = asdl_seq_GET(keywords, i); + VISIT(c, expr, kw->value); } - else { - /* a for loop only executes once */ - for (i = begin; i < end; i++) { - kw = asdl_seq_GET(keywords, i); - ADDOP_O(c, LOAD_CONST, kw->arg, consts); - VISIT(c, expr, kw->value); - } - ADDOP_I(c, BUILD_MAP, n); + keys = PyTuple_New(n); + if (keys == NULL) { + return 0; } + for (i = begin; i < end; i++) { + key = ((keyword_ty) asdl_seq_GET(keywords, i))->arg; + Py_INCREF(key); + PyTuple_SET_ITEM(keys, i - begin, key); + } + ADDOP_N(c, LOAD_CONST, keys, consts); + ADDOP_I(c, BUILD_CONST_KEY_MAP, n); return 1; } @@ -3430,22 +3416,36 @@ compiler_call_helper(struct compiler *c, asdl_seq *args, asdl_seq *keywords) { - int code = 0; - Py_ssize_t nelts, i, nseen; - int nkw; + Py_ssize_t nelts, i, nseen, nkwelts; + int isex = 0, musttupleunpack = 0, mustdictunpack = 0; /* the number of tuples and dictionaries on the stack */ Py_ssize_t nsubargs = 0, nsubkwargs = 0; - nkw = 0; - nseen = 0; /* the number of positional arguments on the stack */ nelts = asdl_seq_LEN(args); + nkwelts = asdl_seq_LEN(keywords); + for (i = 0; i < nelts; i++) { + expr_ty elt = asdl_seq_GET(args, i); + if (elt->kind == Starred_kind) { + isex = 1; + musttupleunpack = 1; + break; + } + } + for (i = 0; i < nkwelts; i++) { + keyword_ty kw = asdl_seq_GET(keywords, i); + if (kw->arg == NULL) { + isex = 1; + mustdictunpack = 1; + break; + } + } + nseen = 0; /* the number of positional arguments on the stack */ for (i = 0; i < nelts; i++) { expr_ty elt = asdl_seq_GET(args, i); if (elt->kind == Starred_kind) { /* A star-arg. If we've seen positional arguments, - pack the positional arguments into a - tuple. */ + pack the positional arguments into a tuple. */ if (nseen) { ADDOP_I(c, BUILD_TUPLE, nseen); nseen = 0; @@ -3454,101 +3454,75 @@ compiler_call_helper(struct compiler *c, VISIT(c, expr, elt->v.Starred.value); nsubargs++; } - else if (nsubargs) { - /* We've seen star-args already, so we - count towards items-to-pack-into-tuple. */ - VISIT(c, expr, elt); - nseen++; - } else { - /* Positional arguments before star-arguments - are left on the stack. */ VISIT(c, expr, elt); - n++; + nseen++; } } - if (nseen) { - /* Pack up any trailing positional arguments. */ - ADDOP_I(c, BUILD_TUPLE, nseen); - nsubargs++; - } - if (nsubargs) { - code |= 1; - if (nsubargs > 1) { + + /* Same dance again for keyword arguments */ + if (isex) { + if (nseen) { + /* Pack up any trailing positional arguments. */ + ADDOP_I(c, BUILD_TUPLE, nseen); + nsubargs++; + } + if (musttupleunpack || nsubargs > 1) { /* If we ended up with more than one stararg, we need to concatenate them into a single sequence. */ - ADDOP_I(c, BUILD_LIST_UNPACK, nsubargs); + ADDOP_I(c, BUILD_TUPLE_UNPACK, nsubargs); } - } - - /* Same dance again for keyword arguments */ - nseen = 0; /* the number of keyword arguments on the stack following */ - nelts = asdl_seq_LEN(keywords); - for (i = 0; i < nelts; i++) { - keyword_ty kw = asdl_seq_GET(keywords, i); - if (kw->arg == NULL) { - /* A keyword argument unpacking. */ - if (nseen) { - if (nsubkwargs) { + nseen = 0; /* the number of keyword arguments on the stack following */ + for (i = 0; i < nkwelts; i++) { + keyword_ty kw = asdl_seq_GET(keywords, i); + if (kw->arg == NULL) { + /* A keyword argument unpacking. */ + if (nseen) { if (!compiler_subkwargs(c, keywords, i - nseen, i)) return 0; nsubkwargs++; + nseen = 0; } - else { - Py_ssize_t j; - for (j = 0; j < nseen; j++) { - VISIT(c, keyword, asdl_seq_GET(keywords, j)); - } - nkw = nseen; - } - nseen = 0; + VISIT(c, expr, kw->value); + nsubkwargs++; + } + else { + nseen++; } - VISIT(c, expr, kw->value); - nsubkwargs++; - } - else { - nseen++; } - } - if (nseen) { - if (nsubkwargs) { + if (nseen) { /* Pack up any trailing keyword arguments. */ - if (!compiler_subkwargs(c, keywords, nelts - nseen, nelts)) + if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts)) return 0; nsubkwargs++; } - else { - VISIT_SEQ(c, keyword, keywords); - nkw = nseen; + if (mustdictunpack || nsubkwargs > 1) { + /* Pack it all up */ + ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs | (nsubargs == 0) << 15); } + ADDOP_I(c, CALL_FUNCTION_EX, (nsubargs > 0) | ((nsubkwargs > 0) << 1)); + return 1; } - if (nsubkwargs) { - code |= 2; - if (nsubkwargs > 1) { - /* Pack it all up */ - int function_pos = n + (code & 1) + 2 * nkw + 1; - ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs | (function_pos << 8)); + else if (nkwelts) { + PyObject *names; + VISIT_SEQ(c, keyword, keywords); + names = PyTuple_New(nkwelts); + if (names == NULL) { + return 0; + } + for (i = 0; i < nkwelts; i++) { + keyword_ty kw = asdl_seq_GET(keywords, i); + Py_INCREF(kw->arg); + PyTuple_SET_ITEM(names, i, kw->arg); } + ADDOP_N(c, LOAD_CONST, names, consts); + ADDOP_I(c, CALL_FUNCTION_KW, n + nelts + nkwelts); + return 1; } - assert(n < 1<<8); - assert(nkw < 1<<24); - n |= nkw << 8; - - switch (code) { - case 0: - ADDOP_I(c, CALL_FUNCTION, n); - break; - case 1: - ADDOP_I(c, CALL_FUNCTION_VAR, n); - break; - case 2: - ADDOP_I(c, CALL_FUNCTION_KW, n); - break; - case 3: - ADDOP_I(c, CALL_FUNCTION_VAR_KW, n); - break; + else { + ADDOP_I(c, CALL_FUNCTION, n + nelts); + return 1; } - return 1; } @@ -3791,7 +3765,6 @@ compiler_dictcomp(struct compiler *c, expr_ty e) static int compiler_visit_keyword(struct compiler *c, keyword_ty k) { - ADDOP_O(c, LOAD_CONST, k->arg, consts); VISIT(c, expr, k->value); return 1; } diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 6182e80..d0a2326 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -139,9 +139,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&_unknown_opcode, - &&TARGET_CALL_FUNCTION_VAR, + &&_unknown_opcode, &&TARGET_CALL_FUNCTION_KW, - &&TARGET_CALL_FUNCTION_VAR_KW, + &&TARGET_CALL_FUNCTION_EX, &&TARGET_SETUP_WITH, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND,