Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-87729: add LOAD_SUPER_ATTR instruction for faster super()#103497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
carljm merged 23 commits intopython:mainfromcarljm:superopt
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
23 commits
Select commitHold shift + click to select a range
0a0ebe2
gh-87729: add instruction for faster zero-arg super()
carljmApr 10, 2023
f14a3bf
add news entry
carljmApr 13, 2023
5625e73
document LOAD_ZERO_SUPER_ATTR
carljmApr 13, 2023
0775efe
fix gdb test_wrapper_call
carljmApr 13, 2023
f229b5b
optimize 2-arg super also
carljmApr 13, 2023
626999d
fix incompatible assignment
carljmApr 13, 2023
9384106
Merge branch 'main' into superopt
carljmApr 13, 2023
92c943b
fix bad first arg
carljmApr 13, 2023
775ed0f
Apply suggestions from code review
carljmApr 14, 2023
2077f1a
don't unnecessarily re-find args in error case
carljmApr 14, 2023
64da49f
Merge branch 'main' into superopt
carljmApr 14, 2023
4759ad9
update generated cases
carljmApr 14, 2023
94399c2
fix incompatible types
carljmApr 14, 2023
5136459
Merge branch 'main' into superopt
carljmApr 17, 2023
82945b2
review comments
carljmApr 17, 2023
3a3cb74
update generated cases with new comment
carljmApr 17, 2023
e4466a7
simplify oparg & 2 handling
carljmApr 19, 2023
5c0a21c
Merge branch 'main' into superopt
carljmApr 19, 2023
f161268
cleanup and clarification
carljmApr 20, 2023
df442c0
move __class__ special case out of the fast path
carljmApr 20, 2023
19b8025
Merge branch 'main' into superopt
carljmApr 24, 2023
0de5bc6
Merge branch 'main' into superopt
carljmApr 24, 2023
dbe1665
Merge branch 'main' into superopt
carljmApr 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletionsDoc/library/dis.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1036,6 +1036,24 @@ iterations of the loop.
pushed to the stack before the attribute or unbound method respectively.


.. opcode:: LOAD_SUPER_ATTR (namei)

This opcode implements :func:`super` (e.g. ``super().method()`` and
``super().attr``). It works the same as :opcode:`LOAD_ATTR`, except that
``namei`` is shifted left by 2 bits instead of 1, and instead of expecting a
single receiver on the stack, it expects three objects (from top of stack
down): ``self`` (the first argument to the current method), ``cls`` (the
class within which the current method was defined), and the global ``super``.

The low bit of ``namei`` signals to attempt a method load, as with
:opcode:`LOAD_ATTR`.

The second-low bit of ``namei``, if set, means that this was a two-argument
call to :func:`super` (unset means zero-argument).

.. versionadded:: 3.12


.. opcode:: COMPARE_OP (opname)

Performs a Boolean operation. The operation name can be found in
Expand Down
15 changes: 9 additions & 6 deletionsInclude/internal/pycore_opcode.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 3 additions & 0 deletionsInclude/internal/pycore_typeobject.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -98,6 +98,9 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name);
PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name);
PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name);

PyObject *
_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found);

#ifdef __cplusplus
}
#endif
Expand Down
23 changes: 15 additions & 8 deletionsInclude/opcode.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

5 changes: 5 additions & 0 deletionsLib/dis.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -41,6 +41,7 @@
FOR_ITER = opmap['FOR_ITER']
SEND = opmap['SEND']
LOAD_ATTR = opmap['LOAD_ATTR']
LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']

CACHE = opmap["CACHE"]

Expand DownExpand Up@@ -475,6 +476,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
elif deop == LOAD_SUPER_ATTR:
argval, argrepr = _get_name_info(arg//4, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:
Expand Down
5 changes: 3 additions & 2 deletionsLib/importlib/_bootstrap_external.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -439,7 +439,8 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP)
# Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches)
# Python 3.12b1 3525 (Shrink the CALL caches)
# Python 3.12a7 3526 (Add instrumentation support)
# Python 3.12b1 3526 (Add instrumentation support)
# Python 3.12b1 3527 (Optimize super() calls)

# Python 3.13 will start with 3550

Expand All@@ -456,7 +457,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.

MAGIC_NUMBER = (3526).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3527).to_bytes(2, 'little') + b'\r\n'

