From fef345f7721c4d1e7b75f1ddbfcea289f4fe6479 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 13:50:56 +0300 Subject: [PATCH 01/35] Base conf --- crates/compiler-core/opcode.toml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 crates/compiler-core/opcode.toml diff --git a/crates/compiler-core/opcode.toml b/crates/compiler-core/opcode.toml new file mode 100644 index 00000000000..db3e1b4f6bf --- /dev/null +++ b/crates/compiler-core/opcode.toml @@ -0,0 +1,14 @@ +[Opcodes.real] +opcode_enum_name = "Opcode" +instruction_enum_name = "Instruction" +numeric_repr = "u8" +range = { min = 0, max = 255 } + +[Opcodes.pseudo] +opcode_enum_name = "PseudoOpcode" +instruction_enum_name = "PseudoInstruction" +numeric_repr = "u16" +range = { min = 256, max = 65535 } + +[Instructions.real.ContainsOp] +oparg = { name = "invert", type = "oparg::Invert" } From 09eb0b085e4c7a5d59e731ad8a20019ca3634fc6 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 14:22:08 +0300 Subject: [PATCH 02/35] Basic layout --- crates/compiler-core/generate.py | 68 +++++++++++++++++++ .../src/bytecode/instructions.rs | 4 ++ 2 files changed, 72 insertions(+) create mode 100644 crates/compiler-core/generate.py create mode 100644 crates/compiler-core/src/bytecode/instructions.rs diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py new file mode 100644 index 00000000000..126f727354f --- /dev/null +++ b/crates/compiler-core/generate.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +import io +import os +import pathlib +import subprocess +import sys + +import tomllib + +CRATE_ROOT = pathlib.Path(__file__).parent +CONF_FILE = CRATE_ROOT / "opcode.toml" +OUT_FILE = CRATE_ROOT / "src" / "bytecode" / "instructions.rs" + +ROOT = CRATE_ROOT.parents[1] + +try: + CPYTHON_ROOT = pathlib.Path(os.environ["CPYTHON_ROOT"]).expanduser().resolve() +except KeyError: + raise ValueError("Missing environment variable 'CPYTHON_ROOT'") + +CPYTHON_TOOLS_LIB = CPYTHON_ROOT / "Tools" / "cases_generator" + +sys.path.append(CPYTHON_TOOLS_LIB.as_posix()) + +import analyzer +from generators_common import DEFAULT_INPUT + + +def get_analysis() -> analyzer.Analysis: + analysis = analyzer.analyze_files([DEFAULT_INPUT]) + + # We don't differentiate between real and pseudos yet + analysis.instructions |= analysis.pseudos + return analysis + + +def rustfmt(code: str) -> str: + return subprocess.check_output(["rustfmt", "--emit=stdout"], input=code, text=True) + + +def main(): + CONF = tomllib.loads(CONF_FILE.read_text()) + + analysis = get_analysis() + + outfile = io.StringIO() + opcode_conf = CONF["Opcodes"] + + generated = "" + + script_path = pathlib.Path(__file__).resolve().relative_to(ROOT).as_posix() + + output = rustfmt( + f""" +// This file is generated by {script_path} +// Do not edit! + +use crate::bytecode::Arg; + +{generated} + """ + ) + + OUT_FILE.write_text(output) + + +if __name__ == "__main__": + main() diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs new file mode 100644 index 00000000000..fefc43110f5 --- /dev/null +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -0,0 +1,4 @@ +// This file is generated by crates/compiler-core/generate.py +// Do not edit! + +use crate::bytecode::Arg; From 1ddf4440e060e89bcceee8dd6331443b81589d06 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 15:10:24 +0300 Subject: [PATCH 03/35] to from numeric --- crates/compiler-core/generate.py | 125 ++- .../src/bytecode/instructions.rs | 780 ++++++++++++++++++ 2 files changed, 902 insertions(+), 3 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 126f727354f..04ca2e25a98 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +import dataclasses import io import os import pathlib @@ -26,6 +27,98 @@ from generators_common import DEFAULT_INPUT +@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) +class OpcodeGen: + name: str + instructions: list + numeric_repr: str + + def gen(self) -> str: + variants = ",\n".join(instr.name for instr in self.instructions) + + methods = "\n\n".join( + getattr(self, attr).strip() + for attr in sorted(dir(self)) + if attr.startswith("fn_") + ) + + impls = "\n\n".join( + getattr(self, attr).strip() + for attr in sorted(dir(self)) + if attr.startswith("impl_") + ) + + return f""" + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum {self.name} {{ + {variants} + }} + + impl {self.name} {{ + {methods} + }} + + {impls} + """ + + @property + def fn_as_numeric(self) -> str: + arms = ",\n".join( + f"Self::{instr.name} => {instr.opcode}" for instr in self.instructions + ) + return f""" + #[must_use] + pub const fn as_{self.numeric_repr}(self) -> {self.numeric_repr} {{ + match self {{ + {arms}, + }} + }} + """ + + @property + def fn_tryfrom_numeric(self) -> str: + arms = ",\n".join( + f"{instr.opcode} => Self::{instr.name}" for instr in self.instructions + ) + return f""" + #[must_use] + pub const fn from_{self.numeric_repr}( + value: {self.numeric_repr} + ) -> Result {{ + Ok(match value {{ + {arms}, + _ => return Err(crate::MarshalError::InvalidBytecode), + }}) + }} + """ + + @property + def impl_tryfrom_numeric(self) -> str: + return f""" + impl TryFrom<{self.numeric_repr}> for {self.name} {{ + type Error = crate::marshal::MarshalError; + + fn try_from(value: {self.numeric_repr}) -> Result {{ + Self::from_{self.numeric_repr}(value) + }} + }} + """ + + @property + def impl_into_numeric(self) -> str: + return f""" + impl From<{self.name}> for {self.numeric_repr}{{ + fn from(opcode: {self.name}) -> Self {{ + opcode.as_{self.numeric_repr}() + }} + }} + """ + + +def to_pascal_case(s: str) -> str: + return s.title().replace("_", "") + + def get_analysis() -> analyzer.Analysis: analysis = analyzer.analyze_files([DEFAULT_INPUT]) @@ -43,10 +136,36 @@ def main(): analysis = get_analysis() - outfile = io.StringIO() - opcode_conf = CONF["Opcodes"] + opcodes_conf = CONF["Opcodes"] + instructions_conf = CONF["Instructions"] - generated = "" + outfile = io.StringIO() + for key, conf in opcodes_conf.items(): + opcode_enum_name = conf["opcode_enum_name"] + numeric_repr = conf["numeric_repr"] + + opcode_range = conf["range"] + lower, upper = map(int, (opcode_range["min"], opcode_range["max"])) + bounds = range(lower, upper + 1) + + instructions = sorted( + ( + instr + for instr in analysis.instructions.values() + if instr.opcode in bounds + ), + key=lambda x: x.opcode, + ) + + for instr in instructions: + instr.name = to_pascal_case(instr.name) + + code = OpcodeGen( + name=opcode_enum_name, instructions=instructions, numeric_repr=numeric_repr + ).gen() + outfile.write(code) + + generated = outfile.getvalue() script_path = pathlib.Path(__file__).resolve().relative_to(ROOT).as_posix() diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index fefc43110f5..03d56f8d03a 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -2,3 +2,783 @@ // Do not edit! use crate::bytecode::Arg; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Opcode { + Cache, + BinarySlice, + BuildTemplate, + BinaryOpInplaceAddUnicode, + CallFunctionEx, + CheckEgMatch, + CheckExcMatch, + CleanupThrow, + DeleteSubscr, + EndFor, + EndSend, + ExitInitCheck, + FormatSimple, + FormatWithSpec, + GetAiter, + GetAnext, + GetIter, + Reserved, + GetLen, + GetYieldFromIter, + InterpreterExit, + LoadBuildClass, + LoadLocals, + MakeFunction, + MatchKeys, + MatchMapping, + MatchSequence, + Nop, + NotTaken, + PopExcept, + PopIter, + PopTop, + PushExcInfo, + PushNull, + ReturnGenerator, + ReturnValue, + SetupAnnotations, + StoreSlice, + StoreSubscr, + ToBool, + UnaryInvert, + UnaryNegative, + UnaryNot, + WithExceptStart, + BinaryOp, + BuildInterpolation, + BuildList, + BuildMap, + BuildSet, + BuildSlice, + BuildString, + BuildTuple, + Call, + CallIntrinsic1, + CallIntrinsic2, + CallKw, + CompareOp, + ContainsOp, + ConvertValue, + Copy, + CopyFreeVars, + DeleteAttr, + DeleteDeref, + DeleteFast, + DeleteGlobal, + DeleteName, + DictMerge, + DictUpdate, + EndAsyncFor, + ExtendedArg, + ForIter, + GetAwaitable, + ImportFrom, + ImportName, + IsOp, + JumpBackward, + JumpBackwardNoInterrupt, + JumpForward, + ListAppend, + ListExtend, + LoadAttr, + LoadCommonConstant, + LoadConst, + LoadDeref, + LoadFast, + LoadFastAndClear, + LoadFastBorrow, + LoadFastBorrowLoadFastBorrow, + LoadFastCheck, + LoadFastLoadFast, + LoadFromDictOrDeref, + LoadFromDictOrGlobals, + LoadGlobal, + LoadName, + LoadSmallInt, + LoadSpecial, + LoadSuperAttr, + MakeCell, + MapAdd, + MatchClass, + PopJumpIfFalse, + PopJumpIfNone, + PopJumpIfNotNone, + PopJumpIfTrue, + RaiseVarargs, + Reraise, + Send, + SetAdd, + SetFunctionAttribute, + SetUpdate, + StoreAttr, + StoreDeref, + StoreFast, + StoreFastLoadFast, + StoreFastStoreFast, + StoreGlobal, + StoreName, + Swap, + UnpackEx, + UnpackSequence, + YieldValue, + Resume, + BinaryOpAddFloat, + BinaryOpAddInt, + BinaryOpAddUnicode, + BinaryOpExtend, + BinaryOpMultiplyFloat, + BinaryOpMultiplyInt, + BinaryOpSubscrDict, + BinaryOpSubscrGetitem, + BinaryOpSubscrListInt, + BinaryOpSubscrListSlice, + BinaryOpSubscrStrInt, + BinaryOpSubscrTupleInt, + BinaryOpSubtractFloat, + BinaryOpSubtractInt, + CallAllocAndEnterInit, + CallBoundMethodExactArgs, + CallBoundMethodGeneral, + CallBuiltinClass, + CallBuiltinFast, + CallBuiltinFastWithKeywords, + CallBuiltinO, + CallIsinstance, + CallKwBoundMethod, + CallKwNonPy, + CallKwPy, + CallLen, + CallListAppend, + CallMethodDescriptorFast, + CallMethodDescriptorFastWithKeywords, + CallMethodDescriptorNoargs, + CallMethodDescriptorO, + CallNonPyGeneral, + CallPyExactArgs, + CallPyGeneral, + CallStr1, + CallTuple1, + CallType1, + CompareOpFloat, + CompareOpInt, + CompareOpStr, + ContainsOpDict, + ContainsOpSet, + ForIterGen, + ForIterList, + ForIterRange, + ForIterTuple, + JumpBackwardJit, + JumpBackwardNoJit, + LoadAttrClass, + LoadAttrClassWithMetaclassCheck, + LoadAttrGetattributeOverridden, + LoadAttrInstanceValue, + LoadAttrMethodLazyDict, + LoadAttrMethodNoDict, + LoadAttrMethodWithValues, + LoadAttrModule, + LoadAttrNondescriptorNoDict, + LoadAttrNondescriptorWithValues, + LoadAttrProperty, + LoadAttrSlot, + LoadAttrWithHint, + LoadConstImmortal, + LoadConstMortal, + LoadGlobalBuiltin, + LoadGlobalModule, + LoadSuperAttrAttr, + LoadSuperAttrMethod, + ResumeCheck, + SendGen, + StoreAttrInstanceValue, + StoreAttrSlot, + StoreAttrWithHint, + StoreSubscrDict, + StoreSubscrListInt, + ToBoolAlwaysTrue, + ToBoolBool, + ToBoolInt, + ToBoolList, + ToBoolNone, + ToBoolStr, + UnpackSequenceList, + UnpackSequenceTuple, + UnpackSequenceTwoTuple, + InstrumentedEndFor, + InstrumentedPopIter, + InstrumentedEndSend, + InstrumentedForIter, + InstrumentedInstruction, + InstrumentedJumpForward, + InstrumentedNotTaken, + InstrumentedPopJumpIfTrue, + InstrumentedPopJumpIfFalse, + InstrumentedPopJumpIfNone, + InstrumentedPopJumpIfNotNone, + InstrumentedResume, + InstrumentedReturnValue, + InstrumentedYieldValue, + InstrumentedEndAsyncFor, + InstrumentedLoadSuperAttr, + InstrumentedCall, + InstrumentedCallKw, + InstrumentedCallFunctionEx, + InstrumentedJumpBackward, + InstrumentedLine, + EnterExecutor, +} + +impl Opcode { + #[must_use] + pub const fn as_u8(self) -> u8 { + match self { + Self::Cache => 0, + Self::BinarySlice => 1, + Self::BuildTemplate => 2, + Self::BinaryOpInplaceAddUnicode => 3, + Self::CallFunctionEx => 4, + Self::CheckEgMatch => 5, + Self::CheckExcMatch => 6, + Self::CleanupThrow => 7, + Self::DeleteSubscr => 8, + Self::EndFor => 9, + Self::EndSend => 10, + Self::ExitInitCheck => 11, + Self::FormatSimple => 12, + Self::FormatWithSpec => 13, + Self::GetAiter => 14, + Self::GetAnext => 15, + Self::GetIter => 16, + Self::Reserved => 17, + Self::GetLen => 18, + Self::GetYieldFromIter => 19, + Self::InterpreterExit => 20, + Self::LoadBuildClass => 21, + Self::LoadLocals => 22, + Self::MakeFunction => 23, + Self::MatchKeys => 24, + Self::MatchMapping => 25, + Self::MatchSequence => 26, + Self::Nop => 27, + Self::NotTaken => 28, + Self::PopExcept => 29, + Self::PopIter => 30, + Self::PopTop => 31, + Self::PushExcInfo => 32, + Self::PushNull => 33, + Self::ReturnGenerator => 34, + Self::ReturnValue => 35, + Self::SetupAnnotations => 36, + Self::StoreSlice => 37, + Self::StoreSubscr => 38, + Self::ToBool => 39, + Self::UnaryInvert => 40, + Self::UnaryNegative => 41, + Self::UnaryNot => 42, + Self::WithExceptStart => 43, + Self::BinaryOp => 44, + Self::BuildInterpolation => 45, + Self::BuildList => 46, + Self::BuildMap => 47, + Self::BuildSet => 48, + Self::BuildSlice => 49, + Self::BuildString => 50, + Self::BuildTuple => 51, + Self::Call => 52, + Self::CallIntrinsic1 => 53, + Self::CallIntrinsic2 => 54, + Self::CallKw => 55, + Self::CompareOp => 56, + Self::ContainsOp => 57, + Self::ConvertValue => 58, + Self::Copy => 59, + Self::CopyFreeVars => 60, + Self::DeleteAttr => 61, + Self::DeleteDeref => 62, + Self::DeleteFast => 63, + Self::DeleteGlobal => 64, + Self::DeleteName => 65, + Self::DictMerge => 66, + Self::DictUpdate => 67, + Self::EndAsyncFor => 68, + Self::ExtendedArg => 69, + Self::ForIter => 70, + Self::GetAwaitable => 71, + Self::ImportFrom => 72, + Self::ImportName => 73, + Self::IsOp => 74, + Self::JumpBackward => 75, + Self::JumpBackwardNoInterrupt => 76, + Self::JumpForward => 77, + Self::ListAppend => 78, + Self::ListExtend => 79, + Self::LoadAttr => 80, + Self::LoadCommonConstant => 81, + Self::LoadConst => 82, + Self::LoadDeref => 83, + Self::LoadFast => 84, + Self::LoadFastAndClear => 85, + Self::LoadFastBorrow => 86, + Self::LoadFastBorrowLoadFastBorrow => 87, + Self::LoadFastCheck => 88, + Self::LoadFastLoadFast => 89, + Self::LoadFromDictOrDeref => 90, + Self::LoadFromDictOrGlobals => 91, + Self::LoadGlobal => 92, + Self::LoadName => 93, + Self::LoadSmallInt => 94, + Self::LoadSpecial => 95, + Self::LoadSuperAttr => 96, + Self::MakeCell => 97, + Self::MapAdd => 98, + Self::MatchClass => 99, + Self::PopJumpIfFalse => 100, + Self::PopJumpIfNone => 101, + Self::PopJumpIfNotNone => 102, + Self::PopJumpIfTrue => 103, + Self::RaiseVarargs => 104, + Self::Reraise => 105, + Self::Send => 106, + Self::SetAdd => 107, + Self::SetFunctionAttribute => 108, + Self::SetUpdate => 109, + Self::StoreAttr => 110, + Self::StoreDeref => 111, + Self::StoreFast => 112, + Self::StoreFastLoadFast => 113, + Self::StoreFastStoreFast => 114, + Self::StoreGlobal => 115, + Self::StoreName => 116, + Self::Swap => 117, + Self::UnpackEx => 118, + Self::UnpackSequence => 119, + Self::YieldValue => 120, + Self::Resume => 128, + Self::BinaryOpAddFloat => 129, + Self::BinaryOpAddInt => 130, + Self::BinaryOpAddUnicode => 131, + Self::BinaryOpExtend => 132, + Self::BinaryOpMultiplyFloat => 133, + Self::BinaryOpMultiplyInt => 134, + Self::BinaryOpSubscrDict => 135, + Self::BinaryOpSubscrGetitem => 136, + Self::BinaryOpSubscrListInt => 137, + Self::BinaryOpSubscrListSlice => 138, + Self::BinaryOpSubscrStrInt => 139, + Self::BinaryOpSubscrTupleInt => 140, + Self::BinaryOpSubtractFloat => 141, + Self::BinaryOpSubtractInt => 142, + Self::CallAllocAndEnterInit => 143, + Self::CallBoundMethodExactArgs => 144, + Self::CallBoundMethodGeneral => 145, + Self::CallBuiltinClass => 146, + Self::CallBuiltinFast => 147, + Self::CallBuiltinFastWithKeywords => 148, + Self::CallBuiltinO => 149, + Self::CallIsinstance => 150, + Self::CallKwBoundMethod => 151, + Self::CallKwNonPy => 152, + Self::CallKwPy => 153, + Self::CallLen => 154, + Self::CallListAppend => 155, + Self::CallMethodDescriptorFast => 156, + Self::CallMethodDescriptorFastWithKeywords => 157, + Self::CallMethodDescriptorNoargs => 158, + Self::CallMethodDescriptorO => 159, + Self::CallNonPyGeneral => 160, + Self::CallPyExactArgs => 161, + Self::CallPyGeneral => 162, + Self::CallStr1 => 163, + Self::CallTuple1 => 164, + Self::CallType1 => 165, + Self::CompareOpFloat => 166, + Self::CompareOpInt => 167, + Self::CompareOpStr => 168, + Self::ContainsOpDict => 169, + Self::ContainsOpSet => 170, + Self::ForIterGen => 171, + Self::ForIterList => 172, + Self::ForIterRange => 173, + Self::ForIterTuple => 174, + Self::JumpBackwardJit => 175, + Self::JumpBackwardNoJit => 176, + Self::LoadAttrClass => 177, + Self::LoadAttrClassWithMetaclassCheck => 178, + Self::LoadAttrGetattributeOverridden => 179, + Self::LoadAttrInstanceValue => 180, + Self::LoadAttrMethodLazyDict => 181, + Self::LoadAttrMethodNoDict => 182, + Self::LoadAttrMethodWithValues => 183, + Self::LoadAttrModule => 184, + Self::LoadAttrNondescriptorNoDict => 185, + Self::LoadAttrNondescriptorWithValues => 186, + Self::LoadAttrProperty => 187, + Self::LoadAttrSlot => 188, + Self::LoadAttrWithHint => 189, + Self::LoadConstImmortal => 190, + Self::LoadConstMortal => 191, + Self::LoadGlobalBuiltin => 192, + Self::LoadGlobalModule => 193, + Self::LoadSuperAttrAttr => 194, + Self::LoadSuperAttrMethod => 195, + Self::ResumeCheck => 196, + Self::SendGen => 197, + Self::StoreAttrInstanceValue => 198, + Self::StoreAttrSlot => 199, + Self::StoreAttrWithHint => 200, + Self::StoreSubscrDict => 201, + Self::StoreSubscrListInt => 202, + Self::ToBoolAlwaysTrue => 203, + Self::ToBoolBool => 204, + Self::ToBoolInt => 205, + Self::ToBoolList => 206, + Self::ToBoolNone => 207, + Self::ToBoolStr => 208, + Self::UnpackSequenceList => 209, + Self::UnpackSequenceTuple => 210, + Self::UnpackSequenceTwoTuple => 211, + Self::InstrumentedEndFor => 234, + Self::InstrumentedPopIter => 235, + Self::InstrumentedEndSend => 236, + Self::InstrumentedForIter => 237, + Self::InstrumentedInstruction => 238, + Self::InstrumentedJumpForward => 239, + Self::InstrumentedNotTaken => 240, + Self::InstrumentedPopJumpIfTrue => 241, + Self::InstrumentedPopJumpIfFalse => 242, + Self::InstrumentedPopJumpIfNone => 243, + Self::InstrumentedPopJumpIfNotNone => 244, + Self::InstrumentedResume => 245, + Self::InstrumentedReturnValue => 246, + Self::InstrumentedYieldValue => 247, + Self::InstrumentedEndAsyncFor => 248, + Self::InstrumentedLoadSuperAttr => 249, + Self::InstrumentedCall => 250, + Self::InstrumentedCallKw => 251, + Self::InstrumentedCallFunctionEx => 252, + Self::InstrumentedJumpBackward => 253, + Self::InstrumentedLine => 254, + Self::EnterExecutor => 255, + } + } + + #[must_use] + pub const fn from_u8(value: u8) -> Result { + Ok(match value { + 0 => Self::Cache, + 1 => Self::BinarySlice, + 2 => Self::BuildTemplate, + 3 => Self::BinaryOpInplaceAddUnicode, + 4 => Self::CallFunctionEx, + 5 => Self::CheckEgMatch, + 6 => Self::CheckExcMatch, + 7 => Self::CleanupThrow, + 8 => Self::DeleteSubscr, + 9 => Self::EndFor, + 10 => Self::EndSend, + 11 => Self::ExitInitCheck, + 12 => Self::FormatSimple, + 13 => Self::FormatWithSpec, + 14 => Self::GetAiter, + 15 => Self::GetAnext, + 16 => Self::GetIter, + 17 => Self::Reserved, + 18 => Self::GetLen, + 19 => Self::GetYieldFromIter, + 20 => Self::InterpreterExit, + 21 => Self::LoadBuildClass, + 22 => Self::LoadLocals, + 23 => Self::MakeFunction, + 24 => Self::MatchKeys, + 25 => Self::MatchMapping, + 26 => Self::MatchSequence, + 27 => Self::Nop, + 28 => Self::NotTaken, + 29 => Self::PopExcept, + 30 => Self::PopIter, + 31 => Self::PopTop, + 32 => Self::PushExcInfo, + 33 => Self::PushNull, + 34 => Self::ReturnGenerator, + 35 => Self::ReturnValue, + 36 => Self::SetupAnnotations, + 37 => Self::StoreSlice, + 38 => Self::StoreSubscr, + 39 => Self::ToBool, + 40 => Self::UnaryInvert, + 41 => Self::UnaryNegative, + 42 => Self::UnaryNot, + 43 => Self::WithExceptStart, + 44 => Self::BinaryOp, + 45 => Self::BuildInterpolation, + 46 => Self::BuildList, + 47 => Self::BuildMap, + 48 => Self::BuildSet, + 49 => Self::BuildSlice, + 50 => Self::BuildString, + 51 => Self::BuildTuple, + 52 => Self::Call, + 53 => Self::CallIntrinsic1, + 54 => Self::CallIntrinsic2, + 55 => Self::CallKw, + 56 => Self::CompareOp, + 57 => Self::ContainsOp, + 58 => Self::ConvertValue, + 59 => Self::Copy, + 60 => Self::CopyFreeVars, + 61 => Self::DeleteAttr, + 62 => Self::DeleteDeref, + 63 => Self::DeleteFast, + 64 => Self::DeleteGlobal, + 65 => Self::DeleteName, + 66 => Self::DictMerge, + 67 => Self::DictUpdate, + 68 => Self::EndAsyncFor, + 69 => Self::ExtendedArg, + 70 => Self::ForIter, + 71 => Self::GetAwaitable, + 72 => Self::ImportFrom, + 73 => Self::ImportName, + 74 => Self::IsOp, + 75 => Self::JumpBackward, + 76 => Self::JumpBackwardNoInterrupt, + 77 => Self::JumpForward, + 78 => Self::ListAppend, + 79 => Self::ListExtend, + 80 => Self::LoadAttr, + 81 => Self::LoadCommonConstant, + 82 => Self::LoadConst, + 83 => Self::LoadDeref, + 84 => Self::LoadFast, + 85 => Self::LoadFastAndClear, + 86 => Self::LoadFastBorrow, + 87 => Self::LoadFastBorrowLoadFastBorrow, + 88 => Self::LoadFastCheck, + 89 => Self::LoadFastLoadFast, + 90 => Self::LoadFromDictOrDeref, + 91 => Self::LoadFromDictOrGlobals, + 92 => Self::LoadGlobal, + 93 => Self::LoadName, + 94 => Self::LoadSmallInt, + 95 => Self::LoadSpecial, + 96 => Self::LoadSuperAttr, + 97 => Self::MakeCell, + 98 => Self::MapAdd, + 99 => Self::MatchClass, + 100 => Self::PopJumpIfFalse, + 101 => Self::PopJumpIfNone, + 102 => Self::PopJumpIfNotNone, + 103 => Self::PopJumpIfTrue, + 104 => Self::RaiseVarargs, + 105 => Self::Reraise, + 106 => Self::Send, + 107 => Self::SetAdd, + 108 => Self::SetFunctionAttribute, + 109 => Self::SetUpdate, + 110 => Self::StoreAttr, + 111 => Self::StoreDeref, + 112 => Self::StoreFast, + 113 => Self::StoreFastLoadFast, + 114 => Self::StoreFastStoreFast, + 115 => Self::StoreGlobal, + 116 => Self::StoreName, + 117 => Self::Swap, + 118 => Self::UnpackEx, + 119 => Self::UnpackSequence, + 120 => Self::YieldValue, + 128 => Self::Resume, + 129 => Self::BinaryOpAddFloat, + 130 => Self::BinaryOpAddInt, + 131 => Self::BinaryOpAddUnicode, + 132 => Self::BinaryOpExtend, + 133 => Self::BinaryOpMultiplyFloat, + 134 => Self::BinaryOpMultiplyInt, + 135 => Self::BinaryOpSubscrDict, + 136 => Self::BinaryOpSubscrGetitem, + 137 => Self::BinaryOpSubscrListInt, + 138 => Self::BinaryOpSubscrListSlice, + 139 => Self::BinaryOpSubscrStrInt, + 140 => Self::BinaryOpSubscrTupleInt, + 141 => Self::BinaryOpSubtractFloat, + 142 => Self::BinaryOpSubtractInt, + 143 => Self::CallAllocAndEnterInit, + 144 => Self::CallBoundMethodExactArgs, + 145 => Self::CallBoundMethodGeneral, + 146 => Self::CallBuiltinClass, + 147 => Self::CallBuiltinFast, + 148 => Self::CallBuiltinFastWithKeywords, + 149 => Self::CallBuiltinO, + 150 => Self::CallIsinstance, + 151 => Self::CallKwBoundMethod, + 152 => Self::CallKwNonPy, + 153 => Self::CallKwPy, + 154 => Self::CallLen, + 155 => Self::CallListAppend, + 156 => Self::CallMethodDescriptorFast, + 157 => Self::CallMethodDescriptorFastWithKeywords, + 158 => Self::CallMethodDescriptorNoargs, + 159 => Self::CallMethodDescriptorO, + 160 => Self::CallNonPyGeneral, + 161 => Self::CallPyExactArgs, + 162 => Self::CallPyGeneral, + 163 => Self::CallStr1, + 164 => Self::CallTuple1, + 165 => Self::CallType1, + 166 => Self::CompareOpFloat, + 167 => Self::CompareOpInt, + 168 => Self::CompareOpStr, + 169 => Self::ContainsOpDict, + 170 => Self::ContainsOpSet, + 171 => Self::ForIterGen, + 172 => Self::ForIterList, + 173 => Self::ForIterRange, + 174 => Self::ForIterTuple, + 175 => Self::JumpBackwardJit, + 176 => Self::JumpBackwardNoJit, + 177 => Self::LoadAttrClass, + 178 => Self::LoadAttrClassWithMetaclassCheck, + 179 => Self::LoadAttrGetattributeOverridden, + 180 => Self::LoadAttrInstanceValue, + 181 => Self::LoadAttrMethodLazyDict, + 182 => Self::LoadAttrMethodNoDict, + 183 => Self::LoadAttrMethodWithValues, + 184 => Self::LoadAttrModule, + 185 => Self::LoadAttrNondescriptorNoDict, + 186 => Self::LoadAttrNondescriptorWithValues, + 187 => Self::LoadAttrProperty, + 188 => Self::LoadAttrSlot, + 189 => Self::LoadAttrWithHint, + 190 => Self::LoadConstImmortal, + 191 => Self::LoadConstMortal, + 192 => Self::LoadGlobalBuiltin, + 193 => Self::LoadGlobalModule, + 194 => Self::LoadSuperAttrAttr, + 195 => Self::LoadSuperAttrMethod, + 196 => Self::ResumeCheck, + 197 => Self::SendGen, + 198 => Self::StoreAttrInstanceValue, + 199 => Self::StoreAttrSlot, + 200 => Self::StoreAttrWithHint, + 201 => Self::StoreSubscrDict, + 202 => Self::StoreSubscrListInt, + 203 => Self::ToBoolAlwaysTrue, + 204 => Self::ToBoolBool, + 205 => Self::ToBoolInt, + 206 => Self::ToBoolList, + 207 => Self::ToBoolNone, + 208 => Self::ToBoolStr, + 209 => Self::UnpackSequenceList, + 210 => Self::UnpackSequenceTuple, + 211 => Self::UnpackSequenceTwoTuple, + 234 => Self::InstrumentedEndFor, + 235 => Self::InstrumentedPopIter, + 236 => Self::InstrumentedEndSend, + 237 => Self::InstrumentedForIter, + 238 => Self::InstrumentedInstruction, + 239 => Self::InstrumentedJumpForward, + 240 => Self::InstrumentedNotTaken, + 241 => Self::InstrumentedPopJumpIfTrue, + 242 => Self::InstrumentedPopJumpIfFalse, + 243 => Self::InstrumentedPopJumpIfNone, + 244 => Self::InstrumentedPopJumpIfNotNone, + 245 => Self::InstrumentedResume, + 246 => Self::InstrumentedReturnValue, + 247 => Self::InstrumentedYieldValue, + 248 => Self::InstrumentedEndAsyncFor, + 249 => Self::InstrumentedLoadSuperAttr, + 250 => Self::InstrumentedCall, + 251 => Self::InstrumentedCallKw, + 252 => Self::InstrumentedCallFunctionEx, + 253 => Self::InstrumentedJumpBackward, + 254 => Self::InstrumentedLine, + 255 => Self::EnterExecutor, + _ => return Err(crate::MarshalError::InvalidBytecode), + }) + } +} + +impl From for u8 { + fn from(opcode: Opcode) -> Self { + opcode.as_u8() + } +} + +impl TryFrom for Opcode { + type Error = crate::marshal::MarshalError; + + fn try_from(value: u8) -> Result { + Self::from_u8(value) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum PseudoOpcode { + AnnotationsPlaceholder, + Jump, + JumpIfFalse, + JumpIfTrue, + JumpNoInterrupt, + LoadClosure, + PopBlock, + SetupCleanup, + SetupFinally, + SetupWith, + StoreFastMaybeNull, +} + +impl PseudoOpcode { + #[must_use] + pub const fn as_u16(self) -> u16 { + match self { + Self::AnnotationsPlaceholder => 256, + Self::Jump => 257, + Self::JumpIfFalse => 258, + Self::JumpIfTrue => 259, + Self::JumpNoInterrupt => 260, + Self::LoadClosure => 261, + Self::PopBlock => 262, + Self::SetupCleanup => 263, + Self::SetupFinally => 264, + Self::SetupWith => 265, + Self::StoreFastMaybeNull => 266, + } + } + + #[must_use] + pub const fn from_u16(value: u16) -> Result { + Ok(match value { + 256 => Self::AnnotationsPlaceholder, + 257 => Self::Jump, + 258 => Self::JumpIfFalse, + 259 => Self::JumpIfTrue, + 260 => Self::JumpNoInterrupt, + 261 => Self::LoadClosure, + 262 => Self::PopBlock, + 263 => Self::SetupCleanup, + 264 => Self::SetupFinally, + 265 => Self::SetupWith, + 266 => Self::StoreFastMaybeNull, + _ => return Err(crate::MarshalError::InvalidBytecode), + }) + } +} + +impl From for u16 { + fn from(opcode: PseudoOpcode) -> Self { + opcode.as_u16() + } +} + +impl TryFrom for PseudoOpcode { + type Error = crate::marshal::MarshalError; + + fn try_from(value: u16) -> Result { + Self::from_u16(value) + } +} From 1e0c01b388aad4bfd1d39e1b541ccf2576453b24 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 15:22:26 +0300 Subject: [PATCH 04/35] generate has attr --- crates/compiler-core/generate.py | 48 +++ .../src/bytecode/instructions.rs | 327 ++++++++++++++++++ 2 files changed, 375 insertions(+) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 04ca2e25a98..60963aa9a02 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -114,6 +114,54 @@ def impl_into_numeric(self) -> str: }} """ + def build_has_attr_fn(self, fn_attr: str, prop_attr: str, doc_flag: str): + arms = "|".join( + f"Self::{instr.name}" + for instr in self.instructions + if getattr(instr.properties, prop_attr) + ) + + if arms: + inner = f"matches!(self, {arms})" + else: + inner = "false" + + return f""" + /// Does this opcode have '{doc_flag}' set. + #[must_use] + pub const fn has_{fn_attr}(self) -> bool {{ + {inner} + }} + """ + + fn_has_arg = property( + lambda self: self.build_has_attr_fn("arg", "oparg", "HAS_ARG_FLAG") + ) + + fn_has_const = property( + lambda self: self.build_has_attr_fn("const", "uses_co_consts", "HAS_CONST_FLAG") + ) + + fn_has_name = property( + lambda self: self.build_has_attr_fn("name", "uses_co_names", "HAS_NAME_FLAG") + ) + + fn_has_jump = property( + lambda self: self.build_has_attr_fn("jump", "jumps", "HAS_JUMP_FLAG") + ) + + fn_has_free = property( + lambda self: self.build_has_attr_fn("free", "has_free", "HAS_FREE_FLAG") + ) + + fn_has_local = property( + lambda self: self.build_has_attr_fn("local", "uses_locals", "HAS_LOCAL_FLAG") + ) + + fn_has_exc = property( + lambda self: self.build_has_attr_fn("exc", "pure", "HAS_PURE_FLAG") + ) + def to_pascal_case(s: str) -> str: return s.title().replace("_", "") diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 03d56f8d03a..03f0a0c22eb 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -468,6 +468,272 @@ impl Opcode { } } + /// Does this opcode have 'HAS_ARG_FLAG' set. + #[must_use] + pub const fn has_arg(self) -> bool { + matches!( + self, + Self::BinaryOp + | Self::BuildInterpolation + | Self::BuildList + | Self::BuildMap + | Self::BuildSet + | Self::BuildSlice + | Self::BuildString + | Self::BuildTuple + | Self::Call + | Self::CallIntrinsic1 + | Self::CallIntrinsic2 + | Self::CallKw + | Self::CompareOp + | Self::ContainsOp + | Self::ConvertValue + | Self::Copy + | Self::CopyFreeVars + | Self::DeleteAttr + | Self::DeleteDeref + | Self::DeleteFast + | Self::DeleteGlobal + | Self::DeleteName + | Self::DictMerge + | Self::DictUpdate + | Self::EndAsyncFor + | Self::ExtendedArg + | Self::ForIter + | Self::GetAwaitable + | Self::ImportFrom + | Self::ImportName + | Self::IsOp + | Self::JumpBackward + | Self::JumpBackwardNoInterrupt + | Self::JumpForward + | Self::ListAppend + | Self::ListExtend + | Self::LoadAttr + | Self::LoadCommonConstant + | Self::LoadConst + | Self::LoadDeref + | Self::LoadFast + | Self::LoadFastAndClear + | Self::LoadFastBorrow + | Self::LoadFastBorrowLoadFastBorrow + | Self::LoadFastCheck + | Self::LoadFastLoadFast + | Self::LoadFromDictOrDeref + | Self::LoadFromDictOrGlobals + | Self::LoadGlobal + | Self::LoadName + | Self::LoadSmallInt + | Self::LoadSpecial + | Self::LoadSuperAttr + | Self::MakeCell + | Self::MapAdd + | Self::MatchClass + | Self::PopJumpIfFalse + | Self::PopJumpIfNone + | Self::PopJumpIfNotNone + | Self::PopJumpIfTrue + | Self::RaiseVarargs + | Self::Reraise + | Self::Send + | Self::SetAdd + | Self::SetFunctionAttribute + | Self::SetUpdate + | Self::StoreAttr + | Self::StoreDeref + | Self::StoreFast + | Self::StoreFastLoadFast + | Self::StoreFastStoreFast + | Self::StoreGlobal + | Self::StoreName + | Self::Swap + | Self::UnpackEx + | Self::UnpackSequence + | Self::YieldValue + | Self::Resume + | Self::CallAllocAndEnterInit + | Self::CallBoundMethodExactArgs + | Self::CallBoundMethodGeneral + | Self::CallBuiltinClass + | Self::CallBuiltinFast + | Self::CallBuiltinFastWithKeywords + | Self::CallBuiltinO + | Self::CallIsinstance + | Self::CallKwBoundMethod + | Self::CallKwNonPy + | Self::CallKwPy + | Self::CallListAppend + | Self::CallMethodDescriptorFast + | Self::CallMethodDescriptorFastWithKeywords + | Self::CallMethodDescriptorNoargs + | Self::CallMethodDescriptorO + | Self::CallNonPyGeneral + | Self::CallPyExactArgs + | Self::CallPyGeneral + | Self::CallStr1 + | Self::CallTuple1 + | Self::CallType1 + | Self::CompareOpFloat + | Self::CompareOpInt + | Self::CompareOpStr + | Self::ContainsOpDict + | Self::ContainsOpSet + | Self::ForIterGen + | Self::ForIterList + | Self::ForIterRange + | Self::ForIterTuple + | Self::JumpBackwardJit + | Self::JumpBackwardNoJit + | Self::LoadAttrClass + | Self::LoadAttrClassWithMetaclassCheck + | Self::LoadAttrGetattributeOverridden + | Self::LoadAttrInstanceValue + | Self::LoadAttrMethodLazyDict + | Self::LoadAttrMethodNoDict + | Self::LoadAttrMethodWithValues + | Self::LoadAttrModule + | Self::LoadAttrNondescriptorNoDict + | Self::LoadAttrNondescriptorWithValues + | Self::LoadAttrProperty + | Self::LoadAttrSlot + | Self::LoadAttrWithHint + | Self::LoadConstImmortal + | Self::LoadConstMortal + | Self::LoadGlobalBuiltin + | Self::LoadGlobalModule + | Self::LoadSuperAttrAttr + | Self::LoadSuperAttrMethod + | Self::SendGen + | Self::StoreAttrWithHint + | Self::UnpackSequenceList + | Self::UnpackSequenceTuple + | Self::UnpackSequenceTwoTuple + | Self::InstrumentedForIter + | Self::InstrumentedJumpForward + | Self::InstrumentedPopJumpIfTrue + | Self::InstrumentedPopJumpIfFalse + | Self::InstrumentedPopJumpIfNone + | Self::InstrumentedPopJumpIfNotNone + | Self::InstrumentedResume + | Self::InstrumentedYieldValue + | Self::InstrumentedEndAsyncFor + | Self::InstrumentedLoadSuperAttr + | Self::InstrumentedCall + | Self::InstrumentedCallKw + | Self::InstrumentedJumpBackward + | Self::EnterExecutor + ) + } + + /// Does this opcode have 'HAS_CONST_FLAG' set. + #[must_use] + pub const fn has_const(self) -> bool { + matches!( + self, + Self::LoadConst | Self::LoadConstImmortal | Self::LoadConstMortal + ) + } + + /// Does this opcode have 'HAS_PURE_FLAG' set. + #[must_use] + pub const fn has_exc(self) -> bool { + matches!( + self, + Self::EndSend + | Self::Nop + | Self::NotTaken + | Self::PopIter + | Self::PopTop + | Self::PushNull + | Self::UnaryNot + | Self::Copy + | Self::LoadFast + | Self::LoadFastBorrow + | Self::Swap + ) + } + + /// Does this opcode have 'HAS_FREE_FLAG' set. + #[must_use] + pub const fn has_free(self) -> bool { + matches!( + self, + Self::DeleteDeref | Self::LoadFromDictOrDeref | Self::MakeCell | Self::StoreDeref + ) + } + + /// Does this opcode have 'HAS_JUMP_FLAG' set. + #[must_use] + pub const fn has_jump(self) -> bool { + matches!( + self, + Self::EndAsyncFor + | Self::ForIter + | Self::JumpBackward + | Self::JumpBackwardNoInterrupt + | Self::JumpForward + | Self::PopJumpIfFalse + | Self::PopJumpIfNone + | Self::PopJumpIfNotNone + | Self::PopJumpIfTrue + | Self::Send + | Self::ForIterList + | Self::ForIterRange + | Self::ForIterTuple + | Self::JumpBackwardJit + | Self::JumpBackwardNoJit + | Self::InstrumentedForIter + | Self::InstrumentedEndAsyncFor + ) + } + + /// Does this opcode have 'HAS_LOCAL_FLAG' set. + #[must_use] + pub const fn has_local(self) -> bool { + matches!( + self, + Self::BinaryOpInplaceAddUnicode + | Self::DeleteFast + | Self::LoadDeref + | Self::LoadFast + | Self::LoadFastAndClear + | Self::LoadFastBorrow + | Self::LoadFastBorrowLoadFastBorrow + | Self::LoadFastCheck + | Self::LoadFastLoadFast + | Self::StoreFast + | Self::StoreFastLoadFast + | Self::StoreFastStoreFast + ) + } + + /// Does this opcode have 'HAS_NAME_FLAG' set. + #[must_use] + pub const fn has_name(self) -> bool { + matches!( + self, + Self::DeleteAttr + | Self::DeleteGlobal + | Self::DeleteName + | Self::ImportFrom + | Self::ImportName + | Self::LoadAttr + | Self::LoadFromDictOrGlobals + | Self::LoadGlobal + | Self::LoadName + | Self::LoadSuperAttr + | Self::StoreAttr + | Self::StoreGlobal + | Self::StoreName + | Self::LoadAttrGetattributeOverridden + | Self::LoadAttrWithHint + | Self::LoadSuperAttrAttr + | Self::LoadSuperAttrMethod + | Self::StoreAttrWithHint + | Self::InstrumentedLoadSuperAttr + ) + } + #[must_use] pub const fn from_u8(value: u8) -> Result { Ok(match value { @@ -750,6 +1016,67 @@ impl PseudoOpcode { } } + /// Does this opcode have 'HAS_ARG_FLAG' set. + #[must_use] + pub const fn has_arg(self) -> bool { + matches!( + self, + Self::Jump + | Self::JumpIfFalse + | Self::JumpIfTrue + | Self::JumpNoInterrupt + | Self::LoadClosure + | Self::StoreFastMaybeNull + ) + } + + /// Does this opcode have 'HAS_CONST_FLAG' set. + #[must_use] + pub const fn has_const(self) -> bool { + false + } + + /// Does this opcode have 'HAS_PURE_FLAG' set. + #[must_use] + pub const fn has_exc(self) -> bool { + matches!( + self, + Self::AnnotationsPlaceholder + | Self::LoadClosure + | Self::PopBlock + | Self::SetupCleanup + | Self::SetupFinally + | Self::SetupWith + ) + } + + /// Does this opcode have 'HAS_FREE_FLAG' set. + #[must_use] + pub const fn has_free(self) -> bool { + false + } + + /// Does this opcode have 'HAS_JUMP_FLAG' set. + #[must_use] + pub const fn has_jump(self) -> bool { + matches!( + self, + Self::Jump | Self::JumpIfFalse | Self::JumpIfTrue | Self::JumpNoInterrupt + ) + } + + /// Does this opcode have 'HAS_LOCAL_FLAG' set. + #[must_use] + pub const fn has_local(self) -> bool { + matches!(self, Self::LoadClosure | Self::StoreFastMaybeNull) + } + + /// Does this opcode have 'HAS_NAME_FLAG' set. + #[must_use] + pub const fn has_name(self) -> bool { + false + } + #[must_use] pub const fn from_u16(value: u16) -> Result { Ok(match value { From c66eaf695d672ca7f206c8e40b2db6d1a2aecf47 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 16:11:37 +0300 Subject: [PATCH 05/35] Basic instrumented --- crates/compiler-core/generate.py | 106 ++++++++++++++++-- .../src/bytecode/instructions.rs | 52 +++++++++ 2 files changed, 148 insertions(+), 10 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 60963aa9a02..643f3ebb934 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -32,9 +32,10 @@ class OpcodeGen: name: str instructions: list numeric_repr: str + analysis: analyzer.Analysis def gen(self) -> str: - variants = ",\n".join(instr.name for instr in self.instructions) + variants = ",\n".join(instr.name for instr in self) methods = "\n\n".join( getattr(self, attr).strip() @@ -63,9 +64,7 @@ def gen(self) -> str: @property def fn_as_numeric(self) -> str: - arms = ",\n".join( - f"Self::{instr.name} => {instr.opcode}" for instr in self.instructions - ) + arms = ",\n".join(f"Self::{instr.name} => {instr.opcode}" for instr in self) return f""" #[must_use] pub const fn as_{self.numeric_repr}(self) -> {self.numeric_repr} {{ @@ -77,9 +76,7 @@ def fn_as_numeric(self) -> str: @property def fn_tryfrom_numeric(self) -> str: - arms = ",\n".join( - f"{instr.opcode} => Self::{instr.name}" for instr in self.instructions - ) + arms = ",\n".join(f"{instr.opcode} => Self::{instr.name}" for instr in self) return f""" #[must_use] pub const fn from_{self.numeric_repr}( @@ -114,10 +111,10 @@ def impl_into_numeric(self) -> str: }} """ - def build_has_attr_fn(self, fn_attr: str, prop_attr: str, doc_flag: str): + def build_has_attr_fn(self, fn_attr: str, prop_attr: str, doc_flag: str) -> str: arms = "|".join( f"Self::{instr.name}" - for instr in self.instructions + for instr in self if getattr(instr.properties, prop_attr) ) @@ -162,6 +159,91 @@ def build_has_attr_fn(self, fn_attr: str, prop_attr: str, doc_flag: str): lambda self: self.build_has_attr_fn("exc", "pure", "HAS_PURE_FLAG") ) + @property + def instrumented(self) -> list: + return [instr for instr in self if instr.name.startswith("Instrumented")] + + @property + def fn_to_base(self) -> str: + inames = {instr.name for instr in self.instrumented} + names = {instr.name for instr in self} - inames + + arms = "" + for iname in inames: + name = iname.removeprefix("Instrumented") + if name not in names: + continue + arms += f"Self::{iname} => Self::{name},\n" + + arms = arms.strip() + if not arms: + return "" + + inner = f""" + Some(match self {{ + {arms} + _ => return None, + + }}) + """ + + return f""" + #[must_use] + pub const fn to_base(self) -> Option {{ + {inner} + }} + """ + + @property + def fn_to_instrumented(self) -> str: + inames = {instr.name for instr in self.instrumented} + names = {instr.name for instr in self} - inames + + arms = "" + for iname in inames: + name = iname.removeprefix("Instrumented") + if name not in names: + continue + arms += f"Self::{name} => Self::{iname},\n" + + arms = arms.strip() + if not arms: + return "" + + inner = f""" + Some(match self {{ + {arms} + _ => return None, + + }}) + """ + + return f""" + #[must_use] + pub const fn to_instrumented(self) -> Option {{ + {inner} + }} + """ + + @property + def fn_deopt(self) -> str: + names = {instr.name for instr in self} + + for family in self.analysis.families.values(): + family_name = to_pascal_case(family.name) + if family_name not in names: + continue + for member in family.members: + if member.name == family.name: + continue + + print(family_name, member.name) + + return "" + + def __iter__(self): + yield from self.instructions + def to_pascal_case(s: str) -> str: return s.title().replace("_", "") @@ -209,8 +291,12 @@ def main(): instr.name = to_pascal_case(instr.name) code = OpcodeGen( - name=opcode_enum_name, instructions=instructions, numeric_repr=numeric_repr + name=opcode_enum_name, + instructions=instructions, + numeric_repr=numeric_repr, + analysis=analysis, ).gen() + outfile.write(code) generated = outfile.getvalue() diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 03f0a0c22eb..b9cb89a9dda 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -734,6 +734,58 @@ impl Opcode { ) } + #[must_use] + pub const fn to_base(self) -> Option { + Some(match self { + Self::InstrumentedForIter => Self::ForIter, + Self::InstrumentedYieldValue => Self::YieldValue, + Self::InstrumentedNotTaken => Self::NotTaken, + Self::InstrumentedEndSend => Self::EndSend, + Self::InstrumentedJumpBackward => Self::JumpBackward, + Self::InstrumentedResume => Self::Resume, + Self::InstrumentedJumpForward => Self::JumpForward, + Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue, + Self::InstrumentedReturnValue => Self::ReturnValue, + Self::InstrumentedCallFunctionEx => Self::CallFunctionEx, + Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse, + Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone, + Self::InstrumentedEndFor => Self::EndFor, + Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone, + Self::InstrumentedCall => Self::Call, + Self::InstrumentedEndAsyncFor => Self::EndAsyncFor, + Self::InstrumentedPopIter => Self::PopIter, + Self::InstrumentedCallKw => Self::CallKw, + Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr, + _ => return None, + }) + } + + #[must_use] + pub const fn to_instrumented(self) -> Option { + Some(match self { + Self::ForIter => Self::InstrumentedForIter, + Self::YieldValue => Self::InstrumentedYieldValue, + Self::NotTaken => Self::InstrumentedNotTaken, + Self::EndSend => Self::InstrumentedEndSend, + Self::JumpBackward => Self::InstrumentedJumpBackward, + Self::Resume => Self::InstrumentedResume, + Self::JumpForward => Self::InstrumentedJumpForward, + Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue, + Self::ReturnValue => Self::InstrumentedReturnValue, + Self::CallFunctionEx => Self::InstrumentedCallFunctionEx, + Self::PopJumpIfFalse => Self::InstrumentedPopJumpIfFalse, + Self::PopJumpIfNone => Self::InstrumentedPopJumpIfNone, + Self::EndFor => Self::InstrumentedEndFor, + Self::PopJumpIfNotNone => Self::InstrumentedPopJumpIfNotNone, + Self::Call => Self::InstrumentedCall, + Self::EndAsyncFor => Self::InstrumentedEndAsyncFor, + Self::PopIter => Self::InstrumentedPopIter, + Self::CallKw => Self::InstrumentedCallKw, + Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr, + _ => return None, + }) + } + #[must_use] pub const fn from_u8(value: u8) -> Result { Ok(match value { From d1f09822f5e9387096b1619c19f57d00e05c6e70 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 16:14:27 +0300 Subject: [PATCH 06/35] sort instrumeneted --- crates/compiler-core/generate.py | 5 +- .../src/bytecode/instructions.rs | 52 +++++++++---------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 643f3ebb934..887edb98ff3 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -169,7 +169,7 @@ def fn_to_base(self) -> str: names = {instr.name for instr in self} - inames arms = "" - for iname in inames: + for iname in sorted(inames): name = iname.removeprefix("Instrumented") if name not in names: continue @@ -200,7 +200,7 @@ def fn_to_instrumented(self) -> str: names = {instr.name for instr in self} - inames arms = "" - for iname in inames: + for iname in sorted(inames): name = iname.removeprefix("Instrumented") if name not in names: continue @@ -233,6 +233,7 @@ def fn_deopt(self) -> str: family_name = to_pascal_case(family.name) if family_name not in names: continue + for member in family.members: if member.name == family.name: continue diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index b9cb89a9dda..33cbd6214c1 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -737,25 +737,25 @@ impl Opcode { #[must_use] pub const fn to_base(self) -> Option { Some(match self { - Self::InstrumentedForIter => Self::ForIter, - Self::InstrumentedYieldValue => Self::YieldValue, - Self::InstrumentedNotTaken => Self::NotTaken, + Self::InstrumentedCall => Self::Call, + Self::InstrumentedCallFunctionEx => Self::CallFunctionEx, + Self::InstrumentedCallKw => Self::CallKw, + Self::InstrumentedEndAsyncFor => Self::EndAsyncFor, + Self::InstrumentedEndFor => Self::EndFor, Self::InstrumentedEndSend => Self::EndSend, + Self::InstrumentedForIter => Self::ForIter, Self::InstrumentedJumpBackward => Self::JumpBackward, - Self::InstrumentedResume => Self::Resume, Self::InstrumentedJumpForward => Self::JumpForward, - Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue, - Self::InstrumentedReturnValue => Self::ReturnValue, - Self::InstrumentedCallFunctionEx => Self::CallFunctionEx, + Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr, + Self::InstrumentedNotTaken => Self::NotTaken, + Self::InstrumentedPopIter => Self::PopIter, Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse, Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone, - Self::InstrumentedEndFor => Self::EndFor, Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone, - Self::InstrumentedCall => Self::Call, - Self::InstrumentedEndAsyncFor => Self::EndAsyncFor, - Self::InstrumentedPopIter => Self::PopIter, - Self::InstrumentedCallKw => Self::CallKw, - Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr, + Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue, + Self::InstrumentedResume => Self::Resume, + Self::InstrumentedReturnValue => Self::ReturnValue, + Self::InstrumentedYieldValue => Self::YieldValue, _ => return None, }) } @@ -763,25 +763,25 @@ impl Opcode { #[must_use] pub const fn to_instrumented(self) -> Option { Some(match self { - Self::ForIter => Self::InstrumentedForIter, - Self::YieldValue => Self::InstrumentedYieldValue, - Self::NotTaken => Self::InstrumentedNotTaken, + Self::Call => Self::InstrumentedCall, + Self::CallFunctionEx => Self::InstrumentedCallFunctionEx, + Self::CallKw => Self::InstrumentedCallKw, + Self::EndAsyncFor => Self::InstrumentedEndAsyncFor, + Self::EndFor => Self::InstrumentedEndFor, Self::EndSend => Self::InstrumentedEndSend, + Self::ForIter => Self::InstrumentedForIter, Self::JumpBackward => Self::InstrumentedJumpBackward, - Self::Resume => Self::InstrumentedResume, Self::JumpForward => Self::InstrumentedJumpForward, - Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue, - Self::ReturnValue => Self::InstrumentedReturnValue, - Self::CallFunctionEx => Self::InstrumentedCallFunctionEx, + Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr, + Self::NotTaken => Self::InstrumentedNotTaken, + Self::PopIter => Self::InstrumentedPopIter, Self::PopJumpIfFalse => Self::InstrumentedPopJumpIfFalse, Self::PopJumpIfNone => Self::InstrumentedPopJumpIfNone, - Self::EndFor => Self::InstrumentedEndFor, Self::PopJumpIfNotNone => Self::InstrumentedPopJumpIfNotNone, - Self::Call => Self::InstrumentedCall, - Self::EndAsyncFor => Self::InstrumentedEndAsyncFor, - Self::PopIter => Self::InstrumentedPopIter, - Self::CallKw => Self::InstrumentedCallKw, - Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr, + Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue, + Self::Resume => Self::InstrumentedResume, + Self::ReturnValue => Self::InstrumentedReturnValue, + Self::YieldValue => Self::InstrumentedYieldValue, _ => return None, }) } From 5f07a170eef5c48d4567ada51b5086369002567b Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 16:29:44 +0300 Subject: [PATCH 07/35] deopt --- crates/compiler-core/generate.py | 23 +++++- .../src/bytecode/instructions.rs | 80 +++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 887edb98ff3..f11b6b3c6cd 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +import collections import dataclasses import io import os @@ -229,6 +230,7 @@ def fn_to_instrumented(self) -> str: def fn_deopt(self) -> str: names = {instr.name for instr in self} + deopts = collections.defaultdict(list) for family in self.analysis.families.values(): family_name = to_pascal_case(family.name) if family_name not in names: @@ -238,9 +240,26 @@ def fn_deopt(self) -> str: if member.name == family.name: continue - print(family_name, member.name) + deopts[family_name].append(member.name) - return "" + arms = "" + for target, specialized in deopts.items(): + ops = "|".join(f"Self::{op}" for op in specialized) + arms += f"{ops} => Self::{target},\n" + + arms = arms.strip() + if not arms: + return "" + + return f""" + #[must_use] + pub const fn deopt(self) -> Option {{ + Some(match self {{ + {arms} + _ => return None, + }}) + }} + """ def __iter__(self): yield from self.instructions diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 33cbd6214c1..30f7197a69f 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -468,6 +468,86 @@ impl Opcode { } } + #[must_use] + pub const fn deopt(self) -> Option { + Some(match self { + Self::ResumeCheck => Self::Resume, + Self::LoadConstMortal | Self::LoadConstImmortal => Self::LoadConst, + Self::ToBoolAlwaysTrue + | Self::ToBoolBool + | Self::ToBoolInt + | Self::ToBoolList + | Self::ToBoolNone + | Self::ToBoolStr => Self::ToBool, + Self::BinaryOpMultiplyInt + | Self::BinaryOpAddInt + | Self::BinaryOpSubtractInt + | Self::BinaryOpMultiplyFloat + | Self::BinaryOpAddFloat + | Self::BinaryOpSubtractFloat + | Self::BinaryOpAddUnicode + | Self::BinaryOpSubscrListInt + | Self::BinaryOpSubscrListSlice + | Self::BinaryOpSubscrTupleInt + | Self::BinaryOpSubscrStrInt + | Self::BinaryOpSubscrDict + | Self::BinaryOpSubscrGetitem + | Self::BinaryOpExtend + | Self::BinaryOpInplaceAddUnicode => Self::BinaryOp, + Self::StoreSubscrDict | Self::StoreSubscrListInt => Self::StoreSubscr, + Self::SendGen => Self::Send, + Self::UnpackSequenceTwoTuple | Self::UnpackSequenceTuple | Self::UnpackSequenceList => { + Self::UnpackSequence + } + Self::StoreAttrInstanceValue | Self::StoreAttrSlot | Self::StoreAttrWithHint => { + Self::StoreAttr + } + Self::LoadGlobalModule | Self::LoadGlobalBuiltin => Self::LoadGlobal, + Self::LoadSuperAttrAttr | Self::LoadSuperAttrMethod => Self::LoadSuperAttr, + Self::LoadAttrInstanceValue + | Self::LoadAttrModule + | Self::LoadAttrWithHint + | Self::LoadAttrSlot + | Self::LoadAttrClass + | Self::LoadAttrClassWithMetaclassCheck + | Self::LoadAttrProperty + | Self::LoadAttrGetattributeOverridden + | Self::LoadAttrMethodWithValues + | Self::LoadAttrMethodNoDict + | Self::LoadAttrMethodLazyDict + | Self::LoadAttrNondescriptorWithValues + | Self::LoadAttrNondescriptorNoDict => Self::LoadAttr, + Self::CompareOpFloat | Self::CompareOpInt | Self::CompareOpStr => Self::CompareOp, + Self::ContainsOpSet | Self::ContainsOpDict => Self::ContainsOp, + Self::JumpBackwardNoJit | Self::JumpBackwardJit => Self::JumpBackward, + Self::ForIterList | Self::ForIterTuple | Self::ForIterRange | Self::ForIterGen => { + Self::ForIter + } + Self::CallBoundMethodExactArgs + | Self::CallPyExactArgs + | Self::CallType1 + | Self::CallStr1 + | Self::CallTuple1 + | Self::CallBuiltinClass + | Self::CallBuiltinO + | Self::CallBuiltinFast + | Self::CallBuiltinFastWithKeywords + | Self::CallLen + | Self::CallIsinstance + | Self::CallListAppend + | Self::CallMethodDescriptorO + | Self::CallMethodDescriptorFastWithKeywords + | Self::CallMethodDescriptorNoargs + | Self::CallMethodDescriptorFast + | Self::CallAllocAndEnterInit + | Self::CallPyGeneral + | Self::CallBoundMethodGeneral + | Self::CallNonPyGeneral => Self::Call, + Self::CallKwBoundMethod | Self::CallKwPy | Self::CallKwNonPy => Self::CallKw, + _ => return None, + }) + } + /// Does this opcode have 'HAS_ARG_FLAG' set. #[must_use] pub const fn has_arg(self) -> bool { From bea434e7e148612b8aae667907a5c7f9eb013121 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 17:38:59 +0300 Subject: [PATCH 08/35] Cache entries --- crates/compiler-core/generate.py | 35 ++++++++++++++++++- .../src/bytecode/instructions.rs | 26 ++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index f11b6b3c6cd..c1ad2d697e1 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -237,7 +237,7 @@ def fn_deopt(self) -> str: continue for member in family.members: - if member.name == family.name: + if member.name == family_name: continue deopts[family_name].append(member.name) @@ -261,6 +261,39 @@ def fn_deopt(self) -> str: }} """ + @property + def fn_cache_entries(self) -> str: + arms = "" + for instr in self: + name = instr.name + if getattr(instr, "family", None) and (instr.family.name != name): + continue + + if name.startswith("Instrumented"): + continue + + try: + size = instr.size + except AttributeError: + continue + + if size > 1: + arms += f"Self::{name} => {size - 1},\n" + + arms = arms.strip() + if not arms: + return "" + + return f""" + #[must_use] + pub const fn cache_entries(self) -> usize {{ + match self {{ + {arms} + _ => 0, + }} + }} + """ + def __iter__(self): yield from self.instructions diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 30f7197a69f..6817c335f98 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -468,6 +468,32 @@ impl Opcode { } } + #[must_use] + pub const fn cache_entries(self) -> usize { + match self { + Self::StoreSubscr => 1, + Self::ToBool => 3, + Self::BinaryOp => 5, + Self::Call => 3, + Self::CallKw => 3, + Self::CompareOp => 1, + Self::ContainsOp => 1, + Self::ForIter => 1, + Self::JumpBackward => 1, + Self::LoadAttr => 9, + Self::LoadGlobal => 4, + Self::LoadSuperAttr => 1, + Self::PopJumpIfFalse => 1, + Self::PopJumpIfNone => 1, + Self::PopJumpIfNotNone => 1, + Self::PopJumpIfTrue => 1, + Self::Send => 1, + Self::StoreAttr => 4, + Self::UnpackSequence => 1, + _ => 0, + } + } + #[must_use] pub const fn deopt(self) -> Option { Some(match self { From 8768c9f8b48c06447adb333bd9db30654b55ab8a Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 17:45:18 +0300 Subject: [PATCH 09/35] simplify --- crates/compiler-core/generate.py | 31 ++++++++----------- .../src/bytecode/instructions.rs | 17 +++++----- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index c1ad2d697e1..0e7921a0dd7 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -82,10 +82,10 @@ def fn_tryfrom_numeric(self) -> str: #[must_use] pub const fn from_{self.numeric_repr}( value: {self.numeric_repr} - ) -> Result {{ + ) -> Result {{ Ok(match value {{ {arms}, - _ => return Err(crate::MarshalError::InvalidBytecode), + _ => return Err(MarshalError::InvalidBytecode), }}) }} """ @@ -94,7 +94,7 @@ def fn_tryfrom_numeric(self) -> str: def impl_tryfrom_numeric(self) -> str: return f""" impl TryFrom<{self.numeric_repr}> for {self.name} {{ - type Error = crate::marshal::MarshalError; + type Error = MarshalError; fn try_from(value: {self.numeric_repr}) -> Result {{ Self::from_{self.numeric_repr}(value) @@ -180,18 +180,14 @@ def fn_to_base(self) -> str: if not arms: return "" - inner = f""" + return f""" + #[must_use] + pub const fn to_base(self) -> Option {{ Some(match self {{ {arms} _ => return None, }}) - """ - - return f""" - #[must_use] - pub const fn to_base(self) -> Option {{ - {inner} }} """ @@ -211,18 +207,14 @@ def fn_to_instrumented(self) -> str: if not arms: return "" - inner = f""" + return f""" + #[must_use] + pub const fn to_instrumented(self) -> Option {{ Some(match self {{ {arms} _ => return None, }}) - """ - - return f""" - #[must_use] - pub const fn to_instrumented(self) -> Option {{ - {inner} }} """ @@ -361,7 +353,10 @@ def main(): // This file is generated by {script_path} // Do not edit! -use crate::bytecode::Arg; +use crate::{{ + bytecode::{{instruction::StackEffect, oparg::Arg}}, + marshal::MarshalError, +}}; {generated} """ diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 6817c335f98..b9d244ba19c 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -1,7 +1,10 @@ // This file is generated by crates/compiler-core/generate.py // Do not edit! -use crate::bytecode::Arg; +use crate::{ + bytecode::{instruction::StackEffect, oparg::Arg}, + marshal::MarshalError, +}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Opcode { @@ -893,7 +896,7 @@ impl Opcode { } #[must_use] - pub const fn from_u8(value: u8) -> Result { + pub const fn from_u8(value: u8) -> Result { Ok(match value { 0 => Self::Cache, 1 => Self::BinarySlice, @@ -1122,7 +1125,7 @@ impl Opcode { 253 => Self::InstrumentedJumpBackward, 254 => Self::InstrumentedLine, 255 => Self::EnterExecutor, - _ => return Err(crate::MarshalError::InvalidBytecode), + _ => return Err(MarshalError::InvalidBytecode), }) } } @@ -1134,7 +1137,7 @@ impl From for u8 { } impl TryFrom for Opcode { - type Error = crate::marshal::MarshalError; + type Error = MarshalError; fn try_from(value: u8) -> Result { Self::from_u8(value) @@ -1236,7 +1239,7 @@ impl PseudoOpcode { } #[must_use] - pub const fn from_u16(value: u16) -> Result { + pub const fn from_u16(value: u16) -> Result { Ok(match value { 256 => Self::AnnotationsPlaceholder, 257 => Self::Jump, @@ -1249,7 +1252,7 @@ impl PseudoOpcode { 264 => Self::SetupFinally, 265 => Self::SetupWith, 266 => Self::StoreFastMaybeNull, - _ => return Err(crate::MarshalError::InvalidBytecode), + _ => return Err(MarshalError::InvalidBytecode), }) } } @@ -1261,7 +1264,7 @@ impl From for u16 { } impl TryFrom for PseudoOpcode { - type Error = crate::marshal::MarshalError; + type Error = MarshalError; fn try_from(value: u16) -> Result { Self::from_u16(value) From b9f1941b5e3b0a88968b17ef1a2d6aaded41b1a3 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Tue, 5 May 2026 18:09:48 +0300 Subject: [PATCH 10/35] stack effect --- crates/compiler-core/generate.py | 31 ++ .../src/bytecode/instructions.rs | 266 ++++++++++++++++++ 2 files changed, 297 insertions(+) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 0e7921a0dd7..634e9b178ae 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -26,6 +26,7 @@ import analyzer from generators_common import DEFAULT_INPUT +from stack import get_stack_effect @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) @@ -286,6 +287,36 @@ def fn_cache_entries(self) -> str: }} """ + @property + def fn_stack_effect(self) -> str: + arms = "" + for instr in self: + stack = get_stack_effect(instr) + popped = (-stack.base_offset).to_c() + pushed = (stack.logical_sp - stack.base_offset).to_c() + + name = instr.name + arms += f"Self::{name} => ({pushed}, {popped}),\n" + + arms = arms.strip() + + return f""" + fn stack_effect_info(&self, oparg: u32) -> StackEffect {{ + // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)` + // that causes underflow errors. + let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`"); + + let (pushed, popped) = match self {{ + {arms} + }}; + + debug_assert!(u32::try_from(pushed).is_ok()); + debug_assert!(u32::try_from(popped).is_ok()); + + StackEffect::new(pushed as u32, popped as u32) + }} + """ + def __iter__(self): yield from self.instructions diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index b9d244ba19c..7a2dca85be5 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -843,6 +843,247 @@ impl Opcode { ) } + fn stack_effect_info(&self, oparg: u32) -> StackEffect { + // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)` + // that causes underflow errors. + let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`"); + + let (pushed, popped) = match self { + Self::Cache => (0, 0), + Self::BinarySlice => (1, 3), + Self::BuildTemplate => (1, 2), + Self::BinaryOpInplaceAddUnicode => (0, 2), + Self::CallFunctionEx => (1, 4), + Self::CheckEgMatch => (2, 2), + Self::CheckExcMatch => (2, 2), + Self::CleanupThrow => (2, 3), + Self::DeleteSubscr => (0, 2), + Self::EndFor => (0, 1), + Self::EndSend => (1, 2), + Self::ExitInitCheck => (0, 1), + Self::FormatSimple => (1, 1), + Self::FormatWithSpec => (1, 2), + Self::GetAiter => (1, 1), + Self::GetAnext => (2, 1), + Self::GetIter => (1, 1), + Self::Reserved => (0, 0), + Self::GetLen => (2, 1), + Self::GetYieldFromIter => (1, 1), + Self::InterpreterExit => (0, 1), + Self::LoadBuildClass => (1, 0), + Self::LoadLocals => (1, 0), + Self::MakeFunction => (1, 1), + Self::MatchKeys => (3, 2), + Self::MatchMapping => (2, 1), + Self::MatchSequence => (2, 1), + Self::Nop => (0, 0), + Self::NotTaken => (0, 0), + Self::PopExcept => (0, 1), + Self::PopIter => (0, 1), + Self::PopTop => (0, 1), + Self::PushExcInfo => (2, 1), + Self::PushNull => (1, 0), + Self::ReturnGenerator => (1, 0), + Self::ReturnValue => (1, 1), + Self::SetupAnnotations => (0, 0), + Self::StoreSlice => (0, 4), + Self::StoreSubscr => (0, 3), + Self::ToBool => (1, 1), + Self::UnaryInvert => (1, 1), + Self::UnaryNegative => (1, 1), + Self::UnaryNot => (1, 1), + Self::WithExceptStart => (6, 5), + Self::BinaryOp => (1, 2), + Self::BuildInterpolation => (1, 2 + (oparg & 1)), + Self::BuildList => (1, oparg), + Self::BuildMap => (1, oparg * 2), + Self::BuildSet => (1, oparg), + Self::BuildSlice => (1, oparg), + Self::BuildString => (1, oparg), + Self::BuildTuple => (1, oparg), + Self::Call => (1, 2 + oparg), + Self::CallIntrinsic1 => (1, 1), + Self::CallIntrinsic2 => (1, 2), + Self::CallKw => (1, 3 + oparg), + Self::CompareOp => (1, 2), + Self::ContainsOp => (1, 2), + Self::ConvertValue => (1, 1), + Self::Copy => (2 + (oparg - 1), 1 + (oparg - 1)), + Self::CopyFreeVars => (0, 0), + Self::DeleteAttr => (0, 1), + Self::DeleteDeref => (0, 0), + Self::DeleteFast => (0, 0), + Self::DeleteGlobal => (0, 0), + Self::DeleteName => (0, 0), + Self::DictMerge => (4 + (oparg - 1), 5 + (oparg - 1)), + Self::DictUpdate => (1 + (oparg - 1), 2 + (oparg - 1)), + Self::EndAsyncFor => (0, 2), + Self::ExtendedArg => (0, 0), + Self::ForIter => (2, 1), + Self::GetAwaitable => (1, 1), + Self::ImportFrom => (2, 1), + Self::ImportName => (1, 2), + Self::IsOp => (1, 2), + Self::JumpBackward => (0, 0), + Self::JumpBackwardNoInterrupt => (0, 0), + Self::JumpForward => (0, 0), + Self::ListAppend => (1 + (oparg - 1), 2 + (oparg - 1)), + Self::ListExtend => (1 + (oparg - 1), 2 + (oparg - 1)), + Self::LoadAttr => (1 + (oparg & 1), 1), + Self::LoadCommonConstant => (1, 0), + Self::LoadConst => (1, 0), + Self::LoadDeref => (1, 0), + Self::LoadFast => (1, 0), + Self::LoadFastAndClear => (1, 0), + Self::LoadFastBorrow => (1, 0), + Self::LoadFastBorrowLoadFastBorrow => (2, 0), + Self::LoadFastCheck => (1, 0), + Self::LoadFastLoadFast => (2, 0), + Self::LoadFromDictOrDeref => (1, 1), + Self::LoadFromDictOrGlobals => (1, 1), + Self::LoadGlobal => (1 + (oparg & 1), 0), + Self::LoadName => (1, 0), + Self::LoadSmallInt => (1, 0), + Self::LoadSpecial => (2, 1), + Self::LoadSuperAttr => (1 + (oparg & 1), 3), + Self::MakeCell => (0, 0), + Self::MapAdd => (1 + (oparg - 1), 3 + (oparg - 1)), + Self::MatchClass => (1, 3), + Self::PopJumpIfFalse => (0, 1), + Self::PopJumpIfNone => (0, 1), + Self::PopJumpIfNotNone => (0, 1), + Self::PopJumpIfTrue => (0, 1), + Self::RaiseVarargs => (0, oparg), + Self::Reraise => (oparg, 1 + oparg), + Self::Send => (2, 2), + Self::SetAdd => (1 + (oparg - 1), 2 + (oparg - 1)), + Self::SetFunctionAttribute => (1, 2), + Self::SetUpdate => (1 + (oparg - 1), 2 + (oparg - 1)), + Self::StoreAttr => (0, 2), + Self::StoreDeref => (0, 1), + Self::StoreFast => (0, 1), + Self::StoreFastLoadFast => (1, 1), + Self::StoreFastStoreFast => (0, 2), + Self::StoreGlobal => (0, 1), + Self::StoreName => (0, 1), + Self::Swap => (2 + (oparg - 2), 2 + (oparg - 2)), + Self::UnpackEx => (1 + (oparg & 0xFF) + (oparg >> 8), 1), + Self::UnpackSequence => (oparg, 1), + Self::YieldValue => (1, 1), + Self::Resume => (0, 0), + Self::BinaryOpAddFloat => (1, 2), + Self::BinaryOpAddInt => (1, 2), + Self::BinaryOpAddUnicode => (1, 2), + Self::BinaryOpExtend => (1, 2), + Self::BinaryOpMultiplyFloat => (1, 2), + Self::BinaryOpMultiplyInt => (1, 2), + Self::BinaryOpSubscrDict => (1, 2), + Self::BinaryOpSubscrGetitem => (0, 2), + Self::BinaryOpSubscrListInt => (1, 2), + Self::BinaryOpSubscrListSlice => (1, 2), + Self::BinaryOpSubscrStrInt => (1, 2), + Self::BinaryOpSubscrTupleInt => (1, 2), + Self::BinaryOpSubtractFloat => (1, 2), + Self::BinaryOpSubtractInt => (1, 2), + Self::CallAllocAndEnterInit => (0, 2 + oparg), + Self::CallBoundMethodExactArgs => (0, 2 + oparg), + Self::CallBoundMethodGeneral => (0, 2 + oparg), + Self::CallBuiltinClass => (1, 2 + oparg), + Self::CallBuiltinFast => (1, 2 + oparg), + Self::CallBuiltinFastWithKeywords => (1, 2 + oparg), + Self::CallBuiltinO => (1, 2 + oparg), + Self::CallIsinstance => (1, 2 + oparg), + Self::CallKwBoundMethod => (0, 3 + oparg), + Self::CallKwNonPy => (1, 3 + oparg), + Self::CallKwPy => (0, 3 + oparg), + Self::CallLen => (1, 3), + Self::CallListAppend => (0, 3), + Self::CallMethodDescriptorFast => (1, 2 + oparg), + Self::CallMethodDescriptorFastWithKeywords => (1, 2 + oparg), + Self::CallMethodDescriptorNoargs => (1, 2 + oparg), + Self::CallMethodDescriptorO => (1, 2 + oparg), + Self::CallNonPyGeneral => (1, 2 + oparg), + Self::CallPyExactArgs => (0, 2 + oparg), + Self::CallPyGeneral => (0, 2 + oparg), + Self::CallStr1 => (1, 3), + Self::CallTuple1 => (1, 3), + Self::CallType1 => (1, 3), + Self::CompareOpFloat => (1, 2), + Self::CompareOpInt => (1, 2), + Self::CompareOpStr => (1, 2), + Self::ContainsOpDict => (1, 2), + Self::ContainsOpSet => (1, 2), + Self::ForIterGen => (1, 1), + Self::ForIterList => (2, 1), + Self::ForIterRange => (2, 1), + Self::ForIterTuple => (2, 1), + Self::JumpBackwardJit => (0, 0), + Self::JumpBackwardNoJit => (0, 0), + Self::LoadAttrClass => (1 + (oparg & 1), 1), + Self::LoadAttrClassWithMetaclassCheck => (1 + (oparg & 1), 1), + Self::LoadAttrGetattributeOverridden => (1, 1), + Self::LoadAttrInstanceValue => (1 + (oparg & 1), 1), + Self::LoadAttrMethodLazyDict => (2, 1), + Self::LoadAttrMethodNoDict => (2, 1), + Self::LoadAttrMethodWithValues => (2, 1), + Self::LoadAttrModule => (1 + (oparg & 1), 1), + Self::LoadAttrNondescriptorNoDict => (1, 1), + Self::LoadAttrNondescriptorWithValues => (1, 1), + Self::LoadAttrProperty => (0, 1), + Self::LoadAttrSlot => (1 + (oparg & 1), 1), + Self::LoadAttrWithHint => (1 + (oparg & 1), 1), + Self::LoadConstImmortal => (1, 0), + Self::LoadConstMortal => (1, 0), + Self::LoadGlobalBuiltin => (1 + (oparg & 1), 0), + Self::LoadGlobalModule => (1 + (oparg & 1), 0), + Self::LoadSuperAttrAttr => (1, 3), + Self::LoadSuperAttrMethod => (2, 3), + Self::ResumeCheck => (0, 0), + Self::SendGen => (1, 2), + Self::StoreAttrInstanceValue => (0, 2), + Self::StoreAttrSlot => (0, 2), + Self::StoreAttrWithHint => (0, 2), + Self::StoreSubscrDict => (0, 3), + Self::StoreSubscrListInt => (0, 3), + Self::ToBoolAlwaysTrue => (1, 1), + Self::ToBoolBool => (1, 1), + Self::ToBoolInt => (1, 1), + Self::ToBoolList => (1, 1), + Self::ToBoolNone => (1, 1), + Self::ToBoolStr => (1, 1), + Self::UnpackSequenceList => (oparg, 1), + Self::UnpackSequenceTuple => (oparg, 1), + Self::UnpackSequenceTwoTuple => (2, 1), + Self::InstrumentedEndFor => (1, 2), + Self::InstrumentedPopIter => (0, 1), + Self::InstrumentedEndSend => (1, 2), + Self::InstrumentedForIter => (2, 1), + Self::InstrumentedInstruction => (0, 0), + Self::InstrumentedJumpForward => (0, 0), + Self::InstrumentedNotTaken => (0, 0), + Self::InstrumentedPopJumpIfTrue => (0, 1), + Self::InstrumentedPopJumpIfFalse => (0, 1), + Self::InstrumentedPopJumpIfNone => (0, 1), + Self::InstrumentedPopJumpIfNotNone => (0, 1), + Self::InstrumentedResume => (0, 0), + Self::InstrumentedReturnValue => (1, 1), + Self::InstrumentedYieldValue => (1, 1), + Self::InstrumentedEndAsyncFor => (0, 2), + Self::InstrumentedLoadSuperAttr => (1 + (oparg & 1), 3), + Self::InstrumentedCall => (1, 2 + oparg), + Self::InstrumentedCallKw => (1, 3 + oparg), + Self::InstrumentedCallFunctionEx => (1, 4), + Self::InstrumentedJumpBackward => (0, 0), + Self::InstrumentedLine => (0, 0), + Self::EnterExecutor => (0, 0), + }; + + debug_assert!(u32::try_from(pushed).is_ok()); + debug_assert!(u32::try_from(popped).is_ok()); + + StackEffect::new(pushed as u32, popped as u32) + } + #[must_use] pub const fn to_base(self) -> Option { Some(match self { @@ -1238,6 +1479,31 @@ impl PseudoOpcode { false } + fn stack_effect_info(&self, oparg: u32) -> StackEffect { + // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)` + // that causes underflow errors. + let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`"); + + let (pushed, popped) = match self { + Self::AnnotationsPlaceholder => (0, 0), + Self::Jump => (0, 0), + Self::JumpIfFalse => (1, 1), + Self::JumpIfTrue => (1, 1), + Self::JumpNoInterrupt => (0, 0), + Self::LoadClosure => (1, 0), + Self::PopBlock => (0, 0), + Self::SetupCleanup => (2, 0), + Self::SetupFinally => (1, 0), + Self::SetupWith => (1, 0), + Self::StoreFastMaybeNull => (0, 1), + }; + + debug_assert!(u32::try_from(pushed).is_ok()); + debug_assert!(u32::try_from(popped).is_ok()); + + StackEffect::new(pushed as u32, popped as u32) + } + #[must_use] pub const fn from_u16(value: u16) -> Result { Ok(match value { From 566c0cf35beb12efb4c9cdffe40993de16cd1e09 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Wed, 6 May 2026 11:54:41 +0300 Subject: [PATCH 11/35] Simplify conf structure --- crates/compiler-core/generate.py | 12 ++++-------- crates/compiler-core/opcode.toml | 19 +++++++++---------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 634e9b178ae..7b9c92a2610 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -342,13 +342,9 @@ def main(): analysis = get_analysis() - opcodes_conf = CONF["Opcodes"] - instructions_conf = CONF["Instructions"] - outfile = io.StringIO() - for key, conf in opcodes_conf.items(): - opcode_enum_name = conf["opcode_enum_name"] - numeric_repr = conf["numeric_repr"] + for opcode_enum_name, conf in CONF.items(): + size = conf["size"] opcode_range = conf["range"] lower, upper = map(int, (opcode_range["min"], opcode_range["max"])) @@ -369,7 +365,7 @@ def main(): code = OpcodeGen( name=opcode_enum_name, instructions=instructions, - numeric_repr=numeric_repr, + numeric_repr=size, analysis=analysis, ).gen() @@ -386,7 +382,7 @@ def main(): use crate::{{ bytecode::{{instruction::StackEffect, oparg::Arg}}, - marshal::MarshalError, + marshal::MarshalError, }}; {generated} diff --git a/crates/compiler-core/opcode.toml b/crates/compiler-core/opcode.toml index db3e1b4f6bf..8b0b3aac6a4 100644 --- a/crates/compiler-core/opcode.toml +++ b/crates/compiler-core/opcode.toml @@ -1,14 +1,13 @@ -[Opcodes.real] -opcode_enum_name = "Opcode" -instruction_enum_name = "Instruction" -numeric_repr = "u8" +[Opcode] +instruction_enum = "Instruction" +size = "u8" range = { min = 0, max = 255 } -[Opcodes.pseudo] -opcode_enum_name = "PseudoOpcode" -instruction_enum_name = "PseudoInstruction" -numeric_repr = "u16" +[Opcode.opcodes.ContainsOp] +oparg = { name = "invert", type = "oparg::Invert" } + +[PseudoOpcode] +instruction_enum = "PseudoInstruction" +size = "u16" range = { min = 256, max = 65535 } -[Instructions.real.ContainsOp] -oparg = { name = "invert", type = "oparg::Invert" } From 0b933783302d01a81d3f7c2cd16ba241cf363e98 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Wed, 6 May 2026 12:25:22 +0300 Subject: [PATCH 12/35] Switch to numeric_repr --- crates/compiler-core/generate.py | 43 ++++++++++++++++++++++++++++++-- crates/compiler-core/opcode.toml | 4 +-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 7b9c92a2610..472199af9d8 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -321,6 +321,45 @@ def __iter__(self): yield from self.instructions +@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) +class InstructioneGen: + name: str + instructions: list + numeric_repr: str + analysis: analyzer.Analysis + + def gen(self) -> str: + variants = ",\n".join(instr.name for instr in self) + + methods = "\n\n".join( + getattr(self, attr).strip() + for attr in sorted(dir(self)) + if attr.startswith("fn_") + ) + + impls = "\n\n".join( + getattr(self, attr).strip() + for attr in sorted(dir(self)) + if attr.startswith("impl_") + ) + + return f""" + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum {self.name} {{ + {variants} + }} + + impl {self.name} {{ + {methods} + }} + + {impls} + """ + + def __iter__(self): + yield from self.instructions + + def to_pascal_case(s: str) -> str: return s.title().replace("_", "") @@ -344,7 +383,7 @@ def main(): outfile = io.StringIO() for opcode_enum_name, conf in CONF.items(): - size = conf["size"] + numeric_repr = conf["numeric_repr"] opcode_range = conf["range"] lower, upper = map(int, (opcode_range["min"], opcode_range["max"])) @@ -365,7 +404,7 @@ def main(): code = OpcodeGen( name=opcode_enum_name, instructions=instructions, - numeric_repr=size, + numeric_repr=numeric_repr, analysis=analysis, ).gen() diff --git a/crates/compiler-core/opcode.toml b/crates/compiler-core/opcode.toml index 8b0b3aac6a4..2b44a553f1e 100644 --- a/crates/compiler-core/opcode.toml +++ b/crates/compiler-core/opcode.toml @@ -1,6 +1,6 @@ [Opcode] instruction_enum = "Instruction" -size = "u8" +numeric_repr = "u8" range = { min = 0, max = 255 } [Opcode.opcodes.ContainsOp] @@ -8,6 +8,6 @@ oparg = { name = "invert", type = "oparg::Invert" } [PseudoOpcode] instruction_enum = "PseudoInstruction" -size = "u16" +numeric_repr = "u16" range = { min = 256, max = 65535 } From 9ff0a7a3eeabaee4202df2a5537bf4bccd118a47 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Wed, 6 May 2026 14:24:45 +0300 Subject: [PATCH 13/35] Add oparg conf --- crates/compiler-core/opcode.toml | 251 +++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/crates/compiler-core/opcode.toml b/crates/compiler-core/opcode.toml index 2b44a553f1e..04d86283f2f 100644 --- a/crates/compiler-core/opcode.toml +++ b/crates/compiler-core/opcode.toml @@ -3,11 +3,262 @@ instruction_enum = "Instruction" numeric_repr = "u8" range = { min = 0, max = 255 } +[Opcode.opcodes.BinaryOp] +oparg = { name = "op", type = "oparg::BinaryOperator" } + +[Opcode.opcodes.BuildInterpolation] +oparg = { name = "format", type = "u32" } + +[Opcode.opcodes.BuildList] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.BuildMap] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.BuildSet] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.BuildSlice] +oparg = { name = "argc", type = "oparg::BuildSliceArgCount" } + +[Opcode.opcodes.BuildString] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.BuildTuple] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.Call] +oparg = { name = "argc", type = "u32" } + +[Opcode.opcodes.CallIntrinsic1] +oparg = { name = "func", type = "oparg::IntrinsicFunction1" } + +[Opcode.opcodes.CallIntrinsic2] +oparg = { name = "func", type = "oparg::IntrinsicFunction2" } + +[Opcode.opcodes.CallKw] +oparg = { name = "argc", type = "u32" } + +[Opcode.opcodes.CompareOp] +oparg = { name = "opname", type = "oparg::ComparisonOperator" } + [Opcode.opcodes.ContainsOp] oparg = { name = "invert", type = "oparg::Invert" } +[Opcode.opcodes.ConvertValue] +oparg = { name = "oparg", type = "oparg::ConvertValueOparg" } + +[Opcode.opcodes.Copy] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.CopyFreeVars] +oparg = { name = "n", type = "u32" } + +[Opcode.opcodes.DeleteAttr] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.DeleteDeref] +oparg = { name = "i", type = "oparg::VarNum" } + +[Opcode.opcodes.DeleteFast] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.DeleteGlobal] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.DeleteName] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.DictMerge] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.DictUpdate] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.ForIter] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.GetAwaitable] +oparg = { name = "r#where", type = "u32" } + +[Opcode.opcodes.ImportFrom] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.ImportName] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.IsOp] +oparg = { name = "invert", type = "oparg::Invert" } + +[Opcode.opcodes.JumpBackward] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.JumpBackwardNoInterrupt] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.JumpForward] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.ListAppend] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.ListExtend] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.LoadAttr] +oparg = { name = "namei", type = "oparg::LoadAttr" } + +[Opcode.opcodes.LoadCommonConstant] +oparg = { name = "idx", type = "oparg::CommonConstant" } + +[Opcode.opcodes.LoadConst] +oparg = { name = "consti", type = "oparg::ConstIdx" } + +[Opcode.opcodes.LoadDeref] +oparg = { name = "i", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFast] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFastAndClear] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFastBorrow] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFastBorrowLoadFastBorrow] +oparg = { name = "var_nums", type = "oparg::VarNums" } + +[Opcode.opcodes.LoadFastCheck] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFastLoadFast] +oparg = { name = "var_nums", type = "oparg::VarNums" } + +[Opcode.opcodes.LoadFromDictOrDeref] +oparg = { name = "i", type = "oparg::VarNum" } + +[Opcode.opcodes.LoadFromDictOrGlobals] +oparg = { name = "i", type = "oparg::NameIdx" } + +[Opcode.opcodes.LoadGlobal] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.LoadName] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.LoadSmallInt] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.LoadSpecial] +oparg = { name = "method", type = "oparg::SpecialMethod" } + +[Opcode.opcodes.LoadSuperAttr] +oparg = { name = "namei", type = "oparg::LoadSuperAttr" } + +[Opcode.opcodes.MakeCell] +oparg = { name = "i", type = "oparg::VarNum" } + +[Opcode.opcodes.MapAdd] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.MatchClass] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.PopJumpIfFalse] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.PopJumpIfNone] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.PopJumpIfNotNone] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.PopJumpIfTrue] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.RaiseVarargs] +oparg = { name = "argc", type = "oparg::RaiseKind" } + +[Opcode.opcodes.Reraise] +oparg = { name = "depth", type = "u32" } + +[Opcode.opcodes.Send] +oparg = { name = "delta", type = "oparg::Label" } + +[Opcode.opcodes.SetAdd] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.SetFunctionAttribute] +oparg = { name = "flag", type = "oparg::MakeFunctionFlag" } + +[Opcode.opcodes.SetUpdate] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.StoreAttr] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.StoreDeref] +oparg = { name = "i", type = "oparg::VarNum" } + +[Opcode.opcodes.StoreFast] +oparg = { name = "var_num", type = "oparg::VarNum" } + +[Opcode.opcodes.StoreFastLoadFast] +oparg = { name = "var_nums", type = "oparg::VarNums" } + +[Opcode.opcodes.StoreFastStoreFast] +oparg = { name = "var_nums", type = "oparg::VarNums" } + +[Opcode.opcodes.StoreGlobal] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.StoreName] +oparg = { name = "namei", type = "oparg::NameIdx" } + +[Opcode.opcodes.Swap] +oparg = { name = "i", type = "u32" } + +[Opcode.opcodes.UnpackEx] +oparg = { name = "counts", type = "oparg::UnpackExArgs" } + +[Opcode.opcodes.UnpackSequence] +oparg = { name = "count", type = "u32" } + +[Opcode.opcodes.YieldValue] +oparg = { name = "arg", type = "u32" } + +[Opcode.opcodes.Resume] +oparg = { name = "context", type = "oparg::ResumeContext" } + [PseudoOpcode] instruction_enum = "PseudoInstruction" numeric_repr = "u16" range = { min = 256, max = 65535 } +[PseudoOpcode.opcodes.Jump] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.JumpIfFalse] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.JumpIfTrue] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.JumpNoInterrupt] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.LoadClosure] +oparg = { name = "i", type = "oparg::NameIdx" } + +[PseudoOpcode.opcodes.SetupCleanup] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.SetupFinally] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.SetupWith] +oparg = { name = "delta", type = "oparg::Label" } + +[PseudoOpcode.opcodes.StoreFastMaybeNull] +oparg = { name = "var_num", type = "oparg::NameIdx" } From 9c7471547c238237282be5174c16e793f231d22f Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Wed, 6 May 2026 15:55:59 +0300 Subject: [PATCH 14/35] `as_opcode()` --- crates/compiler-core/generate.py | 64 +- .../src/bytecode/instructions.rs | 658 ++++++++++++++++++ 2 files changed, 713 insertions(+), 9 deletions(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index 472199af9d8..bcf705dc236 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -37,8 +37,6 @@ class OpcodeGen: analysis: analyzer.Analysis def gen(self) -> str: - variants = ",\n".join(instr.name for instr in self) - methods = "\n\n".join( getattr(self, attr).strip() for attr in sorted(dir(self)) @@ -51,6 +49,8 @@ def gen(self) -> str: if attr.startswith("impl_") ) + variants = ",\n".join(instr.name for instr in self) + return f""" #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum {self.name} {{ @@ -324,13 +324,12 @@ def __iter__(self): @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class InstructioneGen: name: str + opcode_enum: str instructions: list numeric_repr: str - analysis: analyzer.Analysis + metadata: dict[str, str] def gen(self) -> str: - variants = ",\n".join(instr.name for instr in self) - methods = "\n\n".join( getattr(self, attr).strip() for attr in sorted(dir(self)) @@ -343,8 +342,22 @@ def gen(self) -> str: if attr.startswith("impl_") ) + variants = "" + for instr in self: + name = instr.name + variants += name + + if oparg := self.metadata.get(name, {}).get("oparg"): + oname, otype = oparg["name"], oparg["type"] + + variants += f"{{ {oname}: Arg<{otype}> }}" + + opcode = instr.opcode + variants += f" = {opcode},\n" + return f""" #[derive(Clone, Copy, Debug, Eq, PartialEq)] + #[repr({self.numeric_repr})] // TODO: Remove this `#[repr(...)]` pub enum {self.name} {{ {variants} }} @@ -356,6 +369,27 @@ def gen(self) -> str: {impls} """ + @property + def fn_as_opcode(self) -> str: + arms = "" + for instr in self: + name = instr.name + arms += f"Self::{name}" + if oparg := self.metadata.get(name, {}).get("oparg"): + arms += " { .. }" + + arms += f"=> {self.opcode_enum}::{name},\n" + + return f""" + /// Returns self as a [`{self.opcode_enum}`]. + #[must_use] + pub const fn as_opcode(self) -> {self.opcode_enum} {{ + match self {{ + {arms} + }} + }} + """ + def __iter__(self): yield from self.instructions @@ -382,8 +416,10 @@ def main(): analysis = get_analysis() outfile = io.StringIO() - for opcode_enum_name, conf in CONF.items(): + for opcode_enum, conf in CONF.items(): + metadata = conf["opcodes"] numeric_repr = conf["numeric_repr"] + instruction_enum = conf["instruction_enum"] opcode_range = conf["range"] lower, upper = map(int, (opcode_range["min"], opcode_range["max"])) @@ -401,14 +437,24 @@ def main(): for instr in instructions: instr.name = to_pascal_case(instr.name) - code = OpcodeGen( - name=opcode_enum_name, + opcode_code = OpcodeGen( + name=opcode_enum, instructions=instructions, numeric_repr=numeric_repr, analysis=analysis, ).gen() - outfile.write(code) + outfile.write(opcode_code) + + instruction_code = InstructioneGen( + name=instruction_enum, + opcode_enum=opcode_enum, + instructions=instructions, + numeric_repr=numeric_repr, + metadata=metadata, + ).gen() + + outfile.write(instruction_code) generated = outfile.getvalue() diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index 7a2dca85be5..f17cdd8bd34 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -1385,6 +1385,628 @@ impl TryFrom for Opcode { } } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u8)] // TODO: Remove this `#[repr(...)]` +pub enum Instruction { + Cache = 0, + BinarySlice = 1, + BuildTemplate = 2, + BinaryOpInplaceAddUnicode = 3, + CallFunctionEx = 4, + CheckEgMatch = 5, + CheckExcMatch = 6, + CleanupThrow = 7, + DeleteSubscr = 8, + EndFor = 9, + EndSend = 10, + ExitInitCheck = 11, + FormatSimple = 12, + FormatWithSpec = 13, + GetAiter = 14, + GetAnext = 15, + GetIter = 16, + Reserved = 17, + GetLen = 18, + GetYieldFromIter = 19, + InterpreterExit = 20, + LoadBuildClass = 21, + LoadLocals = 22, + MakeFunction = 23, + MatchKeys = 24, + MatchMapping = 25, + MatchSequence = 26, + Nop = 27, + NotTaken = 28, + PopExcept = 29, + PopIter = 30, + PopTop = 31, + PushExcInfo = 32, + PushNull = 33, + ReturnGenerator = 34, + ReturnValue = 35, + SetupAnnotations = 36, + StoreSlice = 37, + StoreSubscr = 38, + ToBool = 39, + UnaryInvert = 40, + UnaryNegative = 41, + UnaryNot = 42, + WithExceptStart = 43, + BinaryOp { + op: Arg, + } = 44, + BuildInterpolation { + format: Arg, + } = 45, + BuildList { + count: Arg, + } = 46, + BuildMap { + count: Arg, + } = 47, + BuildSet { + count: Arg, + } = 48, + BuildSlice { + argc: Arg, + } = 49, + BuildString { + count: Arg, + } = 50, + BuildTuple { + count: Arg, + } = 51, + Call { + argc: Arg, + } = 52, + CallIntrinsic1 { + func: Arg, + } = 53, + CallIntrinsic2 { + func: Arg, + } = 54, + CallKw { + argc: Arg, + } = 55, + CompareOp { + opname: Arg, + } = 56, + ContainsOp { + invert: Arg, + } = 57, + ConvertValue { + oparg: Arg, + } = 58, + Copy { + i: Arg, + } = 59, + CopyFreeVars { + n: Arg, + } = 60, + DeleteAttr { + namei: Arg, + } = 61, + DeleteDeref { + i: Arg, + } = 62, + DeleteFast { + var_num: Arg, + } = 63, + DeleteGlobal { + namei: Arg, + } = 64, + DeleteName { + namei: Arg, + } = 65, + DictMerge { + i: Arg, + } = 66, + DictUpdate { + i: Arg, + } = 67, + EndAsyncFor = 68, + ExtendedArg = 69, + ForIter { + delta: Arg, + } = 70, + GetAwaitable { + r#where: Arg, + } = 71, + ImportFrom { + namei: Arg, + } = 72, + ImportName { + namei: Arg, + } = 73, + IsOp { + invert: Arg, + } = 74, + JumpBackward { + delta: Arg, + } = 75, + JumpBackwardNoInterrupt { + delta: Arg, + } = 76, + JumpForward { + delta: Arg, + } = 77, + ListAppend { + i: Arg, + } = 78, + ListExtend { + i: Arg, + } = 79, + LoadAttr { + namei: Arg, + } = 80, + LoadCommonConstant { + idx: Arg, + } = 81, + LoadConst { + consti: Arg, + } = 82, + LoadDeref { + i: Arg, + } = 83, + LoadFast { + var_num: Arg, + } = 84, + LoadFastAndClear { + var_num: Arg, + } = 85, + LoadFastBorrow { + var_num: Arg, + } = 86, + LoadFastBorrowLoadFastBorrow { + var_nums: Arg, + } = 87, + LoadFastCheck { + var_num: Arg, + } = 88, + LoadFastLoadFast { + var_nums: Arg, + } = 89, + LoadFromDictOrDeref { + i: Arg, + } = 90, + LoadFromDictOrGlobals { + i: Arg, + } = 91, + LoadGlobal { + namei: Arg, + } = 92, + LoadName { + namei: Arg, + } = 93, + LoadSmallInt { + i: Arg, + } = 94, + LoadSpecial { + method: Arg, + } = 95, + LoadSuperAttr { + namei: Arg, + } = 96, + MakeCell { + i: Arg, + } = 97, + MapAdd { + i: Arg, + } = 98, + MatchClass { + count: Arg, + } = 99, + PopJumpIfFalse { + delta: Arg, + } = 100, + PopJumpIfNone { + delta: Arg, + } = 101, + PopJumpIfNotNone { + delta: Arg, + } = 102, + PopJumpIfTrue { + delta: Arg, + } = 103, + RaiseVarargs { + argc: Arg, + } = 104, + Reraise { + depth: Arg, + } = 105, + Send { + delta: Arg, + } = 106, + SetAdd { + i: Arg, + } = 107, + SetFunctionAttribute { + flag: Arg, + } = 108, + SetUpdate { + i: Arg, + } = 109, + StoreAttr { + namei: Arg, + } = 110, + StoreDeref { + i: Arg, + } = 111, + StoreFast { + var_num: Arg, + } = 112, + StoreFastLoadFast { + var_nums: Arg, + } = 113, + StoreFastStoreFast { + var_nums: Arg, + } = 114, + StoreGlobal { + namei: Arg, + } = 115, + StoreName { + namei: Arg, + } = 116, + Swap { + i: Arg, + } = 117, + UnpackEx { + counts: Arg, + } = 118, + UnpackSequence { + count: Arg, + } = 119, + YieldValue { + arg: Arg, + } = 120, + Resume { + context: Arg, + } = 128, + BinaryOpAddFloat = 129, + BinaryOpAddInt = 130, + BinaryOpAddUnicode = 131, + BinaryOpExtend = 132, + BinaryOpMultiplyFloat = 133, + BinaryOpMultiplyInt = 134, + BinaryOpSubscrDict = 135, + BinaryOpSubscrGetitem = 136, + BinaryOpSubscrListInt = 137, + BinaryOpSubscrListSlice = 138, + BinaryOpSubscrStrInt = 139, + BinaryOpSubscrTupleInt = 140, + BinaryOpSubtractFloat = 141, + BinaryOpSubtractInt = 142, + CallAllocAndEnterInit = 143, + CallBoundMethodExactArgs = 144, + CallBoundMethodGeneral = 145, + CallBuiltinClass = 146, + CallBuiltinFast = 147, + CallBuiltinFastWithKeywords = 148, + CallBuiltinO = 149, + CallIsinstance = 150, + CallKwBoundMethod = 151, + CallKwNonPy = 152, + CallKwPy = 153, + CallLen = 154, + CallListAppend = 155, + CallMethodDescriptorFast = 156, + CallMethodDescriptorFastWithKeywords = 157, + CallMethodDescriptorNoargs = 158, + CallMethodDescriptorO = 159, + CallNonPyGeneral = 160, + CallPyExactArgs = 161, + CallPyGeneral = 162, + CallStr1 = 163, + CallTuple1 = 164, + CallType1 = 165, + CompareOpFloat = 166, + CompareOpInt = 167, + CompareOpStr = 168, + ContainsOpDict = 169, + ContainsOpSet = 170, + ForIterGen = 171, + ForIterList = 172, + ForIterRange = 173, + ForIterTuple = 174, + JumpBackwardJit = 175, + JumpBackwardNoJit = 176, + LoadAttrClass = 177, + LoadAttrClassWithMetaclassCheck = 178, + LoadAttrGetattributeOverridden = 179, + LoadAttrInstanceValue = 180, + LoadAttrMethodLazyDict = 181, + LoadAttrMethodNoDict = 182, + LoadAttrMethodWithValues = 183, + LoadAttrModule = 184, + LoadAttrNondescriptorNoDict = 185, + LoadAttrNondescriptorWithValues = 186, + LoadAttrProperty = 187, + LoadAttrSlot = 188, + LoadAttrWithHint = 189, + LoadConstImmortal = 190, + LoadConstMortal = 191, + LoadGlobalBuiltin = 192, + LoadGlobalModule = 193, + LoadSuperAttrAttr = 194, + LoadSuperAttrMethod = 195, + ResumeCheck = 196, + SendGen = 197, + StoreAttrInstanceValue = 198, + StoreAttrSlot = 199, + StoreAttrWithHint = 200, + StoreSubscrDict = 201, + StoreSubscrListInt = 202, + ToBoolAlwaysTrue = 203, + ToBoolBool = 204, + ToBoolInt = 205, + ToBoolList = 206, + ToBoolNone = 207, + ToBoolStr = 208, + UnpackSequenceList = 209, + UnpackSequenceTuple = 210, + UnpackSequenceTwoTuple = 211, + InstrumentedEndFor = 234, + InstrumentedPopIter = 235, + InstrumentedEndSend = 236, + InstrumentedForIter = 237, + InstrumentedInstruction = 238, + InstrumentedJumpForward = 239, + InstrumentedNotTaken = 240, + InstrumentedPopJumpIfTrue = 241, + InstrumentedPopJumpIfFalse = 242, + InstrumentedPopJumpIfNone = 243, + InstrumentedPopJumpIfNotNone = 244, + InstrumentedResume = 245, + InstrumentedReturnValue = 246, + InstrumentedYieldValue = 247, + InstrumentedEndAsyncFor = 248, + InstrumentedLoadSuperAttr = 249, + InstrumentedCall = 250, + InstrumentedCallKw = 251, + InstrumentedCallFunctionEx = 252, + InstrumentedJumpBackward = 253, + InstrumentedLine = 254, + EnterExecutor = 255, +} + +impl Instruction { + /// Returns self as a [`Opcode`]. + #[must_use] + pub const fn as_opcode(self) -> Opcode { + match self { + Self::Cache => Opcode::Cache, + Self::BinarySlice => Opcode::BinarySlice, + Self::BuildTemplate => Opcode::BuildTemplate, + Self::BinaryOpInplaceAddUnicode => Opcode::BinaryOpInplaceAddUnicode, + Self::CallFunctionEx => Opcode::CallFunctionEx, + Self::CheckEgMatch => Opcode::CheckEgMatch, + Self::CheckExcMatch => Opcode::CheckExcMatch, + Self::CleanupThrow => Opcode::CleanupThrow, + Self::DeleteSubscr => Opcode::DeleteSubscr, + Self::EndFor => Opcode::EndFor, + Self::EndSend => Opcode::EndSend, + Self::ExitInitCheck => Opcode::ExitInitCheck, + Self::FormatSimple => Opcode::FormatSimple, + Self::FormatWithSpec => Opcode::FormatWithSpec, + Self::GetAiter => Opcode::GetAiter, + Self::GetAnext => Opcode::GetAnext, + Self::GetIter => Opcode::GetIter, + Self::Reserved => Opcode::Reserved, + Self::GetLen => Opcode::GetLen, + Self::GetYieldFromIter => Opcode::GetYieldFromIter, + Self::InterpreterExit => Opcode::InterpreterExit, + Self::LoadBuildClass => Opcode::LoadBuildClass, + Self::LoadLocals => Opcode::LoadLocals, + Self::MakeFunction => Opcode::MakeFunction, + Self::MatchKeys => Opcode::MatchKeys, + Self::MatchMapping => Opcode::MatchMapping, + Self::MatchSequence => Opcode::MatchSequence, + Self::Nop => Opcode::Nop, + Self::NotTaken => Opcode::NotTaken, + Self::PopExcept => Opcode::PopExcept, + Self::PopIter => Opcode::PopIter, + Self::PopTop => Opcode::PopTop, + Self::PushExcInfo => Opcode::PushExcInfo, + Self::PushNull => Opcode::PushNull, + Self::ReturnGenerator => Opcode::ReturnGenerator, + Self::ReturnValue => Opcode::ReturnValue, + Self::SetupAnnotations => Opcode::SetupAnnotations, + Self::StoreSlice => Opcode::StoreSlice, + Self::StoreSubscr => Opcode::StoreSubscr, + Self::ToBool => Opcode::ToBool, + Self::UnaryInvert => Opcode::UnaryInvert, + Self::UnaryNegative => Opcode::UnaryNegative, + Self::UnaryNot => Opcode::UnaryNot, + Self::WithExceptStart => Opcode::WithExceptStart, + Self::BinaryOp { .. } => Opcode::BinaryOp, + Self::BuildInterpolation { .. } => Opcode::BuildInterpolation, + Self::BuildList { .. } => Opcode::BuildList, + Self::BuildMap { .. } => Opcode::BuildMap, + Self::BuildSet { .. } => Opcode::BuildSet, + Self::BuildSlice { .. } => Opcode::BuildSlice, + Self::BuildString { .. } => Opcode::BuildString, + Self::BuildTuple { .. } => Opcode::BuildTuple, + Self::Call { .. } => Opcode::Call, + Self::CallIntrinsic1 { .. } => Opcode::CallIntrinsic1, + Self::CallIntrinsic2 { .. } => Opcode::CallIntrinsic2, + Self::CallKw { .. } => Opcode::CallKw, + Self::CompareOp { .. } => Opcode::CompareOp, + Self::ContainsOp { .. } => Opcode::ContainsOp, + Self::ConvertValue { .. } => Opcode::ConvertValue, + Self::Copy { .. } => Opcode::Copy, + Self::CopyFreeVars { .. } => Opcode::CopyFreeVars, + Self::DeleteAttr { .. } => Opcode::DeleteAttr, + Self::DeleteDeref { .. } => Opcode::DeleteDeref, + Self::DeleteFast { .. } => Opcode::DeleteFast, + Self::DeleteGlobal { .. } => Opcode::DeleteGlobal, + Self::DeleteName { .. } => Opcode::DeleteName, + Self::DictMerge { .. } => Opcode::DictMerge, + Self::DictUpdate { .. } => Opcode::DictUpdate, + Self::EndAsyncFor => Opcode::EndAsyncFor, + Self::ExtendedArg => Opcode::ExtendedArg, + Self::ForIter { .. } => Opcode::ForIter, + Self::GetAwaitable { .. } => Opcode::GetAwaitable, + Self::ImportFrom { .. } => Opcode::ImportFrom, + Self::ImportName { .. } => Opcode::ImportName, + Self::IsOp { .. } => Opcode::IsOp, + Self::JumpBackward { .. } => Opcode::JumpBackward, + Self::JumpBackwardNoInterrupt { .. } => Opcode::JumpBackwardNoInterrupt, + Self::JumpForward { .. } => Opcode::JumpForward, + Self::ListAppend { .. } => Opcode::ListAppend, + Self::ListExtend { .. } => Opcode::ListExtend, + Self::LoadAttr { .. } => Opcode::LoadAttr, + Self::LoadCommonConstant { .. } => Opcode::LoadCommonConstant, + Self::LoadConst { .. } => Opcode::LoadConst, + Self::LoadDeref { .. } => Opcode::LoadDeref, + Self::LoadFast { .. } => Opcode::LoadFast, + Self::LoadFastAndClear { .. } => Opcode::LoadFastAndClear, + Self::LoadFastBorrow { .. } => Opcode::LoadFastBorrow, + Self::LoadFastBorrowLoadFastBorrow { .. } => Opcode::LoadFastBorrowLoadFastBorrow, + Self::LoadFastCheck { .. } => Opcode::LoadFastCheck, + Self::LoadFastLoadFast { .. } => Opcode::LoadFastLoadFast, + Self::LoadFromDictOrDeref { .. } => Opcode::LoadFromDictOrDeref, + Self::LoadFromDictOrGlobals { .. } => Opcode::LoadFromDictOrGlobals, + Self::LoadGlobal { .. } => Opcode::LoadGlobal, + Self::LoadName { .. } => Opcode::LoadName, + Self::LoadSmallInt { .. } => Opcode::LoadSmallInt, + Self::LoadSpecial { .. } => Opcode::LoadSpecial, + Self::LoadSuperAttr { .. } => Opcode::LoadSuperAttr, + Self::MakeCell { .. } => Opcode::MakeCell, + Self::MapAdd { .. } => Opcode::MapAdd, + Self::MatchClass { .. } => Opcode::MatchClass, + Self::PopJumpIfFalse { .. } => Opcode::PopJumpIfFalse, + Self::PopJumpIfNone { .. } => Opcode::PopJumpIfNone, + Self::PopJumpIfNotNone { .. } => Opcode::PopJumpIfNotNone, + Self::PopJumpIfTrue { .. } => Opcode::PopJumpIfTrue, + Self::RaiseVarargs { .. } => Opcode::RaiseVarargs, + Self::Reraise { .. } => Opcode::Reraise, + Self::Send { .. } => Opcode::Send, + Self::SetAdd { .. } => Opcode::SetAdd, + Self::SetFunctionAttribute { .. } => Opcode::SetFunctionAttribute, + Self::SetUpdate { .. } => Opcode::SetUpdate, + Self::StoreAttr { .. } => Opcode::StoreAttr, + Self::StoreDeref { .. } => Opcode::StoreDeref, + Self::StoreFast { .. } => Opcode::StoreFast, + Self::StoreFastLoadFast { .. } => Opcode::StoreFastLoadFast, + Self::StoreFastStoreFast { .. } => Opcode::StoreFastStoreFast, + Self::StoreGlobal { .. } => Opcode::StoreGlobal, + Self::StoreName { .. } => Opcode::StoreName, + Self::Swap { .. } => Opcode::Swap, + Self::UnpackEx { .. } => Opcode::UnpackEx, + Self::UnpackSequence { .. } => Opcode::UnpackSequence, + Self::YieldValue { .. } => Opcode::YieldValue, + Self::Resume { .. } => Opcode::Resume, + Self::BinaryOpAddFloat => Opcode::BinaryOpAddFloat, + Self::BinaryOpAddInt => Opcode::BinaryOpAddInt, + Self::BinaryOpAddUnicode => Opcode::BinaryOpAddUnicode, + Self::BinaryOpExtend => Opcode::BinaryOpExtend, + Self::BinaryOpMultiplyFloat => Opcode::BinaryOpMultiplyFloat, + Self::BinaryOpMultiplyInt => Opcode::BinaryOpMultiplyInt, + Self::BinaryOpSubscrDict => Opcode::BinaryOpSubscrDict, + Self::BinaryOpSubscrGetitem => Opcode::BinaryOpSubscrGetitem, + Self::BinaryOpSubscrListInt => Opcode::BinaryOpSubscrListInt, + Self::BinaryOpSubscrListSlice => Opcode::BinaryOpSubscrListSlice, + Self::BinaryOpSubscrStrInt => Opcode::BinaryOpSubscrStrInt, + Self::BinaryOpSubscrTupleInt => Opcode::BinaryOpSubscrTupleInt, + Self::BinaryOpSubtractFloat => Opcode::BinaryOpSubtractFloat, + Self::BinaryOpSubtractInt => Opcode::BinaryOpSubtractInt, + Self::CallAllocAndEnterInit => Opcode::CallAllocAndEnterInit, + Self::CallBoundMethodExactArgs => Opcode::CallBoundMethodExactArgs, + Self::CallBoundMethodGeneral => Opcode::CallBoundMethodGeneral, + Self::CallBuiltinClass => Opcode::CallBuiltinClass, + Self::CallBuiltinFast => Opcode::CallBuiltinFast, + Self::CallBuiltinFastWithKeywords => Opcode::CallBuiltinFastWithKeywords, + Self::CallBuiltinO => Opcode::CallBuiltinO, + Self::CallIsinstance => Opcode::CallIsinstance, + Self::CallKwBoundMethod => Opcode::CallKwBoundMethod, + Self::CallKwNonPy => Opcode::CallKwNonPy, + Self::CallKwPy => Opcode::CallKwPy, + Self::CallLen => Opcode::CallLen, + Self::CallListAppend => Opcode::CallListAppend, + Self::CallMethodDescriptorFast => Opcode::CallMethodDescriptorFast, + Self::CallMethodDescriptorFastWithKeywords => { + Opcode::CallMethodDescriptorFastWithKeywords + } + Self::CallMethodDescriptorNoargs => Opcode::CallMethodDescriptorNoargs, + Self::CallMethodDescriptorO => Opcode::CallMethodDescriptorO, + Self::CallNonPyGeneral => Opcode::CallNonPyGeneral, + Self::CallPyExactArgs => Opcode::CallPyExactArgs, + Self::CallPyGeneral => Opcode::CallPyGeneral, + Self::CallStr1 => Opcode::CallStr1, + Self::CallTuple1 => Opcode::CallTuple1, + Self::CallType1 => Opcode::CallType1, + Self::CompareOpFloat => Opcode::CompareOpFloat, + Self::CompareOpInt => Opcode::CompareOpInt, + Self::CompareOpStr => Opcode::CompareOpStr, + Self::ContainsOpDict => Opcode::ContainsOpDict, + Self::ContainsOpSet => Opcode::ContainsOpSet, + Self::ForIterGen => Opcode::ForIterGen, + Self::ForIterList => Opcode::ForIterList, + Self::ForIterRange => Opcode::ForIterRange, + Self::ForIterTuple => Opcode::ForIterTuple, + Self::JumpBackwardJit => Opcode::JumpBackwardJit, + Self::JumpBackwardNoJit => Opcode::JumpBackwardNoJit, + Self::LoadAttrClass => Opcode::LoadAttrClass, + Self::LoadAttrClassWithMetaclassCheck => Opcode::LoadAttrClassWithMetaclassCheck, + Self::LoadAttrGetattributeOverridden => Opcode::LoadAttrGetattributeOverridden, + Self::LoadAttrInstanceValue => Opcode::LoadAttrInstanceValue, + Self::LoadAttrMethodLazyDict => Opcode::LoadAttrMethodLazyDict, + Self::LoadAttrMethodNoDict => Opcode::LoadAttrMethodNoDict, + Self::LoadAttrMethodWithValues => Opcode::LoadAttrMethodWithValues, + Self::LoadAttrModule => Opcode::LoadAttrModule, + Self::LoadAttrNondescriptorNoDict => Opcode::LoadAttrNondescriptorNoDict, + Self::LoadAttrNondescriptorWithValues => Opcode::LoadAttrNondescriptorWithValues, + Self::LoadAttrProperty => Opcode::LoadAttrProperty, + Self::LoadAttrSlot => Opcode::LoadAttrSlot, + Self::LoadAttrWithHint => Opcode::LoadAttrWithHint, + Self::LoadConstImmortal => Opcode::LoadConstImmortal, + Self::LoadConstMortal => Opcode::LoadConstMortal, + Self::LoadGlobalBuiltin => Opcode::LoadGlobalBuiltin, + Self::LoadGlobalModule => Opcode::LoadGlobalModule, + Self::LoadSuperAttrAttr => Opcode::LoadSuperAttrAttr, + Self::LoadSuperAttrMethod => Opcode::LoadSuperAttrMethod, + Self::ResumeCheck => Opcode::ResumeCheck, + Self::SendGen => Opcode::SendGen, + Self::StoreAttrInstanceValue => Opcode::StoreAttrInstanceValue, + Self::StoreAttrSlot => Opcode::StoreAttrSlot, + Self::StoreAttrWithHint => Opcode::StoreAttrWithHint, + Self::StoreSubscrDict => Opcode::StoreSubscrDict, + Self::StoreSubscrListInt => Opcode::StoreSubscrListInt, + Self::ToBoolAlwaysTrue => Opcode::ToBoolAlwaysTrue, + Self::ToBoolBool => Opcode::ToBoolBool, + Self::ToBoolInt => Opcode::ToBoolInt, + Self::ToBoolList => Opcode::ToBoolList, + Self::ToBoolNone => Opcode::ToBoolNone, + Self::ToBoolStr => Opcode::ToBoolStr, + Self::UnpackSequenceList => Opcode::UnpackSequenceList, + Self::UnpackSequenceTuple => Opcode::UnpackSequenceTuple, + Self::UnpackSequenceTwoTuple => Opcode::UnpackSequenceTwoTuple, + Self::InstrumentedEndFor => Opcode::InstrumentedEndFor, + Self::InstrumentedPopIter => Opcode::InstrumentedPopIter, + Self::InstrumentedEndSend => Opcode::InstrumentedEndSend, + Self::InstrumentedForIter => Opcode::InstrumentedForIter, + Self::InstrumentedInstruction => Opcode::InstrumentedInstruction, + Self::InstrumentedJumpForward => Opcode::InstrumentedJumpForward, + Self::InstrumentedNotTaken => Opcode::InstrumentedNotTaken, + Self::InstrumentedPopJumpIfTrue => Opcode::InstrumentedPopJumpIfTrue, + Self::InstrumentedPopJumpIfFalse => Opcode::InstrumentedPopJumpIfFalse, + Self::InstrumentedPopJumpIfNone => Opcode::InstrumentedPopJumpIfNone, + Self::InstrumentedPopJumpIfNotNone => Opcode::InstrumentedPopJumpIfNotNone, + Self::InstrumentedResume => Opcode::InstrumentedResume, + Self::InstrumentedReturnValue => Opcode::InstrumentedReturnValue, + Self::InstrumentedYieldValue => Opcode::InstrumentedYieldValue, + Self::InstrumentedEndAsyncFor => Opcode::InstrumentedEndAsyncFor, + Self::InstrumentedLoadSuperAttr => Opcode::InstrumentedLoadSuperAttr, + Self::InstrumentedCall => Opcode::InstrumentedCall, + Self::InstrumentedCallKw => Opcode::InstrumentedCallKw, + Self::InstrumentedCallFunctionEx => Opcode::InstrumentedCallFunctionEx, + Self::InstrumentedJumpBackward => Opcode::InstrumentedJumpBackward, + Self::InstrumentedLine => Opcode::InstrumentedLine, + Self::EnterExecutor => Opcode::EnterExecutor, + } + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PseudoOpcode { AnnotationsPlaceholder, @@ -1536,3 +2158,39 @@ impl TryFrom for PseudoOpcode { Self::from_u16(value) } } + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u16)] // TODO: Remove this `#[repr(...)]` +pub enum PseudoInstruction { + AnnotationsPlaceholder = 256, + Jump { delta: Arg } = 257, + JumpIfFalse { delta: Arg } = 258, + JumpIfTrue { delta: Arg } = 259, + JumpNoInterrupt { delta: Arg } = 260, + LoadClosure { i: Arg } = 261, + PopBlock = 262, + SetupCleanup { delta: Arg } = 263, + SetupFinally { delta: Arg } = 264, + SetupWith { delta: Arg } = 265, + StoreFastMaybeNull { var_num: Arg } = 266, +} + +impl PseudoInstruction { + /// Returns self as a [`PseudoOpcode`]. + #[must_use] + pub const fn as_opcode(self) -> PseudoOpcode { + match self { + Self::AnnotationsPlaceholder => PseudoOpcode::AnnotationsPlaceholder, + Self::Jump { .. } => PseudoOpcode::Jump, + Self::JumpIfFalse { .. } => PseudoOpcode::JumpIfFalse, + Self::JumpIfTrue { .. } => PseudoOpcode::JumpIfTrue, + Self::JumpNoInterrupt { .. } => PseudoOpcode::JumpNoInterrupt, + Self::LoadClosure { .. } => PseudoOpcode::LoadClosure, + Self::PopBlock => PseudoOpcode::PopBlock, + Self::SetupCleanup { .. } => PseudoOpcode::SetupCleanup, + Self::SetupFinally { .. } => PseudoOpcode::SetupFinally, + Self::SetupWith { .. } => PseudoOpcode::SetupWith, + Self::StoreFastMaybeNull { .. } => PseudoOpcode::StoreFastMaybeNull, + } + } +} From 9e6382ab820cec6d1f64ce699abf303a427b70c3 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Thu, 7 May 2026 11:59:47 +0300 Subject: [PATCH 15/35] as_{opcode,instruction} --- crates/compiler-core/generate.py | 48 ++- .../src/bytecode/instructions.rs | 406 ++++++++++++++++++ 2 files changed, 453 insertions(+), 1 deletion(-) diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py index bcf705dc236..835001c394d 100644 --- a/crates/compiler-core/generate.py +++ b/crates/compiler-core/generate.py @@ -32,8 +32,10 @@ @dataclasses.dataclass(frozen=True, kw_only=True, slots=True) class OpcodeGen: name: str + instruction_enum: str instructions: list numeric_repr: str + metadata: dict[str, str] analysis: analyzer.Analysis def gen(self) -> str: @@ -106,7 +108,7 @@ def impl_tryfrom_numeric(self) -> str: @property def impl_into_numeric(self) -> str: return f""" - impl From<{self.name}> for {self.numeric_repr}{{ + impl From<{self.name}> for {self.numeric_repr} {{ fn from(opcode: {self.name}) -> Self {{ opcode.as_{self.numeric_repr}() }} @@ -317,6 +319,38 @@ def fn_stack_effect(self) -> str: }} """ + @property + def fn_as_instruction(self) -> str: + arms = "" + for instr in self: + name = instr.name + arms += f"Self::{name} => {self.instruction_enum}::{name}" + if oparg := self.metadata.get(name, {}).get("oparg"): + oname = oparg["name"] + arms += f" {{ {oname}: Arg::marker() }}" + + arms += ",\n" + + return f""" + /// Returns self as [`{self.instruction_enum}`]. + #[must_use] + pub const fn as_instruction(self) -> {self.instruction_enum} {{ + match self {{ + {arms} + }} + }} + """ + + @property + def impl_as_instruction(self) -> str: + return f""" + impl From<{self.name}> for {self.instruction_enum} {{ + fn from(opcode: {self.name}) -> Self {{ + opcode.as_instruction() + }} + }} + """ + def __iter__(self): yield from self.instructions @@ -390,6 +424,16 @@ def fn_as_opcode(self) -> str: }} """ + @property + def impl_as_opcode(self) -> str: + return f""" + impl From<{self.name}> for {self.opcode_enum} {{ + fn from(instruction: {self.name}) -> Self {{ + instruction.as_opcode() + }} + }} + """ + def __iter__(self): yield from self.instructions @@ -439,8 +483,10 @@ def main(): opcode_code = OpcodeGen( name=opcode_enum, + instruction_enum=instruction_enum, instructions=instructions, numeric_repr=numeric_repr, + metadata=metadata, analysis=analysis, ).gen() diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs index f17cdd8bd34..8fa6c4be62e 100644 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ b/crates/compiler-core/src/bytecode/instructions.rs @@ -238,6 +238,354 @@ pub enum Opcode { } impl Opcode { + /// Returns self as [`Instruction`]. + #[must_use] + pub const fn as_instruction(self) -> Instruction { + match self { + Self::Cache => Instruction::Cache, + Self::BinarySlice => Instruction::BinarySlice, + Self::BuildTemplate => Instruction::BuildTemplate, + Self::BinaryOpInplaceAddUnicode => Instruction::BinaryOpInplaceAddUnicode, + Self::CallFunctionEx => Instruction::CallFunctionEx, + Self::CheckEgMatch => Instruction::CheckEgMatch, + Self::CheckExcMatch => Instruction::CheckExcMatch, + Self::CleanupThrow => Instruction::CleanupThrow, + Self::DeleteSubscr => Instruction::DeleteSubscr, + Self::EndFor => Instruction::EndFor, + Self::EndSend => Instruction::EndSend, + Self::ExitInitCheck => Instruction::ExitInitCheck, + Self::FormatSimple => Instruction::FormatSimple, + Self::FormatWithSpec => Instruction::FormatWithSpec, + Self::GetAiter => Instruction::GetAiter, + Self::GetAnext => Instruction::GetAnext, + Self::GetIter => Instruction::GetIter, + Self::Reserved => Instruction::Reserved, + Self::GetLen => Instruction::GetLen, + Self::GetYieldFromIter => Instruction::GetYieldFromIter, + Self::InterpreterExit => Instruction::InterpreterExit, + Self::LoadBuildClass => Instruction::LoadBuildClass, + Self::LoadLocals => Instruction::LoadLocals, + Self::MakeFunction => Instruction::MakeFunction, + Self::MatchKeys => Instruction::MatchKeys, + Self::MatchMapping => Instruction::MatchMapping, + Self::MatchSequence => Instruction::MatchSequence, + Self::Nop => Instruction::Nop, + Self::NotTaken => Instruction::NotTaken, + Self::PopExcept => Instruction::PopExcept, + Self::PopIter => Instruction::PopIter, + Self::PopTop => Instruction::PopTop, + Self::PushExcInfo => Instruction::PushExcInfo, + Self::PushNull => Instruction::PushNull, + Self::ReturnGenerator => Instruction::ReturnGenerator, + Self::ReturnValue => Instruction::ReturnValue, + Self::SetupAnnotations => Instruction::SetupAnnotations, + Self::StoreSlice => Instruction::StoreSlice, + Self::StoreSubscr => Instruction::StoreSubscr, + Self::ToBool => Instruction::ToBool, + Self::UnaryInvert => Instruction::UnaryInvert, + Self::UnaryNegative => Instruction::UnaryNegative, + Self::UnaryNot => Instruction::UnaryNot, + Self::WithExceptStart => Instruction::WithExceptStart, + Self::BinaryOp => Instruction::BinaryOp { op: Arg::marker() }, + Self::BuildInterpolation => Instruction::BuildInterpolation { + format: Arg::marker(), + }, + Self::BuildList => Instruction::BuildList { + count: Arg::marker(), + }, + Self::BuildMap => Instruction::BuildMap { + count: Arg::marker(), + }, + Self::BuildSet => Instruction::BuildSet { + count: Arg::marker(), + }, + Self::BuildSlice => Instruction::BuildSlice { + argc: Arg::marker(), + }, + Self::BuildString => Instruction::BuildString { + count: Arg::marker(), + }, + Self::BuildTuple => Instruction::BuildTuple { + count: Arg::marker(), + }, + Self::Call => Instruction::Call { + argc: Arg::marker(), + }, + Self::CallIntrinsic1 => Instruction::CallIntrinsic1 { + func: Arg::marker(), + }, + Self::CallIntrinsic2 => Instruction::CallIntrinsic2 { + func: Arg::marker(), + }, + Self::CallKw => Instruction::CallKw { + argc: Arg::marker(), + }, + Self::CompareOp => Instruction::CompareOp { + opname: Arg::marker(), + }, + Self::ContainsOp => Instruction::ContainsOp { + invert: Arg::marker(), + }, + Self::ConvertValue => Instruction::ConvertValue { + oparg: Arg::marker(), + }, + Self::Copy => Instruction::Copy { i: Arg::marker() }, + Self::CopyFreeVars => Instruction::CopyFreeVars { n: Arg::marker() }, + Self::DeleteAttr => Instruction::DeleteAttr { + namei: Arg::marker(), + }, + Self::DeleteDeref => Instruction::DeleteDeref { i: Arg::marker() }, + Self::DeleteFast => Instruction::DeleteFast { + var_num: Arg::marker(), + }, + Self::DeleteGlobal => Instruction::DeleteGlobal { + namei: Arg::marker(), + }, + Self::DeleteName => Instruction::DeleteName { + namei: Arg::marker(), + }, + Self::DictMerge => Instruction::DictMerge { i: Arg::marker() }, + Self::DictUpdate => Instruction::DictUpdate { i: Arg::marker() }, + Self::EndAsyncFor => Instruction::EndAsyncFor, + Self::ExtendedArg => Instruction::ExtendedArg, + Self::ForIter => Instruction::ForIter { + delta: Arg::marker(), + }, + Self::GetAwaitable => Instruction::GetAwaitable { + r#where: Arg::marker(), + }, + Self::ImportFrom => Instruction::ImportFrom { + namei: Arg::marker(), + }, + Self::ImportName => Instruction::ImportName { + namei: Arg::marker(), + }, + Self::IsOp => Instruction::IsOp { + invert: Arg::marker(), + }, + Self::JumpBackward => Instruction::JumpBackward { + delta: Arg::marker(), + }, + Self::JumpBackwardNoInterrupt => Instruction::JumpBackwardNoInterrupt { + delta: Arg::marker(), + }, + Self::JumpForward => Instruction::JumpForward { + delta: Arg::marker(), + }, + Self::ListAppend => Instruction::ListAppend { i: Arg::marker() }, + Self::ListExtend => Instruction::ListExtend { i: Arg::marker() }, + Self::LoadAttr => Instruction::LoadAttr { + namei: Arg::marker(), + }, + Self::LoadCommonConstant => Instruction::LoadCommonConstant { idx: Arg::marker() }, + Self::LoadConst => Instruction::LoadConst { + consti: Arg::marker(), + }, + Self::LoadDeref => Instruction::LoadDeref { i: Arg::marker() }, + Self::LoadFast => Instruction::LoadFast { + var_num: Arg::marker(), + }, + Self::LoadFastAndClear => Instruction::LoadFastAndClear { + var_num: Arg::marker(), + }, + Self::LoadFastBorrow => Instruction::LoadFastBorrow { + var_num: Arg::marker(), + }, + Self::LoadFastBorrowLoadFastBorrow => Instruction::LoadFastBorrowLoadFastBorrow { + var_nums: Arg::marker(), + }, + Self::LoadFastCheck => Instruction::LoadFastCheck { + var_num: Arg::marker(), + }, + Self::LoadFastLoadFast => Instruction::LoadFastLoadFast { + var_nums: Arg::marker(), + }, + Self::LoadFromDictOrDeref => Instruction::LoadFromDictOrDeref { i: Arg::marker() }, + Self::LoadFromDictOrGlobals => Instruction::LoadFromDictOrGlobals { i: Arg::marker() }, + Self::LoadGlobal => Instruction::LoadGlobal { + namei: Arg::marker(), + }, + Self::LoadName => Instruction::LoadName { + namei: Arg::marker(), + }, + Self::LoadSmallInt => Instruction::LoadSmallInt { i: Arg::marker() }, + Self::LoadSpecial => Instruction::LoadSpecial { + method: Arg::marker(), + }, + Self::LoadSuperAttr => Instruction::LoadSuperAttr { + namei: Arg::marker(), + }, + Self::MakeCell => Instruction::MakeCell { i: Arg::marker() }, + Self::MapAdd => Instruction::MapAdd { i: Arg::marker() }, + Self::MatchClass => Instruction::MatchClass { + count: Arg::marker(), + }, + Self::PopJumpIfFalse => Instruction::PopJumpIfFalse { + delta: Arg::marker(), + }, + Self::PopJumpIfNone => Instruction::PopJumpIfNone { + delta: Arg::marker(), + }, + Self::PopJumpIfNotNone => Instruction::PopJumpIfNotNone { + delta: Arg::marker(), + }, + Self::PopJumpIfTrue => Instruction::PopJumpIfTrue { + delta: Arg::marker(), + }, + Self::RaiseVarargs => Instruction::RaiseVarargs { + argc: Arg::marker(), + }, + Self::Reraise => Instruction::Reraise { + depth: Arg::marker(), + }, + Self::Send => Instruction::Send { + delta: Arg::marker(), + }, + Self::SetAdd => Instruction::SetAdd { i: Arg::marker() }, + Self::SetFunctionAttribute => Instruction::SetFunctionAttribute { + flag: Arg::marker(), + }, + Self::SetUpdate => Instruction::SetUpdate { i: Arg::marker() }, + Self::StoreAttr => Instruction::StoreAttr { + namei: Arg::marker(), + }, + Self::StoreDeref => Instruction::StoreDeref { i: Arg::marker() }, + Self::StoreFast => Instruction::StoreFast { + var_num: Arg::marker(), + }, + Self::StoreFastLoadFast => Instruction::StoreFastLoadFast { + var_nums: Arg::marker(), + }, + Self::StoreFastStoreFast => Instruction::StoreFastStoreFast { + var_nums: Arg::marker(), + }, + Self::StoreGlobal => Instruction::StoreGlobal { + namei: Arg::marker(), + }, + Self::StoreName => Instruction::StoreName { + namei: Arg::marker(), + }, + Self::Swap => Instruction::Swap { i: Arg::marker() }, + Self::UnpackEx => Instruction::UnpackEx { + counts: Arg::marker(), + }, + Self::UnpackSequence => Instruction::UnpackSequence { + count: Arg::marker(), + }, + Self::YieldValue => Instruction::YieldValue { arg: Arg::marker() }, + Self::Resume => Instruction::Resume { + context: Arg::marker(), + }, + Self::BinaryOpAddFloat => Instruction::BinaryOpAddFloat, + Self::BinaryOpAddInt => Instruction::BinaryOpAddInt, + Self::BinaryOpAddUnicode => Instruction::BinaryOpAddUnicode, + Self::BinaryOpExtend => Instruction::BinaryOpExtend, + Self::BinaryOpMultiplyFloat => Instruction::BinaryOpMultiplyFloat, + Self::BinaryOpMultiplyInt => Instruction::BinaryOpMultiplyInt, + Self::BinaryOpSubscrDict => Instruction::BinaryOpSubscrDict, + Self::BinaryOpSubscrGetitem => Instruction::BinaryOpSubscrGetitem, + Self::BinaryOpSubscrListInt => Instruction::BinaryOpSubscrListInt, + Self::BinaryOpSubscrListSlice => Instruction::BinaryOpSubscrListSlice, + Self::BinaryOpSubscrStrInt => Instruction::BinaryOpSubscrStrInt, + Self::BinaryOpSubscrTupleInt => Instruction::BinaryOpSubscrTupleInt, + Self::BinaryOpSubtractFloat => Instruction::BinaryOpSubtractFloat, + Self::BinaryOpSubtractInt => Instruction::BinaryOpSubtractInt, + Self::CallAllocAndEnterInit => Instruction::CallAllocAndEnterInit, + Self::CallBoundMethodExactArgs => Instruction::CallBoundMethodExactArgs, + Self::CallBoundMethodGeneral => Instruction::CallBoundMethodGeneral, + Self::CallBuiltinClass => Instruction::CallBuiltinClass, + Self::CallBuiltinFast => Instruction::CallBuiltinFast, + Self::CallBuiltinFastWithKeywords => Instruction::CallBuiltinFastWithKeywords, + Self::CallBuiltinO => Instruction::CallBuiltinO, + Self::CallIsinstance => Instruction::CallIsinstance, + Self::CallKwBoundMethod => Instruction::CallKwBoundMethod, + Self::CallKwNonPy => Instruction::CallKwNonPy, + Self::CallKwPy => Instruction::CallKwPy, + Self::CallLen => Instruction::CallLen, + Self::CallListAppend => Instruction::CallListAppend, + Self::CallMethodDescriptorFast => Instruction::CallMethodDescriptorFast, + Self::CallMethodDescriptorFastWithKeywords => { + Instruction::CallMethodDescriptorFastWithKeywords + } + Self::CallMethodDescriptorNoargs => Instruction::CallMethodDescriptorNoargs, + Self::CallMethodDescriptorO => Instruction::CallMethodDescriptorO, + Self::CallNonPyGeneral => Instruction::CallNonPyGeneral, + Self::CallPyExactArgs => Instruction::CallPyExactArgs, + Self::CallPyGeneral => Instruction::CallPyGeneral, + Self::CallStr1 => Instruction::CallStr1, + Self::CallTuple1 => Instruction::CallTuple1, + Self::CallType1 => Instruction::CallType1, + Self::CompareOpFloat => Instruction::CompareOpFloat, + Self::CompareOpInt => Instruction::CompareOpInt, + Self::CompareOpStr => Instruction::CompareOpStr, + Self::ContainsOpDict => Instruction::ContainsOpDict, + Self::ContainsOpSet => Instruction::ContainsOpSet, + Self::ForIterGen => Instruction::ForIterGen, + Self::ForIterList => Instruction::ForIterList, + Self::ForIterRange => Instruction::ForIterRange, + Self::ForIterTuple => Instruction::ForIterTuple, + Self::JumpBackwardJit => Instruction::JumpBackwardJit, + Self::JumpBackwardNoJit => Instruction::JumpBackwardNoJit, + Self::LoadAttrClass => Instruction::LoadAttrClass, + Self::LoadAttrClassWithMetaclassCheck => Instruction::LoadAttrClassWithMetaclassCheck, + Self::LoadAttrGetattributeOverridden => Instruction::LoadAttrGetattributeOverridden, + Self::LoadAttrInstanceValue => Instruction::LoadAttrInstanceValue, + Self::LoadAttrMethodLazyDict => Instruction::LoadAttrMethodLazyDict, + Self::LoadAttrMethodNoDict => Instruction::LoadAttrMethodNoDict, + Self::LoadAttrMethodWithValues => Instruction::LoadAttrMethodWithValues, + Self::LoadAttrModule => Instruction::LoadAttrModule, + Self::LoadAttrNondescriptorNoDict => Instruction::LoadAttrNondescriptorNoDict, + Self::LoadAttrNondescriptorWithValues => Instruction::LoadAttrNondescriptorWithValues, + Self::LoadAttrProperty => Instruction::LoadAttrProperty, + Self::LoadAttrSlot => Instruction::LoadAttrSlot, + Self::LoadAttrWithHint => Instruction::LoadAttrWithHint, + Self::LoadConstImmortal => Instruction::LoadConstImmortal, + Self::LoadConstMortal => Instruction::LoadConstMortal, + Self::LoadGlobalBuiltin => Instruction::LoadGlobalBuiltin, + Self::LoadGlobalModule => Instruction::LoadGlobalModule, + Self::LoadSuperAttrAttr => Instruction::LoadSuperAttrAttr, + Self::LoadSuperAttrMethod => Instruction::LoadSuperAttrMethod, + Self::ResumeCheck => Instruction::ResumeCheck, + Self::SendGen => Instruction::SendGen, + Self::StoreAttrInstanceValue => Instruction::StoreAttrInstanceValue, + Self::StoreAttrSlot => Instruction::StoreAttrSlot, + Self::StoreAttrWithHint => Instruction::StoreAttrWithHint, + Self::StoreSubscrDict => Instruction::StoreSubscrDict, + Self::StoreSubscrListInt => Instruction::StoreSubscrListInt, + Self::ToBoolAlwaysTrue => Instruction::ToBoolAlwaysTrue, + Self::ToBoolBool => Instruction::ToBoolBool, + Self::ToBoolInt => Instruction::ToBoolInt, + Self::ToBoolList => Instruction::ToBoolList, + Self::ToBoolNone => Instruction::ToBoolNone, + Self::ToBoolStr => Instruction::ToBoolStr, + Self::UnpackSequenceList => Instruction::UnpackSequenceList, + Self::UnpackSequenceTuple => Instruction::UnpackSequenceTuple, + Self::UnpackSequenceTwoTuple => Instruction::UnpackSequenceTwoTuple, + Self::InstrumentedEndFor => Instruction::InstrumentedEndFor, + Self::InstrumentedPopIter => Instruction::InstrumentedPopIter, + Self::InstrumentedEndSend => Instruction::InstrumentedEndSend, + Self::InstrumentedForIter => Instruction::InstrumentedForIter, + Self::InstrumentedInstruction => Instruction::InstrumentedInstruction, + Self::InstrumentedJumpForward => Instruction::InstrumentedJumpForward, + Self::InstrumentedNotTaken => Instruction::InstrumentedNotTaken, + Self::InstrumentedPopJumpIfTrue => Instruction::InstrumentedPopJumpIfTrue, + Self::InstrumentedPopJumpIfFalse => Instruction::InstrumentedPopJumpIfFalse, + Self::InstrumentedPopJumpIfNone => Instruction::InstrumentedPopJumpIfNone, + Self::InstrumentedPopJumpIfNotNone => Instruction::InstrumentedPopJumpIfNotNone, + Self::InstrumentedResume => Instruction::InstrumentedResume, + Self::InstrumentedReturnValue => Instruction::InstrumentedReturnValue, + Self::InstrumentedYieldValue => Instruction::InstrumentedYieldValue, + Self::InstrumentedEndAsyncFor => Instruction::InstrumentedEndAsyncFor, + Self::InstrumentedLoadSuperAttr => Instruction::InstrumentedLoadSuperAttr, + Self::InstrumentedCall => Instruction::InstrumentedCall, + Self::InstrumentedCallKw => Instruction::InstrumentedCallKw, + Self::InstrumentedCallFunctionEx => Instruction::InstrumentedCallFunctionEx, + Self::InstrumentedJumpBackward => Instruction::InstrumentedJumpBackward, + Self::InstrumentedLine => Instruction::InstrumentedLine, + Self::EnterExecutor => Instruction::EnterExecutor, + } + } + #[must_use] pub const fn as_u8(self) -> u8 { match self { @@ -1371,6 +1719,12 @@ impl Opcode { } } +impl From for Instruction { + fn from(opcode: Opcode) -> Self { + opcode.as_instruction() + } +} + impl From for u8 { fn from(opcode: Opcode) -> Self { opcode.as_u8() @@ -2007,6 +2361,12 @@ impl Instruction { } } +impl From for Opcode { + fn from(instruction: Instruction) -> Self { + instruction.as_opcode() + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PseudoOpcode { AnnotationsPlaceholder, @@ -2023,6 +2383,40 @@ pub enum PseudoOpcode { } impl PseudoOpcode { + /// Returns self as [`PseudoInstruction`]. + #[must_use] + pub const fn as_instruction(self) -> PseudoInstruction { + match self { + Self::AnnotationsPlaceholder => PseudoInstruction::AnnotationsPlaceholder, + Self::Jump => PseudoInstruction::Jump { + delta: Arg::marker(), + }, + Self::JumpIfFalse => PseudoInstruction::JumpIfFalse { + delta: Arg::marker(), + }, + Self::JumpIfTrue => PseudoInstruction::JumpIfTrue { + delta: Arg::marker(), + }, + Self::JumpNoInterrupt => PseudoInstruction::JumpNoInterrupt { + delta: Arg::marker(), + }, + Self::LoadClosure => PseudoInstruction::LoadClosure { i: Arg::marker() }, + Self::PopBlock => PseudoInstruction::PopBlock, + Self::SetupCleanup => PseudoInstruction::SetupCleanup { + delta: Arg::marker(), + }, + Self::SetupFinally => PseudoInstruction::SetupFinally { + delta: Arg::marker(), + }, + Self::SetupWith => PseudoInstruction::SetupWith { + delta: Arg::marker(), + }, + Self::StoreFastMaybeNull => PseudoInstruction::StoreFastMaybeNull { + var_num: Arg::marker(), + }, + } + } + #[must_use] pub const fn as_u16(self) -> u16 { match self { @@ -2145,6 +2539,12 @@ impl PseudoOpcode { } } +impl From for PseudoInstruction { + fn from(opcode: PseudoOpcode) -> Self { + opcode.as_instruction() + } +} + impl From for u16 { fn from(opcode: PseudoOpcode) -> Self { opcode.as_u16() @@ -2194,3 +2594,9 @@ impl PseudoInstruction { } } } + +impl From for PseudoOpcode { + fn from(instruction: PseudoInstruction) -> Self { + instruction.as_opcode() + } +} From 9f88f88b736ec7a8e2a935b182987cc5aca5304e Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Thu, 7 May 2026 12:27:14 +0300 Subject: [PATCH 16/35] save progress --- .../compiler-core/src/bytecode/instruction.rs | 1090 +---------------- 1 file changed, 20 insertions(+), 1070 deletions(-) diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 21869601598..068d729f92c 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -1,515 +1,6 @@ use core::{fmt, marker::PhantomData}; -use crate::{ - bytecode::oparg::{ - self, BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator, - ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr, - LoadSuperAttr, MakeFunctionFlag, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind, - SpecialMethod, UnpackExArgs, - }, - marshal::MarshalError, -}; - -macro_rules! define_opcodes { - ( - #[repr($typ:ident)] - $opcode_vis:vis enum $opcode_name:ident; - - $(#[$instr_meta:meta])* - $instr_vis:vis enum $instr_name:ident { - $( - $(#[$op_meta:meta])* - $op_name:ident $({ $arg_name:ident: Arg<$arg_type:ty> $(,)? })? = ($op_id:expr, $op_display:literal) - ),* $(,)? - } - ) => { - #[derive(Clone, Copy, Debug)] - $opcode_vis enum $opcode_name { - $($op_name),* - } - - impl $opcode_name { - #[doc = concat!("Converts this opcode to [`", stringify!($instr_name), "`].")] - #[must_use] - $opcode_vis const fn as_instruction(&self) -> $instr_name { - match self { - $( - Self::$op_name => $instr_name::$op_name $({ $arg_name: Arg::marker() })?, - )* - } - } - - /// Gets the CPython name representation. - #[must_use] - $opcode_vis const fn name(&self) -> &str { - match self { - $(Self::$op_name => $op_display,)* - } - } - } - - impl From<$opcode_name> for $instr_name { - fn from(opcode: $opcode_name) -> Self { - opcode.as_instruction() - } - } - - - impl TryFrom<$typ> for $opcode_name { - type Error = $crate::marshal::MarshalError; - - fn try_from(value: $typ) -> Result { - match value { - $($op_id => Ok(Self::$op_name),)* - _ => Err(Self::Error::InvalidBytecode), - } - } - } - - impl From<$opcode_name> for $typ { - fn from(opcode: $opcode_name) -> Self { - match opcode { - $($opcode_name::$op_name => $op_id,)* - } - } - } - - impl ::core::fmt::Display for $opcode_name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - self.name().fmt(f) - } - } - - #[derive(Clone, Copy, Debug)] - #[repr($typ)] // TODO: Remove this repr - $instr_vis enum $instr_name { - $( - $(#[$op_meta])* - $op_name $({ $arg_name: Arg<$arg_type> })? = $op_id // TODO: Don't assign value - ),* - } - - impl $instr_name { - #[doc = concat!("Get the corresponding [`", stringify!($opcode_name), "`].")] - #[must_use] - $instr_vis const fn opcode(&self) -> $opcode_name { - match self { - $( - Self::$op_name $({ $arg_name: _ })? => $opcode_name::$op_name, - )* - } - } - - } - - impl From<$instr_name> for $opcode_name { - fn from(instr: $instr_name) -> Self { - instr.opcode() - } - } - - impl TryFrom<$typ> for $instr_name { - type Error = $crate::marshal::MarshalError; - - fn try_from(value: $typ) -> Result { - $opcode_name::try_from(value).map(Into::into) - } - } - - impl From<$instr_name> for $typ { - fn from(instr: $instr_name) -> Self { - instr.opcode().into() - } - } - }; -} - -define_opcodes!( - #[repr(u8)] - pub enum Opcode; - - pub enum Instruction { - Cache = (0, "CACHE"), - BinarySlice = (1, "BINARY_SLICE"), - BuildTemplate = (2, "BUILD_TEMPLATE"), - BinaryOpInplaceAddUnicode = (3, "BINARY_OP_INPLACE_ADD_UNICODE"), - CallFunctionEx = (4, "CALL_FUNCTION_EX"), - CheckEgMatch = (5, "CHECK_EG_MATCH"), - CheckExcMatch = (6, "CHECK_EXC_MATCH"), - CleanupThrow = (7, "CLEANUP_THROW"), - DeleteSubscr = (8, "DELETE_SUBSCR"), - EndFor = (9, "END_FOR"), - EndSend = (10, "END_SEND"), - ExitInitCheck = (11, "EXIT_INIT_CHECK"), - FormatSimple = (12, "FORMAT_SIMPLE"), - FormatWithSpec = (13, "FORMAT_WITH_SPEC"), - GetAIter = (14, "GET_AITER"), - GetANext = (15, "GET_ANEXT"), - GetIter = (16, "GET_ITER"), - Reserved = (17, "RESERVED"), - GetLen = (18, "GET_LEN"), - GetYieldFromIter = (19, "GET_YIELD_FROM_ITER"), - InterpreterExit = (20, "INTERPRETER_EXIT"), - LoadBuildClass = (21, "LOAD_BUILD_CLASS"), - LoadLocals = (22, "LOAD_LOCALS"), - MakeFunction = (23, "MAKE_FUNCTION"), - MatchKeys = (24, "MATCH_KEYS"), - MatchMapping = (25, "MATCH_MAPPING"), - MatchSequence = (26, "MATCH_SEQUENCE"), - Nop = (27, "NOP"), - NotTaken = (28, "NOT_TAKEN"), - PopExcept = (29, "POP_EXCEPT"), - PopIter = (30, "POP_ITER"), - PopTop = (31, "POP_TOP"), - PushExcInfo = (32, "PUSH_EXC_INFO"), - PushNull = (33, "PUSH_NULL"), - ReturnGenerator = (34, "RETURN_GENERATOR"), - ReturnValue = (35, "RETURN_VALUE"), - SetupAnnotations = (36, "SETUP_ANNOTATIONS"), - StoreSlice = (37, "STORE_SLICE"), - StoreSubscr = (38, "STORE_SUBSCR"), - ToBool = (39, "TO_BOOL"), - UnaryInvert = (40, "UNARY_INVERT"), - UnaryNegative = (41, "UNARY_NEGATIVE"), - UnaryNot = (42, "UNARY_NOT"), - WithExceptStart = (43, "WITH_EXCEPT_START"), - BinaryOp { - op: Arg, - } = (44, "BINARY_OP"), - BuildInterpolation { - format: Arg, - } = (45, "BUILD_INTERPOLATION"), - BuildList { - count: Arg, - } = (46, "BUILD_LIST"), - BuildMap { - count: Arg, - } = (47, "BUILD_MAP"), - BuildSet { - count: Arg, - } = (48, "BUILD_SET"), - BuildSlice { - argc: Arg, - } = (49, "BUILD_SLICE"), - BuildString { - count: Arg, - } = (50, "BUILD_STRING"), - BuildTuple { - count: Arg, - } = (51, "BUILD_TUPLE"), - Call { - argc: Arg, - } = (52, "CALL"), - CallIntrinsic1 { - func: Arg, - } = (53, "CALL_INTRINSIC_1"), - CallIntrinsic2 { - func: Arg, - } = (54, "CALL_INTRINSIC_2"), - CallKw { - argc: Arg, - } = (55, "CALL_KW"), - CompareOp { - opname: Arg, - } = (56, "COMPARE_OP"), - ContainsOp { - invert: Arg, - } = (57, "CONTAINS_OP"), - ConvertValue { - oparg: Arg, - } = (58, "CONVERT_VALUE"), - Copy { - i: Arg, - } = (59, "COPY"), - CopyFreeVars { - n: Arg, - } = (60, "COPY_FREE_VARS"), - DeleteAttr { - namei: Arg, - } = (61, "DELETE_ATTR"), - DeleteDeref { - i: Arg, - } = (62, "DELETE_DEREF"), - DeleteFast { - var_num: Arg, - } = (63, "DELETE_FAST"), - DeleteGlobal { - namei: Arg, - } = (64, "DELETE_GLOBAL"), - DeleteName { - namei: Arg, - } = (65, "DELETE_NAME"), - DictMerge { - i: Arg, - } = (66, "DICT_MERGE"), - DictUpdate { - i: Arg, - } = (67, "DICT_UPDATE"), - EndAsyncFor = (68, "END_ASYNC_FOR"), - ExtendedArg = (69, "EXTENDED_ARG"), - ForIter { - delta: Arg