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.
This commit is contained in:
Victor Stinner 2016-09-09 10:17:08 -07:00
parent e53592091a
commit f9b760f48a
12 changed files with 3372 additions and 3478 deletions

View File

@ -108,9 +108,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

View File

@ -314,7 +314,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,

View File

@ -236,6 +236,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.6b1 3373 (add BUILD_STRING opcode #27078)
# Python 3.6b1 3375 (add SETUP_ANNOTATIONS and STORE_ANNOTATION opcodes
# #27985)
# Python 3.6a1 3376 (simplify CALL_FUNCTIONs & BUILD_MAP_UNPACK_WITH_CALL)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually
@ -244,7 +245,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 = (3375).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3376).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'

View File

@ -31,7 +31,7 @@ hasjabs = []
haslocal = []
hascompare = []
hasfree = []
hasnargs = []
hasnargs = [] # unused
opmap = {}
opname = ['<%r>' % (op,) for op in range(256)]
@ -172,8 +172,7 @@ haslocal.append(126)
name_op('STORE_ANNOTATION', 127) # Index in name list
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)
@ -185,12 +184,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)

View File

@ -96,7 +96,7 @@ def _f(a):
dis_f = """\
%3d 0 LOAD_GLOBAL 0 (print)
2 LOAD_FAST 0 (a)
4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
4 CALL_FUNCTION 1
6 POP_TOP
%3d 8 LOAD_CONST 1 (1)
@ -108,7 +108,7 @@ dis_f = """\
dis_f_co_code = """\
0 LOAD_GLOBAL 0 (0)
2 LOAD_FAST 0 (0)
4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 1 (1)
10 RETURN_VALUE
@ -126,7 +126,7 @@ dis_bug708901 = """\
4 LOAD_CONST 1 (1)
%3d 6 LOAD_CONST 2 (10)
8 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
8 CALL_FUNCTION 2
10 GET_ITER
>> 12 FOR_ITER 4 (to 18)
14 STORE_FAST 0 (res)
@ -154,11 +154,11 @@ dis_bug1333982 = """\
10 MAKE_FUNCTION 0
12 LOAD_FAST 0 (x)
14 GET_ITER
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
16 CALL_FUNCTION 1
%3d 18 LOAD_CONST 4 (1)
20 BINARY_ADD
22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 CALL_FUNCTION 1
24 RAISE_VARARGS 1
%3d >> 26 LOAD_CONST 0 (None)
@ -224,14 +224,14 @@ dis_annot_stmt_str = """\
3 10 LOAD_NAME 2 (fun)
12 LOAD_CONST 0 (1)
14 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
14 CALL_FUNCTION 1
16 STORE_ANNOTATION 3 (y)
4 18 LOAD_CONST 0 (1)
20 LOAD_NAME 4 (lst)
22 LOAD_NAME 2 (fun)
24 LOAD_CONST 1 (0)
26 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
26 CALL_FUNCTION 1
28 STORE_SUBSCR
30 LOAD_NAME 1 (int)
32 POP_TOP
@ -698,7 +698,7 @@ expected_opinfo_outer = [
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=32, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=32, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=36, starts_line=8, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False),
@ -720,7 +720,7 @@ expected_opinfo_f = [
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=30, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=30, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=34, starts_line=6, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False),
@ -734,7 +734,7 @@ expected_opinfo_inner = [
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=14, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
@ -744,13 +744,13 @@ expected_opinfo_jumpy = [
Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=54, argrepr='to 54', offset=0, starts_line=3, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=44, argrepr='to 44', offset=10, starts_line=None, is_jump_target=True),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=14, starts_line=4, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=5, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=24, starts_line=None, is_jump_target=False),
@ -766,14 +766,14 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=46, starts_line=10, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=48, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=50, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=108, argrepr='to 108', offset=54, starts_line=11, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=True),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=98, argval=98, argrepr='', offset=58, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=60, starts_line=12, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=64, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=64, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=13, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=70, starts_line=None, is_jump_target=False),
@ -793,7 +793,7 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=98, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=100, starts_line=19, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=102, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=104, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=104, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True),
Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=124, argrepr='to 124', offset=110, starts_line=None, is_jump_target=False),
@ -812,7 +812,7 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=138, starts_line=23, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=140, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=176, argrepr='to 176', offset=148, starts_line=None, is_jump_target=False),
@ -822,7 +822,7 @@ expected_opinfo_jumpy = [
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=156, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=158, starts_line=26, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=160, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=168, starts_line=None, is_jump_target=False),
@ -833,7 +833,7 @@ expected_opinfo_jumpy = [
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=178, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=180, starts_line=28, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=182, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=184, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=184, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=190, starts_line=None, is_jump_target=False),

