https://github.com/python/cpython/commit/0cb52220790d8bc70ec325fd89d52b5f3b7ad29c
commit: 0cb52220790d8bc70ec325fd89d52b5f3b7ad29c
branch: main
author: Neil Schemenauer <nas-git...@arctrix.com>
committer: nascheme <nas-git...@arctrix.com>
date: 2024-12-03T09:32:26-08:00
summary:

gh-115999: Specialize `LOAD_SUPER_ATTR` in free-threaded builds (gh-127128)

Use existing helpers to atomically modify the bytecode.  Add unit tests
to ensure specializing is happening as expected.  Add test_specialize.py
that can be used with ThreadSanitizer to detect data races.  
Fix thread safety issue with cell_set_contents().

files:
M Lib/test/test_opcache.py
M Objects/cellobject.c
M Python/bytecodes.c
M Python/ceval.c
M Python/generated_cases.c.h
M Python/specialize.c

diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index b989b21cd9b3a9..527114445ac13b 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1249,6 +1249,45 @@ def binary_op_add_unicode():
         self.assert_specialized(binary_op_add_unicode, "BINARY_OP_ADD_UNICODE")
         self.assert_no_opcode(binary_op_add_unicode, "BINARY_OP")
 
+    @cpython_only
+    @requires_specialization_ft
+    def test_load_super_attr(self):
+        """Ensure that LOAD_SUPER_ATTR is specialized as expected."""
+
+        class A:
+            def __init__(self):
+                meth = super().__init__
+                super().__init__()
+
+        for _ in range(100):
+            A()
+
+        self.assert_specialized(A.__init__, "LOAD_SUPER_ATTR_ATTR")
+        self.assert_specialized(A.__init__, "LOAD_SUPER_ATTR_METHOD")
+        self.assert_no_opcode(A.__init__, "LOAD_SUPER_ATTR")
+
+        # Temporarily replace super() with something else.
+        real_super = super
+
+        def fake_super():
+            def init(self):
+                pass
+
+            return init
+
+        # Force unspecialize
+        globals()['super'] = fake_super
+        try:
+            # Should be unspecialized after enough calls.
+            for _ in range(100):
+                A()
+        finally:
+            globals()['super'] = real_super
+
+        # Ensure the specialized instructions are not present
+        self.assert_no_opcode(A.__init__, "LOAD_SUPER_ATTR_ATTR")
+        self.assert_no_opcode(A.__init__, "LOAD_SUPER_ATTR_METHOD")
+
     @cpython_only
     @requires_specialization_ft
     def test_contain_op(self):
diff --git a/Objects/cellobject.c b/Objects/cellobject.c
index 590c8a80857699..4ab9083af5e300 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -145,8 +145,9 @@ cell_get_contents(PyObject *self, void *closure)
 static int
 cell_set_contents(PyObject *self, PyObject *obj, void *Py_UNUSED(ignored))
 {
-    PyCellObject *op = _PyCell_CAST(self);
-    Py_XSETREF(op->ob_ref, Py_XNewRef(obj));
+    PyCellObject *cell = _PyCell_CAST(self);
+    Py_XINCREF(obj);
+    PyCell_SetTakeRef((PyCellObject *)cell, obj);
     return 0;
 }
 
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index e96674c3502ef1..dd28aae6a3cb61 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1946,7 +1946,7 @@ dummy_func(
         };
 
         specializing op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, 
global_super_st, class_st, unused -- global_super_st, class_st, unused)) {
-            #if ENABLE_SPECIALIZATION
+            #if ENABLE_SPECIALIZATION_FT
             int load_method = oparg & 1;
             if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
                 next_instr = this_instr;
@@ -1955,7 +1955,7 @@ dummy_func(
             }
             OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR);
             ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
-            #endif  /* ENABLE_SPECIALIZATION */
+            #endif  /* ENABLE_SPECIALIZATION_FT */
         }
 
         tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- 
attr, null if (oparg & 1))) {
diff --git a/Python/ceval.c b/Python/ceval.c
index f9514a6bf25c1b..6795a160506231 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -28,7 +28,6 @@
 #include "pycore_setobject.h"     // _PySet_Update()
 #include "pycore_sliceobject.h"   // _PyBuildSlice_ConsumeRefs
 #include "pycore_tuple.h"         // _PyTuple_ITEMS()
-#include "pycore_typeobject.h"    // _PySuper_Lookup()
 #include "pycore_uop_ids.h"       // Uops
 #include "pycore_pyerrors.h"
 
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index e1f951558de7da..c31601f6d82b77 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -6330,7 +6330,7 @@
                 global_super_st = stack_pointer[-3];
                 uint16_t counter = read_u16(&this_instr[1].cache);
                 (void)counter;
-                #if ENABLE_SPECIALIZATION
+                #if ENABLE_SPECIALIZATION_FT
                 int load_method = oparg & 1;
                 if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
                     next_instr = this_instr;
@@ -6341,7 +6341,7 @@
                 }
                 OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR);
                 ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
-                #endif  /* ENABLE_SPECIALIZATION */
+                #endif  /* ENABLE_SPECIALIZATION_FT */
             }
             // _LOAD_SUPER_ATTR
             {
diff --git a/Python/specialize.c b/Python/specialize.c
index ba13b02a29b133..0fe4e7904de9f8 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -794,9 +794,8 @@ _Py_Specialize_LoadSuperAttr(_PyStackRef global_super_st, 
_PyStackRef cls_st, _P
     PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st);
     PyObject *cls = PyStackRef_AsPyObjectBorrow(cls_st);
 
-    assert(ENABLE_SPECIALIZATION);
+    assert(ENABLE_SPECIALIZATION_FT);
     assert(_PyOpcode_Caches[LOAD_SUPER_ATTR] == 
INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR);
-    _PySuperAttrCache *cache = (_PySuperAttrCache *)(instr + 1);
     if (global_super != (PyObject *)&PySuper_Type) {
         SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_SHADOWED);
         goto fail;
@@ -805,19 +804,11 @@ _Py_Specialize_LoadSuperAttr(_PyStackRef global_super_st, 
_PyStackRef cls_st, _P
         SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_BAD_CLASS);
         goto fail;
     }
-    instr->op.code = load_method ? LOAD_SUPER_ATTR_METHOD : 
LOAD_SUPER_ATTR_ATTR;
-    goto success;
-
-fail:
-    STAT_INC(LOAD_SUPER_ATTR, failure);
-    assert(!PyErr_Occurred());
-    instr->op.code = LOAD_SUPER_ATTR;
-    cache->counter = adaptive_counter_backoff(cache->counter);
+    uint8_t load_code = load_method ? LOAD_SUPER_ATTR_METHOD : 
LOAD_SUPER_ATTR_ATTR;
+    specialize(instr, load_code);
     return;
-success:
-    STAT_INC(LOAD_SUPER_ATTR, success);
-    assert(!PyErr_Occurred());
-    cache->counter = adaptive_counter_cooldown();
+fail:
+    unspecialize(instr);
 }
 
 typedef enum {

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to