diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 906ea0db0a5fe0..b2cd876a0867aa 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1507,10 +1507,10 @@ _PyOpcode_macro_expansion[256] = { [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { _UNARY_NEGATIVE, OPARG_SIMPLE, 0 } } }, [UNARY_NOT] = { .nuops = 1, .uops = { { _UNARY_NOT, OPARG_SIMPLE, 0 } } }, [UNPACK_EX] = { .nuops = 1, .uops = { { _UNPACK_EX, OPARG_SIMPLE, 0 } } }, - [UNPACK_SEQUENCE] = { .nuops = 1, .uops = { { _UNPACK_SEQUENCE, OPARG_SIMPLE, 0 } } }, - [UNPACK_SEQUENCE_LIST] = { .nuops = 2, .uops = { { _GUARD_TOS_LIST, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_LIST, OPARG_SIMPLE, 1 } } }, - [UNPACK_SEQUENCE_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 } } }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 } } }, + [UNPACK_SEQUENCE] = { .nuops = 2, .uops = { { _UNPACK_SEQUENCE, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 } } }, + [UNPACK_SEQUENCE_LIST] = { .nuops = 3, .uops = { { _GUARD_TOS_LIST, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_LIST, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, + [UNPACK_SEQUENCE_TUPLE] = { .nuops = 3, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 3, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { _WITH_EXCEPT_START, OPARG_SIMPLE, 0 } } }, [YIELD_VALUE] = { .nuops = 1, .uops = { { _YIELD_VALUE, OPARG_SIMPLE, 0 } } }, }; diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index f73aad9de1c0bf..5c550e0fa9e1a9 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -1089,13 +1089,14 @@ extern "C" { #define _UNARY_NOT_r22 1282 #define _UNARY_NOT_r33 1283 #define _UNPACK_EX_r10 1284 -#define _UNPACK_SEQUENCE_r10 1285 -#define _UNPACK_SEQUENCE_LIST_r10 1286 -#define _UNPACK_SEQUENCE_TUPLE_r10 1287 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1288 -#define _WITH_EXCEPT_START_r33 1289 -#define _YIELD_VALUE_r11 1290 -#define MAX_UOP_REGS_ID 1290 +#define _UNPACK_SEQUENCE_r11 1285 +#define _UNPACK_SEQUENCE_LIST_r11 1286 +#define _UNPACK_SEQUENCE_TUPLE_r11 1287 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r03 1288 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r13 1289 +#define _WITH_EXCEPT_START_r33 1290 +#define _YIELD_VALUE_r11 1291 +#define MAX_UOP_REGS_ID 1291 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 0cc38919565bc1..b6dc0a86a5e4d9 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -148,9 +148,9 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_STORE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_DELETE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_UNPACK_SEQUENCE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_UNPACK_SEQUENCE_TWO_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_UNPACK_SEQUENCE_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_UNPACK_SEQUENCE_LIST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_UNPACK_SEQUENCE_TWO_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_UNPACK_SEQUENCE_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_UNPACK_SEQUENCE_LIST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_UNPACK_EX] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_DELETE_ATTR] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -1377,16 +1377,16 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .best = { 1, 1, 1, 1 }, .entries = { { -1, -1, -1 }, - { 0, 1, _UNPACK_SEQUENCE_r10 }, + { 1, 1, _UNPACK_SEQUENCE_r11 }, { -1, -1, -1 }, { -1, -1, -1 }, }, }, [_UNPACK_SEQUENCE_TWO_TUPLE] = { - .best = { 1, 1, 1, 1 }, + .best = { 0, 1, 1, 1 }, .entries = { - { -1, -1, -1 }, - { 2, 1, _UNPACK_SEQUENCE_TWO_TUPLE_r12 }, + { 3, 0, _UNPACK_SEQUENCE_TWO_TUPLE_r03 }, + { 3, 1, _UNPACK_SEQUENCE_TWO_TUPLE_r13 }, { -1, -1, -1 }, { -1, -1, -1 }, }, @@ -1395,7 +1395,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .best = { 1, 1, 1, 1 }, .entries = { { -1, -1, -1 }, - { 0, 1, _UNPACK_SEQUENCE_TUPLE_r10 }, + { 1, 1, _UNPACK_SEQUENCE_TUPLE_r11 }, { -1, -1, -1 }, { -1, -1, -1 }, }, @@ -1404,7 +1404,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .best = { 1, 1, 1, 1 }, .entries = { { -1, -1, -1 }, - { 0, 1, _UNPACK_SEQUENCE_LIST_r10 }, + { 1, 1, _UNPACK_SEQUENCE_LIST_r11 }, { -1, -1, -1 }, { -1, -1, -1 }, }, @@ -3469,10 +3469,11 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_LOAD_BUILD_CLASS_r01] = _LOAD_BUILD_CLASS, [_STORE_NAME_r10] = _STORE_NAME, [_DELETE_NAME_r00] = _DELETE_NAME, - [_UNPACK_SEQUENCE_r10] = _UNPACK_SEQUENCE, - [_UNPACK_SEQUENCE_TWO_TUPLE_r12] = _UNPACK_SEQUENCE_TWO_TUPLE, - [_UNPACK_SEQUENCE_TUPLE_r10] = _UNPACK_SEQUENCE_TUPLE, - [_UNPACK_SEQUENCE_LIST_r10] = _UNPACK_SEQUENCE_LIST, + [_UNPACK_SEQUENCE_r11] = _UNPACK_SEQUENCE, + [_UNPACK_SEQUENCE_TWO_TUPLE_r03] = _UNPACK_SEQUENCE_TWO_TUPLE, + [_UNPACK_SEQUENCE_TWO_TUPLE_r13] = _UNPACK_SEQUENCE_TWO_TUPLE, + [_UNPACK_SEQUENCE_TUPLE_r11] = _UNPACK_SEQUENCE_TUPLE, + [_UNPACK_SEQUENCE_LIST_r11] = _UNPACK_SEQUENCE_LIST, [_UNPACK_EX_r10] = _UNPACK_EX, [_STORE_ATTR_r20] = _STORE_ATTR, [_DELETE_ATTR_r10] = _DELETE_ATTR, @@ -4864,13 +4865,14 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_UNPACK_EX] = "_UNPACK_EX", [_UNPACK_EX_r10] = "_UNPACK_EX_r10", [_UNPACK_SEQUENCE] = "_UNPACK_SEQUENCE", - [_UNPACK_SEQUENCE_r10] = "_UNPACK_SEQUENCE_r10", + [_UNPACK_SEQUENCE_r11] = "_UNPACK_SEQUENCE_r11", [_UNPACK_SEQUENCE_LIST] = "_UNPACK_SEQUENCE_LIST", - [_UNPACK_SEQUENCE_LIST_r10] = "_UNPACK_SEQUENCE_LIST_r10", + [_UNPACK_SEQUENCE_LIST_r11] = "_UNPACK_SEQUENCE_LIST_r11", [_UNPACK_SEQUENCE_TUPLE] = "_UNPACK_SEQUENCE_TUPLE", - [_UNPACK_SEQUENCE_TUPLE_r10] = "_UNPACK_SEQUENCE_TUPLE_r10", + [_UNPACK_SEQUENCE_TUPLE_r11] = "_UNPACK_SEQUENCE_TUPLE_r11", [_UNPACK_SEQUENCE_TWO_TUPLE] = "_UNPACK_SEQUENCE_TWO_TUPLE", - [_UNPACK_SEQUENCE_TWO_TUPLE_r12] = "_UNPACK_SEQUENCE_TWO_TUPLE_r12", + [_UNPACK_SEQUENCE_TWO_TUPLE_r03] = "_UNPACK_SEQUENCE_TWO_TUPLE_r03", + [_UNPACK_SEQUENCE_TWO_TUPLE_r13] = "_UNPACK_SEQUENCE_TWO_TUPLE_r13", [_WITH_EXCEPT_START] = "_WITH_EXCEPT_START", [_WITH_EXCEPT_START_r33] = "_WITH_EXCEPT_START_r33", [_YIELD_VALUE] = "_YIELD_VALUE", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 6f1b115b31257f..c957e74c9afa75 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -433,6 +433,75 @@ def testfunc(n, m): uops = get_opnames(ex) self.assertIn("_FOR_ITER_TIER_TWO", uops) + def test_unpack_sequence_generic(self): + def testfunc(x): + i = 0 + while i < x: + i += 1 + # Use an iterator to force generic UNPACK_SEQUENCE + a, b = iter((1, 2)) + return a, b + + res = testfunc(TIER2_THRESHOLD) + self.assertEqual(res, (1, 2)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_UNPACK_SEQUENCE", uops) + + def test_unpack_sequence_two_tuple(self): + def testfunc(x): + i = 0 + while i < x: + i += 1 + t = (i, i) + a, b = t + return a, b + + res = testfunc(TIER2_THRESHOLD) + self.assertEqual(res, (TIER2_THRESHOLD, TIER2_THRESHOLD)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_UNPACK_SEQUENCE_TWO_TUPLE", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_unpack_sequence_tuple(self): + def testfunc(x): + i = 0 + while i < x: + i += 1 + t = (i, i, i) + a, b, c = t + return a, b, c + + res = testfunc(TIER2_THRESHOLD) + self.assertEqual(res, (TIER2_THRESHOLD, TIER2_THRESHOLD, TIER2_THRESHOLD)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_UNPACK_SEQUENCE_TUPLE", uops) + self.assertNotIn("_POP_TOP", uops) + + def test_unpack_sequence_list(self): + def testfunc(x): + i = 0 + while i < x: + i += 1 + a, b = [1, 2] + return a, b + + res = testfunc(TIER2_THRESHOLD) + self.assertEqual(res, (1, 2)) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_UNPACK_SEQUENCE_LIST", uops) + @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3e3b3d2f446d33..5e1845b9ba9ee0 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1576,19 +1576,23 @@ dummy_func( (void)counter; } - op(_UNPACK_SEQUENCE, (seq -- unused[oparg], top[0])) { - PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); + op(_UNPACK_SEQUENCE, (seq -- unused[oparg], top[0], s)) { + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top); - Py_DECREF(seq_o); - ERROR_IF(res == 0); + if (res == 0) { + PyStackRef_CLOSE(seq); + ERROR_IF(1); + } + s = seq; + INPUTS_DEAD(); } - macro(UNPACK_SEQUENCE) = _SPECIALIZE_UNPACK_SEQUENCE + _UNPACK_SEQUENCE; + macro(UNPACK_SEQUENCE) = _SPECIALIZE_UNPACK_SEQUENCE + _UNPACK_SEQUENCE + POP_TOP; macro(UNPACK_SEQUENCE_TWO_TUPLE) = - _GUARD_TOS_TUPLE + unused/1 + _UNPACK_SEQUENCE_TWO_TUPLE; + _GUARD_TOS_TUPLE + unused/1 + _UNPACK_SEQUENCE_TWO_TUPLE + POP_TOP; - op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { + op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0, s)) { assert(oparg == 2); PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyTuple_CheckExact(seq_o)); @@ -1596,13 +1600,14 @@ dummy_func( STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); - PyStackRef_CLOSE(seq); + s = seq; + INPUTS_DEAD(); } macro(UNPACK_SEQUENCE_TUPLE) = - _GUARD_TOS_TUPLE + unused/1 + _UNPACK_SEQUENCE_TUPLE; + _GUARD_TOS_TUPLE + unused/1 + _UNPACK_SEQUENCE_TUPLE + POP_TOP; - op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) { + op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg], s)) { PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyTuple_CheckExact(seq_o)); DEOPT_IF(PyTuple_GET_SIZE(seq_o) != oparg); @@ -1611,13 +1616,14 @@ dummy_func( for (int i = oparg; --i >= 0; ) { *values++ = PyStackRef_FromPyObjectNew(items[i]); } - DECREF_INPUTS(); + s = seq; + INPUTS_DEAD(); } macro(UNPACK_SEQUENCE_LIST) = - _GUARD_TOS_LIST + unused/1 + _UNPACK_SEQUENCE_LIST; + _GUARD_TOS_LIST + unused/1 + _UNPACK_SEQUENCE_LIST + POP_TOP; - op(_UNPACK_SEQUENCE_LIST, (seq -- values[oparg])) { + op(_UNPACK_SEQUENCE_LIST, (seq -- values[oparg], s)) { PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); assert(PyList_CheckExact(seq_o)); DEOPT_IF(!LOCK_OBJECT(seq_o)); @@ -1631,7 +1637,8 @@ dummy_func( *values++ = PyStackRef_FromPyObjectNew(items[i]); } UNLOCK_OBJECT(seq_o); - DECREF_INPUTS(); + s = seq; + INPUTS_DEAD(); } inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8], top[0])) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b7ee752cd44e16..75bd0fc5434ad8 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -6092,40 +6092,81 @@ break; } - case _UNPACK_SEQUENCE_r10: { + case _UNPACK_SEQUENCE_r11: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *top; + _PyStackRef s; _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); seq = _stack_item_0; top = &stack_pointer[oparg]; - PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); + stack_pointer[0] = seq; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top); - Py_DECREF(seq_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res == 0) { + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(seq); + stack_pointer = _PyFrame_GetStackPointer(frame); SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - _tos_cache0 = PyStackRef_ZERO_BITS; + s = seq; + _tos_cache0 = s; _tos_cache1 = PyStackRef_ZERO_BITS; _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(0); - stack_pointer += oparg; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1 + oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_TWO_TUPLE_r12: { + case _UNPACK_SEQUENCE_TWO_TUPLE_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef seq; + _PyStackRef val1; + _PyStackRef val0; + _PyStackRef s; + oparg = CURRENT_OPARG(); + seq = stack_pointer[-1]; + assert(oparg == 2); + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); + assert(PyTuple_CheckExact(seq_o)); + if (PyTuple_GET_SIZE(seq_o) != 2) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(UNPACK_SEQUENCE, hit); + val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); + val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); + s = seq; + _tos_cache2 = s; + _tos_cache1 = val0; + _tos_cache0 = val1; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _UNPACK_SEQUENCE_TWO_TUPLE_r13: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef val1; _PyStackRef val0; + _PyStackRef s; _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); seq = _stack_item_0; @@ -6141,28 +6182,21 @@ STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); - stack_pointer[0] = val1; - stack_pointer[1] = val0; - stack_pointer += 2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); - stack_pointer = _PyFrame_GetStackPointer(frame); + s = seq; + _tos_cache2 = s; _tos_cache1 = val0; _tos_cache0 = val1; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(2); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(3); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_TUPLE_r10: { + case _UNPACK_SEQUENCE_TUPLE_r11: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *values; + _PyStackRef s; _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); seq = _stack_item_0; @@ -6180,24 +6214,21 @@ for (int i = oparg; --i >= 0; ) { *values++ = PyStackRef_FromPyObjectNew(items[i]); } + s = seq; + _tos_cache0 = s; + SET_CURRENT_CACHED_VALUES(1); stack_pointer += oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); - stack_pointer = _PyFrame_GetStackPointer(frame); - _tos_cache0 = PyStackRef_ZERO_BITS; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _UNPACK_SEQUENCE_LIST_r10: { + case _UNPACK_SEQUENCE_LIST_r11: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef seq; _PyStackRef *values; + _PyStackRef s; _PyStackRef _stack_item_0 = _tos_cache0; oparg = CURRENT_OPARG(); seq = _stack_item_0; @@ -6225,15 +6256,11 @@ *values++ = PyStackRef_FromPyObjectNew(items[i]); } UNLOCK_OBJECT(seq_o); + s = seq; + _tos_cache0 = s; + SET_CURRENT_CACHED_VALUES(1); stack_pointer += oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); - stack_pointer = _PyFrame_GetStackPointer(frame); - _tos_cache0 = PyStackRef_ZERO_BITS; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 28dc7b25f0d2cc..5d86f93f75905c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -11767,6 +11767,8 @@ (void)this_instr; _PyStackRef seq; _PyStackRef *top; + _PyStackRef s; + _PyStackRef value; // _SPECIALIZE_UNPACK_SEQUENCE { seq = stack_pointer[-1]; @@ -11789,19 +11791,29 @@ // _UNPACK_SEQUENCE { top = &stack_pointer[-1 + oparg]; - PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq); _PyFrame_SetStackPointer(frame, stack_pointer); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top); - Py_DECREF(seq_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (res == 0) { + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(seq); + stack_pointer = _PyFrame_GetStackPointer(frame); JUMP_TO_LABEL(error); } + s = seq; + } + // _POP_TOP + { + value = s; + stack_pointer += -1 + oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); } - stack_pointer += oparg; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } @@ -11819,6 +11831,8 @@ _PyStackRef tos; _PyStackRef seq; _PyStackRef *values; + _PyStackRef s; + _PyStackRef value; // _GUARD_TOS_LIST { tos = stack_pointer[-1]; @@ -11855,10 +11869,15 @@ *values++ = PyStackRef_FromPyObjectNew(items[i]); } UNLOCK_OBJECT(seq_o); + s = seq; + } + // _POP_TOP + { + value = s; stack_pointer += -1 + oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } DISPATCH(); @@ -11878,6 +11897,8 @@ _PyStackRef tos; _PyStackRef seq; _PyStackRef *values; + _PyStackRef s; + _PyStackRef value; // _GUARD_TOS_TUPLE { tos = stack_pointer[-1]; @@ -11905,10 +11926,15 @@ for (int i = oparg; --i >= 0; ) { *values++ = PyStackRef_FromPyObjectNew(items[i]); } + s = seq; + } + // _POP_TOP + { + value = s; stack_pointer += -1 + oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } DISPATCH(); @@ -11929,6 +11955,8 @@ _PyStackRef seq; _PyStackRef val1; _PyStackRef val0; + _PyStackRef s; + _PyStackRef value; // _GUARD_TOS_TUPLE { tos = stack_pointer[-1]; @@ -11954,12 +11982,17 @@ STAT_INC(UNPACK_SEQUENCE, hit); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); + s = seq; + } + // _POP_TOP + { + value = s; stack_pointer[-1] = val1; stack_pointer[0] = val0; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(seq); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } DISPATCH(); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e3921054f7cb43..cca4f34d33f528 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -954,12 +954,13 @@ dummy_func(void) { } } - op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) { + op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0], s)) { (void)top; /* This has to be done manually */ for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); } + s = seq; } op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8], top[0])) { @@ -1136,15 +1137,24 @@ dummy_func(void) { set = sym_new_type(ctx, &PySet_Type); } - op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0)) { + op(_UNPACK_SEQUENCE_TWO_TUPLE, (seq -- val1, val0, s)) { val0 = sym_tuple_getitem(ctx, seq, 0); val1 = sym_tuple_getitem(ctx, seq, 1); + s = seq; } - op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg])) { + op(_UNPACK_SEQUENCE_TUPLE, (seq -- values[oparg], s)) { for (int i = 0; i < oparg; i++) { values[i] = sym_tuple_getitem(ctx, seq, oparg - i - 1); } + s = seq; + } + + op(_UNPACK_SEQUENCE_LIST, (seq -- values[oparg], s)) { + for (int i = 0; i < oparg; i++) { + values[i] = sym_new_not_null(ctx); + } + s = seq; } op(_CALL_TUPLE_1, (callable, null, arg -- res, a)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 32d60c76a4f3ce..df8e8c1e91ade5 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1108,16 +1108,21 @@ } case _UNPACK_SEQUENCE: { + JitOptRef seq; JitOptRef *values; JitOptRef *top; + JitOptRef s; + seq = stack_pointer[-1]; values = &stack_pointer[-1]; top = &stack_pointer[-1 + oparg]; (void)top; for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); } - CHECK_STACK_BOUNDS(-1 + oparg); - stack_pointer += -1 + oparg; + s = seq; + CHECK_STACK_BOUNDS(oparg); + stack_pointer[-1 + oparg] = s; + stack_pointer += oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1126,13 +1131,16 @@ JitOptRef seq; JitOptRef val1; JitOptRef val0; + JitOptRef s; seq = stack_pointer[-1]; val0 = sym_tuple_getitem(ctx, seq, 0); val1 = sym_tuple_getitem(ctx, seq, 1); - CHECK_STACK_BOUNDS(1); + s = seq; + CHECK_STACK_BOUNDS(2); stack_pointer[-1] = val1; stack_pointer[0] = val0; - stack_pointer += 1; + stack_pointer[1] = s; + stack_pointer += 2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -1140,25 +1148,33 @@ case _UNPACK_SEQUENCE_TUPLE: { JitOptRef seq; JitOptRef *values; + JitOptRef s; seq = stack_pointer[-1]; values = &stack_pointer[-1]; for (int i = 0; i < oparg; i++) { values[i] = sym_tuple_getitem(ctx, seq, oparg - i - 1); } - CHECK_STACK_BOUNDS(-1 + oparg); - stack_pointer += -1 + oparg; + s = seq; + CHECK_STACK_BOUNDS(oparg); + stack_pointer[-1 + oparg] = s; + stack_pointer += oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } case _UNPACK_SEQUENCE_LIST: { + JitOptRef seq; JitOptRef *values; + JitOptRef s; + seq = stack_pointer[-1]; values = &stack_pointer[-1]; - for (int _i = oparg; --_i >= 0;) { - values[_i] = sym_new_not_null(ctx); + for (int i = 0; i < oparg; i++) { + values[i] = sym_new_not_null(ctx); } - CHECK_STACK_BOUNDS(-1 + oparg); - stack_pointer += -1 + oparg; + s = seq; + CHECK_STACK_BOUNDS(oparg); + stack_pointer[-1 + oparg] = s; + stack_pointer += oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; }