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:
parent
e53592091a
commit
f9b760f48a
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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__'
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
502
Python/ceval.c
502
Python/ceval.c
|
@ -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,48 +4981,57 @@ 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 {
|
||||
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
||||
/* optimize access to bound methods */
|
||||
PyObject *self = PyMethod_GET_SELF(func);
|
||||
PCALL(PCALL_METHOD);
|
||||
PCALL(PCALL_BOUND_METHOD);
|
||||
Py_INCREF(self);
|
||||
func = PyMethod_GET_FUNCTION(func);
|
||||
Py_INCREF(func);
|
||||
Py_SETREF(*pfunc, self);
|
||||
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);
|
||||
}
|
||||
READ_TIMESTAMP(*pintr1);
|
||||
Py_DECREF(func);
|
||||
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
|
||||
/* optimize access to bound methods */
|
||||
PyObject *self = PyMethod_GET_SELF(func);
|
||||
PCALL(PCALL_METHOD);
|
||||
PCALL(PCALL_BOUND_METHOD);
|
||||
Py_INCREF(self);
|
||||
func = PyMethod_GET_FUNCTION(func);
|
||||
Py_INCREF(func);
|
||||
Py_SETREF(*pfunc, self);
|
||||
nargs++;
|
||||
}
|
||||
else {
|
||||
Py_INCREF(func);
|
||||
}
|
||||
|
||||
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
|
||||
READ_TIMESTAMP(*pintr0);
|
||||
if (PyFunction_Check(func)) {
|
||||
x = fast_function(func, pp_stack, nargs, names);
|
||||
} else {
|
||||
x = do_call(func, pp_stack, nargs, names);
|
||||
}
|
||||
READ_TIMESTAMP(*pintr1);
|
||||
|
||||
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
|
||||
|
|
163
Python/compile.c
163
Python/compile.c
|
@ -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,102 +3527,80 @@ compiler_call_helper(struct compiler *c,
|
|||
}
|
||||
VISIT(c, expr, elt->v.Starred.value);
|
||||
nsubargs++;
|
||||
}
|
||||
else if (nsubargs) {
|
||||
/* We've seen star-args already, so we
|
||||
count towards items-to-pack-into-tuple. */
|
||||
VISIT(c, expr, elt);
|
||||
nseen++;
|
||||
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++;
|
||||
}
|
||||
else {
|
||||
nseen++;
|
||||
}
|
||||
VISIT(c, expr, kw->value);
|
||||
nsubkwargs++;
|
||||
}
|
||||
else {
|
||||
nseen++;
|
||||
}
|
||||
}
|
||||
if (nseen) {
|
||||
if (nsubkwargs) {
|
||||
if (nseen) {
|
||||
/* Pack up any trailing keyword arguments. */
|
||||
if (!compiler_subkwargs(c, keywords, nelts - nseen, nelts))
|
||||
if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts))
|
||||
return 0;
|
||||
nsubkwargs++;
|
||||
}
|
||||
else {
|
||||
VISIT_SEQ(c, keyword, keywords);
|
||||
nkw = nseen;
|
||||
}
|
||||
}
|
||||
if (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;
|
||||
}
|
||||
else {
|
||||
ADDOP_I(c, CALL_FUNCTION, n + nelts);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
2894
Python/importlib.h
2894
Python/importlib.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue