Rework CALL_FUNCTION* opcodes

Issue #27213: Rework CALL_FUNCTION* opcodes to produce shorter and more
efficient bytecode:

* CALL_FUNCTION now only accepts position arguments
* CALL_FUNCTION_KW accepts position arguments and keyword arguments, but keys
  of keyword arguments are packed into a constant tuple.
* CALL_FUNCTION_EX is the most generic, it expects a tuple and a dict for
  positional and keyword arguments.

CALL_FUNCTION_VAR and CALL_FUNCTION_VAR_KW opcodes have been removed.

2 tests of test_traceback are currently broken: skip test, the issue #28050 was
created to track the issue.

Patch by Demur Rumed, design by Serhiy Storchaka, reviewed by Serhiy Storchaka
and Victor Stinner.
diff --git a/Python/compile.c b/Python/compile.c
index 20fe4bc..36683d3 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -991,7 +991,7 @@
         case BUILD_MAP_UNPACK:
             return 1 - oparg;
         case BUILD_MAP_UNPACK_WITH_CALL:
-            return 1 - (oparg & 0xFF);
+            return 1 - oparg;
         case BUILD_MAP:
             return 1 - 2*oparg;
         case BUILD_CONST_KEY_MAP:
@@ -1038,15 +1038,12 @@
 
         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);
@@ -3500,22 +3497,29 @@
                      asdl_seq *args,
                      asdl_seq *keywords)
 {
-    int code = 0;
-    Py_ssize_t nelts, i, nseen;
-    int nkw;
+    Py_ssize_t i, nseen, nelts, nkwelts;
+    int 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 < nkwelts; i++) {
+        keyword_ty kw = asdl_seq_GET(keywords, i);
+        if (kw->arg == NULL) {
+            mustdictunpack = 1;
+            break;
+        }
+    }
+
+    nseen = n;  /* 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;
@@ -3523,102 +3527,80 @@
             }
             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++;
+            musttupleunpack = 1;
         }
         else {
-            /* Positional arguments before star-arguments
-               are left on the stack. */
             VISIT(c, expr, elt);
-            n++;
-        }
-    }
-    if (nseen) {
-        /* Pack up any trailing positional arguments. */
-        ADDOP_I(c, BUILD_TUPLE, nseen);
-        nsubargs++;
-    }
-    if (nsubargs) {
-        code |= 1;
-        if (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);
+            nseen++;
         }
     }
 
     /* 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) {
+    if (musttupleunpack || mustdictunpack) {
+        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_TUPLE_UNPACK, nsubargs);
+        }
+        else if (nsubargs == 0) {
+            ADDOP_I(c, BUILD_TUPLE, 0);
+        }
+        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++;
             }
-            VISIT(c, expr, kw->value);
-            nsubkwargs++;
+            else {
+                nseen++;
+            }
         }
-        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 (nsubkwargs) {
-        code |= 2;
-        if (nsubkwargs > 1) {
+        if (mustdictunpack || 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));
+            ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs);
         }
+        ADDOP_I(c, CALL_FUNCTION_EX, nsubkwargs > 0);
+        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 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;
     }
-    return 1;
+    else {
+        ADDOP_I(c, CALL_FUNCTION, n + nelts);
+        return 1;
+    }
 }
 
 
@@ -4040,7 +4022,6 @@
 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;
 }