mirror of
https://github.com/python/cpython.git
synced 2025-08-22 17:55:18 +00:00
gh-103865: add monitoring support to LOAD_SUPER_ATTR (#103866)
This commit is contained in:
parent
febcc6ccfb
commit
f40890b124
10 changed files with 535 additions and 236 deletions
4
Include/internal/pycore_opcode.h
generated
4
Include/internal/pycore_opcode.h
generated
|
@ -138,6 +138,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
|
||||||
[INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
|
[INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
|
||||||
[INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
|
[INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
|
||||||
[INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
|
[INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
|
||||||
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
|
||||||
[INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
|
[INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
|
||||||
[INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
|
[INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
|
||||||
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
||||||
|
@ -481,7 +482,7 @@ static const char *const _PyOpcode_OpName[267] = {
|
||||||
[234] = "<234>",
|
[234] = "<234>",
|
||||||
[235] = "<235>",
|
[235] = "<235>",
|
||||||
[236] = "<236>",
|
[236] = "<236>",
|
||||||
[237] = "<237>",
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR",
|
||||||
[INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE",
|
[INSTRUMENTED_POP_JUMP_IF_NONE] = "INSTRUMENTED_POP_JUMP_IF_NONE",
|
||||||
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE",
|
[INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = "INSTRUMENTED_POP_JUMP_IF_NOT_NONE",
|
||||||
[INSTRUMENTED_RESUME] = "INSTRUMENTED_RESUME",
|
[INSTRUMENTED_RESUME] = "INSTRUMENTED_RESUME",
|
||||||
|
@ -577,7 +578,6 @@ static const char *const _PyOpcode_OpName[267] = {
|
||||||
case 234: \
|
case 234: \
|
||||||
case 235: \
|
case 235: \
|
||||||
case 236: \
|
case 236: \
|
||||||
case 237: \
|
|
||||||
case 255: \
|
case 255: \
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
3
Include/opcode.h
generated
3
Include/opcode.h
generated
|
@ -120,7 +120,8 @@ extern "C" {
|
||||||
#define CALL_INTRINSIC_2 174
|
#define CALL_INTRINSIC_2 174
|
||||||
#define LOAD_FROM_DICT_OR_GLOBALS 175
|
#define LOAD_FROM_DICT_OR_GLOBALS 175
|
||||||
#define LOAD_FROM_DICT_OR_DEREF 176
|
#define LOAD_FROM_DICT_OR_DEREF 176
|
||||||
#define MIN_INSTRUMENTED_OPCODE 238
|
#define MIN_INSTRUMENTED_OPCODE 237
|
||||||
|
#define INSTRUMENTED_LOAD_SUPER_ATTR 237
|
||||||
#define INSTRUMENTED_POP_JUMP_IF_NONE 238
|
#define INSTRUMENTED_POP_JUMP_IF_NONE 238
|
||||||
#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239
|
#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239
|
||||||
#define INSTRUMENTED_RESUME 240
|
#define INSTRUMENTED_RESUME 240
|
||||||
|
|
|
@ -233,8 +233,9 @@ def_op('LOAD_FROM_DICT_OR_DEREF', 176)
|
||||||
hasfree.append(176)
|
hasfree.append(176)
|
||||||
|
|
||||||
# Instrumented instructions
|
# Instrumented instructions
|
||||||
MIN_INSTRUMENTED_OPCODE = 238
|
MIN_INSTRUMENTED_OPCODE = 237
|
||||||
|
|
||||||
|
def_op('INSTRUMENTED_LOAD_SUPER_ATTR', 237)
|
||||||
def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238)
|
def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238)
|
||||||
def_op('INSTRUMENTED_POP_JUMP_IF_NOT_NONE', 239)
|
def_op('INSTRUMENTED_POP_JUMP_IF_NOT_NONE', 239)
|
||||||
def_op('INSTRUMENTED_RESUME', 240)
|
def_op('INSTRUMENTED_RESUME', 240)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
"""Test suite for the sys.monitoring."""
|
"""Test suite for the sys.monitoring."""
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import dis
|
||||||
import functools
|
import functools
|
||||||
import operator
|
import operator
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -506,7 +508,7 @@ class LineMonitoringTest(MonitoringTestBase, unittest.TestCase):
|
||||||
sys.monitoring.set_events(TEST_TOOL, 0)
|
sys.monitoring.set_events(TEST_TOOL, 0)
|
||||||
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
||||||
start = LineMonitoringTest.test_lines_single.__code__.co_firstlineno
|
start = LineMonitoringTest.test_lines_single.__code__.co_firstlineno
|
||||||
self.assertEqual(events, [start+7, 14, start+8])
|
self.assertEqual(events, [start+7, 16, start+8])
|
||||||
finally:
|
finally:
|
||||||
sys.monitoring.set_events(TEST_TOOL, 0)
|
sys.monitoring.set_events(TEST_TOOL, 0)
|
||||||
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
||||||
|
@ -524,7 +526,7 @@ class LineMonitoringTest(MonitoringTestBase, unittest.TestCase):
|
||||||
sys.monitoring.set_events(TEST_TOOL, 0)
|
sys.monitoring.set_events(TEST_TOOL, 0)
|
||||||
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
||||||
start = LineMonitoringTest.test_lines_loop.__code__.co_firstlineno
|
start = LineMonitoringTest.test_lines_loop.__code__.co_firstlineno
|
||||||
self.assertEqual(events, [start+7, 21, 22, 21, 22, 21, start+8])
|
self.assertEqual(events, [start+7, 23, 24, 23, 24, 23, start+8])
|
||||||
finally:
|
finally:
|
||||||
sys.monitoring.set_events(TEST_TOOL, 0)
|
sys.monitoring.set_events(TEST_TOOL, 0)
|
||||||
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
||||||
|
@ -546,7 +548,7 @@ class LineMonitoringTest(MonitoringTestBase, unittest.TestCase):
|
||||||
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
|
||||||
sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None)
|
sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None)
|
||||||
start = LineMonitoringTest.test_lines_two.__code__.co_firstlineno
|
start = LineMonitoringTest.test_lines_two.__code__.co_firstlineno
|
||||||
expected = [start+10, 14, start+11]
|
expected = [start+10, 16, start+11]
|
||||||
self.assertEqual(events, expected)
|
self.assertEqual(events, expected)
|
||||||
self.assertEqual(events2, expected)
|
self.assertEqual(events2, expected)
|
||||||
finally:
|
finally:
|
||||||
|
@ -1177,6 +1179,221 @@ class TestBranchAndJumpEvents(CheckEvents):
|
||||||
('return', None),
|
('return', None),
|
||||||
('line', 'check_events', 11)])
|
('line', 'check_events', 11)])
|
||||||
|
|
||||||
|
class TestLoadSuperAttr(CheckEvents):
|
||||||
|
RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder
|
||||||
|
|
||||||
|
def _exec(self, co):
|
||||||
|
d = {}
|
||||||
|
exec(co, d, d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def _exec_super(self, codestr, optimized=False):
|
||||||
|
# The compiler checks for statically visible shadowing of the name
|
||||||
|
# `super`, and declines to emit `LOAD_SUPER_ATTR` if shadowing is found.
|
||||||
|
# So inserting `super = super` prevents the compiler from emitting
|
||||||
|
# `LOAD_SUPER_ATTR`, and allows us to test that monitoring events for
|
||||||
|
# `LOAD_SUPER_ATTR` are equivalent to those we'd get from the
|
||||||
|
# un-optimized `LOAD_GLOBAL super; CALL; LOAD_ATTR` form.
|
||||||
|
assignment = "x = 1" if optimized else "super = super"
|
||||||
|
codestr = f"{assignment}\n{textwrap.dedent(codestr)}"
|
||||||
|
co = compile(codestr, "<string>", "exec")
|
||||||
|
# validate that we really do have a LOAD_SUPER_ATTR, only when optimized
|
||||||
|
self.assertEqual(self._has_load_super_attr(co), optimized)
|
||||||
|
return self._exec(co)
|
||||||
|
|
||||||
|
def _has_load_super_attr(self, co):
|
||||||
|
has = any(instr.opname == "LOAD_SUPER_ATTR" for instr in dis.get_instructions(co))
|
||||||
|
if not has:
|
||||||
|
has = any(
|
||||||
|
isinstance(c, types.CodeType) and self._has_load_super_attr(c)
|
||||||
|
for c in co.co_consts
|
||||||
|
)
|
||||||
|
return has
|
||||||
|
|
||||||
|
def _super_method_call(self, optimized=False):
|
||||||
|
codestr = """
|
||||||
|
class A:
|
||||||
|
def method(self, x):
|
||||||
|
return x
|
||||||
|
|
||||||
|
class B(A):
|
||||||
|
def method(self, x):
|
||||||
|
return super(
|
||||||
|
).method(
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|
||||||
|
b = B()
|
||||||
|
def f():
|
||||||
|
return b.method(1)
|
||||||
|
"""
|
||||||
|
d = self._exec_super(codestr, optimized)
|
||||||
|
expected = [
|
||||||
|
('line', 'check_events', 10),
|
||||||
|
('call', 'f', sys.monitoring.MISSING),
|
||||||
|
('line', 'f', 1),
|
||||||
|
('call', 'method', d["b"]),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('call', 'super', sys.monitoring.MISSING),
|
||||||
|
('C return', 'super', sys.monitoring.MISSING),
|
||||||
|
('line', 'method', 2),
|
||||||
|
('line', 'method', 3),
|
||||||
|
('line', 'method', 2),
|
||||||
|
('call', 'method', 1),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('line', 'check_events', 11),
|
||||||
|
('call', 'set_events', 2),
|
||||||
|
]
|
||||||
|
return d["f"], expected
|
||||||
|
|
||||||
|
def test_method_call(self):
|
||||||
|
nonopt_func, nonopt_expected = self._super_method_call(optimized=False)
|
||||||
|
opt_func, opt_expected = self._super_method_call(optimized=True)
|
||||||
|
|
||||||
|
self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected)
|
||||||
|
self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected)
|
||||||
|
|
||||||
|
def _super_method_call_error(self, optimized=False):
|
||||||
|
codestr = """
|
||||||
|
class A:
|
||||||
|
def method(self, x):
|
||||||
|
return x
|
||||||
|
|
||||||
|
class B(A):
|
||||||
|
def method(self, x):
|
||||||
|
return super(
|
||||||
|
x,
|
||||||
|
self,
|
||||||
|
).method(
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|
||||||
|
b = B()
|
||||||
|
def f():
|
||||||
|
try:
|
||||||
|
return b.method(1)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
assert False, "should have raised TypeError"
|
||||||
|
"""
|
||||||
|
d = self._exec_super(codestr, optimized)
|
||||||
|
expected = [
|
||||||
|
('line', 'check_events', 10),
|
||||||
|
('call', 'f', sys.monitoring.MISSING),
|
||||||
|
('line', 'f', 1),
|
||||||
|
('line', 'f', 2),
|
||||||
|
('call', 'method', d["b"]),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('line', 'method', 2),
|
||||||
|
('line', 'method', 3),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('call', 'super', 1),
|
||||||
|
('C raise', 'super', 1),
|
||||||
|
('line', 'f', 3),
|
||||||
|
('line', 'f', 4),
|
||||||
|
('line', 'check_events', 11),
|
||||||
|
('call', 'set_events', 2),
|
||||||
|
]
|
||||||
|
return d["f"], expected
|
||||||
|
|
||||||
|
def test_method_call_error(self):
|
||||||
|
nonopt_func, nonopt_expected = self._super_method_call_error(optimized=False)
|
||||||
|
opt_func, opt_expected = self._super_method_call_error(optimized=True)
|
||||||
|
|
||||||
|
self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected)
|
||||||
|
self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected)
|
||||||
|
|
||||||
|
def _super_attr(self, optimized=False):
|
||||||
|
codestr = """
|
||||||
|
class A:
|
||||||
|
x = 1
|
||||||
|
|
||||||
|
class B(A):
|
||||||
|
def method(self):
|
||||||
|
return super(
|
||||||
|
).x
|
||||||
|
|
||||||
|
b = B()
|
||||||
|
def f():
|
||||||
|
return b.method()
|
||||||
|
"""
|
||||||
|
d = self._exec_super(codestr, optimized)
|
||||||
|
expected = [
|
||||||
|
('line', 'check_events', 10),
|
||||||
|
('call', 'f', sys.monitoring.MISSING),
|
||||||
|
('line', 'f', 1),
|
||||||
|
('call', 'method', d["b"]),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('call', 'super', sys.monitoring.MISSING),
|
||||||
|
('C return', 'super', sys.monitoring.MISSING),
|
||||||
|
('line', 'method', 2),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('line', 'check_events', 11),
|
||||||
|
('call', 'set_events', 2)
|
||||||
|
]
|
||||||
|
return d["f"], expected
|
||||||
|
|
||||||
|
def test_attr(self):
|
||||||
|
nonopt_func, nonopt_expected = self._super_attr(optimized=False)
|
||||||
|
opt_func, opt_expected = self._super_attr(optimized=True)
|
||||||
|
|
||||||
|
self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected)
|
||||||
|
self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected)
|
||||||
|
|
||||||
|
def test_vs_other_type_call(self):
|
||||||
|
code_template = textwrap.dedent("""
|
||||||
|
class C:
|
||||||
|
def method(self):
|
||||||
|
return {cls}().__repr__{call}
|
||||||
|
c = C()
|
||||||
|
def f():
|
||||||
|
return c.method()
|
||||||
|
""")
|
||||||
|
|
||||||
|
def get_expected(name, call_method, ns):
|
||||||
|
repr_arg = 0 if name == "int" else sys.monitoring.MISSING
|
||||||
|
return [
|
||||||
|
('line', 'check_events', 10),
|
||||||
|
('call', 'f', sys.monitoring.MISSING),
|
||||||
|
('line', 'f', 1),
|
||||||
|
('call', 'method', ns["c"]),
|
||||||
|
('line', 'method', 1),
|
||||||
|
('call', name, sys.monitoring.MISSING),
|
||||||
|
('C return', name, sys.monitoring.MISSING),
|
||||||
|
*(
|
||||||
|
[
|
||||||
|
('call', '__repr__', repr_arg),
|
||||||
|
('C return', '__repr__', repr_arg),
|
||||||
|
] if call_method else []
|
||||||
|
),
|
||||||
|
('line', 'check_events', 11),
|
||||||
|
('call', 'set_events', 2),
|
||||||
|
]
|
||||||
|
|
||||||
|
for call_method in [True, False]:
|
||||||
|
with self.subTest(call_method=call_method):
|
||||||
|
call_str = "()" if call_method else ""
|
||||||
|
code_super = code_template.format(cls="super", call=call_str)
|
||||||
|
code_int = code_template.format(cls="int", call=call_str)
|
||||||
|
co_super = compile(code_super, '<string>', 'exec')
|
||||||
|
self.assertTrue(self._has_load_super_attr(co_super))
|
||||||
|
ns_super = self._exec(co_super)
|
||||||
|
ns_int = self._exec(code_int)
|
||||||
|
|
||||||
|
self.check_events(
|
||||||
|
ns_super["f"],
|
||||||
|
recorders=self.RECORDERS,
|
||||||
|
expected=get_expected("super", call_method, ns_super)
|
||||||
|
)
|
||||||
|
self.check_events(
|
||||||
|
ns_int["f"],
|
||||||
|
recorders=self.RECORDERS,
|
||||||
|
expected=get_expected("int", call_method, ns_int)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestSetGetEvents(MonitoringTestBase, unittest.TestCase):
|
class TestSetGetEvents(MonitoringTestBase, unittest.TestCase):
|
||||||
|
|
||||||
def test_global(self):
|
def test_global(self):
|
||||||
|
|
|
@ -1582,6 +1582,14 @@ dummy_func(
|
||||||
PREDICT(JUMP_BACKWARD);
|
PREDICT(JUMP_BACKWARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused if (oparg & 1), unused)) {
|
||||||
|
_PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
|
||||||
|
// cancel out the decrement that will happen in LOAD_SUPER_ATTR; we
|
||||||
|
// don't want to specialize instrumented instructions
|
||||||
|
INCREMENT_ADAPTIVE_COUNTER(cache->counter);
|
||||||
|
GO_TO_INSTRUCTION(LOAD_SUPER_ATTR);
|
||||||
|
}
|
||||||
|
|
||||||
family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
|
family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
|
||||||
LOAD_SUPER_ATTR,
|
LOAD_SUPER_ATTR,
|
||||||
LOAD_SUPER_ATTR_ATTR,
|
LOAD_SUPER_ATTR_ATTR,
|
||||||
|
@ -1602,10 +1610,34 @@ dummy_func(
|
||||||
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
|
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
|
||||||
#endif /* ENABLE_SPECIALIZATION */
|
#endif /* ENABLE_SPECIALIZATION */
|
||||||
|
|
||||||
|
if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) {
|
||||||
|
PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING;
|
||||||
|
int err = _Py_call_instrumentation_2args(
|
||||||
|
tstate, PY_MONITORING_EVENT_CALL,
|
||||||
|
frame, next_instr-1, global_super, arg);
|
||||||
|
ERROR_IF(err, error);
|
||||||
|
}
|
||||||
|
|
||||||
// we make no attempt to optimize here; specializations should
|
// we make no attempt to optimize here; specializations should
|
||||||
// handle any case whose performance we care about
|
// handle any case whose performance we care about
|
||||||
PyObject *stack[] = {class, self};
|
PyObject *stack[] = {class, self};
|
||||||
PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
|
PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
|
||||||
|
if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) {
|
||||||
|
PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING;
|
||||||
|
if (super == NULL) {
|
||||||
|
_Py_call_instrumentation_exc2(
|
||||||
|
tstate, PY_MONITORING_EVENT_C_RAISE,
|
||||||
|
frame, next_instr-1, global_super, arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int err = _Py_call_instrumentation_2args(
|
||||||
|
tstate, PY_MONITORING_EVENT_C_RETURN,
|
||||||
|
frame, next_instr-1, global_super, arg);
|
||||||
|
if (err < 0) {
|
||||||
|
Py_CLEAR(super);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
DECREF_INPUTS();
|
DECREF_INPUTS();
|
||||||
ERROR_IF(super == NULL, error);
|
ERROR_IF(super == NULL, error);
|
||||||
res = PyObject_GetAttr(super, name);
|
res = PyObject_GetAttr(super, name);
|
||||||
|
|
|
@ -4846,6 +4846,8 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
|
||||||
int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ?
|
int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ?
|
||||||
LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD;
|
LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD;
|
||||||
ADDOP_NAME(c, loc, opcode, meth->v.Attribute.attr, names);
|
ADDOP_NAME(c, loc, opcode, meth->v.Attribute.attr, names);
|
||||||
|
loc = update_start_location_to_match_attr(c, loc, meth);
|
||||||
|
ADDOP(c, loc, NOP);
|
||||||
} else {
|
} else {
|
||||||
VISIT(c, expr, meth->v.Attribute.value);
|
VISIT(c, expr, meth->v.Attribute.value);
|
||||||
loc = update_start_location_to_match_attr(c, loc, meth);
|
loc = update_start_location_to_match_attr(c, loc, meth);
|
||||||
|
@ -6079,6 +6081,8 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
|
||||||
int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ?
|
int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ?
|
||||||
LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR;
|
LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR;
|
||||||
ADDOP_NAME(c, loc, opcode, e->v.Attribute.attr, names);
|
ADDOP_NAME(c, loc, opcode, e->v.Attribute.attr, names);
|
||||||
|
loc = update_start_location_to_match_attr(c, loc, e);
|
||||||
|
ADDOP(c, loc, NOP);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
VISIT(c, expr, e->v.Attribute.value);
|
VISIT(c, expr, e->v.Attribute.value);
|
||||||
|
|
490
Python/generated_cases.c.h
generated
490
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -35,6 +35,8 @@ static const int8_t EVENT_FOR_OPCODE[256] = {
|
||||||
[INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL,
|
[INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL,
|
||||||
[CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
|
[CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
|
||||||
[INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
|
[INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
|
||||||
|
[LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL,
|
||||||
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL,
|
||||||
[RESUME] = -1,
|
[RESUME] = -1,
|
||||||
[YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
|
[YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
|
||||||
[INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
|
[INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
|
||||||
|
@ -74,6 +76,7 @@ static const uint8_t DE_INSTRUMENT[256] = {
|
||||||
[INSTRUMENTED_FOR_ITER] = FOR_ITER,
|
[INSTRUMENTED_FOR_ITER] = FOR_ITER,
|
||||||
[INSTRUMENTED_END_FOR] = END_FOR,
|
[INSTRUMENTED_END_FOR] = END_FOR,
|
||||||
[INSTRUMENTED_END_SEND] = END_SEND,
|
[INSTRUMENTED_END_SEND] = END_SEND,
|
||||||
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t INSTRUMENTED_OPCODES[256] = {
|
static const uint8_t INSTRUMENTED_OPCODES[256] = {
|
||||||
|
@ -107,6 +110,8 @@ static const uint8_t INSTRUMENTED_OPCODES[256] = {
|
||||||
[INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
|
[INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
|
||||||
[FOR_ITER] = INSTRUMENTED_FOR_ITER,
|
[FOR_ITER] = INSTRUMENTED_FOR_ITER,
|
||||||
[INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
|
[INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
|
||||||
|
[LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
|
||||||
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
|
||||||
|
|
||||||
[INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
|
[INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
|
||||||
[INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
|
[INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
|
||||||
|
|
|
@ -211,6 +211,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
|
||||||
return 1;
|
return 1;
|
||||||
case MAP_ADD:
|
case MAP_ADD:
|
||||||
return 2;
|
return 2;
|
||||||
|
case INSTRUMENTED_LOAD_SUPER_ATTR:
|
||||||
|
return 3;
|
||||||
case LOAD_SUPER_ATTR:
|
case LOAD_SUPER_ATTR:
|
||||||
return 3;
|
return 3;
|
||||||
case LOAD_SUPER_ATTR_ATTR:
|
case LOAD_SUPER_ATTR_ATTR:
|
||||||
|
@ -605,6 +607,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
|
||||||
return 0;
|
return 0;
|
||||||
case MAP_ADD:
|
case MAP_ADD:
|
||||||
return 0;
|
return 0;
|
||||||
|
case INSTRUMENTED_LOAD_SUPER_ATTR:
|
||||||
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_SUPER_ATTR:
|
case LOAD_SUPER_ATTR:
|
||||||
return ((oparg & 1) ? 1 : 0) + 1;
|
return ((oparg & 1) ? 1 : 0) + 1;
|
||||||
case LOAD_SUPER_ATTR_ATTR:
|
case LOAD_SUPER_ATTR_ATTR:
|
||||||
|
@ -902,6 +906,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
|
||||||
[DICT_UPDATE] = { true, INSTR_FMT_IB },
|
[DICT_UPDATE] = { true, INSTR_FMT_IB },
|
||||||
[DICT_MERGE] = { true, INSTR_FMT_IB },
|
[DICT_MERGE] = { true, INSTR_FMT_IB },
|
||||||
[MAP_ADD] = { true, INSTR_FMT_IB },
|
[MAP_ADD] = { true, INSTR_FMT_IB },
|
||||||
|
[INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 },
|
||||||
[LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC },
|
||||||
[LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC },
|
||||||
[LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC },
|
[LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC },
|
||||||
|
|
2
Python/opcode_targets.h
generated
2
Python/opcode_targets.h
generated
|
@ -236,7 +236,7 @@ static void *opcode_targets[256] = {
|
||||||
&&_unknown_opcode,
|
&&_unknown_opcode,
|
||||||
&&_unknown_opcode,
|
&&_unknown_opcode,
|
||||||
&&_unknown_opcode,
|
&&_unknown_opcode,
|
||||||
&&_unknown_opcode,
|
&&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR,
|
||||||
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
|
||||||
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
&&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
|
||||||
&&TARGET_INSTRUMENTED_RESUME,
|
&&TARGET_INSTRUMENTED_RESUME,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue