Skip to content

Commit 7881549

Browse files
authored
bpo-47053: Refactor BINARY_OP_INPLACE_ADD_UNICODE (GH-32122)
1 parent bad86a6 commit 7881549

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

Python/ceval.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,28 +2003,32 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
20032003
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
20042004
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
20052005
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
2006-
int next_oparg = _Py_OPARG(true_next);
20072006
assert(_Py_OPCODE(true_next) == STORE_FAST ||
20082007
_Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST);
2009-
/* In the common case, there are 2 references to the value
2010-
* stored in 'variable' when the v = v + ... is performed: one
2011-
* on the value stack (in 'v') and one still stored in the
2012-
* 'variable'. We try to delete the variable now to reduce
2013-
* the refcnt to 1.
2014-
*/
2015-
PyObject *var = GETLOCAL(next_oparg);
2016-
DEOPT_IF(var != left, BINARY_OP);
2008+
PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next));
2009+
DEOPT_IF(*target_local != left, BINARY_OP);
20172010
STAT_INC(BINARY_OP, hit);
2018-
GETLOCAL(next_oparg) = NULL;
2011+
/* Handle `left = left + right` or `left += right` for str.
2012+
*
2013+
* When possible, extend `left` in place rather than
2014+
* allocating a new PyUnicodeObject. This attempts to avoid
2015+
* quadratic behavior when one neglects to use str.join().
2016+
*
2017+
* If `left` has only two references remaining (one from
2018+
* the stack, one in the locals), DECREFing `left` leaves
2019+
* only the locals reference, so PyUnicode_Append knows
2020+
* that the string is safe to mutate.
2021+
*/
20192022
assert(Py_REFCNT(left) >= 2);
20202023
Py_DECREF(left); // XXX never need to dealloc
2021-
STACK_SHRINK(1);
2022-
PyUnicode_Append(&TOP(), right);
2024+
STACK_SHRINK(2);
2025+
PyUnicode_Append(target_local, right);
20232026
Py_DECREF(right);
2024-
if (TOP() == NULL) {
2027+
if (*target_local == NULL) {
20252028
goto error;
20262029
}
2027-
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
2030+
// The STORE_FAST is already done.
2031+
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
20282032
NOTRACE_DISPATCH();
20292033
}
20302034

0 commit comments

Comments
 (0)