Skip to content

Commit 0481258

Browse files
committed
fix BINARY_OP_INPLACE_ADD_UNICODE check
1 parent fb8d8d9 commit 0481258

File tree

9 files changed

+91
-38
lines changed

9 files changed

+91
-38
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_capi/test_opt.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4407,6 +4407,67 @@ def g():
44074407
PYTHON_JIT="1", PYTHON_JIT_STRESS="1")
44084408
self.assertEqual(result[0].rc, 0, result)
44094409

4410+
def test_143820(self):
4411+
# https://github.com/python/cpython/issues/143358
4412+
4413+
result = script_helper.run_python_until_end('-c', textwrap.dedent(f"""
4414+
import sys
4415+
import random
4416+
4417+
int_v1 = 981679
4418+
int_v2 = -3791744241805517
4419+
any_v3 = 939.217
4420+
4421+
def f1(): int_v1 ^ int_v1
4422+
4423+
for i_f1 in range(300):
4424+
f1()
4425+
4426+
def f2():
4427+
class Int(int):
4428+
def __index__(self):...
4429+
4430+
inf = float('inf')
4431+
nzero = -0
4432+
zero = 0.0
4433+
dummy = 0
4434+
print('', file=sys.stderr)
4435+
4436+
def f_0_dc_6103(p): return p + 1
4437+
def f_1_dc_6103(p): return f_0_dc_6103(p) + 1
4438+
def f_2_dc_6103(p): return f_1_dc_6103(p) + 1
4439+
def f_3_dc_6103(p): return f_2_dc_6103(p) + 1
4440+
def f_4_dc_6103(p): return f_3_dc_6103(p) + 1
4441+
def f_5_dc_6103(p): return f_4_dc_6103(p) + 1
4442+
def f_6_dc_6103(p): return f_5_dc_6103(p) + 1
4443+
def f_7_dc_6103(p): return f_6_dc_6103(p) + 1
4444+
def f_8_dc_6103(p): return f_7_dc_6103(p) + 1
4445+
def f_9_dc_6103(p): return f_8_dc_6103(p) + 1
4446+
4447+
if inf == inf: dummy += 1
4448+
s = ''
4449+
try:
4450+
for _ in range(10):
4451+
s += ''
4452+
s += 'y'
4453+
except Exception: pass
4454+
int_v1 ^ int_v1
4455+
int_v1 ^ int_v1
4456+
int_v1 ^ int_v1
4457+
int_v2 - int_v1
4458+
int_v2 - int_v1
4459+
int_v2 - int_v1
4460+
int_v2 - int_v1
4461+
int_v2 - int_v1
4462+
not any_v3
4463+
not any_v3
4464+
not any_v3
4465+
4466+
for i_f2 in range(300):
4467+
f2()
4468+
"""), PYTHON_JIT="1", PYTHON_JIT_STRESS="1")
4469+
self.assertEqual(result[0].rc, 0, result)
4470+
44104471
def global_identity(x):
44114472
return x
44124473

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -794,18 +794,12 @@ dummy_func(
794794
// This is a subtle one. We write NULL to the local
795795
// of the following STORE_FAST and leave the result for STORE_FAST
796796
// later to store.
797-
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- res)) {
797+
op(_BINARY_OP_INPLACE_ADD_UNICODE, (next_oparg_idx/1, left, right -- res)) {
798798
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
799799
assert(PyUnicode_CheckExact(left_o));
800800
assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(right)));
801801

802-
int next_oparg;
803-
#if TIER_ONE
804-
assert(next_instr->op.code == STORE_FAST);
805-
next_oparg = next_instr->op.arg;
806-
#else
807-
next_oparg = (int)CURRENT_OPERAND0_16();
808-
#endif
802+
int next_oparg = (int)next_oparg_idx;
809803
_PyStackRef *target_local = &GETLOCAL(next_oparg);
810804
assert(PyUnicode_CheckExact(left_o));
811805
EXIT_IF(PyStackRef_AsPyObjectBorrow(*target_local) != left_o);
@@ -870,7 +864,7 @@ dummy_func(
870864
unused/1 + _GUARD_BINARY_OP_EXTEND + rewind/-4 + _BINARY_OP_EXTEND + POP_TOP + POP_TOP;
871865

872866
macro(BINARY_OP_INPLACE_ADD_UNICODE) =
873-
_GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_INPLACE_ADD_UNICODE;
867+
_GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/4 + _BINARY_OP_INPLACE_ADD_UNICODE;
874868

875869
specializing op(_SPECIALIZE_BINARY_SLICE, (container, start, stop -- container, start, stop)) {
876870
// Placeholder until we implement BINARY_SLICE specialization

Python/executor_cases.c.h

Lines changed: 2 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_bytecodes.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ dummy_func(void) {
355355
r = right;
356356
}
357357

358-
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- res)) {
358+
op(_BINARY_OP_INPLACE_ADD_UNICODE, (next_oparg_idx/1, left, right -- res)) {
359359
if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) {
360360
assert(PyUnicode_CheckExact(sym_get_const(ctx, left)));
361361
assert(PyUnicode_CheckExact(sym_get_const(ctx, right)));
@@ -369,7 +369,7 @@ dummy_func(void) {
369369
else {
370370
res = sym_new_type(ctx, &PyUnicode_Type);
371371
}
372-
GETLOCAL(this_instr->operand0) = sym_new_null(ctx);
372+
GETLOCAL(next_oparg_idx) = sym_new_null(ctx);
373373
}
374374

375375
op(_BINARY_OP_SUBSCR_CHECK_FUNC, (container, unused -- container, unused, getitem)) {

Python/optimizer_cases.c.h

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,10 +2251,22 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in
22512251
break;
22522252
}
22532253
if (PyUnicode_CheckExact(lhs)) {
2254-
_Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1];
2254+
int offset = INLINE_CACHE_ENTRIES_BINARY_OP + 1;
2255+
int locals_index = 0;
2256+
// Walk through EXTENDED_ARG instructions to compute full oparg
2257+
while (instr[offset].op.code == EXTENDED_ARG) {
2258+
locals_index = (locals_index | instr[offset].op.arg) << 8;
2259+
offset++;
2260+
}
2261+
_Py_CODEUNIT next = instr[offset];
22552262
bool to_store = (next.op.code == STORE_FAST);
2256-
if (to_store && PyStackRef_AsPyObjectBorrow(locals[next.op.arg]) == lhs) {
2263+
locals_index |= next.op.arg;
2264+
if (to_store && PyStackRef_AsPyObjectBorrow(locals[locals_index]) == lhs) {
22572265
specialize(instr, BINARY_OP_INPLACE_ADD_UNICODE);
2266+
// Store local index in the last cache slot
2267+
// so we don't need to peek at next_instr at runtime.
2268+
instr[INLINE_CACHE_ENTRIES_BINARY_OP].cache =
2269+
(uint16_t)locals_index;
22582270
return;
22592271
}
22602272
specialize(instr, BINARY_OP_ADD_UNICODE);

0 commit comments

Comments
 (0)