From 8868b82ace8f2ff79743cfa24bfa205ba5aac64c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 02:43:05 -0700 Subject: [PATCH 01/21] Simple input-output stack effects No arrays; no conditionals; no types; no cache effects. --- Python/bytecodes.c | 104 +++++++++--------------- Python/generated_cases.c.h | 77 ++++++++++-------- Tools/cases_generator/generate_cases.py | 6 ++ Tools/cases_generator/parser.py | 2 +- 4 files changed, 88 insertions(+), 101 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e87ca6ebe8a051..cf3f82377b40f7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -69,6 +69,7 @@ do { \ #define DISPATCH() ((void)0) #define inst(name) case name: +#define instr(name, arg) case name: #define family(name) static int family_##name #define NAME_ERROR_MSG \ @@ -103,12 +104,10 @@ dummy_func( and that all operation that succeed call DISPATCH() ! */ // BEGIN BYTECODES // - // stack effect: ( -- ) - inst(NOP) { + instr(NOP, (--)) { } - // stack effect: ( -- ) - inst(RESUME) { + instr(RESUME, (--)) { assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { @@ -116,45 +115,35 @@ dummy_func( } } - // stack effect: ( -- __0) - inst(LOAD_CLOSURE) { + instr(LOAD_CLOSURE, (-- value)) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ - PyObject *value = GETLOCAL(oparg); + value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; } Py_INCREF(value); - PUSH(value); } - // stack effect: ( -- __0) - inst(LOAD_FAST_CHECK) { - PyObject *value = GETLOCAL(oparg); + instr(LOAD_FAST_CHECK, (-- value)) { + value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; } Py_INCREF(value); - PUSH(value); } - // stack effect: ( -- __0) - inst(LOAD_FAST) { - PyObject *value = GETLOCAL(oparg); + instr(LOAD_FAST, (-- value)) { + value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - PUSH(value); } - // stack effect: ( -- __0) - inst(LOAD_CONST) { - PyObject *value = GETITEM(consts, oparg); + instr(LOAD_CONST, (-- value)) { + value = GETITEM(consts, oparg); Py_INCREF(value); - PUSH(value); } - // stack effect: (__0 -- ) - inst(STORE_FAST) { - PyObject *value = POP(); + instr(STORE_FAST, (value --)) { SETLOCAL(oparg, value); } @@ -220,9 +209,7 @@ dummy_func( PUSH(value); } - // stack effect: (__0 -- ) - inst(POP_TOP) { - PyObject *value = POP(); + instr(POP_TOP, (value --)) { Py_DECREF(value); } @@ -232,76 +219,59 @@ dummy_func( BASIC_PUSH(NULL); } - // stack effect: (__0, __1 -- ) - inst(END_FOR) { - PyObject *value = POP(); - Py_DECREF(value); - value = POP(); - Py_DECREF(value); + instr(END_FOR, (value1, value2 --)) { + Py_DECREF(value1); + Py_DECREF(value2); } - // stack effect: ( -- ) - inst(UNARY_POSITIVE) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Positive(value); + instr(UNARY_POSITIVE, (value -- res)) { + res = PyNumber_Positive(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } } - // stack effect: ( -- ) - inst(UNARY_NEGATIVE) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Negative(value); + instr(UNARY_NEGATIVE, (value -- res)) { + res = PyNumber_Negative(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } } - // stack effect: ( -- ) - inst(UNARY_NOT) { - PyObject *value = TOP(); + instr(UNARY_NOT, (value -- res)) { int err = PyObject_IsTrue(value); Py_DECREF(value); if (err == 0) { - Py_INCREF(Py_True); - SET_TOP(Py_True); - DISPATCH(); + res = Py_True; } else if (err > 0) { - Py_INCREF(Py_False); - SET_TOP(Py_False); - DISPATCH(); + res = Py_False; } - STACK_SHRINK(1); - goto error; + else { + goto error; + } + Py_INCREF(res); } - // stack effect: ( -- ) - inst(UNARY_INVERT) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Invert(value); + instr(UNARY_INVERT, (value -- res)) { + res = PyNumber_Invert(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } } - // stack effect: (__0 -- ) - inst(BINARY_OP_MULTIPLY_INT) { + instr(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) { + // TODO: Don't pop from the stack before DEOPF_IF() calls. assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(prod); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); if (prod == NULL) { goto error; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c678de5dff335b..d238fb0b5dedd6 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -15,8 +15,9 @@ } TARGET(LOAD_CLOSURE) { + PyObject *value; /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ - PyObject *value = GETLOCAL(oparg); + value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; } @@ -26,7 +27,8 @@ } TARGET(LOAD_FAST_CHECK) { - PyObject *value = GETLOCAL(oparg); + PyObject *value; + value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; } @@ -36,7 +38,8 @@ } TARGET(LOAD_FAST) { - PyObject *value = GETLOCAL(oparg); + PyObject *value; + value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); PUSH(value); @@ -44,8 +47,9 @@ } TARGET(LOAD_CONST) { + PyObject *value; PREDICTED(LOAD_CONST); - PyObject *value = GETITEM(consts, oparg); + value = GETITEM(consts, oparg); Py_INCREF(value); PUSH(value); DISPATCH(); @@ -132,77 +136,84 @@ } TARGET(END_FOR) { - PyObject *value = POP(); - Py_DECREF(value); - value = POP(); - Py_DECREF(value); + PyObject *value2 = POP(); + PyObject *value1 = POP(); + Py_DECREF(value1); + Py_DECREF(value2); DISPATCH(); } TARGET(UNARY_POSITIVE) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Positive(value); + PyObject *value = POP(); + PyObject *res; + res = PyNumber_Positive(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } + PUSH(res); DISPATCH(); } TARGET(UNARY_NEGATIVE) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Negative(value); + PyObject *value = POP(); + PyObject *res; + res = PyNumber_Negative(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } + PUSH(res); DISPATCH(); } TARGET(UNARY_NOT) { - PyObject *value = TOP(); + PyObject *value = POP(); + PyObject *res; int err = PyObject_IsTrue(value); Py_DECREF(value); if (err == 0) { - Py_INCREF(Py_True); - SET_TOP(Py_True); - DISPATCH(); + res = Py_True; } else if (err > 0) { - Py_INCREF(Py_False); - SET_TOP(Py_False); - DISPATCH(); + res = Py_False; } - STACK_SHRINK(1); - goto error; + else { + goto error; + } + Py_INCREF(res); + PUSH(res); + DISPATCH(); } TARGET(UNARY_INVERT) { - PyObject *value = TOP(); - PyObject *res = PyNumber_Invert(value); + PyObject *value = POP(); + PyObject *res; + res = PyNumber_Invert(value); Py_DECREF(value); - SET_TOP(res); - if (res == NULL) + if (res == NULL) { goto error; + } + PUSH(res); DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_INT) { + PyObject *right = POP(); + PyObject *left = POP(); + PyObject *prod; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(prod); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); if (prod == NULL) { goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + PUSH(prod); DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ec2481b31b9fd6..bfe236ffc982b6 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -73,6 +73,10 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): for instr in instrs: assert isinstance(instr, InstDef) f.write(f"\n{indent}TARGET({instr.name}) {{\n") + for input in reversed(instr.inputs or ()): + f.write(f"{indent} PyObject *{input} = POP();\n") + for output in instr.outputs or (): + f.write(f"{indent} PyObject *{output};\n") if instr.name in predictions: f.write(f"{indent} PREDICTED({instr.name});\n") # input = ", ".join(instr.inputs) @@ -96,6 +100,8 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): # Write the body for line in blocklines: f.write(line) + for output in instr.outputs or (): + f.write(f"{indent} PUSH({output});\n") assert instr.block if not always_exits(instr.block): f.write(f"{indent} DISPATCH();\n") diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index d5e4de21772543..be4852e51cde36 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -83,7 +83,7 @@ def inst_header(self): # inst(NAME) | inst(NAME, (inputs -- outputs)) # TODO: Error out when there is something unexpected. # TODO: Make INST a keyword in the lexer. - if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst": + if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text in ("inst", "instr"): if (self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER))): name = tkn.text From 069cfb41c3eac24cec2d70cd52a01ce320aacae7 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 14:46:33 -0700 Subject: [PATCH 02/21] Use PEEK instead of POP; STACK_GROW; etc. --- Python/bytecodes.c | 11 ++--- Python/generated_cases.c.h | 59 ++++++++++++++----------- Tools/cases_generator/generate_cases.py | 17 ++++--- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index cf3f82377b40f7..f4c203c926af3b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -264,12 +264,11 @@ dummy_func( } instr(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) { - // TODO: Don't pop from the stack before DEOPF_IF() calls. assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); + prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) { @@ -279,20 +278,16 @@ dummy_func( } // stack effect: (__0 -- ) - inst(BINARY_OP_MULTIPLY_FLOAT) { + instr(BINARY_OP_MULTIPLY_FLOAT, (left, right -- prod)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; - PyObject *prod = PyFloat_FromDouble(dprod); - SET_SECOND(prod); + prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); if (prod == NULL) { goto error; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d238fb0b5dedd6..4e4ef08ad0860f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -22,7 +22,8 @@ goto unbound_local_error; } Py_INCREF(value); - PUSH(value); + STACK_GROW(1); + PEEK(1) = value; DISPATCH(); } @@ -33,7 +34,8 @@ goto unbound_local_error; } Py_INCREF(value); - PUSH(value); + STACK_GROW(1); + PEEK(1) = value; DISPATCH(); } @@ -42,7 +44,8 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - PUSH(value); + STACK_GROW(1); + PEEK(1) = value; DISPATCH(); } @@ -51,13 +54,15 @@ PREDICTED(LOAD_CONST); value = GETITEM(consts, oparg); Py_INCREF(value); - PUSH(value); + STACK_GROW(1); + PEEK(1) = value; DISPATCH(); } TARGET(STORE_FAST) { - PyObject *value = POP(); + PyObject *value = PEEK(1); SETLOCAL(oparg, value); + STACK_GROW(-1); DISPATCH(); } @@ -124,8 +129,9 @@ } TARGET(POP_TOP) { - PyObject *value = POP(); + PyObject *value = PEEK(1); Py_DECREF(value); + STACK_GROW(-1); DISPATCH(); } @@ -136,39 +142,40 @@ } TARGET(END_FOR) { - PyObject *value2 = POP(); - PyObject *value1 = POP(); + PyObject *value2 = PEEK(1); + PyObject *value1 = PEEK(2); Py_DECREF(value1); Py_DECREF(value2); + STACK_GROW(-2); DISPATCH(); } TARGET(UNARY_POSITIVE) { - PyObject *value = POP(); + PyObject *value = PEEK(1); PyObject *res; res = PyNumber_Positive(value); Py_DECREF(value); if (res == NULL) { goto error; } - PUSH(res); + PEEK(1) = res; DISPATCH(); } TARGET(UNARY_NEGATIVE) { - PyObject *value = POP(); + PyObject *value = PEEK(1); PyObject *res; res = PyNumber_Negative(value); Py_DECREF(value); if (res == NULL) { goto error; } - PUSH(res); + PEEK(1) = res; DISPATCH(); } TARGET(UNARY_NOT) { - PyObject *value = POP(); + PyObject *value = PEEK(1); PyObject *res; int err = PyObject_IsTrue(value); Py_DECREF(value); @@ -182,59 +189,61 @@ goto error; } Py_INCREF(res); - PUSH(res); + PEEK(1) = res; DISPATCH(); } TARGET(UNARY_INVERT) { - PyObject *value = POP(); + PyObject *value = PEEK(1); PyObject *res; res = PyNumber_Invert(value); Py_DECREF(value); if (res == NULL) { goto error; } - PUSH(res); + PEEK(1) = res; DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_INT) { - PyObject *right = POP(); - PyObject *left = POP(); + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); PyObject *prod; assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); + prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) { goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - PUSH(prod); + STACK_GROW(-1); + PEEK(1) = prod; DISPATCH(); } TARGET(BINARY_OP_MULTIPLY_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *prod; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; - PyObject *prod = PyFloat_FromDouble(dprod); - SET_SECOND(prod); + prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); if (prod == NULL) { goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_GROW(-1); + PEEK(1) = prod; DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index bfe236ffc982b6..a698c7f5d79c5f 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -63,8 +63,9 @@ def always_exits(block: parser.Block) -> bool: def write_cases(f: io.TextIOBase, instrs: list[InstDef]): - predictions = set() + predictions: set[str] = set() for inst in instrs: + assert inst.block is not None for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", inst.block.text): predictions.add(target) indent = " " @@ -73,8 +74,9 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): for instr in instrs: assert isinstance(instr, InstDef) f.write(f"\n{indent}TARGET({instr.name}) {{\n") - for input in reversed(instr.inputs or ()): - f.write(f"{indent} PyObject *{input} = POP();\n") + # TODO: Is it better to count forward or backward? + for i, input in enumerate(reversed(instr.inputs or ()), 1): + f.write(f"{indent} PyObject *{input} = PEEK({i});\n") for output in instr.outputs or (): f.write(f"{indent} PyObject *{output};\n") if instr.name in predictions: @@ -82,7 +84,7 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): # input = ", ".join(instr.inputs) # output = ", ".join(instr.outputs) # f.write(f"{indent} // {input} -- {output}\n") - assert instr.block + assert instr.block is not None blocklines = instr.block.text.splitlines(True) # Remove blank lines from ends while blocklines and not blocklines[0].strip(): @@ -100,8 +102,11 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): # Write the body for line in blocklines: f.write(line) - for output in instr.outputs or (): - f.write(f"{indent} PUSH({output});\n") + diff = len(instr.outputs or ()) - len(instr.inputs or ()) + if diff != 0: + f.write(f"{indent} STACK_GROW({diff});\n") + for i, output in enumerate(reversed(instr.outputs or ()), 1): + f.write(f"{indent} PEEK({i}) = {output};\n") assert instr.block if not always_exits(instr.block): f.write(f"{indent} DISPATCH();\n") From 51db97b86ff5cdfc7efaf0a2c4ed134c3582a9c4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 15:17:33 -0700 Subject: [PATCH 03/21] Use POKE(i, v) --- Python/bytecodes.c | 1 + Python/ceval.c | 1 + Python/generated_cases.c.h | 20 ++++++++++---------- Tools/cases_generator/generate_cases.py | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f4c203c926af3b..aff4888858ba5c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -43,6 +43,7 @@ void _PyUnicode_ExactDealloc(PyObject *); #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) #define PEEK(n) (stack_pointer[-(n)]) +#define POKE(n, v) (stack_pointer[-(n)] = (v)) #define PUSH(val) (*(stack_pointer++) = (val)) #define POP() (*(--stack_pointer)) #define TOP() PEEK(1) diff --git a/Python/ceval.c b/Python/ceval.c index 85011afadf7fb1..da8cfccdf758fd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -806,6 +806,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define THIRD() (stack_pointer[-3]) #define FOURTH() (stack_pointer[-4]) #define PEEK(n) (stack_pointer[-(n)]) +#define POKE(n, v) (stack_pointer[-(n)] = (v)) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) #define BASIC_STACKADJ(n) (stack_pointer += n) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4e4ef08ad0860f..fc79bb894ad1bb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -23,7 +23,7 @@ } Py_INCREF(value); STACK_GROW(1); - PEEK(1) = value; + POKE(1, value); DISPATCH(); } @@ -35,7 +35,7 @@ } Py_INCREF(value); STACK_GROW(1); - PEEK(1) = value; + POKE(1, value); DISPATCH(); } @@ -45,7 +45,7 @@ assert(value != NULL); Py_INCREF(value); STACK_GROW(1); - PEEK(1) = value; + POKE(1, value); DISPATCH(); } @@ -55,7 +55,7 @@ value = GETITEM(consts, oparg); Py_INCREF(value); STACK_GROW(1); - PEEK(1) = value; + POKE(1, value); DISPATCH(); } @@ -158,7 +158,7 @@ if (res == NULL) { goto error; } - PEEK(1) = res; + POKE(1, res); DISPATCH(); } @@ -170,7 +170,7 @@ if (res == NULL) { goto error; } - PEEK(1) = res; + POKE(1, res); DISPATCH(); } @@ -189,7 +189,7 @@ goto error; } Py_INCREF(res); - PEEK(1) = res; + POKE(1, res); DISPATCH(); } @@ -201,7 +201,7 @@ if (res == NULL) { goto error; } - PEEK(1) = res; + POKE(1, res); DISPATCH(); } @@ -221,7 +221,7 @@ } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); - PEEK(1) = prod; + POKE(1, prod); DISPATCH(); } @@ -243,7 +243,7 @@ } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); - PEEK(1) = prod; + POKE(1, prod); DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a698c7f5d79c5f..5bd0b0072e5b61 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -106,7 +106,7 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): if diff != 0: f.write(f"{indent} STACK_GROW({diff});\n") for i, output in enumerate(reversed(instr.outputs or ()), 1): - f.write(f"{indent} PEEK({i}) = {output};\n") + f.write(f"{indent} POKE({i}, {output});\n") assert instr.block if not always_exits(instr.block): f.write(f"{indent} DISPATCH();\n") From 700dd3a168f27c2e7304d9cef1384b96615accaf Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 15:45:51 -0700 Subject: [PATCH 04/21] Use ERROR_IF() --- Python/bytecodes.c | 35 ++++++++++------------------------- Python/ceval.c | 2 ++ Python/generated_cases.c.h | 34 +++++++++------------------------- 3 files changed, 21 insertions(+), 50 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index aff4888858ba5c..633103b4223f61 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -64,6 +64,7 @@ do { \ /* Flow control macros */ #define DEOPT_IF(cond, instname) ((void)0) +#define ERROR_IF(cond, labelname) ((void)0) #define JUMPBY(offset) ((void)0) #define GO_TO_INSTRUCTION(instname) ((void)0) #define DISPATCH_SAME_OPARG() ((void)0) @@ -119,17 +120,13 @@ dummy_func( instr(LOAD_CLOSURE, (-- value)) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); - if (value == NULL) { - goto unbound_local_error; - } + ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } instr(LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); - if (value == NULL) { - goto unbound_local_error; - } + ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } @@ -228,30 +225,24 @@ dummy_func( instr(UNARY_POSITIVE, (value -- res)) { res = PyNumber_Positive(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); } instr(UNARY_NEGATIVE, (value -- res)) { res = PyNumber_Negative(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); } instr(UNARY_NOT, (value -- res)) { int err = PyObject_IsTrue(value); Py_DECREF(value); + ERROR_IF(err < 0, error); if (err == 0) { res = Py_True; } - else if (err > 0) { - res = Py_False; - } else { - goto error; + res = Py_False; } Py_INCREF(res); } @@ -259,9 +250,7 @@ dummy_func( instr(UNARY_INVERT, (value -- res)) { res = PyNumber_Invert(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); } instr(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) { @@ -272,9 +261,7 @@ dummy_func( prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (prod == NULL) { - goto error; - } + ERROR_IF(prod == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } @@ -289,9 +276,7 @@ dummy_func( prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (prod == NULL) { - goto error; - } + ERROR_IF(prod == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } diff --git a/Python/ceval.c b/Python/ceval.c index da8cfccdf758fd..00427c6e526f1b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -855,6 +855,8 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define DEOPT_IF(cond, instname) if (cond) { goto miss; } +#define ERROR_IF(cond, label) if (cond) { goto label; } + #define GLOBALS() frame->f_globals #define BUILTINS() frame->f_builtins diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index fc79bb894ad1bb..29c51e901d11b1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -18,9 +18,7 @@ PyObject *value; /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); - if (value == NULL) { - goto unbound_local_error; - } + ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -30,9 +28,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; value = GETLOCAL(oparg); - if (value == NULL) { - goto unbound_local_error; - } + ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -155,9 +151,7 @@ PyObject *res; res = PyNumber_Positive(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); POKE(1, res); DISPATCH(); } @@ -167,9 +161,7 @@ PyObject *res; res = PyNumber_Negative(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); POKE(1, res); DISPATCH(); } @@ -179,14 +171,12 @@ PyObject *res; int err = PyObject_IsTrue(value); Py_DECREF(value); + ERROR_IF(err < 0, error); if (err == 0) { res = Py_True; } - else if (err > 0) { - res = Py_False; - } else { - goto error; + res = Py_False; } Py_INCREF(res); POKE(1, res); @@ -198,9 +188,7 @@ PyObject *res; res = PyNumber_Invert(value); Py_DECREF(value); - if (res == NULL) { - goto error; - } + ERROR_IF(res == NULL, error); POKE(1, res); DISPATCH(); } @@ -216,9 +204,7 @@ prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (prod == NULL) { - goto error; - } + ERROR_IF(prod == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); POKE(1, prod); @@ -238,9 +224,7 @@ prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (prod == NULL) { - goto error; - } + ERROR_IF(prod == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); POKE(1, prod); From 4c990fde08902022b57bd2b6313f782b8866edb0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 16:21:45 -0700 Subject: [PATCH 05/21] Expand ERROR_IF(), to include SHRINK_STACK() --- Python/ceval.c | 2 -- Python/generated_cases.c.h | 16 ++++++++-------- Tools/cases_generator/generate_cases.py | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 00427c6e526f1b..da8cfccdf758fd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -855,8 +855,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define DEOPT_IF(cond, instname) if (cond) { goto miss; } -#define ERROR_IF(cond, label) if (cond) { goto label; } - #define GLOBALS() frame->f_globals #define BUILTINS() frame->f_builtins diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 29c51e901d11b1..ee2ad0296f8f8e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -18,7 +18,7 @@ PyObject *value; /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); - ERROR_IF(value == NULL, unbound_local_error); + if (value == NULL) { goto unbound_local_error; } Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -28,7 +28,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; value = GETLOCAL(oparg); - ERROR_IF(value == NULL, unbound_local_error); + if (value == NULL) { goto unbound_local_error; } Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -151,7 +151,7 @@ PyObject *res; res = PyNumber_Positive(value); Py_DECREF(value); - ERROR_IF(res == NULL, error); + if (res == NULL) { STACK_SHRINK(1); goto error; } POKE(1, res); DISPATCH(); } @@ -161,7 +161,7 @@ PyObject *res; res = PyNumber_Negative(value); Py_DECREF(value); - ERROR_IF(res == NULL, error); + if (res == NULL) { STACK_SHRINK(1); goto error; } POKE(1, res); DISPATCH(); } @@ -171,7 +171,7 @@ PyObject *res; int err = PyObject_IsTrue(value); Py_DECREF(value); - ERROR_IF(err < 0, error); + if (err < 0) { STACK_SHRINK(1); goto error; } if (err == 0) { res = Py_True; } @@ -188,7 +188,7 @@ PyObject *res; res = PyNumber_Invert(value); Py_DECREF(value); - ERROR_IF(res == NULL, error); + if (res == NULL) { STACK_SHRINK(1); goto error; } POKE(1, res); DISPATCH(); } @@ -204,7 +204,7 @@ prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - ERROR_IF(prod == NULL, error); + if (prod == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); POKE(1, prod); @@ -224,7 +224,7 @@ prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - ERROR_IF(prod == NULL, error); + if (prod == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_GROW(-1); POKE(1, prod); diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 5bd0b0072e5b61..8165bbfbcae740 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -100,9 +100,20 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): while blocklines and not blocklines[-1].strip(): blocklines.pop() # Write the body + ninputs = len(instr.inputs or ()) for line in blocklines: - f.write(line) - diff = len(instr.outputs or ()) - len(instr.inputs or ()) + if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s$", line): + space, cond, label = m.groups() + # ERROR_IF() must remove the inputs from the stack. + # The code block is responsible for DECREF()ing them. + if ninputs: + f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n") + else: + f.write(f"{space}if ({cond}) {{ goto {label}; }}\n") + else: + f.write(line) + noutputs = len(instr.outputs or ()) + diff = noutputs - ninputs if diff != 0: f.write(f"{indent} STACK_GROW({diff});\n") for i, output in enumerate(reversed(instr.outputs or ()), 1): From 2fa60625c6e0e8aca809bfbf5205adeee5cfab18 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 20:03:07 -0700 Subject: [PATCH 06/21] Use a varargs inst() macro --- Python/bytecodes.c | 33 ++++++++++++++++----------------- Tools/cases_generator/parser.py | 2 +- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 633103b4223f61..407a8cd7244649 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -70,8 +70,7 @@ do { \ #define DISPATCH_SAME_OPARG() ((void)0) #define DISPATCH() ((void)0) -#define inst(name) case name: -#define instr(name, arg) case name: +#define inst(name, ...) case name: #define family(name) static int family_##name #define NAME_ERROR_MSG \ @@ -106,10 +105,10 @@ dummy_func( and that all operation that succeed call DISPATCH() ! */ // BEGIN BYTECODES // - instr(NOP, (--)) { + inst(NOP, (--)) { } - instr(RESUME, (--)) { + inst(RESUME, (--)) { assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { @@ -117,31 +116,31 @@ dummy_func( } } - instr(LOAD_CLOSURE, (-- value)) { + inst(LOAD_CLOSURE, (-- value)) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } - instr(LOAD_FAST_CHECK, (-- value)) { + inst(LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } - instr(LOAD_FAST, (-- value)) { + inst(LOAD_FAST, (-- value)) { value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); } - instr(LOAD_CONST, (-- value)) { + inst(LOAD_CONST, (-- value)) { value = GETITEM(consts, oparg); Py_INCREF(value); } - instr(STORE_FAST, (value --)) { + inst(STORE_FAST, (value --)) { SETLOCAL(oparg, value); } @@ -207,7 +206,7 @@ dummy_func( PUSH(value); } - instr(POP_TOP, (value --)) { + inst(POP_TOP, (value --)) { Py_DECREF(value); } @@ -217,24 +216,24 @@ dummy_func( BASIC_PUSH(NULL); } - instr(END_FOR, (value1, value2 --)) { + inst(END_FOR, (value1, value2 --)) { Py_DECREF(value1); Py_DECREF(value2); } - instr(UNARY_POSITIVE, (value -- res)) { + inst(UNARY_POSITIVE, (value -- res)) { res = PyNumber_Positive(value); Py_DECREF(value); ERROR_IF(res == NULL, error); } - instr(UNARY_NEGATIVE, (value -- res)) { + inst(UNARY_NEGATIVE, (value -- res)) { res = PyNumber_Negative(value); Py_DECREF(value); ERROR_IF(res == NULL, error); } - instr(UNARY_NOT, (value -- res)) { + inst(UNARY_NOT, (value -- res)) { int err = PyObject_IsTrue(value); Py_DECREF(value); ERROR_IF(err < 0, error); @@ -247,13 +246,13 @@ dummy_func( Py_INCREF(res); } - instr(UNARY_INVERT, (value -- res)) { + inst(UNARY_INVERT, (value -- res)) { res = PyNumber_Invert(value); Py_DECREF(value); ERROR_IF(res == NULL, error); } - instr(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) { + inst(BINARY_OP_MULTIPLY_INT, (left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -266,7 +265,7 @@ dummy_func( } // stack effect: (__0 -- ) - instr(BINARY_OP_MULTIPLY_FLOAT, (left, right -- prod)) { + inst(BINARY_OP_MULTIPLY_FLOAT, (left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index be4852e51cde36..d5e4de21772543 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -83,7 +83,7 @@ def inst_header(self): # inst(NAME) | inst(NAME, (inputs -- outputs)) # TODO: Error out when there is something unexpected. # TODO: Make INST a keyword in the lexer. - if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text in ("inst", "instr"): + if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst": if (self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER))): name = tkn.text From 73fab6215a9828713ac33d7daf4c25da9f528946 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 20:18:06 -0700 Subject: [PATCH 07/21] Do a few more instructions --- Python/bytecodes.c | 40 ++++++++------------------------- Python/generated_cases.c.h | 45 ++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 55 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 407a8cd7244649..3e2540ad6da4d9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -264,7 +264,6 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) inst(BINARY_OP_MULTIPLY_FLOAT, (left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); @@ -279,61 +278,40 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_OP_SUBTRACT_INT) { + inst(BINARY_OP_SUBTRACT_INT, (left, right -- sub)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(sub); + sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); - if (sub == NULL) { - goto error; - } + ERROR_IF(sub == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_OP_SUBTRACT_FLOAT) { + inst(BINARY_OP_SUBTRACT_FLOAT, (left, right -- sub)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; - PyObject *sub = PyFloat_FromDouble(dsub); - SET_SECOND(sub); + sub = PyFloat_FromDouble(dsub); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); - if (sub == NULL) { - goto error; - } + ERROR_IF(sub == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_OP_ADD_UNICODE) { + inst(BINARY_OP_ADD_UNICODE, (left, right -- res)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *res = PyUnicode_Concat(left, right); - STACK_SHRINK(1); - SET_TOP(res); + res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (TOP() == NULL) { - goto error; - } + ERROR_IF(TOP() == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ee2ad0296f8f8e..08a9f74ef531db 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -232,60 +232,57 @@ } TARGET(BINARY_OP_SUBTRACT_INT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sub; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(sub); + sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); - if (sub == NULL) { - goto error; - } + if (sub == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_GROW(-1); + POKE(1, sub); DISPATCH(); } TARGET(BINARY_OP_SUBTRACT_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sub; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; - PyObject *sub = PyFloat_FromDouble(dsub); - SET_SECOND(sub); + sub = PyFloat_FromDouble(dsub); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); - if (sub == NULL) { - goto error; - } + if (sub == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_GROW(-1); + POKE(1, sub); DISPATCH(); } TARGET(BINARY_OP_ADD_UNICODE) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *res; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *res = PyUnicode_Concat(left, right); - STACK_SHRINK(1); - SET_TOP(res); + res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (TOP() == NULL) { - goto error; - } + if (TOP() == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_GROW(-1); + POKE(1, res); DISPATCH(); } From f23b6fb30e2fdfe14323a9e27760c8dfe905d7d7 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 20:40:38 -0700 Subject: [PATCH 08/21] BINARY_OP_INPLACE_ADD_UNICODE --- Python/bytecodes.c | 16 ++++++++-------- Python/generated_cases.c.h | 10 ++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3e2540ad6da4d9..f04c40ce0eb52c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -315,11 +315,14 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_OP_INPLACE_ADD_UNICODE) { + // This is a weird one. It's a super-instruction for + // BINARY_OP_ADD_UNICODE followed by STORE_FAST + // where the store goes into the left argument. + // So the inputs are the same as for all BINARY_OP + // specializations, but there is no output. + // At the end we just skip over the STORE_FAST. + inst(BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; @@ -341,12 +344,9 @@ dummy_func( */ assert(Py_REFCNT(left) >= 2); _Py_DECREF_NO_DEALLOC(left); - STACK_SHRINK(2); PyUnicode_Append(target_local, right); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (*target_local == NULL) { - goto error; - } + ERROR_IF(*target_local == NULL, error); // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 08a9f74ef531db..2ec0c5cc895d02 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -287,9 +287,9 @@ } TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; @@ -311,14 +311,12 @@ */ assert(Py_REFCNT(left) >= 2); _Py_DECREF_NO_DEALLOC(left); - STACK_SHRINK(2); PyUnicode_Append(target_local, right); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (*target_local == NULL) { - goto error; - } + if (*target_local == NULL) { STACK_SHRINK(2); goto error; } // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + STACK_GROW(-2); DISPATCH(); } From fa507a2dd58c58cd596732e3d127a237ffa93b98 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 5 Nov 2022 23:48:45 -0700 Subject: [PATCH 09/21] Use STACK_SHRINK as needed --- Python/generated_cases.c.h | 18 +++++++++--------- Tools/cases_generator/generate_cases.py | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2ec0c5cc895d02..2ea7c51edadae5 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -58,7 +58,7 @@ TARGET(STORE_FAST) { PyObject *value = PEEK(1); SETLOCAL(oparg, value); - STACK_GROW(-1); + STACK_SHRINK(1); DISPATCH(); } @@ -127,7 +127,7 @@ TARGET(POP_TOP) { PyObject *value = PEEK(1); Py_DECREF(value); - STACK_GROW(-1); + STACK_SHRINK(1); DISPATCH(); } @@ -142,7 +142,7 @@ PyObject *value1 = PEEK(2); Py_DECREF(value1); Py_DECREF(value2); - STACK_GROW(-2); + STACK_SHRINK(2); DISPATCH(); } @@ -206,7 +206,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - STACK_GROW(-1); + STACK_SHRINK(1); POKE(1, prod); DISPATCH(); } @@ -226,7 +226,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); if (prod == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - STACK_GROW(-1); + STACK_SHRINK(1); POKE(1, prod); DISPATCH(); } @@ -244,7 +244,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - STACK_GROW(-1); + STACK_SHRINK(1); POKE(1, sub); DISPATCH(); } @@ -263,7 +263,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); if (sub == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - STACK_GROW(-1); + STACK_SHRINK(1); POKE(1, sub); DISPATCH(); } @@ -281,7 +281,7 @@ _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (TOP() == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); - STACK_GROW(-1); + STACK_SHRINK(1); POKE(1, res); DISPATCH(); } @@ -316,7 +316,7 @@ if (*target_local == NULL) { STACK_SHRINK(2); goto error; } // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - STACK_GROW(-2); + STACK_SHRINK(2); DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 8165bbfbcae740..d81773b7c62171 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -114,8 +114,10 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): f.write(line) noutputs = len(instr.outputs or ()) diff = noutputs - ninputs - if diff != 0: + if diff > 0: f.write(f"{indent} STACK_GROW({diff});\n") + elif diff < 0: + f.write(f"{indent} STACK_SHRINK({-diff});\n") for i, output in enumerate(reversed(instr.outputs or ()), 1): f.write(f"{indent} POKE({i}, {output});\n") assert instr.block From 119850299c38298c594d449de9b080fb30f63fb2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 00:13:20 -0700 Subject: [PATCH 10/21] BINARY_OP_ADD_FLOAT, BINARY_OP_ADD_INT --- Python/bytecodes.c | 26 ++++++-------------------- Python/generated_cases.c.h | 30 ++++++++++++++---------------- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f04c40ce0eb52c..781f4561fd25b1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -351,43 +351,29 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } - // stack effect: (__0 -- ) - inst(BINARY_OP_ADD_FLOAT) { + inst(BINARY_OP_ADD_FLOAT, (left, right -- sum)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; - PyObject *sum = PyFloat_FromDouble(dsum); - SET_SECOND(sum); + sum = PyFloat_FromDouble(dsum); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); - if (sum == NULL) { - goto error; - } + ERROR_IF(sum == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_OP_ADD_INT) { + inst(BINARY_OP_ADD_INT, (left, right -- sum)) { assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(sum); + sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); - if (sum == NULL) { - goto error; - } + ERROR_IF(sum == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2ea7c51edadae5..59f6795e384e2c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -321,42 +321,40 @@ } TARGET(BINARY_OP_ADD_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sum; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; - PyObject *sum = PyFloat_FromDouble(dsum); - SET_SECOND(sum); + sum = PyFloat_FromDouble(dsum); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - STACK_SHRINK(1); - if (sum == NULL) { - goto error; - } + if (sum == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_SHRINK(1); + POKE(1, sum); DISPATCH(); } TARGET(BINARY_OP_ADD_INT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sum; assert(cframe.use_tracing == 0); - PyObject *left = SECOND(); - PyObject *right = TOP(); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); STAT_INC(BINARY_OP, hit); - PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - SET_SECOND(sum); + sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - STACK_SHRINK(1); - if (sum == NULL) { - goto error; - } + if (sum == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); + STACK_SHRINK(1); + POKE(1, sum); DISPATCH(); } From ea277ce8d3f7bcd22d2eb0847f92cbd32c693fbe Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 00:30:07 -0700 Subject: [PATCH 11/21] Move PREDICTED() up (bad bug) --- Tools/cases_generator/generate_cases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index d81773b7c62171..1b7a2fc157f325 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -74,13 +74,13 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): for instr in instrs: assert isinstance(instr, InstDef) f.write(f"\n{indent}TARGET({instr.name}) {{\n") + if instr.name in predictions: + f.write(f"{indent} PREDICTED({instr.name});\n") # TODO: Is it better to count forward or backward? for i, input in enumerate(reversed(instr.inputs or ()), 1): f.write(f"{indent} PyObject *{input} = PEEK({i});\n") for output in instr.outputs or (): f.write(f"{indent} PyObject *{output};\n") - if instr.name in predictions: - f.write(f"{indent} PREDICTED({instr.name});\n") # input = ", ".join(instr.inputs) # output = ", ".join(instr.outputs) # f.write(f"{indent} // {input} -- {output}\n") From fe2767c84621571720456b679cc5f1bbd790bcd4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 00:30:44 -0700 Subject: [PATCH 12/21] BINARY_SUBSCR --- Python/bytecodes.c | 11 +++-------- Python/generated_cases.c.h | 15 ++++++++------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 781f4561fd25b1..0f7c8ecad7d2d9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -377,16 +377,11 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // stack effect: (__0 -- ) - inst(BINARY_SUBSCR) { - PyObject *sub = POP(); - PyObject *container = TOP(); - PyObject *res = PyObject_GetItem(container, sub); + inst(BINARY_SUBSCR, (container, sub -- res)) { + res = PyObject_GetItem(container, sub); Py_DECREF(container); Py_DECREF(sub); - SET_TOP(res); - if (res == NULL) - goto error; + ERROR_IF(res == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 59f6795e384e2c..2027f3d64d9a44 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -46,8 +46,8 @@ } TARGET(LOAD_CONST) { - PyObject *value; PREDICTED(LOAD_CONST); + PyObject *value; value = GETITEM(consts, oparg); Py_INCREF(value); STACK_GROW(1); @@ -360,15 +360,16 @@ TARGET(BINARY_SUBSCR) { PREDICTED(BINARY_SUBSCR); - PyObject *sub = POP(); - PyObject *container = TOP(); - PyObject *res = PyObject_GetItem(container, sub); + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + PyObject *res; + res = PyObject_GetItem(container, sub); Py_DECREF(container); Py_DECREF(sub); - SET_TOP(res); - if (res == NULL) - goto error; + if (res == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + STACK_SHRINK(1); + POKE(1, res); DISPATCH(); } From e737bcb2d39d65d98aadae24a4ec1988cdac50ab Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 00:37:01 -0700 Subject: [PATCH 13/21] BINARY_SLICE --- Python/bytecodes.c | 20 ++++++++------------ Python/generated_cases.c.h | 23 +++++++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0f7c8ecad7d2d9..1cde9716a9efd9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -385,23 +385,19 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); } - // stack effect: (__0, __1 -- ) - inst(BINARY_SLICE) { - PyObject *stop = POP(); - PyObject *start = POP(); - PyObject *container = TOP(); - + inst(BINARY_SLICE, (container, start, stop -- res)) { PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + // Can't use ERROR_IF() here, because we haven't + // DECREF'ed container yet, and we still own slice. if (slice == NULL) { - goto error; + res = NULL; } - PyObject *res = PyObject_GetItem(container, slice); - Py_DECREF(slice); - if (res == NULL) { - goto error; + else { + res = PyObject_GetItem(container, slice); + Py_DECREF(slice); } - SET_TOP(res); Py_DECREF(container); + ERROR_IF(res == NULL, error); } // stack effect: (__0, __1, __2, __3 -- ) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2027f3d64d9a44..a9da7f991050ce 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -374,21 +374,24 @@ } TARGET(BINARY_SLICE) { - PyObject *stop = POP(); - PyObject *start = POP(); - PyObject *container = TOP(); - + PyObject *stop = PEEK(1); + PyObject *start = PEEK(2); + PyObject *container = PEEK(3); + PyObject *res; PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + // Can't use ERROR_IF() here, because we haven't + // DECREF'ed container yet, and we still own slice. if (slice == NULL) { - goto error; + res = NULL; } - PyObject *res = PyObject_GetItem(container, slice); - Py_DECREF(slice); - if (res == NULL) { - goto error; + else { + res = PyObject_GetItem(container, slice); + Py_DECREF(slice); } - SET_TOP(res); Py_DECREF(container); + if (res == NULL) { STACK_SHRINK(3); goto error; } + STACK_SHRINK(2); + POKE(1, res); DISPATCH(); } From 19b989cf11c30c701e12e8c98a7db2f0c3b84a10 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 02:12:29 -0800 Subject: [PATCH 14/21] Bugfix (thanks to Irit) --- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1cde9716a9efd9..0ef03a062d32ca 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -311,7 +311,7 @@ dummy_func( res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - ERROR_IF(TOP() == NULL, error); + ERROR_IF(res == NULL, error); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a9da7f991050ce..170e060dde1089 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -279,7 +279,7 @@ res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (TOP() == NULL) { STACK_SHRINK(2); goto error; } + if (res == NULL) { STACK_SHRINK(2); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, res); From b8b4f152d0965f735b3416bcde97bead025c529e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 02:19:18 -0800 Subject: [PATCH 15/21] Fix regex nit --- Tools/cases_generator/generate_cases.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1b7a2fc157f325..87488262cdfaa9 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -102,7 +102,7 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef]): # Write the body ninputs = len(instr.inputs or ()) for line in blocklines: - if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s$", line): + if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line): space, cond, label = m.groups() # ERROR_IF() must remove the inputs from the stack. # The code block is responsible for DECREF()ing them. From 62c67b08143ac19b86b65b2a4a72547cf4e5f199 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 11:30:34 -0800 Subject: [PATCH 16/21] Fix code generated for super instructions --- Python/generated_cases.c.h | 27 ++++++ Tools/cases_generator/generate_cases.py | 122 +++++++++++++----------- 2 files changed, 91 insertions(+), 58 deletions(-) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f22eff1c7dcfe3..450455877c7c7a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3842,72 +3842,99 @@ TARGET(LOAD_FAST__LOAD_FAST) { { + PyObject *value; value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } NEXTOPARG(); next_instr++; { + PyObject *value; value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } DISPATCH(); } TARGET(LOAD_FAST__LOAD_CONST) { { + PyObject *value; value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } NEXTOPARG(); next_instr++; { + PyObject *value; value = GETITEM(consts, oparg); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } DISPATCH(); } TARGET(STORE_FAST__LOAD_FAST) { { + PyObject *value = PEEK(1); SETLOCAL(oparg, value); + STACK_SHRINK(1); } NEXTOPARG(); next_instr++; { + PyObject *value; value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } DISPATCH(); } TARGET(STORE_FAST__STORE_FAST) { { + PyObject *value = PEEK(1); SETLOCAL(oparg, value); + STACK_SHRINK(1); } NEXTOPARG(); next_instr++; { + PyObject *value = PEEK(1); SETLOCAL(oparg, value); + STACK_SHRINK(1); } DISPATCH(); } TARGET(LOAD_CONST__LOAD_FAST) { { + PyObject *value; value = GETITEM(consts, oparg); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } NEXTOPARG(); next_instr++; { + PyObject *value; value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); } DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 26840c819d5677..eed78fdfc62ea8 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -5,10 +5,10 @@ # TODO: Reuse C generation framework from deepfreeze.py? import argparse -import io import os import re import sys +from typing import TextIO, cast import parser from parser import InstDef # TODO: Use parser.InstDef @@ -20,13 +20,13 @@ arg_parser.add_argument("-q", "--quiet", action="store_true") -def eopen(filename: str, mode: str = "r"): +def eopen(filename: str, mode: str = "r") -> TextIO: if filename == "-": if "r" in mode: return sys.stdin else: return sys.stdout - return open(filename, mode) + return cast(TextIO, open(filename, mode)) def parse_cases( @@ -67,66 +67,73 @@ def always_exits(block: parser.Block) -> bool: return line.startswith(("goto ", "return ", "DISPATCH", "GO_TO_", "Py_UNREACHABLE()")) -def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Super]): +def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, dedent: int = 0): + assert instr.block + if dedent < 0: + indent += " " * -dedent + # TODO: Is it better to count forward or backward? + for i, input in enumerate(reversed(instr.inputs or ()), 1): + f.write(f"{indent} PyObject *{input} = PEEK({i});\n") + for output in instr.outputs or (): + f.write(f"{indent} PyObject *{output};\n") + # input = ", ".join(instr.inputs) + # output = ", ".join(instr.outputs) + # f.write(f"{indent} // {input} -- {output}\n") + assert instr.block is not None + blocklines = instr.block.to_text(dedent=dedent).splitlines(True) + # Remove blank lines from ends + while blocklines and not blocklines[0].strip(): + blocklines.pop(0) + while blocklines and not blocklines[-1].strip(): + blocklines.pop() + # Remove leading '{' and trailing '}' + assert blocklines and blocklines[0].strip() == "{" + assert blocklines and blocklines[-1].strip() == "}" + blocklines.pop() + blocklines.pop(0) + # Remove trailing blank lines + while blocklines and not blocklines[-1].strip(): + blocklines.pop() + # Write the body + ninputs = len(instr.inputs or ()) + for line in blocklines: + if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line): + space, cond, label = m.groups() + # ERROR_IF() must remove the inputs from the stack. + # The code block is responsible for DECREF()ing them. + if ninputs: + f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n") + else: + f.write(f"{space}if ({cond}) {{ goto {label}; }}\n") + else: + f.write(line) + noutputs = len(instr.outputs or ()) + diff = noutputs - ninputs + if diff > 0: + f.write(f"{indent} STACK_GROW({diff});\n") + elif diff < 0: + f.write(f"{indent} STACK_SHRINK({-diff});\n") + for i, output in enumerate(reversed(instr.outputs or ()), 1): + f.write(f"{indent} POKE({i}, {output});\n") + assert instr.block + +def write_cases(f: TextIO, instrs: list[InstDef], supers: list[parser.Super]): predictions: set[str] = set() - for inst in instrs: - assert inst.block is not None - for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", inst.block.text): + for instr in instrs: + assert isinstance(instr, InstDef) + assert instr.block is not None + for target in re.findall(r"(?:PREDICT|GO_TO_INSTRUCTION)\((\w+)\)", instr.block.text): predictions.add(target) indent = " " f.write(f"// This file is generated by {os.path.relpath(__file__)}\n") - f.write("// Do not edit!\n") + f.write(f"// Do not edit!\n") instr_index: dict[str, InstDef] = {} for instr in instrs: - assert isinstance(instr, InstDef) instr_index[instr.name] = instr f.write(f"\n{indent}TARGET({instr.name}) {{\n") if instr.name in predictions: f.write(f"{indent} PREDICTED({instr.name});\n") - # TODO: Is it better to count forward or backward? - for i, input in enumerate(reversed(instr.inputs or ()), 1): - f.write(f"{indent} PyObject *{input} = PEEK({i});\n") - for output in instr.outputs or (): - f.write(f"{indent} PyObject *{output};\n") - # input = ", ".join(instr.inputs) - # output = ", ".join(instr.outputs) - # f.write(f"{indent} // {input} -- {output}\n") - assert instr.block is not None - blocklines = instr.block.text.splitlines(True) - # Remove blank lines from ends - while blocklines and not blocklines[0].strip(): - blocklines.pop(0) - while blocklines and not blocklines[-1].strip(): - blocklines.pop() - # Remove leading '{' and trailing '}' - assert blocklines and blocklines[0].strip() == "{" - assert blocklines and blocklines[-1].strip() == "}" - blocklines.pop() - blocklines.pop(0) - # Remove trailing blank lines - while blocklines and not blocklines[-1].strip(): - blocklines.pop() - # Write the body - ninputs = len(instr.inputs or ()) - for line in blocklines: - if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line): - space, cond, label = m.groups() - # ERROR_IF() must remove the inputs from the stack. - # The code block is responsible for DECREF()ing them. - if ninputs: - f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n") - else: - f.write(f"{space}if ({cond}) {{ goto {label}; }}\n") - else: - f.write(line) - noutputs = len(instr.outputs or ()) - diff = noutputs - ninputs - if diff > 0: - f.write(f"{indent} STACK_GROW({diff});\n") - elif diff < 0: - f.write(f"{indent} STACK_SHRINK({-diff});\n") - for i, output in enumerate(reversed(instr.outputs or ()), 1): - f.write(f"{indent} POKE({i}, {output});\n") + write_instr(instr, predictions, indent, f) assert instr.block if not always_exits(instr.block): f.write(f"{indent} DISPATCH();\n") @@ -138,14 +145,13 @@ def write_cases(f: io.TextIOBase, instrs: list[InstDef], supers: list[parser.Sup components = [instr_index[name] for name in sup.ops] f.write(f"\n{indent}TARGET({sup.name}) {{\n") for i, instr in enumerate(components): + assert instr.block if i > 0: f.write(f"{indent} NEXTOPARG();\n") f.write(f"{indent} next_instr++;\n") - text = instr.block.to_text(-4) - textlines = text.splitlines(True) - textlines = [line for line in textlines if not line.strip().startswith("PREDICTED(")] - text = "".join(textlines) - f.write(f"{indent} {text.strip()}\n") + f.write(f"{indent} {{\n") + write_instr(instr, predictions, indent, f, dedent=-4) + f.write(f" {indent}}}\n") f.write(f"{indent} DISPATCH();\n") f.write(f"{indent}}}\n") From 5fbe7b07cee8bb59b2d0c4187bba17ec2ce9dc5f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 13:29:10 -0800 Subject: [PATCH 17/21] STORE_SLICE --- Python/bytecodes.c | 20 +++++++------------- Python/generated_cases.c.h | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5cd7c75db957ea..64fe4131001beb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -345,25 +345,19 @@ dummy_func( ERROR_IF(res == NULL, error); } - // stack effect: (__0, __1, __2, __3 -- ) - inst(STORE_SLICE) { - PyObject *stop = POP(); - PyObject *start = POP(); - PyObject *container = TOP(); - PyObject *v = SECOND(); - + inst(STORE_SLICE, (v, container, start, stop -- )) { PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + int err; if (slice == NULL) { - goto error; + err = 1; } - int err = PyObject_SetItem(container, slice, v); - Py_DECREF(slice); - if (err) { - goto error; + else { + err = PyObject_SetItem(container, slice, v); + Py_DECREF(slice); } - STACK_SHRINK(2); Py_DECREF(v); Py_DECREF(container); + ERROR_IF(err, error); } // stack effect: (__0 -- ) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 450455877c7c7a..dda1ded68476ff 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -334,23 +334,23 @@ } TARGET(STORE_SLICE) { - PyObject *stop = POP(); - PyObject *start = POP(); - PyObject *container = TOP(); - PyObject *v = SECOND(); - + PyObject *stop = PEEK(1); + PyObject *start = PEEK(2); + PyObject *container = PEEK(3); + PyObject *v = PEEK(4); PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + int err; if (slice == NULL) { - goto error; + err = 1; } - int err = PyObject_SetItem(container, slice, v); - Py_DECREF(slice); - if (err) { - goto error; + else { + err = PyObject_SetItem(container, slice, v); + Py_DECREF(slice); } - STACK_SHRINK(2); Py_DECREF(v); Py_DECREF(container); + if (err) { STACK_SHRINK(4); goto error; } + STACK_SHRINK(4); DISPATCH(); } From fba1de2d1e62ce680b77d247f768e4d2f960419f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 14:45:13 -0800 Subject: [PATCH 18/21] Refactor parser to be more type-correct Also detect whether names that occur in both inputs and outputs are at the same position. --- Tools/cases_generator/generate_cases.py | 15 +++--- Tools/cases_generator/parser.py | 70 +++++++++++++++++-------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index eed78fdfc62ea8..32b7995eb08c33 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -72,13 +72,11 @@ def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, d if dedent < 0: indent += " " * -dedent # TODO: Is it better to count forward or backward? - for i, input in enumerate(reversed(instr.inputs or ()), 1): + for i, input in enumerate(reversed(instr.inputs), 1): f.write(f"{indent} PyObject *{input} = PEEK({i});\n") - for output in instr.outputs or (): - f.write(f"{indent} PyObject *{output};\n") - # input = ", ".join(instr.inputs) - # output = ", ".join(instr.outputs) - # f.write(f"{indent} // {input} -- {output}\n") + for output in instr.outputs: + if output not in instr.inputs: + f.write(f"{indent} PyObject *{output};\n") assert instr.block is not None blocklines = instr.block.to_text(dedent=dedent).splitlines(True) # Remove blank lines from ends @@ -97,7 +95,7 @@ def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, d # Write the body ninputs = len(instr.inputs or ()) for line in blocklines: - if m := re.match(r"(\s*)ERROR_IF\(([^,]+), (\w+)\);\s*$", line): + if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*$", line): space, cond, label = m.groups() # ERROR_IF() must remove the inputs from the stack. # The code block is responsible for DECREF()ing them. @@ -114,7 +112,8 @@ def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, d elif diff < 0: f.write(f"{indent} STACK_SHRINK({-diff});\n") for i, output in enumerate(reversed(instr.outputs or ()), 1): - f.write(f"{indent} POKE({i}, {output});\n") + if output not in (instr.inputs or ()): + f.write(f"{indent} POKE({i}, {output});\n") assert instr.block def write_cases(f: TextIO, instrs: list[InstDef], supers: list[parser.Super]): diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index f603bc6a9868e1..9e95cdb42d42db 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -57,11 +57,28 @@ class Block(Node): @dataclass -class InstDef(Node): +class InstHeader(Node): name: str - inputs: list[str] | None - outputs: list[str] | None - block: Block | None + inputs: list[str] + outputs: list[str] + + +@dataclass +class InstDef(Node): + header: InstHeader + block: Block + + @property + def name(self): + return self.header.name + + @property + def inputs(self): + return self.header.inputs + + @property + def outputs(self): + return self.header.outputs @dataclass @@ -82,30 +99,42 @@ class Parser(PLexer): def inst_def(self) -> InstDef | None: if header := self.inst_header(): if block := self.block(): - header.block = block - return header + return InstDef(header, block) raise self.make_syntax_error("Expected block") return None @contextual - def inst_header(self): + def inst_header(self) -> InstHeader | None: # inst(NAME) | inst(NAME, (inputs -- outputs)) # TODO: Error out when there is something unexpected. - # TODO: Make INST a keyword in the lexer. + # TODO: Make INST a keyword in the lexer.`` if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst": if (self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER))): name = tkn.text if self.expect(lx.COMMA): inp, outp = self.stack_effect() - if (self.expect(lx.RPAREN) - and self.peek().kind == lx.LBRACE): - return InstDef(name, inp, outp, []) + if self.expect(lx.RPAREN): + if ((tkn := self.peek()) + and tkn.kind == lx.LBRACE): + self.check_overlaps(inp, outp) + return InstHeader(name, inp, outp) elif self.expect(lx.RPAREN): - return InstDef(name, None, None, []) + return InstHeader(name, [], []) return None - def stack_effect(self): + def check_overlaps(self, inp: list[str], outp: list[str]): + for i, name in enumerate(inp): + try: + j = outp.index(name) + except ValueError: + continue + else: + if i != j: + raise self.make_syntax_error( + f"Input {name!r} at pos {i} repeated in output at different pos {j}") + + def stack_effect(self) -> tuple[list[str], list[str]]: # '(' [inputs] '--' [outputs] ')' if self.expect(lx.LPAREN): inp = self.inputs() or [] @@ -115,7 +144,7 @@ def stack_effect(self): return inp, outp raise self.make_syntax_error("Expected stack effect") - def inputs(self): + def inputs(self) -> list[str] | None: # input (, input)* here = self.getpos() if inp := self.input(): @@ -128,7 +157,7 @@ def inputs(self): self.setpos(here) return None - def input(self): + def input(self) -> str | None: # IDENTIFIER if (tkn := self.expect(lx.IDENTIFIER)): if self.expect(lx.LBRACKET): @@ -148,7 +177,7 @@ def input(self): return "??" return None - def outputs(self): + def outputs(self) -> list[str] | None: # output (, output)* here = self.getpos() if outp := self.output(): @@ -161,7 +190,7 @@ def outputs(self): self.setpos(here) return None - def output(self): + def output(self) -> str | None: return self.input() # TODO: They're not quite the same. @contextual @@ -176,7 +205,6 @@ def super_def(self) -> Super | None: return res def ops(self) -> list[str] | None: - here = self.getpos() if tkn := self.expect(lx.IDENTIFIER): ops = [tkn.text] while self.expect(lx.PLUS): @@ -197,7 +225,7 @@ def family_def(self) -> Family | None: return Family(tkn.text, members) return None - def members(self): + def members(self) -> list[str] | None: here = self.getpos() if tkn := self.expect(lx.IDENTIFIER): near = self.getpos() @@ -214,8 +242,8 @@ def block(self) -> Block: tokens = self.c_blob() return Block(tokens) - def c_blob(self): - tokens = [] + def c_blob(self) -> list[lx.Token]: + tokens: list[lx.Token] = [] level = 0 while tkn := self.next(raw=True): if tkn.kind in (lx.LBRACE, lx.LPAREN, lx.LBRACKET): From 80741b361852286adc8c83d15fbf70a02b4b797d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sun, 6 Nov 2022 17:14:37 -0800 Subject: [PATCH 19/21] STORE_SUBSCR --- Python/bytecodes.c | 11 ++--------- Python/generated_cases.c.h | 12 +++++------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 64fe4131001beb..199be0c1c1fd4a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -506,21 +506,14 @@ dummy_func( PREDICT(JUMP_BACKWARD); } - // stack effect: (__0, __1, __2 -- ) - inst(STORE_SUBSCR) { - PyObject *sub = TOP(); - PyObject *container = SECOND(); - PyObject *v = THIRD(); + inst(STORE_SUBSCR, (v, container, sub -- )) { int err; - STACK_SHRINK(3); /* container[sub] = v */ err = PyObject_SetItem(container, sub, v); Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - if (err != 0) { - goto error; - } + ERROR_IF(err != 0, error); JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index dda1ded68476ff..b2361c8f0ae5b0 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -501,20 +501,18 @@ TARGET(STORE_SUBSCR) { PREDICTED(STORE_SUBSCR); - PyObject *sub = TOP(); - PyObject *container = SECOND(); - PyObject *v = THIRD(); + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + PyObject *v = PEEK(3); int err; - STACK_SHRINK(3); /* container[sub] = v */ err = PyObject_SetItem(container, sub, v); Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - if (err != 0) { - goto error; - } + if (err != 0) { STACK_SHRINK(3); goto error; } JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR); + STACK_SHRINK(3); DISPATCH(); } From 415757f6b38484161205442158433759c5f8f075 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 7 Nov 2022 15:47:17 -0800 Subject: [PATCH 20/21] Fewer jumps in ERROR_IF expansion --- Python/bytecodes.c | 2 +- Python/ceval.c | 8 ++++++ Python/generated_cases.c.h | 36 ++++++++++++------------- Tools/cases_generator/generate_cases.py | 4 +-- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 199be0c1c1fd4a..5a5b5037527e9a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -260,7 +260,7 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); } - // This is a weird one. It's a super-instruction for + // This is a subtle one. It's a super-instruction for // BINARY_OP_ADD_UNICODE followed by STORE_FAST // where the store goes into the left argument. // So the inputs are the same as for all BINARY_OP diff --git a/Python/ceval.c b/Python/ceval.c index da8cfccdf758fd..95e8f39bc9724c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1275,6 +1275,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; } +pop_4_error: + STACK_SHRINK(1); +pop_3_error: + STACK_SHRINK(1); +pop_2_error: + STACK_SHRINK(1); +pop_1_error: + STACK_SHRINK(1); error: call_shape.kwnames = NULL; /* Double-check exception status. */ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b2361c8f0ae5b0..66d6b4bad0684f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -18,7 +18,7 @@ PyObject *value; /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); - if (value == NULL) { goto unbound_local_error; } + if (value == NULL) goto unbound_local_error; Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -28,7 +28,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; value = GETLOCAL(oparg); - if (value == NULL) { goto unbound_local_error; } + if (value == NULL) goto unbound_local_error; Py_INCREF(value); STACK_GROW(1); POKE(1, value); @@ -89,7 +89,7 @@ PyObject *res; res = PyNumber_Positive(value); Py_DECREF(value); - if (res == NULL) { STACK_SHRINK(1); goto error; } + if (res == NULL) goto pop_1_error; POKE(1, res); DISPATCH(); } @@ -99,7 +99,7 @@ PyObject *res; res = PyNumber_Negative(value); Py_DECREF(value); - if (res == NULL) { STACK_SHRINK(1); goto error; } + if (res == NULL) goto pop_1_error; POKE(1, res); DISPATCH(); } @@ -109,7 +109,7 @@ PyObject *res; int err = PyObject_IsTrue(value); Py_DECREF(value); - if (err < 0) { STACK_SHRINK(1); goto error; } + if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; } @@ -126,7 +126,7 @@ PyObject *res; res = PyNumber_Invert(value); Py_DECREF(value); - if (res == NULL) { STACK_SHRINK(1); goto error; } + if (res == NULL) goto pop_1_error; POKE(1, res); DISPATCH(); } @@ -142,7 +142,7 @@ prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (prod == NULL) { STACK_SHRINK(2); goto error; } + if (prod == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, prod); @@ -162,7 +162,7 @@ prod = PyFloat_FromDouble(dprod); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (prod == NULL) { STACK_SHRINK(2); goto error; } + if (prod == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, prod); @@ -180,7 +180,7 @@ sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (sub == NULL) { STACK_SHRINK(2); goto error; } + if (sub == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, sub); @@ -199,7 +199,7 @@ sub = PyFloat_FromDouble(dsub); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sub == NULL) { STACK_SHRINK(2); goto error; } + if (sub == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, sub); @@ -217,7 +217,7 @@ res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (res == NULL) { STACK_SHRINK(2); goto error; } + if (res == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, res); @@ -251,7 +251,7 @@ _Py_DECREF_NO_DEALLOC(left); PyUnicode_Append(target_local, right); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (*target_local == NULL) { STACK_SHRINK(2); goto error; } + if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); STACK_SHRINK(2); @@ -271,7 +271,7 @@ sum = PyFloat_FromDouble(dsum); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sum == NULL) { STACK_SHRINK(2); goto error; } + if (sum == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, sum); @@ -289,7 +289,7 @@ sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (sum == NULL) { STACK_SHRINK(2); goto error; } + if (sum == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP); STACK_SHRINK(1); POKE(1, sum); @@ -304,7 +304,7 @@ res = PyObject_GetItem(container, sub); Py_DECREF(container); Py_DECREF(sub); - if (res == NULL) { STACK_SHRINK(2); goto error; } + if (res == NULL) goto pop_2_error; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); STACK_SHRINK(1); POKE(1, res); @@ -327,7 +327,7 @@ Py_DECREF(slice); } Py_DECREF(container); - if (res == NULL) { STACK_SHRINK(3); goto error; } + if (res == NULL) goto pop_3_error; STACK_SHRINK(2); POKE(1, res); DISPATCH(); @@ -349,7 +349,7 @@ } Py_DECREF(v); Py_DECREF(container); - if (err) { STACK_SHRINK(4); goto error; } + if (err) goto pop_4_error; STACK_SHRINK(4); DISPATCH(); } @@ -510,7 +510,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - if (err != 0) { STACK_SHRINK(3); goto error; } + if (err != 0) goto pop_3_error; JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR); STACK_SHRINK(3); DISPATCH(); diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 32b7995eb08c33..e5610343880f86 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -100,9 +100,9 @@ def write_instr(instr: InstDef, predictions: set[str], indent: str, f: TextIO, d # ERROR_IF() must remove the inputs from the stack. # The code block is responsible for DECREF()ing them. if ninputs: - f.write(f"{space}if ({cond}) {{ STACK_SHRINK({ninputs}); goto {label}; }}\n") + f.write(f"{space}if ({cond}) goto pop_{ninputs}_{label};\n") else: - f.write(f"{space}if ({cond}) {{ goto {label}; }}\n") + f.write(f"{space}if ({cond}) goto {label};\n") else: f.write(line) noutputs = len(instr.outputs or ()) From 48c2a209c786ea12959dfdacb7ae959223ff75ca Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 7 Nov 2022 15:52:25 -0800 Subject: [PATCH 21/21] Add dummy variables for stack effects --- Python/bytecodes.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5a5b5037527e9a..d04d15941d3234 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -81,6 +81,10 @@ typedef struct { PyObject *kwnames; } CallShape; +// Dummy variables for stack effects. +static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; +static PyObject *container, *start, *stop, *v; + static PyObject * dummy_func( PyThreadState *tstate,