Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cca43b7

Browse files
authored
bpo-47053: Reduce deoptimization in BINARY_OP_INPLACE_ADD_UNICODE (pythonGH-31318)
* Don't deopt if refcounts are too big * Detect more at specialization time
1 parent d7163bb commit cca43b7

4 files changed

Lines changed: 11 additions & 7 deletions

File tree

Include/internal/pycore_code.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ extern int _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr,
263263
extern int _Py_Specialize_Precall(PyObject *callable, _Py_CODEUNIT *instr,
264264
int nargs, PyObject *kwnames, int oparg);
265265
extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
266-
int oparg);
266+
int oparg, PyObject **locals);
267267
extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
268268
_Py_CODEUNIT *instr, int oparg);
269269
extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reduce de-optimization in the specialized ``BINARY_OP_INPLACE_ADD_UNICODE`` opcode.

Python/ceval.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,10 +2002,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
20022002
PyObject *right = TOP();
20032003
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
20042004
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
2005-
DEOPT_IF(Py_REFCNT(left) != 2, BINARY_OP);
20062005
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
20072006
int next_oparg = _Py_OPARG(true_next);
2008-
assert(_Py_OPCODE(true_next) == STORE_FAST);
2007+
assert(_Py_OPCODE(true_next) == STORE_FAST ||
2008+
_Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST);
20092009
/* In the common case, there are 2 references to the value
20102010
* stored in 'variable' when the v = v + ... is performed: one
20112011
* on the value stack (in 'v') and one still stored in the
@@ -2016,7 +2016,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
20162016
DEOPT_IF(var != left, BINARY_OP);
20172017
STAT_INC(BINARY_OP, hit);
20182018
GETLOCAL(next_oparg) = NULL;
2019-
Py_DECREF(left);
2019+
assert(Py_REFCNT(left) >= 2);
2020+
Py_DECREF(left); // XXX never need to dealloc
20202021
STACK_SHRINK(1);
20212022
PyUnicode_Append(&TOP(), right);
20222023
Py_DECREF(right);
@@ -5378,7 +5379,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
53785379
PyObject *lhs = SECOND();
53795380
PyObject *rhs = TOP();
53805381
next_instr--;
5381-
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg);
5382+
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0));
53825383
DISPATCH();
53835384
}
53845385
else {

Python/specialize.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,7 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
17421742

17431743
void
17441744
_Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
1745-
int oparg)
1745+
int oparg, PyObject **locals)
17461746
{
17471747
assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP);
17481748
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1);
@@ -1754,7 +1754,9 @@ _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
17541754
}
17551755
if (PyUnicode_CheckExact(lhs)) {
17561756
_Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
1757-
if (_Py_OPCODE(next) == STORE_FAST && Py_REFCNT(lhs) == 2) {
1757+
bool to_store = (_Py_OPCODE(next) == STORE_FAST ||
1758+
_Py_OPCODE(next) == STORE_FAST__LOAD_FAST);
1759+
if (to_store && locals[_Py_OPARG(next)] == lhs) {
17581760
_Py_SET_OPCODE(*instr, BINARY_OP_INPLACE_ADD_UNICODE);
17591761
goto success;
17601762
}

0 commit comments

Comments
 (0)