]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-114806. Don't specialize calls to classes with metaclasses. (GH-114870)
authorMark Shannon <mark@hotpy.org>
Thu, 1 Feb 2024 19:39:32 +0000 (19:39 +0000)
committerGitHub <noreply@github.com>
Thu, 1 Feb 2024 19:39:32 +0000 (19:39 +0000)
Lib/test/test_class.py
Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst [new file with mode: 0644]
Python/specialize.c

index 1531aad4f1f779d24d63bafb0c66fa8919749355..d59271435e9eb05ba3439be1d6e0cd7524123ddf 100644 (file)
@@ -771,6 +771,22 @@ class ClassTests(unittest.TestCase):
         with self.assertRaises(RecursionError):
             add_one_level()
 
+    def testMetaclassCallOptimization(self):
+        calls = 0
+
+        class TypeMetaclass(type):
+            def __call__(cls, *args, **kwargs):
+                nonlocal calls
+                calls += 1
+                return type.__call__(cls, *args, **kwargs)
+
+        class Type(metaclass=TypeMetaclass):
+            def __init__(self, obj):
+                self._obj = obj
+
+        for i in range(100):
+            Type(i)
+        self.assertEqual(calls, 100)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst b/Misc/NEWS.d/next/Core and Builtins/2024-02-01-18-16-52.gh-issue-114806.wrH2J6.rst
new file mode 100644 (file)
index 0000000..795f252
--- /dev/null
@@ -0,0 +1,3 @@
+No longer specialize calls to classes, if those classes have metaclasses.
+Fixes bug where the ``__call__`` method of the metaclass was not being
+called.
index a9efbe0453b94e20920b12212b7b18aa5f48aec4..e38e3556a6d6425bcb12cb959cb8666b3c8e52ae 100644 (file)
@@ -540,6 +540,7 @@ _PyCode_Quicken(PyCodeObject *code)
 #define SPEC_FAIL_CALL_METHOD_WRAPPER 28
 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
 #define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30
+#define SPEC_FAIL_CALL_METACLASS 31
 
 /* COMPARE_OP */
 #define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
@@ -1757,6 +1758,10 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs)
             SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
         return -1;
     }
+    if (Py_TYPE(tp) != &PyType_Type) {
+        SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_METACLASS);
+        return -1;
+    }
     if (tp->tp_new == PyBaseObject_Type.tp_new) {
         PyFunctionObject *init = get_init_for_simple_managed_python_class(tp);
         if (type_get_version(tp, CALL) == 0) {