]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-99298: Clean up attribute specializations (GH-99398)
authorBrandt Bucher <brandtbucher@microsoft.com>
Thu, 17 Nov 2022 23:09:18 +0000 (15:09 -0800)
committerGitHub <noreply@github.com>
Thu, 17 Nov 2022 23:09:18 +0000 (15:09 -0800)
Include/internal/pycore_code.h
Misc/NEWS.d/next/Core and Builtins/2022-11-10-16-53-40.gh-issue-99298.HqRJES.rst [new file with mode: 0644]
Python/bytecodes.c
Python/generated_cases.c.h
Python/specialize.c

index 0af240ca3621036ccc7e27760cf1c524e7511a6b..ba36ee38d2b0ba008ecde805435462d3e30261c2 100644 (file)
@@ -213,10 +213,10 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
 
 /* Specialization functions */
 
-extern int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
-                                   PyObject *name);
-extern int _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr,
+extern void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
                                     PyObject *name);
+extern void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr,
+                                     PyObject *name);
 extern void _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins,
                                       _Py_CODEUNIT *instr, PyObject *name);
 extern void _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container,
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-10-16-53-40.gh-issue-99298.HqRJES.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-10-16-53-40.gh-issue-99298.HqRJES.rst
new file mode 100644 (file)
index 0000000..79a5b3b
--- /dev/null
@@ -0,0 +1,3 @@
+Remove the remaining error paths for attribute specializations, and refuse
+to specialize attribute accesses on types that haven't had
+:c:func:`PyType_Ready` called on them yet.
index 27ef45fba066f05d7b6e6f129e76553bf0939384..a3e02674c2905c7df414309a3001cc2eabd1d62f 100644 (file)
@@ -1137,11 +1137,7 @@ dummy_func(
                 PyObject *owner = TOP();
                 PyObject *name = GETITEM(names, oparg);
                 next_instr--;
-                if (_Py_Specialize_StoreAttr(owner, next_instr, name)) {
-                    // "undo" the rewind so end up in the correct handler:
-                    next_instr++;
-                    goto error;
-                }
+                _Py_Specialize_StoreAttr(owner, next_instr, name);
                 DISPATCH_SAME_OPARG();
             }
             STAT_INC(STORE_ATTR, deferred);
@@ -1713,11 +1709,7 @@ dummy_func(
                 PyObject *owner = TOP();
                 PyObject *name = GETITEM(names, oparg>>1);
                 next_instr--;
-                if (_Py_Specialize_LoadAttr(owner, next_instr, name)) {
-                    // "undo" the rewind so end up in the correct handler:
-                    next_instr++;
-                    goto error;
-                }
+                _Py_Specialize_LoadAttr(owner, next_instr, name);
                 DISPATCH_SAME_OPARG();
             }
             STAT_INC(LOAD_ATTR, deferred);
index b60655884c1c897a2088e2e89b20bf73addb05b1..ba00203da301d34a622ccba0a7e4843cffd55b20 100644 (file)
                 PyObject *owner = TOP();
                 PyObject *name = GETITEM(names, oparg);
                 next_instr--;
-                if (_Py_Specialize_StoreAttr(owner, next_instr, name)) {
-                    // "undo" the rewind so end up in the correct handler:
-                    next_instr++;
-                    goto error;
-                }
+                _Py_Specialize_StoreAttr(owner, next_instr, name);
                 DISPATCH_SAME_OPARG();
             }
             STAT_INC(STORE_ATTR, deferred);
                 PyObject *owner = TOP();
                 PyObject *name = GETITEM(names, oparg>>1);
                 next_instr--;
-                if (_Py_Specialize_LoadAttr(owner, next_instr, name)) {
-                    // "undo" the rewind so end up in the correct handler:
-                    next_instr++;
-                    goto error;
-                }
+                _Py_Specialize_LoadAttr(owner, next_instr, name);
                 DISPATCH_SAME_OPARG();
             }
             STAT_INC(LOAD_ATTR, deferred);
index eea9d1c74884d26fa32ca6bff315a83a7881d4dc..cd09b188b7fa97e6ba445efbb1bcdf9908932f32 100644 (file)
@@ -663,32 +663,33 @@ static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyOb
     PyObject* descr, DescriptorClassification kind);
 static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
 
-int
+void
 _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
 {
     assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
     _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
+    PyTypeObject *type = Py_TYPE(owner);
+    if (!_PyType_IsReady(type)) {
+        // We *might* not really need this check, but we inherited it from
+        // PyObject_GenericGetAttr and friends... and this way we still do the
+        // right thing if someone forgets to call PyType_Ready(type):
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
+        goto fail;
+    }
     if (PyModule_CheckExact(owner)) {
-        int err = specialize_module_load_attr(owner, instr, name, LOAD_ATTR,
-                                              LOAD_ATTR_MODULE);
-        if (err) {
+        if (specialize_module_load_attr(owner, instr, name, LOAD_ATTR,
+                                        LOAD_ATTR_MODULE))
+        {
             goto fail;
         }
         goto success;
     }
     if (PyType_Check(owner)) {
-        int err = specialize_class_load_attr(owner, instr, name);
-        if (err) {
+        if (specialize_class_load_attr(owner, instr, name)) {
             goto fail;
         }
         goto success;
     }
-    PyTypeObject *type = Py_TYPE(owner);
-    if (type->tp_dict == NULL) {
-        if (PyType_Ready(type) < 0) {
-            return -1;
-        }
-    }
     PyObject *descr = NULL;
     DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
     assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
@@ -803,14 +804,9 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
         case ABSENT:
             break;
     }
-    int err = specialize_dict_access(
-        owner, instr, type, kind, name,
-        LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT
-    );
-    if (err < 0) {
-        return -1;
-    }
-    if (err) {
+    if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
+                               LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
+    {
         goto success;
     }
 fail:
@@ -818,20 +814,26 @@ fail:
     assert(!PyErr_Occurred());
     _Py_SET_OPCODE(*instr, LOAD_ATTR);
     cache->counter = adaptive_counter_backoff(cache->counter);
-    return 0;
+    return;
 success:
     STAT_INC(LOAD_ATTR, success);
     assert(!PyErr_Occurred());
     cache->counter = adaptive_counter_cooldown();
-    return 0;
 }
 
-int
+void
 _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
 {
     assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR);
     _PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
     PyTypeObject *type = Py_TYPE(owner);
+    if (!_PyType_IsReady(type)) {
+        // We *might* not really need this check, but we inherited it from
+        // PyObject_GenericSetAttr and friends... and this way we still do the
+        // right thing if someone forgets to call PyType_Ready(type):
+        SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
+        goto fail;
+    }
     if (PyModule_CheckExact(owner)) {
         SPECIALIZATION_FAIL(STORE_ATTR, SPEC_FAIL_OVERRIDDEN);
         goto fail;
@@ -890,15 +892,9 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
         case ABSENT:
             break;
     }
-
-    int err = specialize_dict_access(
-        owner, instr, type, kind, name,
-        STORE_ATTR, STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT
-    );
-    if (err < 0) {
-        return -1;
-    }
-    if (err) {
+    if (specialize_dict_access(owner, instr, type, kind, name, STORE_ATTR,
+                               STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_WITH_HINT))
+    {
         goto success;
     }
 fail:
@@ -906,12 +902,11 @@ fail:
     assert(!PyErr_Occurred());
     _Py_SET_OPCODE(*instr, STORE_ATTR);
     cache->counter = adaptive_counter_backoff(cache->counter);
-    return 0;
+    return;
 success:
     STAT_INC(STORE_ATTR, success);
     assert(!PyErr_Occurred());
     cache->counter = adaptive_counter_cooldown();
-    return 0;
 }