Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
21d9632
POC: automated instruction gen
ShaharNaveh Sep 23, 2025
f6ab8d2
Add generated file
ShaharNaveh Sep 23, 2025
b8ebe9b
Add note about pseudos opcode
ShaharNaveh Sep 23, 2025
8510815
Use `properties.oparg` instead
ShaharNaveh Sep 23, 2025
bcea0bf
Sort by id. impl TryFrom
ShaharNaveh Sep 25, 2025
c7ffa2a
Have `is_valid` as a seperate method
ShaharNaveh Sep 25, 2025
f1948c6
Include in tree
ShaharNaveh Sep 25, 2025
84c7f45
Impl `has_X` methods
ShaharNaveh Sep 25, 2025
9adf908
is_pseudo
ShaharNaveh Sep 25, 2025
99ed360
Set `Self::`
ShaharNaveh Sep 25, 2025
56c0dc8
refactor
ShaharNaveh Sep 26, 2025
3fdc479
impl num_{pushed,popped}
ShaharNaveh Sep 26, 2025
5cf1888
Resolve some errors
ShaharNaveh Sep 26, 2025
eaee21e
Sort like cpython does it
ShaharNaveh Sep 26, 2025
acd74c7
Make more things compile
ShaharNaveh Sep 26, 2025
f71ad1b
Don't use the new Instruction yet
ShaharNaveh Oct 5, 2025
b860f65
pivot to only generating opcodeid atm
ShaharNaveh Oct 5, 2025
ff4fb09
Remove `enum` related code
ShaharNaveh Oct 5, 2025
493da32
Use `OpcodeId` in `_opcode`
ShaharNaveh Oct 5, 2025
657660f
add auto generated file to .gitattributes
ShaharNaveh Oct 5, 2025
eacab03
clippy
ShaharNaveh Oct 5, 2025
7b36086
Apply coderabbit suggestion
ShaharNaveh Oct 5, 2025
dd761d0
Switch back to enum
ShaharNaveh Oct 5, 2025
aeedbdc
Re-add `num_{popped,pushed}`
ShaharNaveh Oct 5, 2025
33a90f3
Improve `_opcode.stack_effect`
ShaharNaveh Oct 5, 2025
4a11f38
Add missing dis attrs for tests
ShaharNaveh Oct 5, 2025
029e534
Unmark passing tests
ShaharNaveh Oct 5, 2025
11369f8
More changes to `dis.py` from 3.13.7
ShaharNaveh Oct 5, 2025
a5813ea
Add reason for failing tests
ShaharNaveh Oct 5, 2025
6e6accd
Base `Opcode` impl
ShaharNaveh Oct 6, 2025
f8a887a
clippy
ShaharNaveh Oct 6, 2025
a2014b5
Fix another test
ShaharNaveh Oct 6, 2025
6c48b49
clippy
ShaharNaveh Oct 6, 2025
46f3e29
clippy
ShaharNaveh Oct 6, 2025
742b709
cspell
ShaharNaveh Oct 6, 2025
2a8fb1e
Add `new_unchecked`
ShaharNaveh Oct 6, 2025
465528e
More docs
ShaharNaveh Oct 6, 2025
e437232
unused import
ShaharNaveh Oct 6, 2025
1ae0c7e
nits
ShaharNaveh Oct 6, 2025
28bab70
Trigger CI
ShaharNaveh Oct 6, 2025
fe3f94a
Merge remote-tracking branch 'upstream/main' into instruction-autogen
ShaharNaveh Oct 13, 2025
aca4508
Use `num_enum` for opcode enums
ShaharNaveh Oct 13, 2025
3daec5a
Remove unused code
ShaharNaveh Oct 13, 2025
9436354
typo
ShaharNaveh Oct 13, 2025
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
1 change: 1 addition & 0 deletions .cspell.dict/cpython.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ cellvar
cellvars
cmpop
denom
deopt
dictoffset
elts
excepthandler
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Lib/** linguist-vendored
Cargo.lock linguist-generated
*.snap linguist-generated -merge
vm/src/stdlib/ast/gen.rs linguist-generated -merge
compiler/core/src/opcodes.rs linguist-generated=true
Lib/*.py text working-tree-encoding=UTF-8 eol=LF
**/*.rs text working-tree-encoding=UTF-8 eol=LF
*.pck binary
2 changes: 2 additions & 0 deletions Cargo.lock

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

68 changes: 68 additions & 0 deletions Lib/dis.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,73 @@
import types # XXX: From CPython 3.13.7
from _dis import *

# XXX: From CPython 3.13.7
from opcode import *
# XXX: From CPython 3.13.7
from opcode import (
__all__ as _opcodes_all,
_cache_format,
_inline_cache_entries,
_nb_ops,
_intrinsic_1_descs,
_intrinsic_2_descs,
_specializations,
_specialized_opmap,
)

# XXX: From CPython 3.13.7
from _opcode import get_executor

# XXX: From CPython 3.13.7
__all__ = ["code_info", "dis", "disassemble", "distb", "disco",
"findlinestarts", "findlabels", "show_code",
"get_instructions", "Instruction", "Bytecode"] + _opcodes_all
del _opcodes_all

