| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -51,6 +51,15 @@ typedef struct { | |||
| 51 | 51 | ||
| 52 | 52 | #define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache) | |
| 53 | 53 | ||
| 54 | + typedef struct { | ||
| 55 | + uint16_t counter; | ||
| 56 | + uint16_t class_version[2]; | ||
| 57 | + uint16_t self_type_version[2]; | ||
| 58 | + uint16_t method[4]; | ||
| 59 | + } _PySuperAttrCache; | ||
| 60 | + | ||
| 61 | + #define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache) | ||
| 62 | + | ||
| 54 | 63 | typedef struct { | |
| 55 | 64 | uint16_t counter; | |
| 56 | 65 | uint16_t version[2]; | |
@@ -217,6 +226,8 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); | |||
| 217 | 226 | ||
| 218 | 227 | /* Specialization functions */ | |
| 219 | 228 | ||
| 229 | + extern void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *class, PyObject *self, | ||
| 230 | + _Py_CODEUNIT *instr, PyObject *name, int load_method); | ||
| 220 | 231 | extern void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, | |
| 221 | 232 | PyObject *name); | |
| 222 | 233 | extern void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -119,6 +119,8 @@ PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); | |||
| 119 | 119 | ||
| 120 | 120 | PyObject * | |
| 121 | 121 | _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); | |
| 122 | + PyObject * | ||
| 123 | + _PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name); | ||
| 122 | 124 | ||
| 123 | 125 | #ifdef __cplusplus | |
| 124 | 126 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -440,7 +440,8 @@ def _write_atomic(path, data, mode=0o666): | |||
| 440 | 440 | # Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches) | |
| 441 | 441 | # Python 3.12b1 3525 (Shrink the CALL caches) | |
| 442 | 442 | # Python 3.12b1 3526 (Add instrumentation support) | |
| 443 | - # Python 3.12b1 3527 (Optimize super() calls) | ||
| 443 | + # Python 3.12b1 3527 (Add LOAD_SUPER_ATTR) | ||
| 444 | + # Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization) | ||
| 444 | 445 | ||
| 445 | 446 | # Python 3.13 will start with 3550 | |
| 446 | 447 | ||
@@ -457,7 +458,7 @@ def _write_atomic(path, data, mode=0o666): | |||
| 457 | 458 | # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array | |
| 458 | 459 | # in PC/launcher.c must also be updated. | |
| 459 | 460 | ||
| 460 | - MAGIC_NUMBER = (3527).to_bytes(2, 'little') + b'\r\n' | ||
| 461 | + MAGIC_NUMBER = (3528).to_bytes(2, 'little') + b'\r\n' | ||
| 461 | 462 | ||
| 462 | 463 | _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c | |
| 463 | 464 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -353,6 +353,9 @@ def pseudo_op(name, op, real_ops): | |||
| 353 | 353 | "FOR_ITER_RANGE", | |
| 354 | 354 | "FOR_ITER_GEN", | |
| 355 | 355 | ], | |
| 356 | + "LOAD_SUPER_ATTR": [ | ||
| 357 | + "LOAD_SUPER_ATTR_METHOD", | ||
| 358 | + ], | ||
| 356 | 359 | "LOAD_ATTR": [ | |
| 357 | 360 | # These potentially push [NULL, bound method] onto the stack. | |
| 358 | 361 | "LOAD_ATTR_CLASS", | |
@@ -426,6 +429,12 @@ def pseudo_op(name, op, real_ops): | |||
| 426 | 429 | "FOR_ITER": { | |
| 427 | 430 | "counter": 1, | |
| 428 | 431 | }, | |
| 432 | + "LOAD_SUPER_ATTR": { | ||
| 433 | + "counter": 1, | ||
| 434 | + "class_version": 2, | ||
| 435 | + "self_type_version": 2, | ||
| 436 | + "method": 4, | ||
| 437 | + }, | ||
| 429 | 438 | "LOAD_ATTR": { | |
| 430 | 439 | "counter": 1, | |
| 431 | 440 | "version": 2, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,29 @@ | |||
| 1 | 1 | import unittest | |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | + class TestLoadSuperAttrCache(unittest.TestCase): | ||
| 5 | + def test_descriptor_not_double_executed_on_spec_fail(self): | ||
| 6 | + calls = [] | ||
| 7 | + class Descriptor: | ||
| 8 | + def __get__(self, instance, owner): | ||
| 9 | + calls.append((instance, owner)) | ||
| 10 | + return lambda: 1 | ||
| 11 | + | ||
| 12 | + class C: | ||
| 13 | + d = Descriptor() | ||
| 14 | + | ||
| 15 | + class D(C): | ||
| 16 | + def f(self): | ||
| 17 | + return super().d() | ||
| 18 | + | ||
| 19 | + d = D() | ||
| 20 | + | ||
| 21 | + self.assertEqual(d.f(), 1) # warmup | ||
| 22 | + calls.clear() | ||
| 23 | + self.assertEqual(d.f(), 1) # try to specialize | ||
| 24 | + self.assertEqual(calls, [(d, D)]) | ||
| 25 | + | ||
| 26 | + | ||
| 4 | 27 | class TestLoadAttrCache(unittest.TestCase): | |
| 5 | 28 | def test_descriptor_added_after_optimization(self): | |
| 6 | 29 | class Descriptor: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1 +1,4 @@ | |||
| 1 | - Add :opcode:`LOAD_SUPER_ATTR` to speed up ``super().meth()`` and ``super().attr`` calls. | ||
| 1 | + Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for ``super().method()``) to | ||
| 2 | + speed up ``super().method()`` and ``super().attr``. This makes | ||
| 3 | + ``super().method()`` roughly 2.3x faster and brings it within 20% of the | ||
| 4 | + performance of a simple method call. Patch by Vladimir Matveev and Carl Meyer. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments