Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(27892)

Unified Diff: Python/compile.c

Issue 27095: Simplify MAKE_FUNCTION
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Python/ceval.c ('k') | Python/opcode_targets.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
index 2d59d38..6fed82e 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1030,11 +1030,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;
@@ -1472,53 +1471,50 @@ compiler_lookup_arg(PyObject *dict, PyObject *name)
}
static int
-compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t args, PyObject *qualname)
+compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags, PyObject *qualname)
{
Py_ssize_t i, free = PyCode_GetNumFree(co);
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);
+ flags |= 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, flags);
return 1;
}
@@ -1536,137 +1532,187 @@ compiler_decorators(struct compiler *c, asdl_seq* decos)
return 1;
}
-static int
+static Py_ssize_t
compiler_visit_kwonlydefaults(struct compiler *c, asdl_seq *kwonlyargs,
asdl_seq *kw_defaults)
{
- int i, default_count = 0;
+ int i;
+ PyObject *keys = NULL;
+
for (i = 0; i < asdl_seq_LEN(kwonlyargs); i++) {
arg_ty arg = asdl_seq_GET(kwonlyargs, i);
expr_ty default_ = asdl_seq_GET(kw_defaults, i);
if (default_) {
PyObject *mangled = _Py_Mangle(c->u->u_private, arg->arg);
- if (!mangled)
- return -1;
- ADDOP_O(c, LOAD_CONST, mangled, consts);
- Py_DECREF(mangled);
+ if (!mangled) {
+ goto error;
+ }
+ if (keys == NULL) {
+ keys = PyList_New(1);
+ if (keys == NULL) {
+ Py_DECREF(mangled);
+ return -1;
+ }
+ PyList_SET_ITEM(keys, 0, mangled);
+ }
+ else {
+ int res = PyList_Append(keys, mangled);
+ Py_DECREF(mangled);
+ if (res == -1) {
+ goto error;
+ }
+ }
if (!compiler_visit_expr(c, default_)) {
- return -1;
+ goto error;
}
- default_count++;
}
}
- return default_count;
+ if (keys != NULL) {
+ Py_ssize_t default_count = PyList_Size(keys);
+ PyObject *keys_tuple = PyList_AsTuple(keys);
+ Py_DECREF(keys);
+ if (keys_tuple == NULL) {
+ return -1;
+ }
+ ADDOP_N(c, LOAD_CONST, keys_tuple, consts);
+ ADDOP_I(c, BUILD_CONST_KEY_MAP, default_count);
+ return default_count;
+ }
+ else {
+ return 0;
+ }
+
+error:
+ if (keys != NULL) {
storchaka 2016/06/12 06:55:56 Just Py_XDECREF(keys).
+ Py_DECREF(keys);
+ }
+ return -1;
}
static int
compiler_visit_argannotation(struct compiler *c, identifier id,
- expr_ty annotation, PyObject *names)
+ expr_ty annotation, PyObject* keylist)
storchaka 2016/06/12 06:55:56 It looks to me that this function can be left unch
{
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);
+ int res;
+ PyObject *mangled = _Py_Mangle(c->u->u_private, id);
+ if (!mangled) {
return 0;
}
+ res = PyList_Append(keylist, mangled);
Py_DECREF(mangled);
+ if (res == -1) {
+ return 0;
+ }
+ VISIT(c, expr, annotation);
}
return 1;
}
static int
-compiler_visit_argannotations(struct compiler *c, asdl_seq* args,
- PyObject *names)
+compiler_visit_argannotations(struct compiler *c, asdl_seq *args, PyObject *keylist)
storchaka 2016/06/12 06:55:56 It looks to me that this function can be left unch
{
int i;
- for (i = 0; i < asdl_seq_LEN(args); i++) {
+ Py_ssize_t 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))
+ int res = compiler_visit_argannotation(c, arg->arg,
+ arg->annotation, keylist);
+ if (res == 0) {
return 0;
+ }
}
+
return 1;
}
-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)
+ PyObject* keylist = PyList_New(0);
storchaka 2016/06/12 06:55:56 I think the large part of this function can be lef
+
+ if (keylist == NULL) {
return -1;
+ }
- if (!compiler_visit_argannotations(c, args->args, names))
+ if (compiler_visit_argannotations(c, args->args, keylist) == 0) {
goto error;
+ }
+
if (args->vararg && args->vararg->annotation &&
- !compiler_visit_argannotation(c, args->vararg->arg,
- args->vararg->annotation, names))
+ compiler_visit_argannotation(c, args->vararg->arg,
+ args->vararg->annotation, keylist) == 0) {
goto error;
- if (!compiler_visit_argannotations(c, args->kwonlyargs, names))
+ }
+
+ if (compiler_visit_argannotations(c, args->kwonlyargs, keylist) == 0) {
goto error;
+ }
+
if (args->kwarg && args->kwarg->annotation &&
- !compiler_visit_argannotation(c, args->kwarg->arg,
- args->kwarg->annotation, names))
+ compiler_visit_argannotation(c, args->kwarg->arg,
+ args->kwarg->annotation, keylist) == 0) {
goto error;
+ }
if (!return_str) {
return_str = PyUnicode_InternFromString("return");
- if (!return_str)
+ if (!return_str) {
goto error;
- }
- if (!compiler_visit_argannotation(c, return_str, returns, names)) {
- goto error;
+ }
}
- 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");
+ if (compiler_visit_argannotation(c, return_str, returns, keylist) == 0) {
goto error;
}
- if (len) {
- /* convert names to a tuple and place on stack */
- PyObject *elt;
- Py_ssize_t i;
- PyObject *s = PyTuple_New(len);
- if (!s)
+
+ len = PyList_Size(keylist);
+ if (len != 0) {
+ PyObject *keytuple = PyList_AsTuple(keylist);
+ if (keytuple == NULL) {
goto error;
- for (i = 0; i < len; i++) {
- elt = PyList_GET_ITEM(names, i);
- Py_INCREF(elt);
- PyTuple_SET_ITEM(s, i, elt);
}
- ADDOP_O(c, LOAD_CONST, s, consts);
- Py_DECREF(s);
- len++; /* include the just-pushed tuple */
+ ADDOP_N(c, LOAD_CONST, keytuple, consts);
storchaka 2016/06/12 06:55:56 ADDOP_N and ADDOP_I can return from the function a
+ ADDOP_I(c, BUILD_CONST_KEY_MAP, len);
}
- Py_DECREF(names);
-
- /* We just checked that len <= 65535, see above */
- return Py_SAFE_DOWNCAST(len, Py_ssize_t, int);
+ Py_DECREF(keylist);
+ return len;
error:
- Py_DECREF(names);
+ Py_DECREF(keylist);
return -1;
}
+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 (args->kwonlyargs) {
+ Py_ssize_t res = compiler_visit_kwonlydefaults(c, args->kwonlyargs,
+ args->kw_defaults);
+ if (res < 0) {
+ return -1;
+ }
+ else if (res > 0) {
+ funcflags |= 0x02;
+ }
+ }
+ return funcflags;
+}
+
static int
compiler_function(struct compiler *c, stmt_ty s, int is_async)
{
@@ -1678,12 +1724,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);
@@ -1708,24 +1753,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);
@@ -1758,12 +1802,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);
@@ -1923,8 +1964,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);
@@ -1934,14 +1974,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;
@@ -1967,9 +2004,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);
« no previous file with comments | « Python/ceval.c ('k') | Python/opcode_targets.h » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+