aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/executor_cases.c.h
diff options
context:
space:
mode:
authormpage <mpage@meta.com>2025-04-01 10:18:42 -0700
committerGitHub <noreply@github.com>2025-04-01 10:18:42 -0700
commit053c285f6b41f92fbdd1d4ff0c959cceefacd7cd (patch)
treec30af215989dca6fdd8f8ebb74396f29abdca308 /Python/executor_cases.c.h
parente9556e100452ed5a92fcf0e333ab75b0da29cf5b (diff)
downloadcpython-053c285f6b41f92fbdd1d4ff0c959cceefacd7cd.tar.gz
cpython-053c285f6b41f92fbdd1d4ff0c959cceefacd7cd.zip
gh-130704: Strength reduce `LOAD_FAST{_LOAD_FAST}` (#130708)
Optimize `LOAD_FAST` opcodes into faster versions that load borrowed references onto the operand stack when we can prove that the lifetime of the local outlives the lifetime of the temporary that is loaded onto the stack.
Diffstat (limited to 'Python/executor_cases.c.h')
-rw-r--r--Python/executor_cases.c.h120
1 files changed, 113 insertions, 7 deletions
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 29c3a270a27..260d52be02c 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -201,6 +201,113 @@
break;
}
+ case _LOAD_FAST_BORROW_0: {
+ _PyStackRef value;
+ oparg = 0;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_1: {
+ _PyStackRef value;
+ oparg = 1;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_2: {
+ _PyStackRef value;
+ oparg = 2;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_3: {
+ _PyStackRef value;
+ oparg = 3;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_4: {
+ _PyStackRef value;
+ oparg = 4;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_5: {
+ _PyStackRef value;
+ oparg = 5;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_6: {
+ _PyStackRef value;
+ oparg = 6;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW_7: {
+ _PyStackRef value;
+ oparg = 7;
+ assert(oparg == CURRENT_OPARG());
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
+ case _LOAD_FAST_BORROW: {
+ _PyStackRef value;
+ oparg = CURRENT_OPARG();
+ assert(!PyStackRef_IsNull(GETLOCAL(oparg)));
+ value = PyStackRef_Borrow(GETLOCAL(oparg));
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _LOAD_FAST_AND_CLEAR: {
_PyStackRef value;
oparg = CURRENT_OPARG();
@@ -1022,9 +1129,8 @@
right = stack_pointer[-1];
left = stack_pointer[-2];
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
- PyObject *right_o = PyStackRef_AsPyObjectSteal(right);
assert(PyUnicode_CheckExact(left_o));
- assert(PyUnicode_CheckExact(right_o));
+ assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(right)));
int next_oparg;
#if TIER_ONE
assert(next_instr->op.code == STORE_FAST);
@@ -1050,9 +1156,10 @@
* only the locals reference, so PyUnicode_Append knows
* that the string is safe to mutate.
*/
- assert(Py_REFCNT(left_o) >= 2);
+ assert(Py_REFCNT(left_o) >= 2 || !PyStackRef_IsHeapSafe(left));
PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc);
PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local);
+ PyObject *right_o = PyStackRef_AsPyObjectSteal(right);
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -1698,8 +1805,7 @@
_PyStackRef res;
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
- _PyStackRef temp = retval;
- assert(PyStackRef_IsHeapSafe(temp));
+ _PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -1833,7 +1939,7 @@
}
STAT_INC(SEND, hit);
gen_frame = &gen->gi_iframe;
- _PyFrame_StackPush(gen_frame, v);
+ _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v));
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
@@ -1880,7 +1986,7 @@
#endif
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
- value = temp;
+ value = PyStackRef_MakeHeapSafe(temp);
LLTRACE_RESUME_FRAME();
stack_pointer[0] = value;
stack_pointer += 1;