GH-126222: Fix `_PyUop_num_popped` (GH-126507)

This commit is contained in:
Mark Shannon 2024-11-07 10:48:27 +00:00 committed by GitHub
parent c9cda1608e
commit 85036c8d61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 56 deletions

View File

@ -658,7 +658,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _TO_BOOL: case _TO_BOOL:
return 1; return 1;
case _TO_BOOL_BOOL: case _TO_BOOL_BOOL:
return 1; return 0;
case _TO_BOOL_INT: case _TO_BOOL_INT:
return 1; return 1;
case _TO_BOOL_LIST: case _TO_BOOL_LIST:
@ -672,11 +672,11 @@ int _PyUop_num_popped(int opcode, int oparg)
case _UNARY_INVERT: case _UNARY_INVERT:
return 1; return 1;
case _GUARD_BOTH_INT: case _GUARD_BOTH_INT:
return 2; return 0;
case _GUARD_NOS_INT: case _GUARD_NOS_INT:
return 2; return 0;
case _GUARD_TOS_INT: case _GUARD_TOS_INT:
return 1; return 0;
case _BINARY_OP_MULTIPLY_INT: case _BINARY_OP_MULTIPLY_INT:
return 2; return 2;
case _BINARY_OP_ADD_INT: case _BINARY_OP_ADD_INT:
@ -684,11 +684,11 @@ int _PyUop_num_popped(int opcode, int oparg)
case _BINARY_OP_SUBTRACT_INT: case _BINARY_OP_SUBTRACT_INT:
return 2; return 2;
case _GUARD_BOTH_FLOAT: case _GUARD_BOTH_FLOAT:
return 2; return 0;
case _GUARD_NOS_FLOAT: case _GUARD_NOS_FLOAT:
return 2; return 0;
case _GUARD_TOS_FLOAT: case _GUARD_TOS_FLOAT:
return 1; return 0;
case _BINARY_OP_MULTIPLY_FLOAT: case _BINARY_OP_MULTIPLY_FLOAT:
return 2; return 2;
case _BINARY_OP_ADD_FLOAT: case _BINARY_OP_ADD_FLOAT:
@ -696,7 +696,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _BINARY_OP_SUBTRACT_FLOAT: case _BINARY_OP_SUBTRACT_FLOAT:
return 2; return 2;
case _GUARD_BOTH_UNICODE: case _GUARD_BOTH_UNICODE:
return 2; return 0;
case _BINARY_OP_ADD_UNICODE: case _BINARY_OP_ADD_UNICODE:
return 2; return 2;
case _BINARY_OP_INPLACE_ADD_UNICODE: case _BINARY_OP_INPLACE_ADD_UNICODE:
@ -716,13 +716,13 @@ int _PyUop_num_popped(int opcode, int oparg)
case _BINARY_SUBSCR_DICT: case _BINARY_SUBSCR_DICT:
return 2; return 2;
case _BINARY_SUBSCR_CHECK_FUNC: case _BINARY_SUBSCR_CHECK_FUNC:
return 2; return 0;
case _BINARY_SUBSCR_INIT_CALL: case _BINARY_SUBSCR_INIT_CALL:
return 2; return 2;
case _LIST_APPEND: case _LIST_APPEND:
return 2 + (oparg-1); return 1;
case _SET_ADD: case _SET_ADD:
return 2 + (oparg-1); return 1;
case _STORE_SUBSCR: case _STORE_SUBSCR:
return 3; return 3;
case _STORE_SUBSCR_LIST_INT: case _STORE_SUBSCR_LIST_INT:
@ -740,11 +740,11 @@ int _PyUop_num_popped(int opcode, int oparg)
case _GET_AITER: case _GET_AITER:
return 1; return 1;
case _GET_ANEXT: case _GET_ANEXT:
return 1; return 0;
case _GET_AWAITABLE: case _GET_AWAITABLE:
return 1; return 1;
case _SEND_GEN_FRAME: case _SEND_GEN_FRAME:
return 2; return 1;
case _YIELD_VALUE: case _YIELD_VALUE:
return 1; return 1;
case _POP_EXCEPT: case _POP_EXCEPT:
@ -812,9 +812,9 @@ int _PyUop_num_popped(int opcode, int oparg)
case _BUILD_LIST: case _BUILD_LIST:
return oparg; return oparg;
case _LIST_EXTEND: case _LIST_EXTEND:
return 2 + (oparg-1); return 1;
case _SET_UPDATE: case _SET_UPDATE:
return 2 + (oparg-1); return 1;
case _BUILD_SET: case _BUILD_SET:
return oparg; return oparg;
case _BUILD_MAP: case _BUILD_MAP:
@ -822,11 +822,11 @@ int _PyUop_num_popped(int opcode, int oparg)
case _SETUP_ANNOTATIONS: case _SETUP_ANNOTATIONS:
return 0; return 0;
case _DICT_UPDATE: case _DICT_UPDATE:
return 2 + (oparg - 1); return 1;
case _DICT_MERGE: case _DICT_MERGE:
return 5 + (oparg - 1); return 1;
case _MAP_ADD: case _MAP_ADD:
return 3 + (oparg - 1); return 2;
case _LOAD_SUPER_ATTR_ATTR: case _LOAD_SUPER_ATTR_ATTR:
return 3; return 3;
case _LOAD_SUPER_ATTR_METHOD: case _LOAD_SUPER_ATTR_METHOD:
@ -834,9 +834,9 @@ int _PyUop_num_popped(int opcode, int oparg)
case _LOAD_ATTR: case _LOAD_ATTR:
return 1; return 1;
case _GUARD_TYPE_VERSION: case _GUARD_TYPE_VERSION:
return 1; return 0;
case _CHECK_MANAGED_OBJECT_HAS_VALUES: case _CHECK_MANAGED_OBJECT_HAS_VALUES:
return 1; return 0;
case _LOAD_ATTR_INSTANCE_VALUE_0: case _LOAD_ATTR_INSTANCE_VALUE_0:
return 1; return 1;
case _LOAD_ATTR_INSTANCE_VALUE_1: case _LOAD_ATTR_INSTANCE_VALUE_1:
@ -844,11 +844,11 @@ int _PyUop_num_popped(int opcode, int oparg)
case _LOAD_ATTR_INSTANCE_VALUE: case _LOAD_ATTR_INSTANCE_VALUE:
return 1; return 1;
case _CHECK_ATTR_MODULE: case _CHECK_ATTR_MODULE:
return 1; return 0;
case _LOAD_ATTR_MODULE: case _LOAD_ATTR_MODULE:
return 1; return 1;
case _CHECK_ATTR_WITH_HINT: case _CHECK_ATTR_WITH_HINT:
return 1; return 0;
case _LOAD_ATTR_WITH_HINT: case _LOAD_ATTR_WITH_HINT:
return 1; return 1;
case _LOAD_ATTR_SLOT_0: case _LOAD_ATTR_SLOT_0:
@ -858,7 +858,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _LOAD_ATTR_SLOT: case _LOAD_ATTR_SLOT:
return 1; return 1;
case _CHECK_ATTR_CLASS: case _CHECK_ATTR_CLASS:
return 1; return 0;
case _LOAD_ATTR_CLASS_0: case _LOAD_ATTR_CLASS_0:
return 1; return 1;
case _LOAD_ATTR_CLASS_1: case _LOAD_ATTR_CLASS_1:
@ -868,7 +868,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _LOAD_ATTR_PROPERTY_FRAME: case _LOAD_ATTR_PROPERTY_FRAME:
return 1; return 1;
case _GUARD_DORV_NO_DICT: case _GUARD_DORV_NO_DICT:
return 1; return 0;
case _STORE_ATTR_INSTANCE_VALUE: case _STORE_ATTR_INSTANCE_VALUE:
return 2; return 2;
case _STORE_ATTR_WITH_HINT: case _STORE_ATTR_WITH_HINT:
@ -894,59 +894,59 @@ int _PyUop_num_popped(int opcode, int oparg)
case _CHECK_EG_MATCH: case _CHECK_EG_MATCH:
return 2; return 2;
case _CHECK_EXC_MATCH: case _CHECK_EXC_MATCH:
return 2; return 1;
case _IMPORT_NAME: case _IMPORT_NAME:
return 2; return 2;
case _IMPORT_FROM: case _IMPORT_FROM:
return 1; return 0;
case _IS_NONE: case _IS_NONE:
return 1; return 1;
case _GET_LEN: case _GET_LEN:
return 1; return 0;
case _MATCH_CLASS: case _MATCH_CLASS:
return 3; return 3;
case _MATCH_MAPPING: case _MATCH_MAPPING:
return 1; return 0;
case _MATCH_SEQUENCE: case _MATCH_SEQUENCE:
return 1; return 0;
case _MATCH_KEYS: case _MATCH_KEYS:
return 2; return 0;
case _GET_ITER: case _GET_ITER:
return 1; return 1;
case _GET_YIELD_FROM_ITER: case _GET_YIELD_FROM_ITER:
return 1; return 1;
case _FOR_ITER_TIER_TWO: case _FOR_ITER_TIER_TWO:
return 1; return 0;
case _ITER_CHECK_LIST: case _ITER_CHECK_LIST:
return 1; return 0;
case _GUARD_NOT_EXHAUSTED_LIST: case _GUARD_NOT_EXHAUSTED_LIST:
return 1; return 0;
case _ITER_NEXT_LIST: case _ITER_NEXT_LIST:
return 1; return 0;
case _ITER_CHECK_TUPLE: case _ITER_CHECK_TUPLE:
return 1; return 0;
case _GUARD_NOT_EXHAUSTED_TUPLE: case _GUARD_NOT_EXHAUSTED_TUPLE:
return 1; return 0;
case _ITER_NEXT_TUPLE: case _ITER_NEXT_TUPLE:
return 1; return 0;
case _ITER_CHECK_RANGE: case _ITER_CHECK_RANGE:
return 1; return 0;
case _GUARD_NOT_EXHAUSTED_RANGE: case _GUARD_NOT_EXHAUSTED_RANGE:
return 1; return 0;
case _ITER_NEXT_RANGE: case _ITER_NEXT_RANGE:
return 1; return 0;
case _FOR_ITER_GEN_FRAME: case _FOR_ITER_GEN_FRAME:
return 1; return 0;
case _LOAD_SPECIAL: case _LOAD_SPECIAL:
return 1; return 1;
case _WITH_EXCEPT_START: case _WITH_EXCEPT_START:
return 5; return 0;
case _PUSH_EXC_INFO: case _PUSH_EXC_INFO:
return 1; return 1;
case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT:
return 1; return 0;
case _GUARD_KEYS_VERSION: case _GUARD_KEYS_VERSION:
return 1; return 0;
case _LOAD_ATTR_METHOD_WITH_VALUES: case _LOAD_ATTR_METHOD_WITH_VALUES:
return 1; return 1;
case _LOAD_ATTR_METHOD_NO_DICT: case _LOAD_ATTR_METHOD_NO_DICT:
@ -956,7 +956,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT: case _LOAD_ATTR_NONDESCRIPTOR_NO_DICT:
return 1; return 1;
case _CHECK_ATTR_METHOD_LAZY_DICT: case _CHECK_ATTR_METHOD_LAZY_DICT:
return 1; return 0;
case _LOAD_ATTR_METHOD_LAZY_DICT: case _LOAD_ATTR_METHOD_LAZY_DICT:
return 1; return 1;
case _MAYBE_EXPAND_METHOD: case _MAYBE_EXPAND_METHOD:
@ -964,25 +964,25 @@ int _PyUop_num_popped(int opcode, int oparg)
case _PY_FRAME_GENERAL: case _PY_FRAME_GENERAL:
return 2 + oparg; return 2 + oparg;
case _CHECK_FUNCTION_VERSION: case _CHECK_FUNCTION_VERSION:
return 2 + oparg; return 0;
case _CHECK_METHOD_VERSION: case _CHECK_METHOD_VERSION:
return 2 + oparg; return 0;
case _EXPAND_METHOD: case _EXPAND_METHOD:
return 2 + oparg; return 2 + oparg;
case _CHECK_IS_NOT_PY_CALLABLE: case _CHECK_IS_NOT_PY_CALLABLE:
return 2 + oparg; return 0;
case _CALL_NON_PY_GENERAL: case _CALL_NON_PY_GENERAL:
return 2 + oparg; return 2 + oparg;
case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS:
return 2 + oparg; return 0;
case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: case _INIT_CALL_BOUND_METHOD_EXACT_ARGS:
return 2 + oparg; return 2 + oparg;
case _CHECK_PEP_523: case _CHECK_PEP_523:
return 0; return 0;
case _CHECK_FUNCTION_EXACT_ARGS: case _CHECK_FUNCTION_EXACT_ARGS:
return 2 + oparg; return 0;
case _CHECK_STACK_SPACE: case _CHECK_STACK_SPACE:
return 2 + oparg; return 0;
case _INIT_CALL_PY_EXACT_ARGS_0: case _INIT_CALL_PY_EXACT_ARGS_0:
return 2 + oparg; return 2 + oparg;
case _INIT_CALL_PY_EXACT_ARGS_1: case _INIT_CALL_PY_EXACT_ARGS_1:
@ -1036,17 +1036,17 @@ int _PyUop_num_popped(int opcode, int oparg)
case _PY_FRAME_KW: case _PY_FRAME_KW:
return 3 + oparg; return 3 + oparg;
case _CHECK_FUNCTION_VERSION_KW: case _CHECK_FUNCTION_VERSION_KW:
return 3 + oparg; return 0;
case _CHECK_METHOD_VERSION_KW: case _CHECK_METHOD_VERSION_KW:
return 3 + oparg; return 0;
case _EXPAND_METHOD_KW: case _EXPAND_METHOD_KW:
return 3 + oparg; return 3 + oparg;
case _CHECK_IS_NOT_PY_CALLABLE_KW: case _CHECK_IS_NOT_PY_CALLABLE_KW:
return 3 + oparg; return 0;
case _CALL_KW_NON_PY: case _CALL_KW_NON_PY:
return 3 + oparg; return 3 + oparg;
case _MAKE_CALLARGS_A_TUPLE: case _MAKE_CALLARGS_A_TUPLE:
return 3 + (oparg & 1); return 1 + (oparg & 1);
case _MAKE_FUNCTION: case _MAKE_FUNCTION:
return 1; return 1;
case _SET_FUNCTION_ATTRIBUTE: case _SET_FUNCTION_ATTRIBUTE:
@ -1062,7 +1062,7 @@ int _PyUop_num_popped(int opcode, int oparg)
case _FORMAT_WITH_SPEC: case _FORMAT_WITH_SPEC:
return 2; return 2;
case _COPY: case _COPY:
return 1 + (oparg-1); return 0;
case _BINARY_OP: case _BINARY_OP:
return 2; return 2;
case _SWAP: case _SWAP:

View File

@ -1486,6 +1486,14 @@ class TestUopsOptimization(unittest.TestCase):
fn(A()) fn(A())
def test_jit_error_pops(self):
"""
Tests that the correct number of pops are inserted into the
exit stub
"""
items = 17 * [None] + [[]]
with self.assertRaises(TypeError):
{item for item in items}
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -0,0 +1,3 @@
Do not include count of "peek" items in ``_PyUop_num_popped``. This ensures
that the correct number of items are popped from the stack when a micro-op
exits with an error.

View File

@ -51,6 +51,8 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None:
if uop.is_viable() and uop.properties.tier != 1: if uop.is_viable() and uop.properties.tier != 1:
stack = Stack() stack = Stack()
for var in reversed(uop.stack.inputs): for var in reversed(uop.stack.inputs):
if var.peek:
break
stack.pop(var) stack.pop(var)
popped = (-stack.base_offset).to_c() popped = (-stack.base_offset).to_c()
out.emit(f"case {uop.name}:\n") out.emit(f"case {uop.name}:\n")