Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ def test_argument_handling(self):
self.assertRaises(SyntaxError, exec, 'def f(a = 0, a = 1): pass')
self.assertRaises(SyntaxError, exec, 'def f(a): global a; a = 1')

def test_call_opcode_stack_use_limit(self):
def get_call_opcode(positional_count, keyword_count):
args = ["0"] * positional_count
args.extend(f"a{i}=0" for i in range(keyword_count))
code = compile(f"f({', '.join(args)})", "<test>", "exec")
return next(
instr.opname for instr in dis.get_instructions(code)
if instr.opname.startswith("CALL")
)

for positional_count, keyword_count, expected_opcode in [
(0, 16, "CALL_KW"),
(15, 14, "CALL_KW"),
(15, 15, "CALL_FUNCTION_EX"),
]:
with self.subTest(
positional_count=positional_count,
keyword_count=keyword_count,
):
self.assertEqual(
get_call_opcode(positional_count, keyword_count),
expected_opcode,
)

def test_syntax_error(self):
self.assertRaises(SyntaxError, compile, "1+*3", "filename", "exec")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Compile pure-keyword calls with 16 to 29 keyword arguments using the faster
``CALL_KW`` instruction. This includes common cases such as dataclass
constructors with many fields.
7 changes: 5 additions & 2 deletions Python/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ typedef _PyCompile_FBlockInfo fblockinfo;

#define LOC(x) SRC_LOCATION_FROM_AST(x)

#define CALL_STACK_USE(nargs, nkwds) \
((nargs) + (nkwds) + ((nkwds) != 0))

#define NEW_JUMP_TARGET_LABEL(C, NAME) \
jump_target_label NAME = _PyInstructionSequence_NewLabel(INSTR_SEQUENCE(C)); \
if (!IS_JUMP_TARGET_LABEL(NAME)) { \
Expand Down Expand Up @@ -4134,7 +4137,7 @@ maybe_optimize_method_call(compiler *c, expr_ty e)
/* Check that there aren't too many arguments */
argsl = asdl_seq_LEN(args);
kwdsl = asdl_seq_LEN(kwds);
if (argsl + kwdsl + (kwdsl != 0) >= _PY_STACK_USE_GUIDELINE) {
if (CALL_STACK_USE(argsl, kwdsl) >= _PY_STACK_USE_GUIDELINE) {
return 0;
}
/* Check that there are no *varargs types of arguments. */
Expand Down Expand Up @@ -4427,7 +4430,7 @@ codegen_call_helper_impl(compiler *c, location loc,
nelts = asdl_seq_LEN(args);
nkwelts = asdl_seq_LEN(keywords);

if (nelts + nkwelts*2 > _PY_STACK_USE_GUIDELINE) {
if (CALL_STACK_USE(nelts, nkwelts) > _PY_STACK_USE_GUIDELINE) {
goto ex_call;
}
for (i = 0; i < nelts; i++) {
Expand Down
Loading