View File

@ -118,7 +118,7 @@ Verify clearing of SF bug #733667
>>> g(*Nothing())
Traceback (most recent call last):
...
TypeError: g() argument after * must be an iterable, not Nothing
TypeError: 'Nothing' object is not iterable
>>> class Nothing:
... def __len__(self): return 5
@ -127,7 +127,7 @@ Verify clearing of SF bug #733667
>>> g(*Nothing())
Traceback (most recent call last):
...
TypeError: g() argument after * must be an iterable, not Nothing
TypeError: 'Nothing' object is not iterable
>>> class Nothing():
... def __len__(self): return 5
@ -231,34 +231,32 @@ What about willful misconduct?
>>> h(*h)
Traceback (most recent call last):
...
TypeError: h() argument after * must be an iterable, not function
TypeError: 'function' object is not iterable
>>> dir(*h)
Traceback (most recent call last):
...
TypeError: dir() argument after * must be an iterable, not function
TypeError: 'function' object is not iterable
>>> None(*h)
Traceback (most recent call last):
...
TypeError: NoneType object argument after * must be an iterable, \
not function
TypeError: 'function' object is not iterable
>>> h(**h)
Traceback (most recent call last):
...
TypeError: h() argument after ** must be a mapping, not function
TypeError: 'function' object is not a mapping
>>> dir(**h)
Traceback (most recent call last):
...
TypeError: dir() argument after ** must be a mapping, not function
TypeError: 'function' object is not a mapping
>>> None(**h)
Traceback (most recent call last):
...
TypeError: NoneType object argument after ** must be a mapping, \
not function
TypeError: 'function' object is not a mapping
>>> dir(b=1, **{'b': 1})
Traceback (most recent call last):

View File

@ -304,6 +304,7 @@ class TracebackFormatTests(unittest.TestCase):
])
# issue 26823 - Shrink recursive tracebacks
@unittest.skipIf(True, "FIXME: test broken, see issue #28050")
def _check_recursive_traceback_display(self, render_exc):
# Always show full diffs when this test fails
# Note that rearranging things may require adjusting

View File

@ -109,19 +109,15 @@ 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, PyObject *, uint64*, uint64*);
#else
static PyObject * call_function(PyObject ***, int);
static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
#endif
static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, Py_ssize_t);
static PyObject * do_call(PyObject *, PyObject ***, Py_ssize_t, Py_ssize_t);
static PyObject * ext_do_call(PyObject *, PyObject ***, int, Py_ssize_t, Py_ssize_t);
static PyObject * update_keyword_args(PyObject *, Py_ssize_t, PyObject ***,
PyObject *);
static PyObject * update_star_args(Py_ssize_t, Py_ssize_t, PyObject *, PyObject ***);
static PyObject * fast_function(PyObject *, PyObject ***, Py_ssize_t, PyObject *);
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);
#define CALL_FLAG_VAR 1
#define CALL_FLAG_KW 2
#ifdef LLTRACE
static int lltrace;
@ -2659,8 +2655,14 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
TARGET(BUILD_LIST_UNPACK) {
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
Py_ssize_t i;
PyObject *sum = PyList_New(0);
PyObject *sum;
PyObject *return_value;
if (convert_to_tuple && oparg == 1 && PyTuple_CheckExact(TOP())) {
DISPATCH();
}
sum = PyList_New(0);
if (sum == NULL)
goto error;
@ -2847,29 +2849,25 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
TARGET(BUILD_MAP_UNPACK_WITH_CALL)
TARGET(BUILD_MAP_UNPACK) {
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
int num_maps;
int function_location;
Py_ssize_t i;
PyObject *sum = PyDict_New();
if (sum == NULL)
goto error;
if (with_call) {
num_maps = oparg & 0xff;
function_location = (oparg>>8) & 0xff;
}
else {
num_maps = oparg;
PyObject *sum;
if (with_call && oparg == 1 && PyDict_CheckExact(TOP())) {
DISPATCH();
}
for (i = num_maps; i > 0; i--) {
sum = PyDict_New();
if (sum == NULL)
goto error;
for (i = oparg; i > 0; i--) {
PyObject *arg = PEEK(i);
if (with_call) {
if (with_call && PyDict_Size(sum)) {
PyObject *intersection = _PyDictView_Intersect(sum, arg);
if (intersection == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyObject *func = (
PEEK(function_location + num_maps));
PyObject *func = PEEK(2 + oparg);
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after ** "
"must be a mapping, not %.200s",
@ -2884,7 +2882,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
if (PySet_GET_SIZE(intersection)) {
Py_ssize_t idx = 0;
PyObject *key;
PyObject *func = PEEK(function_location + num_maps);
PyObject *func = PEEK(2 + oparg);
Py_hash_t hash;
_PySet_NextEntry(intersection, &idx, &key, &hash);
if (!PyUnicode_Check(key)) {
@ -2918,7 +2916,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
}
}
while (num_maps--)
while (oparg--)
Py_DECREF(POP());
PUSH(sum);
DISPATCH();
@ -3409,63 +3407,62 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
PCALL(PCALL_ALL);
sp = stack_pointer;
#ifdef WITH_TSC
res = call_function(&sp, oparg, &intr0, &intr1);
res = call_function(&sp, oparg, NULL, &intr0, &intr1);
#else
res = call_function(&sp, oparg);
res = call_function(&sp, oparg, NULL);
#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) {
Py_ssize_t nargs = oparg & 0xff;
Py_ssize_t nkwargs = (oparg>>8) & 0xff;
int flags = (opcode - CALL_FUNCTION) & 3;
Py_ssize_t n;
PyObject **pfunc, *func, **sp, *res;
TARGET(CALL_FUNCTION_KW) {
PyObject **sp, *res, *names;
names = POP();
assert(PyTuple_CheckExact(names) && PyTuple_GET_SIZE(names) <= oparg);
PCALL(PCALL_ALL);
n = nargs + 2 * nkwargs;
if (flags & CALL_FLAG_VAR) {
n++;
}
if (flags & CALL_FLAG_KW) {
n++;
}
pfunc = stack_pointer - n - 1;
func = *pfunc;
if (PyMethod_Check(func)
&& PyMethod_GET_SELF(func) != NULL) {
PyObject *self = PyMethod_GET_SELF(func);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
}
else {
Py_INCREF(func);
}
sp = stack_pointer;
READ_TIMESTAMP(intr0);
res = ext_do_call(func, &sp, flags, nargs, nkwargs);
READ_TIMESTAMP(intr1);
#ifdef WITH_TSC
res = call_function(&sp, oparg, names, &intr0, &intr1);
#else
res = call_function(&sp, oparg, names);
#endif
stack_pointer = sp;
Py_DECREF(func);
while (stack_pointer > pfunc) {
PyObject *o = POP();
Py_DECREF(o);
}
PUSH(res);
if (res == NULL)
Py_DECREF(names);
if (res == NULL) {
goto error;
}
DISPATCH();
}
TARGET(CALL_FUNCTION_EX) {
PyObject *func, *callargs, *kwargs = NULL, *result;
PCALL(PCALL_ALL);
if (oparg & 0x01) {
kwargs = POP();
assert(PyDict_CheckExact(kwargs));
}
callargs = POP();
assert(PyTuple_CheckExact(callargs));
func = TOP();
READ_TIMESTAMP(intr0);
result = do_call_core(func, callargs, kwargs);
READ_TIMESTAMP(intr1);
Py_DECREF(func);
Py_DECREF(callargs);
Py_XDECREF(kwargs);
SET_TOP(result);
if (result == NULL) {
goto error;
}
DISPATCH();
}
@ -3950,7 +3947,6 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
Py_DECREF(kwonly_sig);
}
/* This is gonna seem *real weird*, but if you put some other code between
PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
@ -3959,6 +3955,7 @@ static PyObject *
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **args, Py_ssize_t argcount,
PyObject **kws, Py_ssize_t kwcount,
PyObject *kwnames, PyObject **kwstack,
PyObject **defs, Py_ssize_t defcount,
PyObject *kwdefs, PyObject *closure,
PyObject *name, PyObject *qualname)
@ -3972,6 +3969,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
Py_ssize_t i, n;
PyObject *kwdict;
Py_ssize_t kwcount2 = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
assert((kwcount == 0) || (kws != NULL));
@ -4033,7 +4031,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
}
/* Handle keyword arguments (passed as an array of (key, value)) */
/* Handle keyword arguments passed as an array of (key, value) pairs */
for (i = 0; i < kwcount; i++) {
PyObject **co_varnames;
PyObject *keyword = kws[2*i];
@ -4092,6 +4090,61 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
SETLOCAL(j, value);
}
/* Handle keyword arguments passed as keys tuple + values array */
for (i = 0; i < kwcount2; i++) {
PyObject **co_varnames;
PyObject *keyword = PyTuple_GET_ITEM(kwnames, i);
PyObject *value = kwstack[i];
int j;
if (keyword == NULL || !PyUnicode_Check(keyword)) {
PyErr_Format(PyExc_TypeError,
"%U() keywords must be strings",
co->co_name);
goto fail;
}
/* Speed hack: do raw pointer compares. As names are
normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = 0; j < total_args; j++) {
PyObject *nm = co_varnames[j];
if (nm == keyword)
goto kw_found2;
}
/* Slow fallback, just in case */
for (j = 0; j < total_args; j++) {
PyObject *nm = co_varnames[j];
int cmp = PyObject_RichCompareBool(
keyword, nm, Py_EQ);
if (cmp > 0)
goto kw_found2;
else if (cmp < 0)
goto fail;
}
if (j >= total_args && kwdict == NULL) {
PyErr_Format(PyExc_TypeError,
"%U() got an unexpected "
"keyword argument '%S'",
co->co_name,
keyword);
goto fail;
}
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
goto fail;
}
continue;
kw_found2:
if (GETLOCAL(j) != NULL) {
PyErr_Format(PyExc_TypeError,
"%U() got multiple "
"values for argument '%S'",
co->co_name,
keyword);
goto fail;
}
Py_INCREF(value);
SETLOCAL(j, value);
}
/* Check the number of positional arguments */
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
too_many_positional(co, argcount, defcount, fastlocals);
@ -4244,6 +4297,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
return _PyEval_EvalCodeWithName(_co, globals, locals,
args, argcount,
kws, kwcount,
NULL, NULL,
defs, defcount,
kwdefs, closure,
NULL, NULL);
@ -4886,28 +4940,27 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
}
static PyObject *
call_function(PyObject ***pp_stack, int oparg
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names
#ifdef WITH_TSC
, uint64* pintr0, uint64* pintr1
#endif
)
{
Py_ssize_t nargs = oparg & 0xff;
Py_ssize_t nkwargs = (oparg>>8) & 0xff;
int n = nargs + 2 * nkwargs;
PyObject **pfunc = (*pp_stack) - n - 1;
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nk = names == NULL ? 0 : PyTuple_GET_SIZE(names);
Py_ssize_t nargs = oparg - nk;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func) && nkwargs == 0) {
if (PyCFunction_Check(func)) {
int flags = PyCFunction_GET_FLAGS(func);
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
if (flags & (METH_NOARGS | METH_O)) {
if (names == NULL && flags & (METH_NOARGS | METH_O)) {
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
if (flags & METH_NOARGS && nargs == 0) {
@ -4928,17 +4981,25 @@ call_function(PyObject ***pp_stack, int oparg
}
}
else {
PyObject *callargs;
PyObject *callargs, *kwdict = NULL;
if (names != NULL) {
kwdict = create_keyword_args(names, pp_stack, func);
if (kwdict == NULL) {
x = NULL;
goto cfuncerror;
}
}
callargs = load_args(pp_stack, nargs);
if (callargs != NULL) {
READ_TIMESTAMP(*pintr0);
C_TRACE(x, PyCFunction_Call(func,callargs,NULL));
C_TRACE(x, PyCFunction_Call(func, callargs, kwdict));
READ_TIMESTAMP(*pintr1);
Py_XDECREF(callargs);
Py_DECREF(callargs);
}
else {
x = NULL;
}
Py_XDECREF(kwdict);
}
}
else {
@ -4952,24 +5013,25 @@ call_function(PyObject ***pp_stack, int oparg
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
n++;
}
else {
Py_INCREF(func);
}
READ_TIMESTAMP(*pintr0);
if (PyFunction_Check(func)) {
x = fast_function(func, (*pp_stack) - n, nargs, nkwargs);
}
else {
x = do_call(func, pp_stack, nargs, nkwargs);
x = fast_function(func, pp_stack, nargs, names);
} else {
x = do_call(func, pp_stack, nargs, names);
}
READ_TIMESTAMP(*pintr1);
Py_DECREF(func);
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
Py_DECREF(func);
}
cfuncerror:
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).
@ -4980,7 +5042,6 @@ call_function(PyObject ***pp_stack, int oparg
PCALL(PCALL_POP);
}
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
return x;
}
@ -5033,19 +5094,16 @@ _PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
/* Similar to _PyFunction_FastCall() but keywords are passed a (key, value)
pairs in stack */
static PyObject *
fast_function(PyObject *func, PyObject **stack, Py_ssize_t nargs, Py_ssize_t nkwargs)
fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *names)
{
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
PyObject *globals = PyFunction_GET_GLOBALS(func);
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
PyObject *kwdefs, *closure, *name, *qualname;
PyObject **d;
int nd;
assert(func != NULL);
assert(nargs >= 0);
assert(nkwargs >= 0);
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
Py_ssize_t nkwargs = names == NULL ? 0 : PyTuple_GET_SIZE(names);
Py_ssize_t nd;
PyObject **stack = (*pp_stack)-nargs-nkwargs;
PCALL(PCALL_FUNCTION);
PCALL(PCALL_FAST_FUNCTION);
@ -5081,8 +5139,9 @@ fast_function(PyObject *func, PyObject **stack, Py_ssize_t nargs, Py_ssize_t nkw
}
return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
stack, nargs,
stack + nargs, nkwargs,
d, nd, kwdefs,
NULL, 0,
names, stack + nargs,
d, (int)nd, kwdefs,
closure, name, qualname);
}
@ -5166,6 +5225,7 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
args, nargs,
k, nk,
NULL, NULL,
d, nd, kwdefs,
closure, name, qualname);
Py_XDECREF(kwtuple);
@ -5173,22 +5233,17 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
}
static PyObject *
update_keyword_args(PyObject *orig_kwdict, Py_ssize_t 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 "
@ -5196,13 +5251,11 @@ update_keyword_args(PyObject *orig_kwdict, Py_ssize_t 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);
@ -5213,183 +5266,51 @@ update_keyword_args(PyObject *orig_kwdict, Py_ssize_t nk, PyObject ***pp_stack,
}
static PyObject *
update_star_args(Py_ssize_t nstack, Py_ssize_t nstar, PyObject *stararg,
PyObject ***pp_stack)
load_args(PyObject ***pp_stack, Py_ssize_t nargs)
{
PyObject *callargs, *w;
PyObject *args = PyTuple_New(nargs);
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) {
if (args == NULL) {
return NULL;
}
if (nstar) {
Py_ssize_t i;
for (i = 0; i < nstar; i++) {
PyObject *arg = PyTuple_GET_ITEM(stararg, i);
Py_INCREF(arg);
PyTuple_SET_ITEM(callargs, nstack + i, arg);
}
}
while (--nstack >= 0) {
w = EXT_POP(*pp_stack);
PyTuple_SET_ITEM(callargs, nstack, w);
}
return callargs;
}
static PyObject *
load_args(PyObject ***pp_stack, Py_ssize_t na)
{
PyObject *args = PyTuple_New(na);
PyObject *w;
if (args == NULL)
return NULL;
while (--na >= 0) {
w = EXT_POP(*pp_stack);
PyTuple_SET_ITEM(args, na, w);
while (--nargs >= 0) {
PyObject *arg= EXT_POP(*pp_stack);
PyTuple_SET_ITEM(args, nargs, arg);
}
return args;
}
static PyObject *
do_call(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, Py_ssize_t nkwargs)
do_call(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *callargs = NULL;
PyObject *kwdict = NULL;
PyObject *result = NULL;
PyObject *callargs, *kwdict, *result;
if (nkwargs > 0) {
kwdict = update_keyword_args(NULL, nkwargs, pp_stack, func);
if (kwdict == NULL)
goto call_fail;
if (kwnames != NULL) {
kwdict = create_keyword_args(kwnames, pp_stack, func);
if (kwdict == NULL) {
return NULL;
}
}
else {
kwdict = NULL;
}
callargs = load_args(pp_stack, nargs);
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));
if (callargs == NULL) {
Py_XDECREF(kwdict);
return NULL;
}
else
result = PyObject_Call(func, callargs, kwdict);
call_fail:
result = do_call_core(func, callargs, kwdict);
Py_XDECREF(callargs);
Py_XDECREF(kwdict);
return result;
}
static PyObject *
ext_do_call(PyObject *func, PyObject ***pp_stack, int flags,
Py_ssize_t nargs, Py_ssize_t nkwargs)
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
{
Py_ssize_t nstar;
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 (nkwargs > 0) {
kwdict = update_keyword_args(kwdict, nkwargs, 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);
}
else {
nstar = 0;
}
callargs = update_star_args(nargs, 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
@ -5406,19 +5327,16 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags,
else
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 {
result = PyObject_Call(func, callargs, kwdict);
return 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

View File

@ -991,7 +991,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;
case BUILD_MAP:
return 1 - 2*oparg;
case BUILD_CONST_KEY_MAP:
@ -1038,15 +1038,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);
@ -3500,22 +3497,29 @@ 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 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,54 +3527,38 @@ compiler_call_helper(struct compiler *c,
}
VISIT(c, expr, elt->v.Starred.value);
nsubargs++;
musttupleunpack = 1;
}
else if (nsubargs) {
/* We've seen star-args already, so we
count towards items-to-pack-into-tuple. */
else {
VISIT(c, expr, elt);
nseen++;
}
else {
/* Positional arguments before star-arguments
are left on the stack. */
VISIT(c, expr, elt);
n++;
}
}
/* Same dance again for keyword arguments */
if (musttupleunpack || mustdictunpack) {
if (nseen) {
/* Pack up any trailing positional arguments. */
ADDOP_I(c, BUILD_TUPLE, nseen);
nsubargs++;
}
if (nsubargs) {
code |= 1;
if (nsubargs > 1) {
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);
}
else if (nsubargs == 0) {
ADDOP_I(c, BUILD_TUPLE, 0);
}
/* 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++) {
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 (nsubkwargs) {
if (!compiler_subkwargs(c, keywords, i - nseen, i))
return 0;
nsubkwargs++;
}
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);
@ -3581,45 +3569,39 @@ compiler_call_helper(struct compiler *c,
}
}
if (nseen) {
if (nsubkwargs) {
/* 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));
}
}
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;
ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs);
}
ADDOP_I(c, CALL_FUNCTION_EX, nsubkwargs > 0);
return 1;
}
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;
}
else {
ADDOP_I(c, CALL_FUNCTION, n + nelts);
return 1;
}
}
/* List and set comprehensions and generator expressions work by creating a
@ -4040,7 +4022,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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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,