From f95b7468f707b8a1a16ecb7d01578f89709c542a Mon Sep 17 00:00:00 2001 From: Shahar Naveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Wed, 27 May 2026 10:44:58 +0300 Subject: [PATCH] Autogen opcodes metadata (#7983) --- .gitattributes | 19 +- .github/workflows/ci.yaml | 27 +- .pre-commit-config.yaml | 21 +- Lib/_opcode_metadata.py | 2 +- crates/compiler-core/generate.py | 721 ----- crates/compiler-core/opcode.toml | 270 -- crates/compiler-core/src/bytecode.rs | 9 +- .../compiler-core/src/bytecode/instruction.rs | 818 ++++- .../src/bytecode/instructions.rs | 2780 ----------------- crates/compiler-core/src/bytecode/oparg.rs | 2 +- .../src/bytecode/opcode_metadata.rs | 809 +++++ crates/compiler-core/src/lib.rs | 1 + scripts/generate_opcode_metadata.py | 184 -- tools/opcode_metadata/conf.toml | 11 + tools/opcode_metadata/cpython.py | 27 + .../generate_py_opcode_metadata.py | 107 + .../generate_rs_opcode_metadata.py | 364 +++ tools/opcode_metadata/opcodes.py | 159 + tools/opcode_metadata/utils.py | 96 + 19 files changed, 2333 insertions(+), 4094 deletions(-) delete mode 100644 crates/compiler-core/generate.py delete mode 100644 crates/compiler-core/opcode.toml delete mode 100644 crates/compiler-core/src/bytecode/instructions.rs create mode 100644 crates/compiler-core/src/bytecode/opcode_metadata.rs delete mode 100644 scripts/generate_opcode_metadata.py create mode 100644 tools/opcode_metadata/conf.toml create mode 100644 tools/opcode_metadata/cpython.py create mode 100644 tools/opcode_metadata/generate_py_opcode_metadata.py create mode 100644 tools/opcode_metadata/generate_rs_opcode_metadata.py create mode 100644 tools/opcode_metadata/opcodes.py create mode 100644 tools/opcode_metadata/utils.py diff --git a/.gitattributes b/.gitattributes index d076a34f9..b3a782dbe 100644 --- a/.gitattributes +++ b/.gitattributes @@ -58,13 +58,14 @@ Lib/venv/scripts/posix/* text eol=lf # [attr]generated linguist-generated=true diff=generated -Lib/_opcode_metadata.py generated -Lib/keyword.py generated -Lib/idlelib/help.html generated -Lib/test/certdata/*.pem generated -Lib/test/certdata/*.0 generated -Lib/test/levenshtein_examples.json generated -Lib/test/test_stable_abi_ctypes.py generated -Lib/token.py generated +Lib/_opcode_metadata.py generated +Lib/keyword.py generated +Lib/idlelib/help.html generated +Lib/test/certdata/*.pem generated +Lib/test/certdata/*.0 generated +Lib/test/levenshtein_examples.json generated +Lib/test/test_stable_abi_ctypes.py generated +Lib/token.py generated +crates/compiler-core/src/bytecode/opcode_metadata.rs generated -.github/workflows/*.lock.yml linguist-generated=true merge=ours \ No newline at end of file +.github/workflows/*.lock.yml linguist-generated=true merge=ours diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 81961f803..fcab0448f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -519,6 +519,8 @@ jobs: security-events: write # for zizmor steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 @@ -544,12 +546,35 @@ jobs: package-manager-cache: false node-version: "24" - - name: prek + - name: install prek id: prek uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4 with: cache: false show-verbose-logs: false + install-only: true + + - name: prek run + run: prek run --show-diff-on-failure --color=always --all-files + + - name: Get target CPython version + id: cpython-version + run: | + version=$(cat .python-version) + echo "version=${version}" >> "$GITHUB_OUTPUT" + + - name: Clone CPython + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: python/cpython + path: cpython + ref: "v${{ steps.cpython-version.outputs.version }}" + persist-credentials: false + + - name: prek run (manual stage) + run: prek run --show-diff-on-failure --color=always --all-files --hook-stage manual + env: + CPYTHON_ROOT: ${{ github.workspace }}/cpython - name: save prek cache if: ${{ github.ref == 'refs/heads/main' }} # only save on main diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8778283dd..e66122542 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,14 +40,27 @@ repos: types: [rust] priority: 0 - - id: generate-opcode-metadata - name: generate opcode metadata - entry: python scripts/generate_opcode_metadata.py - files: '^(crates/compiler-core/src/bytecode/instruction\.rs|scripts/generate_opcode_metadata\.py)$' + - id: generate-rs-opcode-metadata + name: generate rust opcode metadata + entry: python tools/opcode_metadata/generate_rs_opcode_metadata.py + files: '^(crates/compiler-core/src/bytecode/instruction\.rs|tools/opcode_metadata/*)$' pass_filenames: false language: system require_serial: true priority: 1 # so rustfmt runs first + stages: + - manual + + - id: generate-py-opcode-metadata + name: generate python opcode metadata + entry: python tools/opcode_metadata/generate_py_opcode_metadata.py + files: '^(crates/compiler-core/src/bytecode/instruction\.rs|tools/opcode_metadata/*)$' + pass_filenames: false + language: system + require_serial: true + priority: 1 # so rustfmt runs first + stages: + - manual - repo: https://github.com/streetsidesoftware/cspell-cli rev: v10.0.0 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index 4da6e5077..001a01662 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -1,4 +1,4 @@ -# This file is generated by scripts/generate_opcode_metadata.py +# This file is generated by tools/opcode_metadata/generate_py_opcode_metadata.py # for RustPython bytecode format (CPython 3.14 compatible opcode numbers). # Do not edit! diff --git a/crates/compiler-core/generate.py b/crates/compiler-core/generate.py deleted file mode 100644 index ecb4652ea..000000000 --- a/crates/compiler-core/generate.py +++ /dev/null @@ -1,721 +0,0 @@ -#!/usr/bin/env python -import collections -import dataclasses -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 -from stack import get_stack_effect - - -@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: - 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_") - ) - - variants = ",\n".join(instr.name for instr in self) - - 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) - return f""" - #[must_use] - pub const fn as_{self.numeric_repr}(self) -> {self.numeric_repr} {{ - match self {{ - {arms}, - }} - }} - """ - - @property - def fn_try_from_numeric(self) -> str: - arms = ",\n".join(f"{instr.opcode} => Self::{instr.name}" for instr in self) - return f""" - pub const fn try_from_{self.numeric_repr}( - value: {self.numeric_repr} - ) -> Result {{ - Ok(match value {{ - {arms}, - _ => return Err(MarshalError::InvalidBytecode), - }}) - }} - """ - - @property - def impl_try_from_numeric(self) -> str: - return f""" - impl TryFrom<{self.numeric_repr}> for {self.name} {{ - type Error = MarshalError; - - fn try_from(value: {self.numeric_repr}) -> Result {{ - Self::try_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 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 - 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") - ) - - @property - def instrumented_mapping(self) -> dict[str, str]: - inames = {instr.name for instr in self if instr.name.startswith("Instrumented")} - names = {instr.name for instr in self} - inames - - res = {} - for iname in sorted(inames): - name = iname.removeprefix("Instrumented") - if name not in names: - continue - - res[name] = iname - - return res - - @property - def fn_to_base(self) -> str: - arms = ",\n".join( - f"Self::{iname} => Self::{name}" - for name, iname in self.instrumented_mapping.items() - ) - - arms = arms.strip() - if not arms: - inner = "None" - else: - 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: - arms = ",\n".join( - f"Self::{name} => Self::{iname}" - for name, iname in self.instrumented_mapping.items() - ) - - arms = arms.strip() - if not arms: - inner = "None" - else: - 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} - - deopts = collections.defaultdict(list) - 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 - - deopts[family_name].append(member.name) - - 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: - inner = "None" - else: - inner = f""" - Some(match self {{ - {arms} - _ => return None, - - }}) - """ - - return f""" - #[must_use] - pub const fn deopt(self) -> Option {{ - {inner} - }} - """ - - @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: - inner = "0" - else: - inner = f""" - match self.deoptimize() {{ - {arms} - _ => 0, - }} - """ - - return f""" - #[must_use] - pub const fn cache_entries(self) -> usize {{ - {inner} - }} - """ - - @property - def fn_stack_effect_info(self) -> str: - oparg_used = False - arms = "" - for instr in self: - name = instr.name - stack = get_stack_effect(instr) - - popped = (-stack.base_offset).to_c() - pushed = (stack.logical_sp - stack.base_offset).to_c() - - pushed_comment = "" - popped_comment = "" - - if stack_effect := self.metadata.get(name, {}).get("stack_effect"): - if npushed := stack_effect.get("pushed"): - pushed_comment = f"// TODO: Differs from CPython `{pushed}`" - pushed = npushed - - if npopped := stack_effect.get("popped"): - popped_comment = f"// TODO: Differs from CPython `{popped}`" - popped = npopped - - oparg_used = oparg_used or any("oparg" in expr for expr in (pushed, popped)) - - arms += f""" - Self::{name} => ( - {pushed}, {pushed_comment} - {popped}, {popped_comment} - ), - """.strip() - - arms = arms.strip() - - oparg_arg = "_oparg" - oparg_cast = "" - if oparg_used: - oparg_arg = "oparg" - oparg_cast = f""" - // Reason for converting {oparg_arg} to i32 is because of expressions like `1 + (oparg -1)` - // that causes underflow errors. - let oparg = i32::try_from({oparg_arg}).expect("{oparg_arg} does not fit in an `i32`"); - """ - - return f""" - #[must_use] - pub fn stack_effect_info(&self, {oparg_arg}: u32) -> StackEffect {{ - {oparg_cast} - - 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) - }} - """ - - @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() - }} - }} - """ - - @property - def fn_stack_effect(self) -> str: - return """ - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.stack_effect_info(oparg).effect() - } - """ - - def __iter__(self): - yield from self.instructions - - -@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) -class InstructionGen: - name: str - opcode_enum: str - instructions: list - numeric_repr: str - metadata: dict[str, str] - - def gen(self) -> str: - 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_") - ) - - 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} - }} - - impl {self.name} {{ - {methods} - }} - - {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} - }} - }} - """ - - @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() - }} - }} - """ - - @property - def fn_as_numeric_repr(self) -> str: - return f""" - #[must_use] - pub const fn as_{self.numeric_repr}(self) -> {self.numeric_repr} {{ - self.as_opcode().as_{self.numeric_repr}() - }} - """ - - @property - def impl_as_numeric_repr(self) -> str: - return f""" - impl From<{self.name}> for {self.numeric_repr} {{ - fn from(instruction: {self.name}) -> Self {{ - instruction.as_{self.numeric_repr}() - }} - }} - """ - - @property - def fn_label_arg(self) -> str: - TARGET = "oparg::Label" - - arms = "" - for instr in self: - name = instr.name - if oparg := self.metadata.get(name, {}).get("oparg"): - oname, otype = oparg["name"], oparg["type"] - if otype != TARGET: - continue - - arms += f"Self::{name} {{ {oname} }} => *{oname},\n" - - arms = arms.strip() - - return f""" - #[must_use] - pub const fn label_arg(&self) -> Option> {{ - Some(match self {{ - {arms} - _ => return None, - }}) - }} - """ - - @property - def fn_to_base(self) -> str: - return f""" - #[must_use] - pub const fn to_base(self) -> Option {{ - if let Some(opcode) = self.as_opcode().to_base() {{ - Some(opcode.as_instruction()) - }} else {{ - None - }} - }} - """ - - @property - def fn_to_instrumented(self) -> str: - return f""" - #[must_use] - pub const fn to_instrumented(self) -> Option {{ - if let Some(opcode) = self.as_opcode().to_instrumented() {{ - Some(opcode.as_instruction()) - }} else {{ - None - }} - }} - """ - - @property - def fn_try_from_numeric(self) -> str: - return f""" - pub const fn try_from_{self.numeric_repr}( - value: {self.numeric_repr} - ) -> Result {{ - match {self.opcode_enum}::try_from_{self.numeric_repr}(value) {{ - Ok(opcode) => Ok(opcode.as_instruction()), - Err(e) => Err(e), - }} - }} - """ - - @property - def impl_try_from_numeric(self) -> str: - return f""" - impl TryFrom<{self.numeric_repr}> for {self.name} {{ - type Error = MarshalError; - - fn try_from(value: {self.numeric_repr}) -> Result {{ - Self::try_from_{self.numeric_repr}(value) - }} - }} - """ - - @property - def fn_stack_effect(self) -> str: - return """ - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.as_opcode().stack_effect(oparg) - } - """ - - @property - def fn_cache_entries(self) -> str: - return f""" - #[must_use] - pub const fn cache_entries(self) -> usize {{ - self.as_opcode().cache_entries() - }} - """ - - @property - def fn_deopt(self) -> str: - return f""" - #[must_use] - pub const fn deopt(self) -> Option {{ - if let Some(opcode) = self.as_opcode().deopt() {{ - Some(opcode.as_instruction()) - }} else {{ - None - }} - }} - """ - - @property - def fn_stack_effect_info(self) -> str: - return f""" - #[must_use] - pub fn stack_effect_info(&self, oparg: u32) -> StackEffect {{ - self.as_opcode().stack_effect_info(oparg) - }} - """ - - def __iter__(self): - yield from self.instructions - - -def to_pascal_case(s: str) -> str: - return s.title().replace("_", "") - - -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() - 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"])) - 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) - - opcode_code = OpcodeGen( - name=opcode_enum, - instruction_enum=instruction_enum, - instructions=instructions, - numeric_repr=numeric_repr, - metadata=metadata, - analysis=analysis, - ).gen() - - outfile.write(opcode_code) - - instruction_code = InstructionGen( - name=instruction_enum, - opcode_enum=opcode_enum, - instructions=instructions, - numeric_repr=numeric_repr, - metadata=metadata, - ).gen() - - outfile.write(instruction_code) - - generated = outfile.getvalue() - - 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::{{ - instruction::{{Arg, StackEffect}}, - oparg, - }}, - marshal::MarshalError, -}}; - -{generated} - """ - ) - - OUT_FILE.write_text(output) - - -if __name__ == "__main__": - main() diff --git a/crates/compiler-core/opcode.toml b/crates/compiler-core/opcode.toml deleted file mode 100644 index 6ee0cb865..000000000 --- a/crates/compiler-core/opcode.toml +++ /dev/null @@ -1,270 +0,0 @@ -[Opcode] -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.WithExceptStart] -stack_effect = { pushed = "7", popped = "6" } - -[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" } -stack_effect = { pushed = "0" } - -[PseudoOpcode.opcodes.SetupFinally] -oparg = { name = "delta", type = "oparg::Label" } -stack_effect = { pushed = "0" } - -[PseudoOpcode.opcodes.SetupWith] -oparg = { name = "delta", type = "oparg::Label" } -stack_effect = { pushed = "0" } - -[PseudoOpcode.opcodes.StoreFastMaybeNull] -oparg = { name = "var_num", type = "oparg::NameIdx" } diff --git a/crates/compiler-core/src/bytecode.rs b/crates/compiler-core/src/bytecode.rs index 8b306efd1..7a9e34efc 100644 --- a/crates/compiler-core/src/bytecode.rs +++ b/crates/compiler-core/src/bytecode.rs @@ -20,8 +20,10 @@ use num_complex::Complex64; use rustpython_wtf8::{Wtf8, Wtf8Buf}; pub use crate::bytecode::{ - instruction::{AnyInstruction, AnyOpcode, Arg, StackEffect}, - instructions::{Instruction, Opcode, PseudoInstruction, PseudoOpcode}, + instruction::{ + AnyInstruction, AnyOpcode, Arg, Instruction, Opcode, PseudoInstruction, PseudoOpcode, + StackEffect, + }, oparg::{ BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator, ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr, LoadSuperAttr, @@ -31,7 +33,8 @@ pub use crate::bytecode::{ }; mod instruction; -mod instructions; +mod opcode_metadata; + pub mod oparg; /// Exception table entry for zero-cost exception handling diff --git a/crates/compiler-core/src/bytecode/instruction.rs b/crates/compiler-core/src/bytecode/instruction.rs index 629370697..043893065 100644 --- a/crates/compiler-core/src/bytecode/instruction.rs +++ b/crates/compiler-core/src/bytecode/instruction.rs @@ -2,32 +2,669 @@ use core::{fmt, marker::PhantomData}; use crate::marshal::MarshalError; -use super::{Instruction, OpArg, OpArgByte, OpArgType, Opcode, PseudoInstruction, PseudoOpcode}; +use super::{OpArg, OpArgByte, OpArgType, oparg}; -impl Opcode { - /// Map a specialized or instrumented opcode back to its adaptive (base) variant. - #[must_use] - pub const fn deoptimize(self) -> Self { - match self.deopt() { - Some(v) => v, - None => { - // Instrumented opcodes map back to their base - match self.to_base() { - Some(v) => v, - None => self, +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 + ),* $(,)? + } + ) => { + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + $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() })?, + )* } } + + /// Map a specialized or instrumented opcode back to its adaptive (base) variant. + #[must_use] + $opcode_vis const fn deoptimize(self) -> Self { + match self.deopt() { + Some(v) => v, + None => { + // Instrumented opcodes map back to their base + match self.to_base() { + Some(v) => v, + None => self, + } + } + } + } + + // NOTE: Keep private. Will be exposed under `try_from_u8/try_from_u16`. + pub(super) const fn try_from_numeric(value: $typ) -> Result { + match value { + $($op_id => Ok(Self::$op_name),)* + _ => Err($crate::marshal::MarshalError::InvalidBytecode), + } + } + + // NOTE: Keep private. Will be exposed under `as_u8/as_u16`. + #[must_use] + pub(super) const fn as_numeric(self) -> $typ { + match self { + $(Self::$op_name => $op_id,)* + } + } + /// Stack effect of [`Self::stack_effect_info`]. + #[must_use] + $opcode_vis fn stack_effect(&self, oparg: u32) -> i32 { + self.stack_effect_info(oparg).effect() + } } - } - /// Returns `true` if this is any instrumented opcode - /// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION). - #[must_use] - pub const fn is_instrumented(self) -> bool { - self.to_base().is_some() - || matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction) - } + 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 { + Self::try_from_numeric(value) + } + } + + impl From<$opcode_name> for $typ { + fn from(opcode: $opcode_name) -> Self { + opcode.as_numeric() + } + } + + #[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 as_opcode(&self) -> $opcode_name { + match self { + $( + Self::$op_name $({ $arg_name: _ })? => $opcode_name::$op_name, + )* + } + } + + #[must_use] + $instr_vis const fn label_arg(&self) -> Option> { + //define_opcodes!(@label_arm Self::$op_name $({ $arg_name } : $arg_type)?) + define_opcodes!(@match self, Self, [$($op_name $({ $arg_name : $arg_type })?),*]) + } + + #[must_use] + pub const fn to_base(self) -> Option { + if let Some(op) = self.as_opcode().to_base() { + Some(op.as_instruction()) + } else { + None + } + } + + #[must_use] + pub const fn to_instrumented(self) -> Option { + if let Some(op) = self.as_opcode().to_instrumented() { + Some(op.as_instruction()) + } else { + None + } + } + + /// Returns `true` if this is any instrumented opcode. + #[must_use] + $instr_vis const fn is_instrumented(&self) -> bool { + self.as_opcode().is_instrumented() + } + + #[must_use] + $instr_vis const fn is_unconditional_jump(&self) -> bool { + self.as_opcode().is_unconditional_jump() + } + + #[must_use] + $instr_vis const fn is_block_push(&self) -> bool { + self.as_opcode().is_block_push() + } + + #[must_use] + $instr_vis const fn is_scope_exit(&self) -> bool { + self.as_opcode().is_scope_exit() + } + + #[must_use] + $instr_vis const fn cache_entries(&self) -> usize{ + self.as_opcode().cache_entries() + } + + /// Map a specialized or instrumented opcode back to its adaptive (base) variant. + #[must_use] + $instr_vis const fn deoptimize(&self) -> Self { + self.as_opcode().deoptimize().as_instruction() + } + + #[must_use] + $instr_vis fn stack_effect_jump(&self, oparg: u32) -> i32 { + self.as_opcode().stack_effect_jump(oparg) + } + + #[must_use] + $instr_vis fn stack_effect_info(&self, oparg: u32) -> StackEffect { + self.as_opcode().stack_effect_info(oparg) + } + + #[must_use] + $instr_vis fn stack_effect(&self, oparg: u32) -> i32 { + self.as_opcode().stack_effect(oparg) + } + } + + impl From<$instr_name> for $opcode_name { + fn from(instr: $instr_name) -> Self { + instr.as_opcode() + } + } + + impl TryFrom<$typ> for $instr_name { + type Error = $crate::marshal::MarshalError; + + fn try_from(value: $typ) -> Result { + $opcode_name::try_from_numeric(value).map(Into::into) + } + } + + impl From<$instr_name> for $typ { + fn from(instr: $instr_name) -> Self { + instr.as_opcode().into() + } + } + }; + + // Base case: empty list + (@match $self:expr, $name:ident, []) => { + None + }; + + // Label field variant (with trailing variants) + (@match $self:expr, $name:ident, [$variant:ident { $field:ident : Label } , $($rest:tt)*]) => { + match $self { + $name::$variant { $field } => Some(*$field), + other => define_opcodes!(@match other, $name, [$($rest)*]), + } + }; + + // Label field variant (last in list) + (@match $self:expr, $name:ident, [$variant:ident { $field:ident : Label }]) => { + match $self { + $name::$variant { $field } => Some(*$field), + other => define_opcodes!(@match other, $name, []), + } + }; + + // Non-Label field variant (with trailing variants) + (@match $self:expr, $name:ident, [$variant:ident { $field:ident : $type:ty } , $($rest:tt)*]) => { + match $self { + $name::$variant { .. } => None, + other => define_opcodes!(@match other, $name, [$($rest)*]), + } + }; + + // Non-Label field variant (last in list) + (@match $self:expr, $name:ident, [$variant:ident { $field:ident : $type:ty }]) => { + match $self { + $name::$variant { .. } => None, + _ => define_opcodes!(@match _, $name, []), + } + }; + + // Unit variant (with trailing variants) + (@match $self:expr, $name:ident, [$variant:ident , $($rest:tt)*]) => { + match $self { + $name::$variant => None, + other => define_opcodes!(@match other, $name, [$($rest)*]), + } + }; + + // Unit variant (last in list) + (@match $self:expr, $name:ident, [$variant:ident]) => { + match $self { + $name::$variant => None, + _ => define_opcodes!(@match _, $name, []), + } + }; +} + +define_opcodes!( + #[repr(u8)] + pub enum Opcode; + + 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, + } +); + +define_opcodes!( + #[repr(u16)] + pub enum PseudoOpcode; + + 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 Opcode { #[must_use] pub const fn is_unconditional_jump(&self) -> bool { matches!( @@ -59,11 +696,6 @@ impl Opcode { } impl PseudoOpcode { - #[must_use] - pub const fn is_instrumented(&self) -> bool { - false - } - #[must_use] pub const fn is_block_push(&self) -> bool { matches!( @@ -72,6 +704,16 @@ impl PseudoOpcode { ) } + #[must_use] + pub const fn is_scope_exit(&self) -> bool { + false + } + + #[must_use] + pub const fn is_unconditional_jump(&self) -> bool { + matches!(self, Self::Jump | Self::JumpNoInterrupt) + } + /// Handler entry effect for SETUP_* pseudo ops. /// /// Fallthrough effect is 0 (NOPs), but when the branch is taken the @@ -89,70 +731,6 @@ impl PseudoOpcode { } } -impl Instruction { - /// Returns `true` if this is any instrumented opcode - /// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION). - #[must_use] - pub const fn is_instrumented(self) -> bool { - self.as_opcode().is_instrumented() - } - - #[must_use] - pub const fn is_unconditional_jump(&self) -> bool { - self.as_opcode().is_unconditional_jump() - } - - #[must_use] - pub const fn is_block_push(&self) -> bool { - self.as_opcode().is_block_push() - } - - #[must_use] - pub const fn is_scope_exit(&self) -> bool { - self.as_opcode().is_scope_exit() - } - - /// Map a specialized or instrumented opcode back to its adaptive (base) variant. - #[must_use] - pub const fn deoptimize(self) -> Self { - self.as_opcode().deoptimize().as_instruction() - } - - #[must_use] - pub fn stack_effect_jump(&self, oparg: u32) -> i32 { - self.as_opcode().stack_effect(oparg) - } -} - -impl PseudoInstruction { - /// Returns true if self is one of: - /// - [`PseudoInstruction::SetupCleanup`] - /// - [`PseudoInstruction::SetupFinally`] - /// - [`PseudoInstruction::SetupWith`] - #[must_use] - pub const fn is_block_push(&self) -> bool { - self.as_opcode().is_block_push() - } - - #[must_use] - pub const fn is_unconditional_jump(&self) -> bool { - matches!( - self.as_opcode(), - PseudoOpcode::Jump | PseudoOpcode::JumpNoInterrupt - ) - } - - #[must_use] - pub const fn is_scope_exit(&self) -> bool { - false - } - - #[must_use] - pub fn stack_effect_jump(&self, oparg: u32) -> i32 { - self.as_opcode().stack_effect_jump(oparg) - } -} - macro_rules! either_real_pseudo { // Const ( @@ -191,28 +769,28 @@ pub enum AnyInstruction { impl AnyInstruction { either_real_pseudo!( - #[must_use] - pub const fn is_unconditional_jump(&self) -> bool + #[must_use] + pub const fn is_unconditional_jump(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn is_scope_exit(&self) -> bool + #[must_use] + pub const fn is_scope_exit(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 + #[must_use] + pub fn stack_effect(&self, oparg: u32) -> i32 ); either_real_pseudo!( - #[must_use] - pub fn stack_effect_jump(&self, oparg: u32) -> i32 + #[must_use] + pub fn stack_effect_jump(&self, oparg: u32) -> i32 ); either_real_pseudo!( - #[must_use] - pub fn stack_effect_info(&self, oparg: u32) -> StackEffect + #[must_use] + pub fn stack_effect_info(&self, oparg: u32) -> StackEffect ); } @@ -340,7 +918,7 @@ impl AnyInstruction { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum AnyOpcode { Real(Opcode), Pseudo(PseudoOpcode), @@ -428,53 +1006,53 @@ impl AnyOpcode { } either_real_pseudo!( - #[must_use] - pub const fn has_arg(&self) -> bool + #[must_use] + pub const fn has_arg(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn has_jump(&self) -> bool + #[must_use] + pub const fn has_jump(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn has_free(&self) -> bool + #[must_use] + pub const fn has_free(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn has_local(&self) -> bool + #[must_use] + pub const fn has_local(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn has_name(&self) -> bool + #[must_use] + pub const fn has_name(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn has_const(&self) -> bool + #[must_use] + pub const fn has_const(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn is_instrumented(&self) -> bool + #[must_use] + pub const fn is_instrumented(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub const fn is_block_push(&self) -> bool + #[must_use] + pub const fn is_block_push(&self) -> bool ); either_real_pseudo!( - #[must_use] - pub fn stack_effect_jump(&self, oparg: u32) -> i32 + #[must_use] + pub fn stack_effect_jump(&self, oparg: u32) -> i32 ); either_real_pseudo!( - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 + #[must_use] + pub fn stack_effect(&self, oparg: u32) -> i32 ); #[must_use] diff --git a/crates/compiler-core/src/bytecode/instructions.rs b/crates/compiler-core/src/bytecode/instructions.rs deleted file mode 100644 index 7f16dc42d..000000000 --- a/crates/compiler-core/src/bytecode/instructions.rs +++ /dev/null @@ -1,2780 +0,0 @@ -// This file is generated by crates/compiler-core/generate.py -// Do not edit! - -use crate::{ - bytecode::{ - instruction::{Arg, StackEffect}, - oparg, - }, - marshal::MarshalError, -}; - -#[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 { - /// 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 { - 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 cache_entries(self) -> usize { - match self.deoptimize() { - 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 { - 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 { - 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_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 - ) - } - - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.stack_effect_info(oparg).effect() - } - - #[must_use] - pub 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 => ( - 7, // TODO: Differs from CPython `6` - 6, // TODO: Differs from CPython `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 { - 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::InstrumentedJumpForward => Self::JumpForward, - Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr, - Self::InstrumentedNotTaken => Self::NotTaken, - Self::InstrumentedPopIter => Self::PopIter, - Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse, - Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone, - Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone, - Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue, - Self::InstrumentedResume => Self::Resume, - Self::InstrumentedReturnValue => Self::ReturnValue, - Self::InstrumentedYieldValue => Self::YieldValue, - _ => return None, - }) - } - - #[must_use] - pub const fn to_instrumented(self) -> Option { - Some(match self { - 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::JumpForward => Self::InstrumentedJumpForward, - Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr, - Self::NotTaken => Self::InstrumentedNotTaken, - Self::PopIter => Self::InstrumentedPopIter, - Self::PopJumpIfFalse => Self::InstrumentedPopJumpIfFalse, - Self::PopJumpIfNone => Self::InstrumentedPopJumpIfNone, - Self::PopJumpIfNotNone => Self::InstrumentedPopJumpIfNotNone, - Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue, - Self::Resume => Self::InstrumentedResume, - Self::ReturnValue => Self::InstrumentedReturnValue, - Self::YieldValue => Self::InstrumentedYieldValue, - _ => return None, - }) - } - - pub const fn try_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(MarshalError::InvalidBytecode), - }) - } -} - -impl From for Instruction { - fn from(opcode: Opcode) -> Self { - opcode.as_instruction() - } -} - -impl From for u8 { - fn from(opcode: Opcode) -> Self { - opcode.as_u8() - } -} - -impl TryFrom for Opcode { - type Error = MarshalError; - - fn try_from(value: u8) -> Result { - Self::try_from_u8(value) - } -} - -#[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 { - #[must_use] - pub const fn as_u8(self) -> u8 { - self.as_opcode().as_u8() - } - - /// 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, - } - } - - #[must_use] - pub const fn cache_entries(self) -> usize { - self.as_opcode().cache_entries() - } - - #[must_use] - pub const fn deopt(self) -> Option { - if let Some(opcode) = self.as_opcode().deopt() { - Some(opcode.as_instruction()) - } else { - None - } - } - - #[must_use] - pub const fn label_arg(&self) -> Option> { - Some(match self { - Self::ForIter { delta } => *delta, - Self::JumpBackward { delta } => *delta, - Self::JumpBackwardNoInterrupt { delta } => *delta, - Self::JumpForward { delta } => *delta, - Self::PopJumpIfFalse { delta } => *delta, - Self::PopJumpIfNone { delta } => *delta, - Self::PopJumpIfNotNone { delta } => *delta, - Self::PopJumpIfTrue { delta } => *delta, - Self::Send { delta } => *delta, - _ => return None, - }) - } - - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.as_opcode().stack_effect(oparg) - } - - #[must_use] - pub fn stack_effect_info(&self, oparg: u32) -> StackEffect { - self.as_opcode().stack_effect_info(oparg) - } - - #[must_use] - pub const fn to_base(self) -> Option { - if let Some(opcode) = self.as_opcode().to_base() { - Some(opcode.as_instruction()) - } else { - None - } - } - - #[must_use] - pub const fn to_instrumented(self) -> Option { - if let Some(opcode) = self.as_opcode().to_instrumented() { - Some(opcode.as_instruction()) - } else { - None - } - } - - pub const fn try_from_u8(value: u8) -> Result { - match Opcode::try_from_u8(value) { - Ok(opcode) => Ok(opcode.as_instruction()), - Err(e) => Err(e), - } - } -} - -impl From for u8 { - fn from(instruction: Instruction) -> Self { - instruction.as_u8() - } -} - -impl From for Opcode { - fn from(instruction: Instruction) -> Self { - instruction.as_opcode() - } -} - -impl TryFrom for Instruction { - type Error = MarshalError; - - fn try_from(value: u8) -> Result { - Self::try_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 { - /// 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 { - 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 cache_entries(self) -> usize { - 0 - } - - #[must_use] - pub const fn deopt(self) -> Option { - None - } - - /// 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_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 - } - - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.stack_effect_info(oparg).effect() - } - - #[must_use] - pub fn stack_effect_info(&self, _oparg: u32) -> StackEffect { - 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 => ( - 0, // TODO: Differs from CPython `2` - 0, - ), - Self::SetupFinally => ( - 0, // TODO: Differs from CPython `1` - 0, - ), - Self::SetupWith => ( - 0, // TODO: Differs from CPython `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 to_base(self) -> Option { - None - } - - #[must_use] - pub const fn to_instrumented(self) -> Option { - None - } - - pub const fn try_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(MarshalError::InvalidBytecode), - }) - } -} - -impl From for PseudoInstruction { - fn from(opcode: PseudoOpcode) -> Self { - opcode.as_instruction() - } -} - -impl From for u16 { - fn from(opcode: PseudoOpcode) -> Self { - opcode.as_u16() - } -} - -impl TryFrom for PseudoOpcode { - type Error = MarshalError; - - fn try_from(value: u16) -> Result { - Self::try_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 { - #[must_use] - pub const fn as_u16(self) -> u16 { - self.as_opcode().as_u16() - } - - /// 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, - } - } - - #[must_use] - pub const fn cache_entries(self) -> usize { - self.as_opcode().cache_entries() - } - - #[must_use] - pub const fn deopt(self) -> Option { - if let Some(opcode) = self.as_opcode().deopt() { - Some(opcode.as_instruction()) - } else { - None - } - } - - #[must_use] - pub const fn label_arg(&self) -> Option> { - Some(match self { - Self::Jump { delta } => *delta, - Self::JumpIfFalse { delta } => *delta, - Self::JumpIfTrue { delta } => *delta, - Self::JumpNoInterrupt { delta } => *delta, - Self::SetupCleanup { delta } => *delta, - Self::SetupFinally { delta } => *delta, - Self::SetupWith { delta } => *delta, - _ => return None, - }) - } - - /// Stack effect of [`Self::stack_effect_info`]. - #[must_use] - pub fn stack_effect(&self, oparg: u32) -> i32 { - self.as_opcode().stack_effect(oparg) - } - - #[must_use] - pub fn stack_effect_info(&self, oparg: u32) -> StackEffect { - self.as_opcode().stack_effect_info(oparg) - } - - #[must_use] - pub const fn to_base(self) -> Option { - if let Some(opcode) = self.as_opcode().to_base() { - Some(opcode.as_instruction()) - } else { - None - } - } - - #[must_use] - pub const fn to_instrumented(self) -> Option { - if let Some(opcode) = self.as_opcode().to_instrumented() { - Some(opcode.as_instruction()) - } else { - None - } - } - - pub const fn try_from_u16(value: u16) -> Result { - match PseudoOpcode::try_from_u16(value) { - Ok(opcode) => Ok(opcode.as_instruction()), - Err(e) => Err(e), - } - } -} - -impl From for u16 { - fn from(instruction: PseudoInstruction) -> Self { - instruction.as_u16() - } -} - -impl From for PseudoOpcode { - fn from(instruction: PseudoInstruction) -> Self { - instruction.as_opcode() - } -} - -impl TryFrom for PseudoInstruction { - type Error = MarshalError; - - fn try_from(value: u16) -> Result { - Self::try_from_u16(value) - } -} diff --git a/crates/compiler-core/src/bytecode/oparg.rs b/crates/compiler-core/src/bytecode/oparg.rs index 6cb58b1a6..03628604a 100644 --- a/crates/compiler-core/src/bytecode/oparg.rs +++ b/crates/compiler-core/src/bytecode/oparg.rs @@ -1,7 +1,7 @@ use core::fmt; use crate::{ - bytecode::{CodeUnit, instructions::Instruction}, + bytecode::{CodeUnit, Instruction}, marshal::MarshalError, }; diff --git a/crates/compiler-core/src/bytecode/opcode_metadata.rs b/crates/compiler-core/src/bytecode/opcode_metadata.rs new file mode 100644 index 000000000..2b48500c2 --- /dev/null +++ b/crates/compiler-core/src/bytecode/opcode_metadata.rs @@ -0,0 +1,809 @@ +// This file is generated by tools/opcode_metadata/generate_rs_opcode_metadata.py +// Do not edit! + +use crate::{bytecode::instruction::StackEffect, marshal::MarshalError}; + +impl super::Opcode { + /// Returns [`Self`] as [`u8`]. + #[must_use] + pub const fn as_u8(self) -> u8 { + self.as_numeric() + } + + #[must_use] + pub const fn cache_entries(self) -> usize { + match self.deoptimize() { + 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 { + 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 { + 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_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 is_instrumented(self) -> bool { + matches!( + self, + Self::InstrumentedEndFor + | Self::InstrumentedPopIter + | Self::InstrumentedEndSend + | Self::InstrumentedForIter + | Self::InstrumentedInstruction + | Self::InstrumentedJumpForward + | Self::InstrumentedNotTaken + | Self::InstrumentedPopJumpIfTrue + | Self::InstrumentedPopJumpIfFalse + | Self::InstrumentedPopJumpIfNone + | Self::InstrumentedPopJumpIfNotNone + | Self::InstrumentedResume + | Self::InstrumentedReturnValue + | Self::InstrumentedYieldValue + | Self::InstrumentedEndAsyncFor + | Self::InstrumentedLoadSuperAttr + | Self::InstrumentedCall + | Self::InstrumentedCallKw + | Self::InstrumentedCallFunctionEx + | Self::InstrumentedJumpBackward + | Self::InstrumentedLine + ) + } + + #[must_use] + pub 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 => ( + 7, // TODO: Differs from CPython `6` + 6, // TODO: Differs from CPython `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 { + 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::InstrumentedJumpForward => Self::JumpForward, + Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr, + Self::InstrumentedNotTaken => Self::NotTaken, + Self::InstrumentedPopIter => Self::PopIter, + Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse, + Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone, + Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone, + Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue, + Self::InstrumentedResume => Self::Resume, + Self::InstrumentedReturnValue => Self::ReturnValue, + Self::InstrumentedYieldValue => Self::YieldValue, + _ => return None, + }) + } + + #[must_use] + pub const fn to_instrumented(self) -> Option { + Some(match self { + 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::JumpForward => Self::InstrumentedJumpForward, + Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr, + Self::NotTaken => Self::InstrumentedNotTaken, + Self::PopIter => Self::InstrumentedPopIter, + Self::PopJumpIfFalse => Self::InstrumentedPopJumpIfFalse, + Self::PopJumpIfNone => Self::InstrumentedPopJumpIfNone, + Self::PopJumpIfNotNone => Self::InstrumentedPopJumpIfNotNone, + Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue, + Self::Resume => Self::InstrumentedResume, + Self::ReturnValue => Self::InstrumentedReturnValue, + Self::YieldValue => Self::InstrumentedYieldValue, + _ => return None, + }) + } + + pub const fn try_from_u8(value: u8) -> Result { + Self::try_from_numeric(value) + } +} + +impl super::PseudoOpcode { + /// Returns [`Self`] as [`u16`]. + #[must_use] + pub const fn as_u16(self) -> u16 { + self.as_numeric() + } + + #[must_use] + pub const fn cache_entries(self) -> usize { + 0 + } + + #[must_use] + pub const fn deopt(self) -> Option { + None + } + + /// 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_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 is_instrumented(self) -> bool { + false + } + + #[must_use] + pub fn stack_effect_info(&self, _oparg: u32) -> StackEffect { + 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 => ( + 0, // TODO: Differs from CPython `2` + 0, + ), + Self::SetupFinally => ( + 0, // TODO: Differs from CPython `1` + 0, + ), + Self::SetupWith => ( + 0, // TODO: Differs from CPython `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 to_base(self) -> Option { + None + } + + #[must_use] + pub const fn to_instrumented(self) -> Option { + None + } + + pub const fn try_from_u16(value: u16) -> Result { + Self::try_from_numeric(value) + } +} diff --git a/crates/compiler-core/src/lib.rs b/crates/compiler-core/src/lib.rs index 245713d1a..8fe1146e5 100644 --- a/crates/compiler-core/src/lib.rs +++ b/crates/compiler-core/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![recursion_limit = "256"] // Needed for `define_opcodes!` macro #![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/main/logo.png")] #![doc(html_root_url = "https://docs.rs/rustpython-compiler-core/")] diff --git a/scripts/generate_opcode_metadata.py b/scripts/generate_opcode_metadata.py deleted file mode 100644 index 5b9a0b10b..000000000 --- a/scripts/generate_opcode_metadata.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -Generate Lib/_opcode_metadata.py for RustPython bytecode. - -This file generates opcode metadata that is compatible with CPython 3.13. -""" - -import itertools -import pathlib -import re -import typing - -ROOT = pathlib.Path(__file__).parents[1] -BYTECODE_FILE = ( - ROOT / "crates" / "compiler-core" / "src" / "bytecode" / "instructions.rs" -) -OPCODE_METADATA_FILE = ROOT / "Lib" / "_opcode_metadata.py" - - -# Opcodes that needs to be first, regardless of their opcode ID. -PRIORITY_OPMAP = { - "CACHE", - "RESERVED", - "RESUME", - "INSTRUMENTED_LINE", - "ENTER_EXECUTOR", -} - - -def to_snake_case(s: str) -> str: - res = re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", s) - return re.sub(r"(\D)(\d+)$", r"\1_\2", res).upper() - - -class Opcode(typing.NamedTuple): - rust_name: str - id: int - have_oparg: bool - - @property - def is_instrumented(self): - return self.cpython_name.startswith("INSTRUMENTED_") - - @property - def cpython_name(self): - return to_snake_case(self.rust_name) - - @classmethod - def from_str(cls, text: str): - # Split on commas that are followed by a newline + an uppercase letter (new entry) - entries = re.split(r",\s*\n\s*(?=[A-Z])", text) - for entry in entries: - entry = entry.strip() - if not entry: - continue - have_oparg = "Arg<" in entry # Hacky but works - rust_name = re.match(r"(\w+)", entry).group(1) - id_num = re.findall(r"= (\d+)", entry)[0] - yield cls(rust_name=rust_name, id=int(id_num), have_oparg=have_oparg) - - def __lt__(self, other: typing.Self) -> bool: - sprio, oprio = ( - opcode.cpython_name not in PRIORITY_OPMAP for opcode in (self, other) - ) - return (sprio, self.id) < (oprio, other.id) - - -def extract_enum_body(text: str, name: str) -> str: - # Find the start of the enum block - start_match = re.search(rf"enum\s+{name}\s*\{{", text) - if not start_match: - return None - - # Manually track brace depth from that point - depth = 0 - start = start_match.end() - 1 # position of opening '{' - for i, ch in enumerate(text[start:], start): - if ch == "{": - depth += 1 - elif ch == "}": - depth -= 1 - if depth == 0: - # Return only the inner content (excluding outer braces) - return text[start + 1 : i] - - -def build_deopts(text: str) -> dict[str, list[str]]: - raw_body = re.search(r"fn deopt\(self\)(.*)", text, re.DOTALL).group(1) - match_start = raw_body.find("match self") - if match_start == -1: - raise ValueError("Could not detect a match statement in deopt method") - - brace_depth = 0 - block_start = None - block_end = None - - for i, ch in enumerate(raw_body[match_start:], match_start): - if ch == "{": - brace_depth += 1 - if block_start is None: - block_start = i + 1 - elif ch == "}": - brace_depth -= 1 - if brace_depth == 0: - block_end = i - break - - match_body = raw_body[block_start:block_end] - - arm_pattern = re.compile( - r"((?:Self::\w+\s*\|\s*)*Self::\w+)\s*=>\s*(?:\{\s*)?Self::(\w+)", re.DOTALL - ) - variants_pattern = re.compile(r"Self::(\w+)") - - deopts = {} - for hit in arm_pattern.finditer(match_body): - raw_variants = hit.group(1) - opcode = hit.group(2) - - variants = variants_pattern.findall(raw_variants) - - key = to_snake_case(opcode) - value = [to_snake_case(variant) for variant in variants] - deopts[key] = value - - return deopts - - -contents = BYTECODE_FILE.read_text(encoding="utf-8") - -deopts = build_deopts(contents) - -enum_body = "\n".join( - extract_enum_body(contents, enum_name) - for enum_name in ("Instruction", "PseudoInstruction") -) -opcodes = list(Opcode.from_str(enum_body)) - -have_oparg = min(opcode.id for opcode in opcodes if opcode.have_oparg) - 1 -min_instrumented = min(opcode.id for opcode in opcodes if opcode.is_instrumented) - -# Generate the output file -output = """# This file is generated by scripts/generate_opcode_metadata.py -# for RustPython bytecode format (CPython 3.14 compatible opcode numbers). -# Do not edit! -""" - -output += "\n_specializations = {\n" - -for key, lst in deopts.items(): - output += f' "{key}": [\n' - for item in lst: - output += f' "{item}",\n' - output += " ],\n" - -output += "}\n" - -specialized = set(itertools.chain.from_iterable(deopts.values())) -output += "\n_specialized_opmap = {\n" -for opcode in sorted(opcodes, key=lambda op: op.cpython_name): - cpython_name = opcode.cpython_name - if cpython_name not in specialized: - continue - - output += f" '{cpython_name}': {opcode.id},\n" - -output += "}\n" - -output += "\nopmap = {\n" - -for opcode in sorted(opcodes): - cpython_name = opcode.cpython_name - if cpython_name in specialized: - continue - - output += f" '{cpython_name}': {opcode.id},\n" - -output += "}\n" - -output += f""" -HAVE_ARGUMENT = {have_oparg} -MIN_INSTRUMENTED_OPCODE = {min_instrumented} -""" - -OPCODE_METADATA_FILE.write_text(output, encoding="utf-8") diff --git a/tools/opcode_metadata/conf.toml b/tools/opcode_metadata/conf.toml new file mode 100644 index 000000000..6b2f0afe1 --- /dev/null +++ b/tools/opcode_metadata/conf.toml @@ -0,0 +1,11 @@ +[WithExceptStart] +stack_effect = { pushed = "7", popped = "6" } + +[SetupCleanup] +stack_effect = { pushed = "0" } + +[SetupFinally] +stack_effect = { pushed = "0" } + +[SetupWith] +stack_effect = { pushed = "0" } diff --git a/tools/opcode_metadata/cpython.py b/tools/opcode_metadata/cpython.py new file mode 100644 index 000000000..56743a888 --- /dev/null +++ b/tools/opcode_metadata/cpython.py @@ -0,0 +1,27 @@ +import os +import pathlib +import sys + +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" + + +if (path := CPYTHON_TOOLS_LIB.as_posix()) not in sys.path: + sys.path.append(path) + + +from analyzer import SKIP_PROPERTIES, Analysis, Family, Properties, analyze_files +from stack import get_stack_effect + + +def get_analysis() -> Analysis: + from generators_common import DEFAULT_INPUT + + analysis = analyze_files([DEFAULT_INPUT]) + # Our speration is done at the enum definition + analysis.instructions |= analysis.pseudos + return analysis diff --git a/tools/opcode_metadata/generate_py_opcode_metadata.py b/tools/opcode_metadata/generate_py_opcode_metadata.py new file mode 100644 index 000000000..08f350e4b --- /dev/null +++ b/tools/opcode_metadata/generate_py_opcode_metadata.py @@ -0,0 +1,107 @@ +""" +Generate Lib/_opcode_metadata.py for RustPython bytecode. + +This file generates opcode metadata that is compatible with CPython 3.14. +""" + +import functools +import io +import itertools +import operator +import pathlib +import typing + +from opcodes import OpcodeInfo +from utils import DEFAULT_INPUT, ROOT, get_conf, to_pascal_case, to_upper_snake_case + +OUT_FILE = ROOT / "Lib/_opcode_metadata.py" + + +# Opcodes that needs to be first, regardless of their opcode ID. +PRIORITY_OPMAP = { + "CACHE", + "RESERVED", + "RESUME", + "INSTRUMENTED_LINE", + "ENTER_EXECUTOR", +} + +INDENT = " " * 4 +INDENT2 = INDENT * 2 + + +def main(): + override_conf = get_conf() + inp = DEFAULT_INPUT.read_text() + + infos = tuple(OpcodeInfo.iter_infos(inp, override_conf)) + opcodes = tuple(itertools.chain.from_iterable(info.opcodes for info in infos)) + + script_path = pathlib.Path(__file__).resolve().relative_to(ROOT).as_posix() + out = io.StringIO() + + out.write( + f""" +# This file is generated by {script_path} +# for RustPython bytecode format (CPython 3.14 compatible opcode numbers). +# Do not edit! +""".lstrip() + ) + + # _specializations + out.write("\n") + out.write("_specializations = {\n") + + deopts = functools.reduce(operator.ior, map(operator.attrgetter("deopts"), infos)) + + for key, lst in deopts.items(): + key = to_upper_snake_case(key) + out.write(f'{INDENT}"{key}": [\n') + + for item in map(to_upper_snake_case, lst): + out.write(f'{INDENT2}"{item}",\n') + + out.write(f"{INDENT}],\n") + + out.write("}\n") + + # _specialized_opmap + out.write("\n") + out.write("_specialized_opmap = {\n") + + specialized = set(itertools.chain.from_iterable(deopts.values())) + for opcode in sorted(opcodes, key=lambda op: op.cpython_name): + if opcode.rust_name not in specialized: + continue + out.write(f"{INDENT}'{opcode.cpython_name}': {opcode.id},\n") + + out.write("}\n") + + # opmap + out.write("\n") + out.write("opmap = {\n") + + key = lambda op: (op.cpython_name not in PRIORITY_OPMAP, op.id) + for opcode in sorted(opcodes, key=key): + if opcode.rust_name in specialized: + continue + + out.write(f"{INDENT}'{opcode.cpython_name}': {opcode.id},\n") + + out.write("}\n") + + # min + out.write("\n") + have_argument = min(opcode.id for opcode in opcodes if opcode.have_argument) - 1 + out.write(f"HAVE_ARGUMENT = {have_argument}\n") + + min_instrumented = min(opcode.id for opcode in opcodes if opcode.is_instrumented) + out.write(f"MIN_INSTRUMENTED_OPCODE = {min_instrumented}\n") + + # write output + generated = out.getvalue() + OUT_FILE.write_text(generated) + + +if __name__ == "__main__": + main() diff --git a/tools/opcode_metadata/generate_rs_opcode_metadata.py b/tools/opcode_metadata/generate_rs_opcode_metadata.py new file mode 100644 index 000000000..1d6ce2c0e --- /dev/null +++ b/tools/opcode_metadata/generate_rs_opcode_metadata.py @@ -0,0 +1,364 @@ +#!/usr/bin/env python +from __future__ import annotations + +import collections +import dataclasses +import io +import os +import pathlib +import subprocess +import sys +import typing + +import tomllib +from cpython import Analysis, get_analysis, get_stack_effect +from opcodes import OpcodeInfo +from utils import DEFAULT_INPUT, ROOT, get_conf, to_pascal_case + +OUT_FILE = ROOT / "crates/compiler-core/src/bytecode/opcode_metadata.rs" + + +@dataclasses.dataclass(frozen=True, slots=True) +class OpcodeGen: + info: OpcodeDef + + @property + def fn_as_info_size(self) -> str: + return f""" + /// Returns [`Self`] as [`{self.size}`]. + #[must_use] + pub const fn as_{self.size}(self) -> {self.size} {{ + self.as_numeric() + }} + """ + + @property + def fn_try_from_numeric(self) -> str: + return f""" + pub const fn try_from_{self.size}( + value: {self.size}, + ) -> Result {{ + Self::try_from_numeric(value) + }} + """ + + @property + def fn_has_arg(self) -> str: + return self.gen_fn_has_attr("has_arg", "oparg", "HAS_ARG_FLAG") + + @property + def fn_has_const(self) -> str: + return self.gen_fn_has_attr("has_const", "uses_co_consts", "HAS_CONST_FLAG") + + @property + def fn_has_name(self) -> str: + return self.gen_fn_has_attr("has_name", "uses_co_names", "HAS_NAME_FLAG") + + @property + def fn_has_jump(self) -> str: + return self.gen_fn_has_attr("has_jump", "jumps", "HAS_JUMP_FLAG") + + @property + def fn_has_free(self) -> str: + return self.gen_fn_has_attr("has_free", "has_free", "HAS_FREE_FLAG") + + @property + def fn_has_local(self) -> str: + return self.gen_fn_has_attr("has_local", "uses_locals", "HAS_LOCAL_FLAG") + + @property + def fn_is_instrumented(self) -> str: + arms = "|".join( + f"Self::{opcode.rust_name}" for opcode in self if opcode.is_instrumented + ) + + arms = arms.strip() + if arms: + inner = f"matches!(self, {arms})" + else: + inner = "false" + + return f""" + #[must_use] + pub const fn is_instrumented(self) -> bool {{ + {inner} + }} + """ + + @property + def fn_to_base(self) -> str: + arms = ",\n".join( + f"Self::{iname} => Self::{name}" + for name, iname in self.instrumented_mapping.items() + ) + + arms = arms.strip() + if not arms: + inner = "None" + else: + 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: + arms = ",\n".join( + f"Self::{name} => Self::{iname}" + for name, iname in self.instrumented_mapping.items() + ) + + arms = arms.strip() + if not arms: + inner = "None" + else: + 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: + arms = "" + for target, specialized in self.info.deopts.items(): + ops = "|".join(f"Self::{op}" for op in specialized) + arms += f"{ops} => Self::{target},\n" + + arms = arms.strip() + + if not arms: + inner = "None" + else: + inner = f""" + Some(match self {{ + {arms} + _ => return None, + }}) + """ + + return f""" + #[must_use] + pub const fn deopt(self) -> Option {{ + {inner} + }} + """ + + @property + def fn_cache_entries(self) -> str: + arms = "" + for opcode in self: + name = opcode.rust_name + if opcode.is_instrumented: + continue + if getattr(opcode, "family", None) and (opcode.family.name != name): + continue + + try: + size = opcode.cache_entry + except AttributeError: + continue + + if size > 1: + arms += f"Self::{name} => {size - 1},\n" + + arms = arms.strip() + if not arms: + inner = "0" + else: + inner = f""" + match self.deoptimize() {{ + {arms} + _ => 0, + }} + """ + + return f""" + #[must_use] + pub const fn cache_entries(self) -> usize {{ + {inner} + }} + """ + + @property + def fn_stack_effect_info(self) -> str: + oparg_used = False + arms = "" + for opcode in self: + name = opcode.rust_name + + popped = opcode.stack_effect_popped + pushed = opcode.stack_effect_pushed + + pushed_comment = "" + popped_comment = "" + + if popped != opcode.cpy_popped: + popped_comment = f"// TODO: Differs from CPython `{opcode.cpy_popped}`" + + if pushed != opcode.cpy_pushed: + pushed_comment = f"// TODO: Differs from CPython `{opcode.cpy_pushed}`" + + oparg_used = oparg_used or any("oparg" in expr for expr in (pushed, popped)) + + arms += f""" + Self::{name} => ( + {pushed}, {pushed_comment} + {popped}, {popped_comment} + ), + """.strip() + + arms = arms.strip() + + oparg_arg = "_oparg" + oparg_cast = "" + if oparg_used: + oparg_arg = "oparg" + oparg_cast = f""" + // Reason for converting {oparg_arg} to i32 is because of expressions like `1 + (oparg -1)` + // that causes underflow errors. + let oparg = i32::try_from({oparg_arg}).expect("{oparg_arg} does not fit in an `i32`"); + """ + + return f""" + #[must_use] + pub fn stack_effect_info(&self, {oparg_arg}: u32) -> StackEffect {{ + {oparg_cast} + + 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 gen(self) -> str: + 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""" + impl super::{self.info.enum_name} {{ + {methods} + }} + + {impls} + """ + + def gen_fn_has_attr(self, fn_name: str, properties_attr: str, doc_flag: str) -> str: + arms = "|".join( + f"Self::{opcode.rust_name}" + for opcode in self + if getattr(opcode.properties, properties_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 {fn_name}(self) -> bool {{ + {inner} + }} + """ + + @property + def instrumented_mapping(self) -> dict[str, str]: + names, inames = set(), set() + for opcode in self: + name = opcode.rust_name + if opcode.is_instrumented: + inames.add(name) + else: + names.add(name) + + res = {} + for iname in sorted(inames): + name = iname.removeprefix("Instrumented") + if name not in names: + continue + + res[name] = iname + + return res + + @property + def size(self) -> str: + return self.info.size + + def __iter__(self): + yield from self.info.opcodes + + +def rustfmt(code: str) -> str: + return subprocess.check_output(["rustfmt", "--emit=stdout"], input=code, text=True) + + +def main(): + override_conf = get_conf() + inp = DEFAULT_INPUT.read_text() + opcode_infos = OpcodeInfo.iter_infos(inp, override_conf) + + outfile = io.StringIO() + + for info in opcode_infos: + gen = OpcodeGen(info).gen() + outfile.write(gen) + + generated = outfile.getvalue() + + 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::instruction::StackEffect, + marshal::MarshalError, +}}; + +{generated} + """ + ) + + OUT_FILE.write_text(output) + + +if __name__ == "__main__": + main() diff --git a/tools/opcode_metadata/opcodes.py b/tools/opcode_metadata/opcodes.py new file mode 100644 index 000000000..c1b198017 --- /dev/null +++ b/tools/opcode_metadata/opcodes.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import collections +import dataclasses +import re +import typing +import warnings + +import utils +from cpython import SKIP_PROPERTIES, Family, Properties, get_analysis, get_stack_effect +from utils import SKIP_OVERRIDE, Override, OverrideConfs, StackEffect, to_pascal_case + +if typing.TYPE_CHECKING: + from collections.abc import Iterable + + +@dataclasses.dataclass(frozen=True, slots=True) +class OpcodeInfo: + enum_name: str + size: str + opcodes: tuple[Opcode, ...] + + @property + def deopts(self) -> dict[str, list[str]]: + analysis = get_analysis() + names = {opcode.rust_name for opcode in self} + + res = collections.defaultdict(list) + for family in analysis.families.values(): + family_name = to_pascal_case(family.name) + if family_name not in names: + continue + + for member in family.members: + member_name = to_pascal_case(member.name) + if member.name == family_name: + continue + + res[family_name].append(member_name) + + return dict(res) + + def __iter__(self): + yield from self.opcodes + + @classmethod + def iter_infos( + cls, text: str, override_confs: OverrideConfs + ) -> Iterable[typing.Self]: + for block_match in re.finditer( + r"define_opcodes!\s*\((.+?)\);", text, re.DOTALL + ): + block = block_match.group(1).strip() + + size = re.search(r"#\[repr\((\w+)\)\]", block).group(1) + enum_name = re.search( + r"#\[repr\(\w+\)\]\s*pub\s+enum\s+(\w+)\s*;", block + ).group(1) + + second_enum_match = re.search(r"pub\s+enum\s+(\w+)\s*\{", block, re.DOTALL) + entries = utils.extract_enum_body(block, second_enum_match.end() - 1) + + opcodes = tuple(sorted(iter_opcodes(entries, override_confs))) + + yield cls(enum_name, size, opcodes) + + +def iter_opcodes(text: str, override_confs: OverrideConfs) -> Iterable[Opcode]: + analysis = get_analysis() + # Split on commas that are followed by a newline + an uppercase letter (new entry) + entries = map(str.strip, re.split(r",\s*\n\s*(?=[A-Z])", text)) + for entry in entries: + if not entry: + continue + + opcode = Opcode.from_str(entry) + + rust_name = opcode.rust_name + override = override_confs.get(rust_name, SKIP_OVERRIDE) + + cpython_name = opcode.cpython_name + + kwargs = {} + if instr := analysis.instructions.get(cpython_name): + kwargs["properties"] = instr.properties + kwargs["family"] = getattr(instr, "family", None) + kwargs["cache_entry"] = getattr(instr, "size", -1) + + stack = get_stack_effect(instr) + + popped = (-stack.base_offset).to_c() + pushed = (stack.logical_sp - stack.base_offset).to_c() + kwargs["stack_effect"] = StackEffect(popped=popped, pushed=pushed) + elif override == SKIP_OVERRIDE: + warnings.warn( + f"Could not get instruction metadata for {rust_name}" + " from CPython or override conf" + ) + + yield dataclasses.replace(opcode, override=override, **kwargs) + + +@dataclasses.dataclass(frozen=True, slots=True) +class Opcode: + rust_name: str + id: int + have_argument: bool = False + cache_entry: int = 0 + stack_effect: StackEffect | None = None + properties: Properties = dataclasses.field(default_factory=lambda: SKIP_PROPERTIES) + family: Family | None = None + override: Override = dataclasses.field(default_factory=Override) + + @property + def is_instrumented(self) -> bool: + if (res := self.override.is_instrumented) is not None: + return res + + return self.cpython_name.startswith("INSTRUMENTED_") + + @property + def cpython_name(self): + return utils.to_upper_snake_case(self.rust_name) + + @property + def cpy_popped(self) -> str | None: + return getattr(self.stack_effect, "popped", None) + + @property + def cpy_pushed(self) -> str | None: + return getattr(self.stack_effect, "pushed", None) + + @property + def stack_effect_popped(self) -> str: + ove_popped = self.override.stack_effect.popped + + if (ove_popped is None) and (self.cpy_popped is None): + raise ValueError(f"{self.rust_name} is missing popped stack_effect") + + return ove_popped or self.cpy_popped + + @property + def stack_effect_pushed(self) -> str: + ove_pushed = self.override.stack_effect.pushed + + if (ove_pushed is None) and (self.cpy_pushed is None): + raise ValueError(f"{self.rust_name} is missing pushed stack_effect") + + return ove_pushed or self.cpy_pushed + + @classmethod + def from_str(cls, entry: str) -> typing.Self: + rust_name = re.match(r"(\w+)", entry).group(1) + id_num = re.findall(r"= (\d+)", entry)[0] + have_argument = "Arg<" in entry + return cls(rust_name, int(id_num), have_argument=have_argument) + + def __lt__(self, other: typing.Self) -> bool: + return self.id < other.id diff --git a/tools/opcode_metadata/utils.py b/tools/opcode_metadata/utils.py new file mode 100644 index 000000000..bc3a9ace8 --- /dev/null +++ b/tools/opcode_metadata/utils.py @@ -0,0 +1,96 @@ +import dataclasses +import pathlib +import re +import sys + +import tomllib + +ROOT = pathlib.Path(__file__).parents[2].resolve() +DEFAULT_INPUT = ROOT / "crates/compiler-core/src/bytecode/instruction.rs" +DEFAULT_CONF = pathlib.Path(__file__).parent / "conf.toml" + + +@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) +class StackEffect: + pushed: str | None = None + popped: str | None = None + + +@dataclasses.dataclass(frozen=True, kw_only=True, slots=True) +class Override: + is_instrumented: bool | None = None + stack_effect: StackEffect = dataclasses.field(default_factory=StackEffect) + + +type OverrideConfs = dict[str, Override] + +SKIP_STACK_EFFECT = StackEffect() +SKIP_OVERRIDE = Override() + + +def get_conf(path: pathlib.Path = DEFAULT_CONF) -> OverrideConfs: + data = path.read_text(encoding="utf-8") + conf = tomllib.loads(data) + for k, v in conf.items(): + v["stack_effect"] = StackEffect(**v.get("stack_effect", {})) + conf[k] = Override(**v) + + return conf + + +def to_pascal_case(s: str) -> str: + return s.title().replace("_", "") + + +def to_upper_snake_case(s: str) -> str: + """ + Converts a PascalCaseString to be SNAKE_CASE + + Parameters + ---------- + s : str + Pascal cased string to convert. + + Returns + ------- + str + Uppercased snake case string. + + Examples + -------- + >>> to_upper_snake_case("LoadAttr") + LOAD_ATTR + >>> to_upper_snake_case("CallIntrinsic1") + CALL_INTRINSIC_1 + """ + res = re.sub(r"(?<=[a-z0-9])([A-Z])", r"_\1", s) + return re.sub(r"(\D)(\d+)$", r"\1_\2", res).upper() + + +def extract_enum_body(text: str, start: int) -> str: + """ + Extract the rust enum body from a raw rust source code. + + Parameters + ---------- + text : str + Rust source code containing the enum body. + start : int + Offset to start searching from. + + Returns + ------- + str + Extracted enum body. + """ + assert text[start] == "{" + depth = 0 + for i, ch in enumerate(text[start:], start): + if ch == "{": + depth += 1 + elif ch == "}": + depth -= 1 + if depth == 0: + return text[start + 1 : i].strip() # exclude the outer braces + + raise ValueError("Could not find end to enum body")