Skip to content

Commit e66d039

Browse files
authored
GH-114806. Don't specialize calls to classes with metaclasses. (GH-114870)
1 parent 97cc58f commit e66d039

File tree

3 files changed

+24
-0
lines changed

3 files changed

+24
-0
lines changed

Lib/test/test_class.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,22 @@ def add_one_level():
771771
with self.assertRaises(RecursionError):
772772
add_one_level()
773773

774+
def testMetaclassCallOptimization(self):
775+
calls = 0
776+
777+
class TypeMetaclass(type):
778+
def __call__(cls, *args, **kwargs):
779+
nonlocal calls
780+
calls += 1
781+
return type.__call__(cls, *args, **kwargs)
782+
783+
class Type(metaclass=TypeMetaclass):
784+
def __init__(self, obj):
785+
self._obj = obj
786+
787+
for i in range(100):
788+
Type(i)
789+
self.assertEqual(calls, 100)
774790

775791
if __name__ == '__main__':
776792
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
No longer specialize calls to classes, if those classes have metaclasses.
2+
Fixes bug where the ``__call__`` method of the metaclass was not being
3+
called.

Python/specialize.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ _PyCode_Quicken(PyCodeObject *code)
540540
#define SPEC_FAIL_CALL_METHOD_WRAPPER 28
541541
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29
542542
#define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30
543+
#define SPEC_FAIL_CALL_METACLASS 31
543544

544545
/* COMPARE_OP */
545546
#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
@@ -1757,6 +1758,10 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs)
17571758
SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL);
17581759
return -1;
17591760
}
1761+
if (Py_TYPE(tp) != &PyType_Type) {
1762+
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_METACLASS);
1763+
return -1;
1764+
}
17601765
if (tp->tp_new == PyBaseObject_Type.tp_new) {
17611766
PyFunctionObject *init = get_init_for_simple_managed_python_class(tp);
17621767
if (type_get_version(tp, CALL) == 0) {

0 commit comments

Comments
 (0)