Skip to content

Commit 97f0a1f

Browse files
Fidget-Spinnerblurb-it[bot]savannahostrowski
authored
gh-142276: Watch attribute loads when promoting JIT constants (GH-142303)
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Savannah Ostrowski <savannah@python.org>
1 parent e0451ce commit 97f0a1f

File tree

5 files changed

+38
-13
lines changed

5 files changed

+38
-13
lines changed

Lib/test/test_capi/test_opt.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,28 @@ def recursive_wrapper_4569():
26952695
pass
26962696
"""))
26972697

2698+
def test_attribute_changes_are_watched(self):
2699+
# Just running to make sure it doesn't crash.
2700+
script_helper.assert_python_ok("-c", textwrap.dedent("""
2701+
from concurrent.futures import ThreadPoolExecutor
2702+
from unittest import TestCase
2703+
NTHREADS = 6
2704+
BOTTOM = 0
2705+
TOP = 1250000
2706+
class A:
2707+
attr = 10**1000
2708+
class TestType(TestCase):
2709+
def read(id0):
2710+
for _ in range(BOTTOM, TOP):
2711+
A.attr
2712+
def write(id0):
2713+
x = A.attr
2714+
x += 1
2715+
A.attr = x
2716+
with ThreadPoolExecutor(NTHREADS) as pool:
2717+
pool.submit(read, (1,))
2718+
pool.submit(write, (1,))
2719+
"""))
26982720

26992721
def global_identity(x):
27002722
return x
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix missing type watcher when promoting attribute loads to constants in the JIT. Patch by Ken Jin. Reproducer by Yuancheng Jiang.

Python/optimizer_analysis.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit)
242242
}
243243

244244
static JitOptRef
245-
lookup_attr(JitOptContext *ctx, _PyUOpInstruction *this_instr,
245+
lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction *this_instr,
246246
PyTypeObject *type, PyObject *name, uint16_t immortal,
247247
uint16_t mortal)
248248
{
@@ -252,6 +252,8 @@ lookup_attr(JitOptContext *ctx, _PyUOpInstruction *this_instr,
252252
if (lookup) {
253253
int opcode = _Py_IsImmortal(lookup) ? immortal : mortal;
254254
REPLACE_OP(this_instr, opcode, 0, (uintptr_t)lookup);
255+
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type);
256+
_Py_BloomFilter_Add(dependencies, type);
255257
return sym_new_const(ctx, lookup);
256258
}
257259
}

Python/optimizer_bytecodes.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ dummy_func(void) {
607607
(void)descr;
608608
PyTypeObject *type = (PyTypeObject *)sym_get_const(ctx, owner);
609609
PyObject *name = get_co_name(ctx, oparg >> 1);
610-
attr = lookup_attr(ctx, this_instr, type, name,
610+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
611611
_POP_TOP_LOAD_CONST_INLINE_BORROW,
612612
_POP_TOP_LOAD_CONST_INLINE);
613613
}
@@ -616,7 +616,7 @@ dummy_func(void) {
616616
(void)descr;
617617
PyTypeObject *type = sym_get_type(owner);
618618
PyObject *name = get_co_name(ctx, oparg >> 1);
619-
attr = lookup_attr(ctx, this_instr, type, name,
619+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
620620
_POP_TOP_LOAD_CONST_INLINE_BORROW,
621621
_POP_TOP_LOAD_CONST_INLINE);
622622
}
@@ -625,7 +625,7 @@ dummy_func(void) {
625625
(void)descr;
626626
PyTypeObject *type = sym_get_type(owner);
627627
PyObject *name = get_co_name(ctx, oparg >> 1);
628-
attr = lookup_attr(ctx, this_instr, type, name,
628+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
629629
_POP_TOP_LOAD_CONST_INLINE_BORROW,
630630
_POP_TOP_LOAD_CONST_INLINE);
631631
}
@@ -634,7 +634,7 @@ dummy_func(void) {
634634
(void)descr;
635635
PyTypeObject *type = sym_get_type(owner);
636636
PyObject *name = get_co_name(ctx, oparg >> 1);
637-
attr = lookup_attr(ctx, this_instr, type, name,
637+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
638638
_LOAD_CONST_UNDER_INLINE_BORROW,
639639
_LOAD_CONST_UNDER_INLINE);
640640
self = owner;
@@ -644,7 +644,7 @@ dummy_func(void) {
644644
(void)descr;
645645
PyTypeObject *type = sym_get_type(owner);
646646
PyObject *name = get_co_name(ctx, oparg >> 1);
647-
attr = lookup_attr(ctx, this_instr, type, name,
647+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
648648
_LOAD_CONST_UNDER_INLINE_BORROW,
649649
_LOAD_CONST_UNDER_INLINE);
650650
self = owner;
@@ -654,7 +654,7 @@ dummy_func(void) {
654654
(void)descr;
655655
PyTypeObject *type = sym_get_type(owner);
656656
PyObject *name = get_co_name(ctx, oparg >> 1);
657-
attr = lookup_attr(ctx, this_instr, type, name,
657+
attr = lookup_attr(ctx, dependencies, this_instr, type, name,
658658
_LOAD_CONST_UNDER_INLINE_BORROW,
659659
_LOAD_CONST_UNDER_INLINE);
660660
self = owner;

Python/optimizer_cases.c.h

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

0 commit comments

Comments
 (0)