Skip to content

Commit 9aae164

Browse files
authored
instruction CACHE (RustPython#7251)
* Emit CACHE code units in bytecode to match CPython 3.14 - Add cache_entries() method to Instruction enum - Emit CACHE code units after opcodes in finalize_code - Handle NO_LOCATION (line=-1) in linetable for CACHE entries - Account for CACHE entries in exception table generation - Skip CACHE entries in VM execution loop (with jump detection) - Handle CACHE in InstrumentedLine/InstrumentedInstruction/InstrumentedForIter/InstrumentedNotTaken - Skip CACHE in monitoring instrumentation phases - Update co_branches() for cache-adjusted offsets - Restore _cache_format in Lib/opcode.py - Remove expectedFailure from test_c_call, test_start_offset * Use relative jump offsets and fix bytecode layout - Convert jump arguments from absolute to relative offsets in frame.rs, monitoring.rs, and stack_analysis - Add jump_relative_forward/backward helpers to ExecutingFrame - Resolve pseudo jump instructions before offset fixpoint loop - Emit NOP for break, continue, pass to match line-tracing - Fix async for: emit EndAsyncFor with correct target, add NotTaken - Fix comprehension if-cleanup to use separate block - Fix super() source range for multi-line calls - Fix NOP removal to preserve line-marker NOPs - Fix InstrumentedLine cache skipping after re-dispatch - Match InstrumentedResume/YieldValue in yield_from_target - Remove CALL_FUNCTION_EX cache entry from opcode.py - Remove resolved expectedFailure markers * Align CPython 3.14 LOAD_GLOBAL null-bit and RERAISE semantics * Remove redundant CPython-referencing comments Clean up comments that unnecessarily mention CPython per project convention. Replace with concise descriptions of the behavior itself.
1 parent 38c18b8 commit 9aae164

19 files changed

Lines changed: 1185 additions & 469 deletions

Lib/opcode.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,75 @@
4646
hascompare = [opmap["COMPARE_OP"]]
4747

4848
_cache_format = {
49+
"LOAD_GLOBAL": {
50+
"counter": 1,
51+
"index": 1,
52+
"module_keys_version": 1,
53+
"builtin_keys_version": 1,
54+
},
55+
"BINARY_OP": {
56+
"counter": 1,
57+
"descr": 4,
58+
},
59+
"UNPACK_SEQUENCE": {
60+
"counter": 1,
61+
},
62+
"COMPARE_OP": {
63+
"counter": 1,
64+
},
65+
"CONTAINS_OP": {
66+
"counter": 1,
67+
},
68+
"FOR_ITER": {
69+
"counter": 1,
70+
},
71+
"LOAD_SUPER_ATTR": {
72+
"counter": 1,
73+
},
74+
"LOAD_ATTR": {
75+
"counter": 1,
76+
"version": 2,
77+
"keys_version": 2,
78+
"descr": 4,
79+
},
80+
"STORE_ATTR": {
81+
"counter": 1,
82+
"version": 2,
83+
"index": 1,
84+
},
85+
"CALL": {
86+
"counter": 1,
87+
"func_version": 2,
88+
},
89+
"CALL_KW": {
90+
"counter": 1,
91+
"func_version": 2,
92+
},
93+
"STORE_SUBSCR": {
94+
"counter": 1,
95+
},
96+
"SEND": {
97+
"counter": 1,
98+
},
99+
"JUMP_BACKWARD": {
100+
"counter": 1,
101+
},
102+
"TO_BOOL": {
103+
"counter": 1,
104+
"version": 2,
105+
},
106+
"POP_JUMP_IF_TRUE": {
107+
"counter": 1,
108+
},
109+
"POP_JUMP_IF_FALSE": {
110+
"counter": 1,
111+
},
112+
"POP_JUMP_IF_NONE": {
113+
"counter": 1,
114+
},
115+
"POP_JUMP_IF_NOT_NONE": {
116+
"counter": 1,
117+
},
49118
}
50119

51120
_inline_cache_entries = {

Lib/test/test_dis.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,7 +2236,6 @@ def f(opcode, oparg, offset, *init_args):
22362236
def get_instructions(self, code):
22372237
return dis._get_instructions_bytes(code)
22382238

2239-
@unittest.expectedFailure # TODO: RUSTPYTHON; no inline caches
22402239
def test_start_offset(self):
22412240
# When no extended args are present,
22422241
# start_offset should be equal to offset
@@ -2289,7 +2288,6 @@ def last_item(iterable):
22892288
self.assertEqual(14, instructions[6].offset)
22902289
self.assertEqual(8, instructions[6].start_offset)
22912290

2292-
@unittest.expectedFailure # TODO: RUSTPYTHON; no inline caches
22932291
def test_cache_offset_and_end_offset(self):
22942292
code = bytes([
22952293
opcode.opmap["LOAD_GLOBAL"], 0x01,
@@ -2588,7 +2586,6 @@ def f():
25882586
with contextlib.redirect_stderr(io.StringIO()):
25892587
_ = self.invoke_dis('--unknown')
25902588

2591-
@unittest.expectedFailure # TODO: RUSTPYTHON
25922589
def test_show_cache(self):
25932590
# test 'python -m dis -C/--show-caches'
25942591
source = 'print()'

Lib/test/test_inspect/test_inspect.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,7 +2020,6 @@ def function():
20202020
_global_ref = object()
20212021
class TestGetClosureVars(unittest.TestCase):
20222022

2023-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[132 chars]={'print': <built-in function print>}, unbound=set()) != Closu[132 chars]={'print': <built-in function print>}, unbound={'unbound_ref'})
20242023
def test_name_resolution(self):
20252024
# Basic test of the 4 different resolution mechanisms
20262025
def f(nonlocal_ref):
@@ -2036,7 +2035,6 @@ def g(local_ref):
20362035
builtin_vars, unbound_names)
20372036
self.assertEqual(inspect.getclosurevars(f(_arg)), expected)
20382037

2039-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[132 chars]={'print': <built-in function print>}, unbound=set()) != Closu[132 chars]={'print': <built-in function print>}, unbound={'unbound_ref'})
20402038
def test_generator_closure(self):
20412039
def f(nonlocal_ref):
20422040
def g(local_ref):
@@ -2052,7 +2050,6 @@ def g(local_ref):
20522050
builtin_vars, unbound_names)
20532051
self.assertEqual(inspect.getclosurevars(f(_arg)), expected)
20542052