_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

Expand Down
5 changes: 4 additions & 1 deletionLib/opcode.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -196,7 +196,7 @@ def pseudo_op(name, op, real_ops):
def_op('DELETE_DEREF', 139)
hasfree.append(139)
jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)

name_op('LOAD_SUPER_ATTR', 141)
def_op('CALL_FUNCTION_EX', 142) # Flags

def_op('EXTENDED_ARG', 144)
Expand DownExpand Up@@ -264,6 +264,9 @@ def pseudo_op(name, op, real_ops):
pseudo_op('JUMP_NO_INTERRUPT', 261, ['JUMP_FORWARD', 'JUMP_BACKWARD_NO_INTERRUPT'])

pseudo_op('LOAD_METHOD', 262, ['LOAD_ATTR'])
pseudo_op('LOAD_SUPER_METHOD', 263, ['LOAD_SUPER_ATTR'])
pseudo_op('LOAD_ZERO_SUPER_METHOD', 264, ['LOAD_SUPER_ATTR'])
pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR'])

MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1

Expand Down
7 changes: 7 additions & 0 deletionsLib/test/shadowed_super.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
class super:
msg = "truly super"


class C:
def method(self):
return super().msg
2 changes: 1 addition & 1 deletionLib/test/test_gdb.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -962,7 +962,7 @@ def test_wrapper_call(self):
cmd = textwrap.dedent('''
class MyList(list):
def __init__(self):
super().__init__() # wrapper_call()
super(*[]).__init__() # wrapper_call()

id("first break point")
l = MyList()
Expand Down
91 changes: 88 additions & 3 deletionsLib/test/test_super.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
"""Unit tests for zero-argument super() & related machinery."""

import unittest
from unittest.mock import patch
from test import shadowed_super


class A:
Expand DownExpand Up@@ -283,17 +285,28 @@ def f(self):
def test_obscure_super_errors(self):
def f():
super()
self.assertRaises(RuntimeError, f)
with self.assertRaisesRegex(RuntimeError, r"no arguments"):
f()

class C:
def f():
super()
with self.assertRaisesRegex(RuntimeError, r"no arguments"):
C.f()

def f(x):
del x
super()
self.assertRaises(RuntimeError, f, None)
with self.assertRaisesRegex(RuntimeError, r"arg\[0\] deleted"):
f(None)

class X:
def f(x):
nonlocal __class__
del __class__
super()
self.assertRaises(RuntimeError, X().f)
with self.assertRaisesRegex(RuntimeError, r"empty __class__ cell"):
X().f()

def test_cell_as_self(self):
class X:
Expand DownExpand Up@@ -325,6 +338,78 @@ def test_super_argtype(self):
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
super(1, int)

def test_shadowed_global(self):
self.assertEqual(shadowed_super.C().method(), "truly super")

def test_shadowed_local(self):
class super:
msg = "quite super"

class C:
def method(self):
return super().msg

self.assertEqual(C().method(), "quite super")

def test_shadowed_dynamic(self):
class MySuper:
msg = "super super"

class C:
def method(self):
return super().msg

with patch("test.test_super.super", MySuper) as m:
self.assertEqual(C().method(), "super super")

def test_shadowed_dynamic_two_arg(self):
call_args = []
class MySuper:
def __init__(self, *args):
call_args.append(args)
msg = "super super"

class C:
def method(self):
return super(1, 2).msg

with patch("test.test_super.super", MySuper) as m:
self.assertEqual(C().method(), "super super")
self.assertEqual(call_args, [(1, 2)])

def test_attribute_error(self):
class C:
def method(self):
return super().msg

with self.assertRaisesRegex(AttributeError, "'super' object has no attribute 'msg'"):
C().method()

def test_bad_first_arg(self):
class C:
def method(self):
return super(1, self).method()

with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
C().method()

def test_super___class__(self):
class C:
def method(self):
return super().__class__

self.assertEqual(C().method(), super)

def test_super_subclass___class__(self):
class mysuper(super):
pass

class C:
def method(self):
return mysuper(C, self).__class__

self.assertEqual(C().method(), mysuper)


if __name__ == "__main__":
unittest.main()
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Add :opcode:`LOAD_SUPER_ATTR` to speed up ``super().meth()`` and ``super().attr`` calls.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp