@@ -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