# XXX: From CPython 3.13.7
_have_code = (types.MethodType, types.FunctionType, types.CodeType,
classmethod, staticmethod, type)

# XXX: From CPython 3.13.7
CONVERT_VALUE = opmap['CONVERT_VALUE']

# XXX: From CPython 3.13.7
SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE']
FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')

# XXX: From CPython 3.13.7
ENTER_EXECUTOR = opmap['ENTER_EXECUTOR']
LOAD_CONST = opmap['LOAD_CONST']
RETURN_CONST = opmap['RETURN_CONST']
LOAD_GLOBAL = opmap['LOAD_GLOBAL']
BINARY_OP = opmap['BINARY_OP']
JUMP_BACKWARD = opmap['JUMP_BACKWARD']
FOR_ITER = opmap['FOR_ITER']
SEND = opmap['SEND']
LOAD_ATTR = opmap['LOAD_ATTR']
LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1']
CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2']
LOAD_FAST_LOAD_FAST = opmap['LOAD_FAST_LOAD_FAST']
STORE_FAST_LOAD_FAST = opmap['STORE_FAST_LOAD_FAST']
STORE_FAST_STORE_FAST = opmap['STORE_FAST_STORE_FAST']

# XXX: From CPython 3.13.7
CACHE = opmap["CACHE"]

# XXX: From CPython 3.13.7
_all_opname = list(opname)
_all_opmap = dict(opmap)
for name, op in _specialized_opmap.items():
# fill opname and opmap
assert op < len(_all_opname)
_all_opname[op] = name
_all_opmap[name] = op

# XXX: From CPython 3.13.7
deoptmap = {
specialized: base for base, family in _specializations.items() for specialized in family
}

# Disassembling a file by following cpython Lib/dis.py
def _test():
Expand Down
4 changes: 0 additions & 4 deletions Lib/test/test__opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def test_invalid_opcodes(self):
self.check_bool_function_result(_opcode.has_local, invalid, False)
self.check_bool_function_result(_opcode.has_exc, invalid, False)

@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'dis' has no attribute 'opmap'
def test_is_valid(self):
names = [
'CACHE',
Expand All @@ -39,7 +38,6 @@ def test_is_valid(self):
opcodes = [dis.opmap[opname] for opname in names]
self.check_bool_function_result(_opcode.is_valid, opcodes, True)

@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module 'dis' has no attribute 'hasarg'
def test_oplists(self):
def check_function(self, func, expected):
for op in [-10, 520]:
Expand All @@ -58,7 +56,6 @@ def check_function(self, func, expected):


class StackEffectTests(unittest.TestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_stack_effect(self):
self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
Expand All @@ -79,7 +76,6 @@ def test_stack_effect(self):
self.assertRaises(ValueError, stack_effect, code)
self.assertRaises(ValueError, stack_effect, code, 0)

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_stack_effect_jump(self):
FOR_ITER = dis.opmap['FOR_ITER']
self.assertEqual(stack_effect(FOR_ITER, 0), 1)
Expand Down
2 changes: 2 additions & 0 deletions compiler/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ bitflags = { workspace = true }
itertools = { workspace = true }
malachite-bigint = { workspace = true }
num-complex = { workspace = true }
num_enum = { workspace = true }
num-traits = { workspace = true }

lz4_flex = "0.11"

Expand Down
3 changes: 3 additions & 0 deletions compiler/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ pub mod bytecode;
pub mod frozen;
pub mod marshal;
mod mode;
pub mod opcode;
mod opcodes;

pub use mode::Mode;
pub use opcode::{Opcode, PseudoOpcode, RealOpcode};

pub use ruff_source_file::{LineIndex, OneIndexed, SourceFile, SourceFileBuilder, SourceLocation};
48 changes: 48 additions & 0 deletions compiler/core/src/opcode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::marshal::MarshalError;
pub use crate::opcodes::{PseudoOpcode, RealOpcode};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Opcode {
Real(RealOpcode),
Pseudo(PseudoOpcode),
}

impl TryFrom<u16> for Opcode {
type Error = MarshalError;

fn try_from(raw: u16) -> Result<Self, Self::Error> {
// Try first pseudo opcode. If not, fallback to real opcode.
PseudoOpcode::try_from(raw)
.map(Opcode::Pseudo)
.or_else(|_| {
Self::try_from(u8::try_from(raw).map_err(|_| Self::Error::InvalidBytecode)?)
})
}
}

impl TryFrom<u8> for Opcode {
type Error = MarshalError;

fn try_from(raw: u8) -> Result<Self, Self::Error> {
// u8 can never be a pseudo.
RealOpcode::try_from(raw).map(Opcode::Real)
}
}

macro_rules! impl_try_from {
($struct_name:ident, $($t:ty),+ $(,)?) => {
$(
impl TryFrom<$t> for $struct_name {
type Error = MarshalError;

fn try_from(raw: $t) -> Result<Self, Self::Error> {
Self::try_from(u16::try_from(raw).map_err(|_| Self::Error::InvalidBytecode)?)
}
}
)+
};
}

impl_try_from!(
Opcode, i8, i16, i32, i64, i128, isize, u32, u64, u128, usize
);
Loading
Loading