2055-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[132 chars]={'print': <built-in function print>}, unbound=set()) != Closu[132 chars]={'print': <built-in function print>}, unbound={'unbound_ref'})
20562053
def test_method_closure(self):
20572054
class C:
20582055
def f(self, nonlocal_ref):
@@ -2068,7 +2065,6 @@ def g(local_ref):
20682065
builtin_vars, unbound_names)
20692066
self.assertEqual(inspect.getclosurevars(C().f(_arg)), expected)
20702067

2071-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[139 chars]als={}, builtins={'print': <built-in function [18 chars]et()) != Closu[139 chars]als={'_global_ref': <object object at 0xa4ffee[73 chars]ef'})
20722068
def test_attribute_same_name_as_global_var(self):
20732069
class C:
20742070
_global_ref = object()
@@ -2138,21 +2134,18 @@ def _private_globals(self):
21382134
exec(code, ns)
21392135
return ns["f"], ns
21402136

2141-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[34 chars]uiltins={'print': <built-in function print>}, unbound=set()) != Closu[34 chars]uiltins={'print': <built-in function print>}, unbound={'path'})
21422137
def test_builtins_fallback(self):
21432138
f, ns = self._private_globals()
21442139
ns.pop("__builtins__", None)
21452140
expected = inspect.ClosureVars({}, {}, {"print":print}, {"path"})
21462141
self.assertEqual(inspect.getclosurevars(f), expected)
21472142

2148-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: ClosureVars(nonlocals={}, globals={}, builtins={}, unbound={'print'}) != ClosureVars(nonlocals={}, globals={}, builtins={'path': 1}, unbound={'print'})
21492143
def test_builtins_as_dict(self):
21502144
f, ns = self._private_globals()
21512145
ns["__builtins__"] = {"path":1}
21522146
expected = inspect.ClosureVars({}, {}, {"path":1}, {"print"})
21532147
self.assertEqual(inspect.getclosurevars(f), expected)
21542148

2155-
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: Closu[38 chars]ins={}, unbound={'print'}) != Closu[38 chars]ins={'path': <module 'posixpath' from '/Users/[79 chars]nt'})
21562149
def test_builtins_as_module(self):
21572150
f, ns = self._private_globals()
21582151
ns["__builtins__"] = os

Lib/test/test_monitoring.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,6 @@ def func1():
12361236
('instruction', 'func1', 16),
12371237
('line', 'get_events', 11)])
12381238

1239-
@unittest.expectedFailure # TODO: RUSTPYTHON; - instruction offsets differ from CPython
12401239
def test_c_call(self):
12411240

12421241
def func2():
@@ -1672,7 +1671,6 @@ def func():
16721671
('return', 'func', None),
16731672
('line', 'get_events', 11)])
16741673

1675-
@unittest.expectedFailure # TODO: RUSTPYTHON; - bytecode layout differs from CPython
16761674
def test_while_offset_consistency(self):
16771675

16781676
def foo(n=0):
@@ -1690,7 +1688,6 @@ def foo(n=0):
16901688
in_loop,
16911689
exit_loop])
16921690

1693-
@unittest.expectedFailure # TODO: RUSTPYTHON; - bytecode layout differs from CPython
16941691
def test_async_for(self):
16951692

16961693
def func():
@@ -2126,7 +2123,6 @@ def test_get_local_events_uninitialized(self):
21262123

21272124
class TestRegressions(MonitoringTestBase, unittest.TestCase):
21282125

2129-
@unittest.expectedFailure # TODO: RUSTPYTHON; + inner
21302126
def test_105162(self):
21312127
caught = None
21322128

Lib/test/test_peepholer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,6 @@ def f():
571571
self.check_jump_targets(f)
572572
self.check_lnotab(f)
573573

574-
@unittest.expectedFailure # TODO: RUSTPYTHON; KeyError: 44
575574
def test_elim_jump_to_uncond_jump3(self):
576575
# Intentionally use two-line expressions to test issue37213.
577576
# POP_JUMP_IF_FALSE to POP_JUMP_IF_FALSE --> POP_JUMP_IF_FALSE to non-jump

0 commit comments

Comments
 (0)