diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 5dd497b..e82dbed 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -929,27 +929,16 @@ the more significant byte last. .. opcode:: MAKE_FUNCTION (argc) Pushes a new function object on the stack. From bottom to top, the consumed - stack must consist of - - * ``argc & 0xFF`` default argument objects in positional order - * ``(argc >> 8) & 0xFF`` pairs of name and default argument, with the name - just below the object on the stack, for keyword-only parameters - * ``(argc >> 16) & 0x7FFF`` parameter annotation objects - * a tuple listing the parameter names for the annotations (only if there are - ony annotation objects) + stack must consist of values if the argument carries a specified flag value + + * ``0x01`` a tuple of default argument objects in positional order + * ``0x02`` a dictionary of keyword-only parameters' default values + * ``0x04`` an annotation dictionary + * ``0x08`` a tuple containing cells for free variables, making a closure * the code associated with the function (at TOS1) * the :term:`qualified name` of the function (at TOS) -.. opcode:: MAKE_CLOSURE (argc) - - Creates a new function object, sets its *__closure__* slot, and pushes it on - the stack. TOS is the :term:`qualified name` of the function, TOS1 is the - code associated with the function, and TOS2 is the tuple containing cells for - the closure's free variables. *argc* is interpreted as in ``MAKE_FUNCTION``; - the annotations and defaults are also in the same order below TOS2. - - .. opcode:: BUILD_SLICE (argc) .. index:: builtin: slice diff --git a/Include/opcode.h b/Include/opcode.h index b265368..5cfdd3e 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -102,7 +102,6 @@ extern "C" { #define CALL_FUNCTION 131 #define MAKE_FUNCTION 132 #define BUILD_SLICE 133 -#define MAKE_CLOSURE 134 #define LOAD_CLOSURE 135 #define LOAD_DEREF 136 #define STORE_DEREF 137 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 076ed16..7cf1bb0 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -225,6 +225,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.5b2 3350 (add GET_YIELD_FROM_ITER opcode #24400) # Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483 # Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed) +# Python 3.6a2 3371 (MAKE_FUNCTION simplification) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually diff --git a/Lib/lib2to3/tests/data/py3_test_grammar.py b/Lib/lib2to3/tests/data/py3_test_grammar.py index c0bf7f2..704e10d 100644 --- a/Lib/lib2to3/tests/data/py3_test_grammar.py +++ b/Lib/lib2to3/tests/data/py3_test_grammar.py @@ -319,7 +319,7 @@ class GrammarTests(unittest.TestCase): def f(x) -> list: pass self.assertEquals(f.__annotations__, {'return': list}) - # test MAKE_CLOSURE with a variety of oparg's + # test MAKE_FUNCTION with a variety of oparg's closure = 1 def f(): return closure def f(x=1): return closure diff --git a/Lib/opcode.py b/Lib/opcode.py index ecc24bb..8d4846b 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -173,9 +173,8 @@ 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('MAKE_FUNCTION', 132) # Number of args with default values +def_op('MAKE_FUNCTION', 132) # Flags (default args, kwonly default args, annotations, free variables) def_op('BUILD_SLICE', 133) # Number of items -def_op('MAKE_CLOSURE', 134) def_op('LOAD_CLOSURE', 135) hasfree.append(135) def_op('LOAD_DEREF', 136) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0fd1348..883d0b6 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -649,50 +649,48 @@ expected_jumpy_line = 1 Instruction = dis.Instruction expected_opinfo_outer = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=3, argrepr='3', offset=0, starts_line=2, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=3, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=15, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f', argrepr="'outer..f'", offset=18, starts_line=None, is_jump_target=False), - Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=21, starts_line=None, is_jump_target=False), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=27, starts_line=7, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=30, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=33, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=39, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=45, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=48, starts_line=None, is_jump_target=False), - Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=51, starts_line=None, is_jump_target=False), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=55, starts_line=8, is_jump_target=False), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f', argrepr="'outer..f'", offset=15, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=21, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=7, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=27, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=33, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=39, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=45, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=48, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=52, starts_line=8, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, starts_line=None, is_jump_target=False), ] expected_opinfo_f = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=5, argrepr='5', offset=0, starts_line=3, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=3, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=15, starts_line=None, is_jump_target=False), - Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=21, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f..inner', argrepr="'outer..f..inner'", offset=24, starts_line=None, is_jump_target=False), - Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=27, starts_line=None, is_jump_target=False), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=30, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=33, starts_line=5, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=36, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=39, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=45, starts_line=None, is_jump_target=False), - Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=48, starts_line=None, is_jump_target=False), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=52, starts_line=6, is_jump_target=False), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=15, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f..inner', argrepr="'outer..f..inner'", offset=21, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=27, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=30, starts_line=5, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=33, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=39, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=42, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=45, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=48, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=49, starts_line=6, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False), ] expected_opinfo_inner = [ diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 331f48c..868e578 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -345,7 +345,7 @@ class GrammarTests(unittest.TestCase): def f(x) -> list: pass self.assertEqual(f.__annotations__, {'return': list}) - # test MAKE_CLOSURE with a variety of oparg's + # test MAKE_FUNCTION with a variety of oparg's closure = 1 def f(): return closure def f(x=1): return closure diff --git a/Objects/abstract.c b/Objects/abstract.c index 3e1ff97..55f2ee1 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2114,7 +2114,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) "%s returned NULL without setting an error", where); #ifdef Py_DEBUG - /* Ensure that the bug is catched in debug mode */ + /* Ensure that the bug is caught in debug mode */ Py_FatalError("a function returned NULL without setting an error"); #endif return NULL; diff --git a/PC/launcher.c b/PC/launcher.c index e4d3e8e..9fcc41e 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = { { 3190, 3230, L"3.3" }, { 3250, 3310, L"3.4" }, { 3320, 3350, L"3.5" }, - { 3360, 3361, L"3.6" }, + { 3360, 3371, L"3.6" }, { 0 } }; diff --git a/Python/ceval.c b/Python/ceval.c index 9870a55..241d393 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3258,117 +3258,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) DISPATCH(); } - TARGET_WITH_IMPL(MAKE_CLOSURE, _make_function) - TARGET(MAKE_FUNCTION) - _make_function: { - int posdefaults = oparg & 0xff; - int kwdefaults = (oparg>>8) & 0xff; - int num_annotations = (oparg >> 16) & 0x7fff; - - PyObject *qualname = POP(); /* qualname */ - PyObject *code = POP(); /* code object */ - PyObject *func = PyFunction_NewWithQualName(code, f->f_globals, qualname); - Py_DECREF(code); - Py_DECREF(qualname); + TARGET(MAKE_FUNCTION) { + PyObject *qualname = POP(); + PyObject *codeobj = POP(); + PyFunctionObject *func = (PyFunctionObject *) + PyFunction_NewWithQualName(codeobj, f->f_globals, qualname); - if (func == NULL) + Py_DECREF(codeobj); + Py_DECREF(qualname); + if (func == NULL) { goto error; - - if (opcode == MAKE_CLOSURE) { - PyObject *closure = POP(); - if (PyFunction_SetClosure(func, closure) != 0) { - /* Can't happen unless bytecode is corrupt. */ - Py_DECREF(func); - Py_DECREF(closure); - goto error; - } - Py_DECREF(closure); } - if (num_annotations > 0) { - Py_ssize_t name_ix; - PyObject *names = POP(); /* names of args with annotations */ - PyObject *anns = PyDict_New(); - if (anns == NULL) { - Py_DECREF(func); - Py_DECREF(names); - goto error; - } - name_ix = PyTuple_Size(names); - assert(num_annotations == name_ix+1); - while (name_ix > 0) { - PyObject *name, *value; - int err; - --name_ix; - name = PyTuple_GET_ITEM(names, name_ix); - value = POP(); - err = PyDict_SetItem(anns, name, value); - Py_DECREF(value); - if (err != 0) { - Py_DECREF(anns); - Py_DECREF(func); - Py_DECREF(names); - goto error; - } - } - Py_DECREF(names); - - if (PyFunction_SetAnnotations(func, anns) != 0) { - /* Can't happen unless - PyFunction_SetAnnotations changes. */ - Py_DECREF(anns); - Py_DECREF(func); - goto error; - } - Py_DECREF(anns); + /* NB: Py_None is not an acceptable value for these. */ + if (oparg & 0x08) { + func ->func_closure = POP(); } - - /* XXX Maybe this should be a separate opcode? */ - if (kwdefaults > 0) { - PyObject *defs = PyDict_New(); - if (defs == NULL) { - Py_DECREF(func); - goto error; - } - while (--kwdefaults >= 0) { - PyObject *v = POP(); /* default value */ - PyObject *key = POP(); /* kw only arg name */ - int err = PyDict_SetItem(defs, key, v); - Py_DECREF(v); - Py_DECREF(key); - if (err != 0) { - Py_DECREF(defs); - Py_DECREF(func); - goto error; - } - } - if (PyFunction_SetKwDefaults(func, defs) != 0) { - /* Can't happen unless - PyFunction_SetKwDefaults changes. */ - Py_DECREF(func); - Py_DECREF(defs); - goto error; - } - Py_DECREF(defs); + if (oparg & 0x04) { + func->func_annotations = POP(); } - if (posdefaults > 0) { - PyObject *defs = PyTuple_New(posdefaults); - if (defs == NULL) { - Py_DECREF(func); - goto error; - } - while (--posdefaults >= 0) - PyTuple_SET_ITEM(defs, posdefaults, POP()); - if (PyFunction_SetDefaults(func, defs) != 0) { - /* Can't happen unless - PyFunction_SetDefaults changes. */ - Py_DECREF(defs); - Py_DECREF(func); - goto error; - } - Py_DECREF(defs); + if (oparg & 0x02) { + func->func_kwdefaults = POP(); + } + if (oparg & 0x01) { + func->func_defaults = POP(); } - PUSH(func); + + PUSH((PyObject *)func); DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index 29a2ade..f390e0a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1028,11 +1028,10 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return -NARGS(oparg)-1; case CALL_FUNCTION_VAR_KW: return -NARGS(oparg)-2; - case MAKE_FUNCTION: - return -1 -NARGS(oparg) - ((oparg >> 16) & 0xffff); - case MAKE_CLOSURE: - return -2 - NARGS(oparg) - ((oparg >> 16) & 0xffff); #undef NARGS + case MAKE_FUNCTION: + return -1 - ((oparg & 0x01) != 0) - ((oparg & 0x02) != 0) - + ((oparg & 0x04) != 0) - ((oparg & 0x08) != 0); case BUILD_SLICE: if (oparg == 3) return -2; @@ -1428,47 +1427,44 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t args, PyO if (qualname == NULL) qualname = co->co_name; - if (free == 0) { - ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); - ADDOP_O(c, LOAD_CONST, qualname, consts); - ADDOP_I(c, MAKE_FUNCTION, args); - return 1; - } - for (i = 0; i < free; ++i) { - /* Bypass com_addop_varname because it will generate - LOAD_DEREF but LOAD_CLOSURE is needed. - */ - PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i); - int arg, reftype; - - /* Special case: If a class contains a method with a - free variable that has the same name as a method, - the name will be considered free *and* local in the - class. It should be handled by the closure, as - well as by the normal name loookup logic. - */ - reftype = get_ref_type(c, name); - if (reftype == CELL) - arg = compiler_lookup_arg(c->u->u_cellvars, name); - else /* (reftype == FREE) */ - arg = compiler_lookup_arg(c->u->u_freevars, name); - if (arg == -1) { - fprintf(stderr, - "lookup %s in %s %d %d\n" - "freevars of %s: %s\n", - PyUnicode_AsUTF8(PyObject_Repr(name)), - PyUnicode_AsUTF8(c->u->u_name), - reftype, arg, - PyUnicode_AsUTF8(co->co_name), - PyUnicode_AsUTF8(PyObject_Repr(co->co_freevars))); - Py_FatalError("compiler_make_closure()"); + if (free) { + for (i = 0; i < free; ++i) { + /* Bypass com_addop_varname because it will generate + LOAD_DEREF but LOAD_CLOSURE is needed. + */ + PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i); + int arg, reftype; + + /* Special case: If a class contains a method with a + free variable that has the same name as a method, + the name will be considered free *and* local in the + class. It should be handled by the closure, as + well as by the normal name loookup logic. + */ + reftype = get_ref_type(c, name); + if (reftype == CELL) + arg = compiler_lookup_arg(c->u->u_cellvars, name); + else /* (reftype == FREE) */ + arg = compiler_lookup_arg(c->u->u_freevars, name); + if (arg == -1) { + fprintf(stderr, + "lookup %s in %s %d %d\n" + "freevars of %s: %s\n", + PyUnicode_AsUTF8(PyObject_Repr(name)), + PyUnicode_AsUTF8(c->u->u_name), + reftype, arg, + PyUnicode_AsUTF8(co->co_name), + PyUnicode_AsUTF8(PyObject_Repr(co->co_freevars))); + Py_FatalError("compiler_make_closure()"); + } + ADDOP_I(c, LOAD_CLOSURE, arg); } - ADDOP_I(c, LOAD_CLOSURE, arg); + args |= 0x08; + ADDOP_I(c, BUILD_TUPLE, free); } - ADDOP_I(c, BUILD_TUPLE, free); ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); ADDOP_O(c, LOAD_CONST, qualname, consts); - ADDOP_I(c, MAKE_CLOSURE, args); + ADDOP_I(c, MAKE_FUNCTION, args); return 1; } @@ -1496,8 +1492,9 @@ compiler_visit_kwonlydefaults(struct compiler *c, asdl_seq *kwonlyargs, expr_ty default_ = asdl_seq_GET(kw_defaults, i); if (default_) { PyObject *mangled = _Py_Mangle(c->u->u_private, arg->arg); - if (!mangled) + if (!mangled) { return -1; + } ADDOP_O(c, LOAD_CONST, mangled, consts); Py_DECREF(mangled); if (!compiler_visit_expr(c, default_)) { @@ -1506,115 +1503,128 @@ compiler_visit_kwonlydefaults(struct compiler *c, asdl_seq *kwonlyargs, default_count++; } } + if (default_count > 0) { + ADDOP_I(c, BUILD_MAP, default_count); + } return default_count; } static int compiler_visit_argannotation(struct compiler *c, identifier id, - expr_ty annotation, PyObject *names) + expr_ty annotation) { if (annotation) { - PyObject *mangled; - VISIT(c, expr, annotation); - mangled = _Py_Mangle(c->u->u_private, id); - if (!mangled) - return 0; - if (PyList_Append(names, mangled) < 0) { - Py_DECREF(mangled); - return 0; + PyObject *mangled = _Py_Mangle(c->u->u_private, id); + if (!mangled) { + return -1; } + ADDOP_O(c, LOAD_CONST, mangled, consts); Py_DECREF(mangled); + VISIT(c, expr, annotation); + return 1; } - return 1; + return 0; } -static int -compiler_visit_argannotations(struct compiler *c, asdl_seq* args, - PyObject *names) +static Py_ssize_t +compiler_visit_argannotations(struct compiler *c, asdl_seq* args) { int i; - for (i = 0; i < asdl_seq_LEN(args); i++) { + Py_ssize_t annonum = 0, arglen = asdl_seq_LEN(args); + for (i = 0; i < arglen; i++) { arg_ty arg = (arg_ty)asdl_seq_GET(args, i); - if (!compiler_visit_argannotation( - c, - arg->arg, - arg->annotation, - names)) - return 0; + Py_ssize_t annoret = compiler_visit_argannotation(c, arg->arg, + arg->annotation); + if (annoret == -1) { + return -1; + } + annonum += annoret; } - return 1; + + return annonum; } -static int +static Py_ssize_t compiler_visit_annotations(struct compiler *c, arguments_ty args, expr_ty returns) { - /* Push arg annotations and a list of the argument names. Return the # - of items pushed. The expressions are evaluated out-of-order wrt the - source code. + /* Push arg annotation dict. Return # of items pushed. + The expressions are evaluated out-of-order wrt the source code. - More than 2^16-1 annotations is a SyntaxError. Returns -1 on error. + Returns -1 on error. */ static identifier return_str; - PyObject *names; - Py_ssize_t len; - names = PyList_New(0); - if (!names) + Py_ssize_t len = 0, annoret; + + annoret = compiler_visit_argannotations(c, args->args); + if (annoret == -1) { return -1; + } + len += annoret; - if (!compiler_visit_argannotations(c, args->args, names)) - goto error; - if (args->vararg && args->vararg->annotation && - !compiler_visit_argannotation(c, args->vararg->arg, - args->vararg->annotation, names)) - goto error; - if (!compiler_visit_argannotations(c, args->kwonlyargs, names)) - goto error; - if (args->kwarg && args->kwarg->annotation && - !compiler_visit_argannotation(c, args->kwarg->arg, - args->kwarg->annotation, names)) - goto error; + if (args->vararg && args->vararg->annotation) { + annoret = compiler_visit_argannotation(c, args->vararg->arg, + args->vararg->annotation); + if (annoret == -1) { + return -1; + } + len += annoret; + } + + annoret = compiler_visit_argannotations(c, args->kwonlyargs); + if (annoret == -1) { + return -1; + } + len += annoret; + + if (args->kwarg && args->kwarg->annotation) { + annoret = compiler_visit_argannotation(c, args->kwarg->arg, + args->kwarg->annotation); + if (annoret == -1) { + return -1; + } + len += annoret; + } if (!return_str) { return_str = PyUnicode_InternFromString("return"); - if (!return_str) - goto error; + if (!return_str) { + return -1; + } } - if (!compiler_visit_argannotation(c, return_str, returns, names)) { - goto error; + + annoret = compiler_visit_argannotation(c, return_str, returns); + if (annoret == -1) { + return -1; } + len += annoret; - len = PyList_GET_SIZE(names); - if (len > 65534) { - /* len must fit in 16 bits, and len is incremented below */ - PyErr_SetString(PyExc_SyntaxError, - "too many annotations"); - goto error; + if (len != 0) { + ADDOP_I(c, BUILD_MAP, len); + } + return len; +} + +static Py_ssize_t +compiler_default_arguments(struct compiler *c, arguments_ty args) +{ + Py_ssize_t funcflags = 0; + if (args->defaults && asdl_seq_LEN(args->defaults) > 0) { + VISIT_SEQ(c, expr, args->defaults); + ADDOP_I(c, BUILD_TUPLE, asdl_seq_LEN(args->defaults)); + funcflags |= 0x01; } - if (len) { - /* convert names to a tuple and place on stack */ - PyObject *elt; - Py_ssize_t i; - PyObject *s = PyTuple_New(len); - if (!s) - goto error; - for (i = 0; i < len; i++) { - elt = PyList_GET_ITEM(names, i); - Py_INCREF(elt); - PyTuple_SET_ITEM(s, i, elt); + if (args->kwonlyargs) { + int res = compiler_visit_kwonlydefaults(c, args->kwonlyargs, + args->kw_defaults); + if (res < 0) { + return -1; + } + else if (res > 0) { + funcflags |= 0x02; } - ADDOP_O(c, LOAD_CONST, s, consts); - Py_DECREF(s); - len++; /* include the just-pushed tuple */ } - Py_DECREF(names); - - /* We just checked that len <= 65535, see above */ - return Py_SAFE_DOWNCAST(len, Py_ssize_t, int); - -error: - Py_DECREF(names); - return -1; + return funcflags; } static int @@ -1628,12 +1638,11 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) asdl_seq* decos; asdl_seq *body; stmt_ty st; - Py_ssize_t i, n, arglength; - int docstring, kw_default_count = 0; + Py_ssize_t i, n, funcflags; + int docstring; int num_annotations; int scope_type; - if (is_async) { assert(s->kind == AsyncFunctionDef_kind); @@ -1658,24 +1667,23 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) if (!compiler_decorators(c, decos)) return 0; - if (args->defaults) - VISIT_SEQ(c, expr, args->defaults); - if (args->kwonlyargs) { - int res = compiler_visit_kwonlydefaults(c, args->kwonlyargs, - args->kw_defaults); - if (res < 0) - return 0; - kw_default_count = res; + + funcflags = compiler_default_arguments(c, args); + if (funcflags == -1) { + return 0; } + num_annotations = compiler_visit_annotations(c, args, returns); - if (num_annotations < 0) + if (num_annotations < 0) { return 0; - assert((num_annotations & 0xFFFF) == num_annotations); + } + else if (num_annotations > 0) { + funcflags |= 0x04; + } - if (!compiler_enter_scope(c, name, - scope_type, (void *)s, - s->lineno)) + if (!compiler_enter_scope(c, name, scope_type, (void *)s, s->lineno)) { return 0; + } st = (stmt_ty)asdl_seq_GET(body, 0); docstring = compiler_isdocstring(st); @@ -1708,12 +1716,9 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return 0; } - arglength = asdl_seq_LEN(args->defaults); - arglength |= kw_default_count << 8; - arglength |= num_annotations << 16; if (is_async) co->co_flags |= CO_COROUTINE; - compiler_make_closure(c, co, arglength, qualname); + compiler_make_closure(c, co, funcflags, qualname); Py_DECREF(qualname); Py_DECREF(co); @@ -1873,8 +1878,7 @@ compiler_lambda(struct compiler *c, expr_ty e) PyCodeObject *co; PyObject *qualname; static identifier name; - int kw_default_count = 0; - Py_ssize_t arglength; + Py_ssize_t funcflags; arguments_ty args = e->v.Lambda.args; assert(e->kind == Lambda_kind); @@ -1884,14 +1888,11 @@ compiler_lambda(struct compiler *c, expr_ty e) return 0; } - if (args->defaults) - VISIT_SEQ(c, expr, args->defaults); - if (args->kwonlyargs) { - int res = compiler_visit_kwonlydefaults(c, args->kwonlyargs, - args->kw_defaults); - if (res < 0) return 0; - kw_default_count = res; + funcflags = compiler_default_arguments(c, args); + if (funcflags == -1) { + return 0; } + if (!compiler_enter_scope(c, name, COMPILER_SCOPE_LAMBDA, (void *)e, e->lineno)) return 0; @@ -1917,9 +1918,7 @@ compiler_lambda(struct compiler *c, expr_ty e) if (co == NULL) return 0; - arglength = asdl_seq_LEN(args->defaults); - arglength |= kw_default_count << 8; - compiler_make_closure(c, co, arglength, qualname); + compiler_make_closure(c, co, funcflags, qualname); Py_DECREF(qualname); Py_DECREF(co); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 3872256..7fe0469 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -133,7 +133,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_FUNCTION, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, - &&TARGET_MAKE_CLOSURE, + &&_unknown_opcode, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF,