Skip to main content

rustpython_compiler_core/bytecode/
instruction.rs

1use core::{fmt, marker::PhantomData, mem};
2
3use crate::{
4    bytecode::{
5        BorrowedConstant, Constant, InstrDisplayContext,
6        oparg::{
7            self, BinaryOperator, BuildSliceArgCount, CommonConstant, ComparisonOperator,
8            ConvertValueOparg, IntrinsicFunction1, IntrinsicFunction2, Invert, Label, LoadAttr,
9            LoadSuperAttr, MakeFunctionFlag, NameIdx, OpArg, OpArgByte, OpArgType, RaiseKind,
10            SpecialMethod, UnpackExArgs,
11        },
12    },
13    marshal::MarshalError,
14};
15
16/// A Single bytecode instruction that are executed by the VM.
17///
18/// Currently aligned with CPython 3.14.
19///
20/// ## See also
21/// - [CPython opcode IDs](https://github.com/python/cpython/blob/v3.14.2/Include/opcode_ids.h)
22#[derive(Clone, Copy, Debug)]
23#[repr(u8)]
24pub enum Instruction {
25    // No-argument instructions (opcode < HAVE_ARGUMENT=44)
26    Cache = 0,
27    BinarySlice = 1,
28    BuildTemplate = 2,
29    BinaryOpInplaceAddUnicode = 3,
30    CallFunctionEx = 4,
31    CheckEgMatch = 5,
32    CheckExcMatch = 6,
33    CleanupThrow = 7,
34    DeleteSubscr = 8,
35    EndFor = 9,
36    EndSend = 10,
37    ExitInitCheck = 11, // Placeholder
38    FormatSimple = 12,
39    FormatWithSpec = 13,
40    GetAIter = 14,
41    GetANext = 15,
42    GetIter = 16,
43    Reserved = 17,
44    GetLen = 18,
45    GetYieldFromIter = 19,
46    InterpreterExit = 20, // Placeholder
47    LoadBuildClass = 21,
48    LoadLocals = 22,
49    MakeFunction = 23,
50    MatchKeys = 24,
51    MatchMapping = 25,
52    MatchSequence = 26,
53    Nop = 27,
54    NotTaken = 28,
55    PopExcept = 29,
56    PopIter = 30,
57    PopTop = 31,
58    PushExcInfo = 32,
59    PushNull = 33,
60    ReturnGenerator = 34,
61    ReturnValue = 35,
62    SetupAnnotations = 36,
63    StoreSlice = 37,
64    StoreSubscr = 38,
65    ToBool = 39,
66    UnaryInvert = 40,
67    UnaryNegative = 41,
68    UnaryNot = 42,
69    WithExceptStart = 43,
70    // CPython 3.14 opcodes with arguments (44-120)
71    BinaryOp {
72        op: Arg<BinaryOperator>,
73    } = 44,
74    /// Build an Interpolation from value, expression string, and optional format_spec on stack.
75    ///
76    /// oparg encoding: (conversion << 2) | has_format_spec
77    /// - has_format_spec (bit 0): if 1, format_spec is on stack
78    /// - conversion (bits 2+): 0=None, 1=Str, 2=Repr, 3=Ascii
79    ///
80    /// Stack: [value, expression_str, format_spec?] -> [interpolation]
81    BuildInterpolation {
82        format: Arg<u32>,
83    } = 45,
84    BuildList {
85        count: Arg<u32>,
86    } = 46,
87    BuildMap {
88        count: Arg<u32>,
89    } = 47,
90    BuildSet {
91        count: Arg<u32>,
92    } = 48,
93    BuildSlice {
94        argc: Arg<BuildSliceArgCount>,
95    } = 49,
96    BuildString {
97        count: Arg<u32>,
98    } = 50,
99    BuildTuple {
100        count: Arg<u32>,
101    } = 51,
102    Call {
103        argc: Arg<u32>,
104    } = 52,
105    CallIntrinsic1 {
106        func: Arg<IntrinsicFunction1>,
107    } = 53,
108    CallIntrinsic2 {
109        func: Arg<IntrinsicFunction2>,
110    } = 54,
111    CallKw {
112        argc: Arg<u32>,
113    } = 55,
114    CompareOp {
115        opname: Arg<ComparisonOperator>,
116    } = 56,
117    ContainsOp {
118        invert: Arg<Invert>,
119    } = 57,
120    ConvertValue {
121        oparg: Arg<ConvertValueOparg>,
122    } = 58,
123    Copy {
124        i: Arg<u32>,
125    } = 59,
126    CopyFreeVars {
127        n: Arg<u32>,
128    } = 60,
129    DeleteAttr {
130        namei: Arg<NameIdx>,
131    } = 61,
132    DeleteDeref {
133        i: Arg<oparg::VarNum>,
134    } = 62,
135    DeleteFast {
136        var_num: Arg<oparg::VarNum>,
137    } = 63,
138    DeleteGlobal {
139        namei: Arg<NameIdx>,
140    } = 64,
141    DeleteName {
142        namei: Arg<NameIdx>,
143    } = 65,
144    DictMerge {
145        i: Arg<u32>,
146    } = 66,
147    DictUpdate {
148        i: Arg<u32>,
149    } = 67,
150    EndAsyncFor = 68,
151    ExtendedArg = 69,
152    ForIter {
153        delta: Arg<Label>,
154    } = 70,
155    GetAwaitable {
156        r#where: Arg<u32>,
157    } = 71,
158    ImportFrom {
159        namei: Arg<NameIdx>,
160    } = 72,
161    ImportName {
162        namei: Arg<NameIdx>,
163    } = 73,
164    IsOp {
165        invert: Arg<Invert>,
166    } = 74,
167    JumpBackward {
168        delta: Arg<Label>,
169    } = 75,
170    JumpBackwardNoInterrupt {
171        delta: Arg<Label>,
172    } = 76, // Placeholder
173    JumpForward {
174        delta: Arg<Label>,
175    } = 77,
176    ListAppend {
177        i: Arg<u32>,
178    } = 78,
179    ListExtend {
180        i: Arg<u32>,
181    } = 79,
182    LoadAttr {
183        namei: Arg<LoadAttr>,
184    } = 80,
185    LoadCommonConstant {
186        idx: Arg<CommonConstant>,
187    } = 81,
188    LoadConst {
189        consti: Arg<oparg::ConstIdx>,
190    } = 82,
191    LoadDeref {
192        i: Arg<oparg::VarNum>,
193    } = 83,
194    LoadFast {
195        var_num: Arg<oparg::VarNum>,
196    } = 84,
197    LoadFastAndClear {
198        var_num: Arg<oparg::VarNum>,
199    } = 85,
200    LoadFastBorrow {
201        var_num: Arg<oparg::VarNum>,
202    } = 86,
203    LoadFastBorrowLoadFastBorrow {
204        var_nums: Arg<oparg::VarNums>,
205    } = 87,
206    LoadFastCheck {
207        var_num: Arg<oparg::VarNum>,
208    } = 88,
209    LoadFastLoadFast {
210        var_nums: Arg<oparg::VarNums>,
211    } = 89,
212    LoadFromDictOrDeref {
213        i: Arg<oparg::VarNum>,
214    } = 90,
215    LoadFromDictOrGlobals {
216        i: Arg<NameIdx>,
217    } = 91,
218    LoadGlobal {
219        namei: Arg<NameIdx>,
220    } = 92,
221    LoadName {
222        namei: Arg<NameIdx>,
223    } = 93,
224    LoadSmallInt {
225        i: Arg<u32>,
226    } = 94,
227    LoadSpecial {
228        method: Arg<SpecialMethod>,
229    } = 95,
230    LoadSuperAttr {
231        namei: Arg<LoadSuperAttr>,
232    } = 96,
233    MakeCell {
234        i: Arg<oparg::VarNum>,
235    } = 97,
236    MapAdd {
237        i: Arg<u32>,
238    } = 98,
239    MatchClass {
240        count: Arg<u32>,
241    } = 99,
242    PopJumpIfFalse {
243        delta: Arg<Label>,
244    } = 100,
245    PopJumpIfNone {
246        delta: Arg<Label>,
247    } = 101,
248    PopJumpIfNotNone {
249        delta: Arg<Label>,
250    } = 102,
251    PopJumpIfTrue {
252        delta: Arg<Label>,
253    } = 103,
254    RaiseVarargs {
255        argc: Arg<RaiseKind>,
256    } = 104,
257    Reraise {
258        depth: Arg<u32>,
259    } = 105,
260    Send {
261        delta: Arg<Label>,
262    } = 106,
263    SetAdd {
264        i: Arg<u32>,
265    } = 107,
266    SetFunctionAttribute {
267        flag: Arg<MakeFunctionFlag>,
268    } = 108,
269    SetUpdate {
270        i: Arg<u32>,
271    } = 109,
272    StoreAttr {
273        namei: Arg<NameIdx>,
274    } = 110,
275    StoreDeref {
276        i: Arg<oparg::VarNum>,
277    } = 111,
278    StoreFast {
279        var_num: Arg<oparg::VarNum>,
280    } = 112,
281    StoreFastLoadFast {
282        var_nums: Arg<oparg::VarNums>,
283    } = 113,
284    StoreFastStoreFast {
285        var_nums: Arg<oparg::VarNums>,
286    } = 114,
287    StoreGlobal {
288        namei: Arg<NameIdx>,
289    } = 115,
290    StoreName {
291        namei: Arg<NameIdx>,
292    } = 116,
293    Swap {
294        i: Arg<u32>,
295    } = 117,
296    UnpackEx {
297        counts: Arg<UnpackExArgs>,
298    } = 118,
299    UnpackSequence {
300        count: Arg<u32>,
301    } = 119,
302    YieldValue {
303        arg: Arg<u32>,
304    } = 120,
305    // CPython 3.14 RESUME (128)
306    Resume {
307        context: Arg<oparg::ResumeContext>,
308    } = 128,
309    // CPython 3.14 specialized opcodes (129-211)
310    BinaryOpAddFloat = 129,                     // Placeholder
311    BinaryOpAddInt = 130,                       // Placeholder
312    BinaryOpAddUnicode = 131,                   // Placeholder
313    BinaryOpExtend = 132,                       // Placeholder
314    BinaryOpMultiplyFloat = 133,                // Placeholder
315    BinaryOpMultiplyInt = 134,                  // Placeholder
316    BinaryOpSubscrDict = 135,                   // Placeholder
317    BinaryOpSubscrGetitem = 136,                // Placeholder
318    BinaryOpSubscrListInt = 137,                // Placeholder
319    BinaryOpSubscrListSlice = 138,              // Placeholder
320    BinaryOpSubscrStrInt = 139,                 // Placeholder
321    BinaryOpSubscrTupleInt = 140,               // Placeholder
322    BinaryOpSubtractFloat = 141,                // Placeholder
323    BinaryOpSubtractInt = 142,                  // Placeholder
324    CallAllocAndEnterInit = 143,                // Placeholder
325    CallBoundMethodExactArgs = 144,             // Placeholder
326    CallBoundMethodGeneral = 145,               // Placeholder
327    CallBuiltinClass = 146,                     // Placeholder
328    CallBuiltinFast = 147,                      // Placeholder
329    CallBuiltinFastWithKeywords = 148,          // Placeholder
330    CallBuiltinO = 149,                         // Placeholder
331    CallIsinstance = 150,                       // Placeholder
332    CallKwBoundMethod = 151,                    // Placeholder
333    CallKwNonPy = 152,                          // Placeholder
334    CallKwPy = 153,                             // Placeholder
335    CallLen = 154,                              // Placeholder
336    CallListAppend = 155,                       // Placeholder
337    CallMethodDescriptorFast = 156,             // Placeholder
338    CallMethodDescriptorFastWithKeywords = 157, // Placeholder
339    CallMethodDescriptorNoargs = 158,           // Placeholder
340    CallMethodDescriptorO = 159,                // Placeholder
341    CallNonPyGeneral = 160,                     // Placeholder
342    CallPyExactArgs = 161,                      // Placeholder
343    CallPyGeneral = 162,                        // Placeholder
344    CallStr1 = 163,                             // Placeholder
345    CallTuple1 = 164,                           // Placeholder
346    CallType1 = 165,                            // Placeholder
347    CompareOpFloat = 166,                       // Placeholder
348    CompareOpInt = 167,                         // Placeholder
349    CompareOpStr = 168,                         // Placeholder
350    ContainsOpDict = 169,                       // Placeholder
351    ContainsOpSet = 170,                        // Placeholder
352    ForIterGen = 171,                           // Placeholder
353    ForIterList = 172,                          // Placeholder
354    ForIterRange = 173,                         // Placeholder
355    ForIterTuple = 174,                         // Placeholder
356    JumpBackwardJit = 175,                      // Placeholder
357    JumpBackwardNoJit = 176,                    // Placeholder
358    LoadAttrClass = 177,                        // Placeholder
359    LoadAttrClassWithMetaclassCheck = 178,      // Placeholder
360    LoadAttrGetattributeOverridden = 179,       // Placeholder
361    LoadAttrInstanceValue = 180,                // Placeholder
362    LoadAttrMethodLazyDict = 181,               // Placeholder
363    LoadAttrMethodNoDict = 182,                 // Placeholder
364    LoadAttrMethodWithValues = 183,             // Placeholder
365    LoadAttrModule = 184,                       // Placeholder
366    LoadAttrNondescriptorNoDict = 185,          // Placeholder
367    LoadAttrNondescriptorWithValues = 186,      // Placeholder
368    LoadAttrProperty = 187,                     // Placeholder
369    LoadAttrSlot = 188,                         // Placeholder
370    LoadAttrWithHint = 189,                     // Placeholder
371    LoadConstImmortal = 190,                    // Placeholder
372    LoadConstMortal = 191,                      // Placeholder
373    LoadGlobalBuiltin = 192,                    // Placeholder
374    LoadGlobalModule = 193,                     // Placeholder
375    LoadSuperAttrAttr = 194,                    // Placeholder
376    LoadSuperAttrMethod = 195,                  // Placeholder
377    ResumeCheck = 196,                          // Placeholder
378    SendGen = 197,                              // Placeholder
379    StoreAttrInstanceValue = 198,               // Placeholder
380    StoreAttrSlot = 199,                        // Placeholder
381    StoreAttrWithHint = 200,                    // Placeholder
382    StoreSubscrDict = 201,                      // Placeholder
383    StoreSubscrListInt = 202,                   // Placeholder
384    ToBoolAlwaysTrue = 203,                     // Placeholder
385    ToBoolBool = 204,                           // Placeholder
386    ToBoolInt = 205,                            // Placeholder
387    ToBoolList = 206,                           // Placeholder
388    ToBoolNone = 207,                           // Placeholder
389    ToBoolStr = 208,                            // Placeholder
390    UnpackSequenceList = 209,                   // Placeholder
391    UnpackSequenceTuple = 210,                  // Placeholder
392    UnpackSequenceTwoTuple = 211,               // Placeholder
393    // CPython 3.14 instrumented opcodes (234-254)
394    InstrumentedEndFor = 234,
395    InstrumentedPopIter = 235,
396    InstrumentedEndSend = 236,
397    InstrumentedForIter = 237,
398    InstrumentedInstruction = 238,
399    InstrumentedJumpForward = 239,
400    InstrumentedNotTaken = 240,
401    InstrumentedPopJumpIfTrue = 241,
402    InstrumentedPopJumpIfFalse = 242,
403    InstrumentedPopJumpIfNone = 243,
404    InstrumentedPopJumpIfNotNone = 244,
405    InstrumentedResume = 245,
406    InstrumentedReturnValue = 246,
407    InstrumentedYieldValue = 247,
408    InstrumentedEndAsyncFor = 248,
409    InstrumentedLoadSuperAttr = 249,
410    InstrumentedCall = 250,
411    InstrumentedCallKw = 251,
412    InstrumentedCallFunctionEx = 252,
413    InstrumentedJumpBackward = 253,
414    InstrumentedLine = 254,
415    EnterExecutor = 255, // Placeholder
416}
417
418const _: () = assert!(mem::size_of::<Instruction>() == 1);
419
420impl From<Instruction> for u8 {
421    #[inline]
422    fn from(ins: Instruction) -> Self {
423        // SAFETY: there's no padding bits
424        unsafe { mem::transmute::<Instruction, Self>(ins) }
425    }
426}
427
428impl TryFrom<u8> for Instruction {
429    type Error = MarshalError;
430
431    #[inline]
432    fn try_from(value: u8) -> Result<Self, MarshalError> {
433        // CPython-compatible opcodes (0-120)
434        let cpython_start = u8::from(Self::Cache);
435        let cpython_end = u8::from(Self::YieldValue { arg: Arg::marker() });
436
437        // Resume has a non-contiguous opcode (128)
438        let resume_id = u8::from(Self::Resume {
439            context: Arg::marker(),
440        });
441        let enter_executor_id = u8::from(Self::EnterExecutor);
442
443        let specialized_start = u8::from(Self::BinaryOpAddFloat);
444        let specialized_end = u8::from(Self::UnpackSequenceTwoTuple);
445
446        let instrumented_start = u8::from(Self::InstrumentedEndFor);
447        let instrumented_end = u8::from(Self::InstrumentedLine);
448
449        if (cpython_start..=cpython_end).contains(&value)
450            || value == resume_id
451            || value == enter_executor_id
452            || (specialized_start..=specialized_end).contains(&value)
453            || (instrumented_start..=instrumented_end).contains(&value)
454        {
455            Ok(unsafe { mem::transmute::<u8, Self>(value) })
456        } else {
457            Err(Self::Error::InvalidBytecode)
458        }
459    }
460}
461
462impl Instruction {
463    /// Returns `true` if this is any instrumented opcode
464    /// (regular INSTRUMENTED_*, INSTRUMENTED_LINE, or INSTRUMENTED_INSTRUCTION).
465    pub const fn is_instrumented(self) -> bool {
466        self.to_base().is_some()
467            || matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction)
468    }
469
470    /// Map a base opcode to its INSTRUMENTED_* variant.
471    /// Returns `None` if this opcode has no instrumented counterpart.
472    ///
473    /// # Panics (debug)
474    /// Panics if called on an already-instrumented opcode.
475    pub fn to_instrumented(self) -> Option<Self> {
476        debug_assert!(
477            !self.is_instrumented(),
478            "to_instrumented called on already-instrumented opcode {self:?}"
479        );
480        Some(match self {
481            Self::Resume { .. } => Self::InstrumentedResume,
482            Self::ReturnValue => Self::InstrumentedReturnValue,
483            Self::YieldValue { .. } => Self::InstrumentedYieldValue,
484            Self::Call { .. } => Self::InstrumentedCall,
485            Self::CallKw { .. } => Self::InstrumentedCallKw,
486            Self::CallFunctionEx => Self::InstrumentedCallFunctionEx,
487            Self::LoadSuperAttr { .. } => Self::InstrumentedLoadSuperAttr,
488            Self::JumpForward { .. } => Self::InstrumentedJumpForward,
489            Self::JumpBackward { .. } => Self::InstrumentedJumpBackward,
490            Self::ForIter { .. } => Self::InstrumentedForIter,
491            Self::EndFor => Self::InstrumentedEndFor,
492            Self::EndSend => Self::InstrumentedEndSend,
493            Self::PopJumpIfTrue { .. } => Self::InstrumentedPopJumpIfTrue,
494            Self::PopJumpIfFalse { .. } => Self::InstrumentedPopJumpIfFalse,
495            Self::PopJumpIfNone { .. } => Self::InstrumentedPopJumpIfNone,
496            Self::PopJumpIfNotNone { .. } => Self::InstrumentedPopJumpIfNotNone,
497            Self::NotTaken => Self::InstrumentedNotTaken,
498            Self::PopIter => Self::InstrumentedPopIter,
499            Self::EndAsyncFor => Self::InstrumentedEndAsyncFor,
500            _ => return None,
501        })
502    }
503
504    /// Map an INSTRUMENTED_* opcode back to its base variant.
505    /// Returns `None` for non-instrumented opcodes, and also for
506    /// `InstrumentedLine` / `InstrumentedInstruction` which are event-layer
507    /// placeholders without a fixed base opcode (the real opcode is stored in
508    /// `CoMonitoringData`).
509    ///
510    /// The returned base opcode uses `Arg::marker()` for typed fields —
511    /// only the opcode byte matters since `replace_op` preserves the arg byte.
512    pub const fn to_base(self) -> Option<Self> {
513        Some(match self {
514            Self::InstrumentedResume => Self::Resume {
515                context: Arg::marker(),
516            },
517            Self::InstrumentedReturnValue => Self::ReturnValue,
518            Self::InstrumentedYieldValue => Self::YieldValue { arg: Arg::marker() },
519            Self::InstrumentedCall => Self::Call {
520                argc: Arg::marker(),
521            },
522            Self::InstrumentedCallKw => Self::CallKw {
523                argc: Arg::marker(),
524            },
525            Self::InstrumentedCallFunctionEx => Self::CallFunctionEx,
526            Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr {
527                namei: Arg::marker(),
528            },
529            Self::InstrumentedJumpForward => Self::JumpForward {
530                delta: Arg::marker(),
531            },
532            Self::InstrumentedJumpBackward => Self::JumpBackward {
533                delta: Arg::marker(),
534            },
535            Self::InstrumentedForIter => Self::ForIter {
536                delta: Arg::marker(),
537            },
538            Self::InstrumentedEndFor => Self::EndFor,
539            Self::InstrumentedEndSend => Self::EndSend,
540            Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue {
541                delta: Arg::marker(),
542            },
543            Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse {
544                delta: Arg::marker(),
545            },
546            Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone {
547                delta: Arg::marker(),
548            },
549            Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone {
550                delta: Arg::marker(),
551            },
552            Self::InstrumentedNotTaken => Self::NotTaken,
553            Self::InstrumentedPopIter => Self::PopIter,
554            Self::InstrumentedEndAsyncFor => Self::EndAsyncFor,
555            _ => return None,
556        })
557    }
558
559    /// Map a specialized opcode back to its adaptive (base) variant.
560    /// `_PyOpcode_Deopt`
561    pub const fn deopt(self) -> Option<Self> {
562        Some(match self {
563            // RESUME specializations
564            Self::ResumeCheck => Self::Resume {
565                context: Arg::marker(),
566            },
567            // LOAD_CONST specializations
568            Self::LoadConstMortal | Self::LoadConstImmortal => Self::LoadConst {
569                consti: Arg::marker(),
570            },
571            // TO_BOOL specializations
572            Self::ToBoolAlwaysTrue
573            | Self::ToBoolBool
574            | Self::ToBoolInt
575            | Self::ToBoolList
576            | Self::ToBoolNone
577            | Self::ToBoolStr => Self::ToBool,
578            // BINARY_OP specializations
579            Self::BinaryOpMultiplyInt
580            | Self::BinaryOpAddInt
581            | Self::BinaryOpSubtractInt
582            | Self::BinaryOpMultiplyFloat
583            | Self::BinaryOpAddFloat
584            | Self::BinaryOpSubtractFloat
585            | Self::BinaryOpAddUnicode
586            | Self::BinaryOpSubscrListInt
587            | Self::BinaryOpSubscrListSlice
588            | Self::BinaryOpSubscrTupleInt
589            | Self::BinaryOpSubscrStrInt
590            | Self::BinaryOpSubscrDict
591            | Self::BinaryOpSubscrGetitem
592            | Self::BinaryOpExtend
593            | Self::BinaryOpInplaceAddUnicode => Self::BinaryOp { op: Arg::marker() },
594            // STORE_SUBSCR specializations
595            Self::StoreSubscrDict | Self::StoreSubscrListInt => Self::StoreSubscr,
596            // SEND specializations
597            Self::SendGen => Self::Send {
598                delta: Arg::marker(),
599            },
600            // UNPACK_SEQUENCE specializations
601            Self::UnpackSequenceTwoTuple | Self::UnpackSequenceTuple | Self::UnpackSequenceList => {
602                Self::UnpackSequence {
603                    count: Arg::marker(),
604                }
605            }
606            // STORE_ATTR specializations
607            Self::StoreAttrInstanceValue | Self::StoreAttrSlot | Self::StoreAttrWithHint => {
608                Self::StoreAttr {
609                    namei: Arg::marker(),
610                }
611            }
612            // LOAD_GLOBAL specializations
613            Self::LoadGlobalModule | Self::LoadGlobalBuiltin => Self::LoadGlobal {
614                namei: Arg::marker(),
615            },
616            // LOAD_SUPER_ATTR specializations
617            Self::LoadSuperAttrAttr | Self::LoadSuperAttrMethod => Self::LoadSuperAttr {
618                namei: Arg::marker(),
619            },
620            // LOAD_ATTR specializations
621            Self::LoadAttrInstanceValue
622            | Self::LoadAttrModule
623            | Self::LoadAttrWithHint
624            | Self::LoadAttrSlot
625            | Self::LoadAttrClass
626            | Self::LoadAttrClassWithMetaclassCheck
627            | Self::LoadAttrProperty
628            | Self::LoadAttrGetattributeOverridden
629            | Self::LoadAttrMethodWithValues
630            | Self::LoadAttrMethodNoDict
631            | Self::LoadAttrMethodLazyDict
632            | Self::LoadAttrNondescriptorWithValues
633            | Self::LoadAttrNondescriptorNoDict => Self::LoadAttr {
634                namei: Arg::marker(),
635            },
636            // COMPARE_OP specializations
637            Self::CompareOpFloat | Self::CompareOpInt | Self::CompareOpStr => Self::CompareOp {
638                opname: Arg::marker(),
639            },
640            // CONTAINS_OP specializations
641            Self::ContainsOpSet | Self::ContainsOpDict => Self::ContainsOp {
642                invert: Arg::marker(),
643            },
644            // JUMP_BACKWARD specializations
645            Self::JumpBackwardNoJit | Self::JumpBackwardJit => Self::JumpBackward {
646                delta: Arg::marker(),
647            },
648            // FOR_ITER specializations
649            Self::ForIterList | Self::ForIterTuple | Self::ForIterRange | Self::ForIterGen => {
650                Self::ForIter {
651                    delta: Arg::marker(),
652                }
653            }
654            // CALL specializations
655            Self::CallBoundMethodExactArgs
656            | Self::CallPyExactArgs
657            | Self::CallType1
658            | Self::CallStr1
659            | Self::CallTuple1
660            | Self::CallBuiltinClass
661            | Self::CallBuiltinO
662            | Self::CallBuiltinFast
663            | Self::CallBuiltinFastWithKeywords
664            | Self::CallLen
665            | Self::CallIsinstance
666            | Self::CallListAppend
667            | Self::CallMethodDescriptorO
668            | Self::CallMethodDescriptorFastWithKeywords
669            | Self::CallMethodDescriptorNoargs
670            | Self::CallMethodDescriptorFast
671            | Self::CallAllocAndEnterInit
672            | Self::CallPyGeneral
673            | Self::CallBoundMethodGeneral
674            | Self::CallNonPyGeneral => Self::Call {
675                argc: Arg::marker(),
676            },
677            // CALL_KW specializations
678            Self::CallKwBoundMethod | Self::CallKwPy | Self::CallKwNonPy => Self::CallKw {
679                argc: Arg::marker(),
680            },
681            _ => return None,
682        })
683    }
684
685    /// Map a specialized or instrumented opcode back to its adaptive (base) variant.
686    pub const fn deoptimize(self) -> Self {
687        match self.deopt() {
688            Some(v) => v,
689            None => {
690                // Instrumented opcodes map back to their base
691                match self.to_base() {
692                    Some(v) => v,
693                    None => self,
694                }
695            }
696        }
697    }
698
699    /// Number of CACHE code units that follow this instruction.
700    /// _PyOpcode_Caches
701    pub const fn cache_entries(self) -> usize {
702        match self {
703            // LOAD_ATTR: 9 cache entries
704            Self::LoadAttr { .. }
705            | Self::LoadAttrClass
706            | Self::LoadAttrClassWithMetaclassCheck
707            | Self::LoadAttrGetattributeOverridden
708            | Self::LoadAttrInstanceValue
709            | Self::LoadAttrMethodLazyDict
710            | Self::LoadAttrMethodNoDict
711            | Self::LoadAttrMethodWithValues
712            | Self::LoadAttrModule
713            | Self::LoadAttrNondescriptorNoDict
714            | Self::LoadAttrNondescriptorWithValues
715            | Self::LoadAttrProperty
716            | Self::LoadAttrSlot
717            | Self::LoadAttrWithHint => 9,
718
719            // BINARY_OP: 5 cache entries
720            Self::BinaryOp { .. }
721            | Self::BinaryOpAddFloat
722            | Self::BinaryOpAddInt
723            | Self::BinaryOpAddUnicode
724            | Self::BinaryOpExtend
725            | Self::BinaryOpInplaceAddUnicode
726            | Self::BinaryOpMultiplyFloat
727            | Self::BinaryOpMultiplyInt
728            | Self::BinaryOpSubscrDict
729            | Self::BinaryOpSubscrGetitem
730            | Self::BinaryOpSubscrListInt
731            | Self::BinaryOpSubscrListSlice
732            | Self::BinaryOpSubscrStrInt
733            | Self::BinaryOpSubscrTupleInt
734            | Self::BinaryOpSubtractFloat
735            | Self::BinaryOpSubtractInt => 5,
736
737            // LOAD_GLOBAL / STORE_ATTR: 4 cache entries
738            Self::LoadGlobal { .. }
739            | Self::LoadGlobalBuiltin
740            | Self::LoadGlobalModule
741            | Self::StoreAttr { .. }
742            | Self::StoreAttrInstanceValue
743            | Self::StoreAttrSlot
744            | Self::StoreAttrWithHint => 4,
745
746            // CALL / CALL_KW / TO_BOOL: 3 cache entries
747            Self::Call { .. }
748            | Self::CallAllocAndEnterInit
749            | Self::CallBoundMethodExactArgs
750            | Self::CallBoundMethodGeneral
751            | Self::CallBuiltinClass
752            | Self::CallBuiltinFast
753            | Self::CallBuiltinFastWithKeywords
754            | Self::CallBuiltinO
755            | Self::CallIsinstance
756            | Self::CallLen
757            | Self::CallListAppend
758            | Self::CallMethodDescriptorFast
759            | Self::CallMethodDescriptorFastWithKeywords
760            | Self::CallMethodDescriptorNoargs
761            | Self::CallMethodDescriptorO
762            | Self::CallNonPyGeneral
763            | Self::CallPyExactArgs
764            | Self::CallPyGeneral
765            | Self::CallStr1
766            | Self::CallTuple1
767            | Self::CallType1
768            | Self::CallKw { .. }
769            | Self::CallKwBoundMethod
770            | Self::CallKwNonPy
771            | Self::CallKwPy
772            | Self::ToBool
773            | Self::ToBoolAlwaysTrue
774            | Self::ToBoolBool
775            | Self::ToBoolInt
776            | Self::ToBoolList
777            | Self::ToBoolNone
778            | Self::ToBoolStr => 3,
779
780            // 1 cache entry
781            Self::CompareOp { .. }
782            | Self::CompareOpFloat
783            | Self::CompareOpInt
784            | Self::CompareOpStr
785            | Self::ContainsOp { .. }
786            | Self::ContainsOpDict
787            | Self::ContainsOpSet
788            | Self::ForIter { .. }
789            | Self::ForIterGen
790            | Self::ForIterList
791            | Self::ForIterRange
792            | Self::ForIterTuple
793            | Self::JumpBackward { .. }
794            | Self::JumpBackwardJit
795            | Self::JumpBackwardNoJit
796            | Self::LoadSuperAttr { .. }
797            | Self::LoadSuperAttrAttr
798            | Self::LoadSuperAttrMethod
799            | Self::PopJumpIfTrue { .. }
800            | Self::PopJumpIfFalse { .. }
801            | Self::PopJumpIfNone { .. }
802            | Self::PopJumpIfNotNone { .. }
803            | Self::Send { .. }
804            | Self::SendGen
805            | Self::StoreSubscr
806            | Self::StoreSubscrDict
807            | Self::StoreSubscrListInt
808            | Self::UnpackSequence { .. }
809            | Self::UnpackSequenceList
810            | Self::UnpackSequenceTuple
811            | Self::UnpackSequenceTwoTuple => 1,
812
813            // Instrumented opcodes have the same cache entries as their base
814            _ => match self.to_base() {
815                Some(base) => base.cache_entries(),
816                None => 0,
817            },
818        }
819    }
820}
821
822impl InstructionMetadata for Instruction {
823    #[inline]
824    fn label_arg(&self) -> Option<Arg<Label>> {
825        match self {
826            Self::JumpBackward { delta: l }
827            | Self::JumpBackwardNoInterrupt { delta: l }
828            | Self::JumpForward { delta: l }
829            | Self::PopJumpIfTrue { delta: l }
830            | Self::PopJumpIfFalse { delta: l }
831            | Self::PopJumpIfNone { delta: l }
832            | Self::PopJumpIfNotNone { delta: l }
833            | Self::ForIter { delta: l }
834            | Self::Send { delta: l } => Some(*l),
835            _ => None,
836        }
837    }
838
839    fn is_unconditional_jump(&self) -> bool {
840        matches!(
841            self,
842            Self::JumpForward { .. }
843                | Self::JumpBackward { .. }
844                | Self::JumpBackwardNoInterrupt { .. }
845        )
846    }
847
848    fn is_scope_exit(&self) -> bool {
849        matches!(
850            self,
851            Self::ReturnValue | Self::RaiseVarargs { .. } | Self::Reraise { .. }
852        )
853    }
854
855    fn stack_effect_info(&self, oparg: u32) -> StackEffect {
856        // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)`
857        // that causes underflow errors.
858        let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`");
859
860        // NOTE: Please don't "simplify" expressions here (i.e. `1 + (oparg - 1)`)
861        // as it will be harder to see diff with what CPython auto-generates
862        let (pushed, popped) = match self {
863            Self::BinaryOp { .. } => (1, 2),
864            Self::BinaryOpAddFloat => (1, 2),
865            Self::BinaryOpAddInt => (1, 2),
866            Self::BinaryOpAddUnicode => (1, 2),
867            Self::BinaryOpExtend => (1, 2),
868            Self::BinaryOpInplaceAddUnicode => (0, 2),
869            Self::BinaryOpMultiplyFloat => (1, 2),
870            Self::BinaryOpMultiplyInt => (1, 2),
871            Self::BinaryOpSubscrDict => (1, 2),
872            Self::BinaryOpSubscrGetitem => (0, 2),
873            Self::BinaryOpSubscrListInt => (1, 2),
874            Self::BinaryOpSubscrListSlice => (1, 2),
875            Self::BinaryOpSubscrStrInt => (1, 2),
876            Self::BinaryOpSubscrTupleInt => (1, 2),
877            Self::BinaryOpSubtractFloat => (1, 2),
878            Self::BinaryOpSubtractInt => (1, 2),
879            Self::BinarySlice { .. } => (1, 3),
880            Self::BuildInterpolation { .. } => (1, 2 + (oparg & 1)),
881            Self::BuildList { .. } => (1, oparg),
882            Self::BuildMap { .. } => (1, oparg * 2),
883            Self::BuildSet { .. } => (1, oparg),
884            Self::BuildSlice { .. } => (1, oparg),
885            Self::BuildString { .. } => (1, oparg),
886            Self::BuildTemplate { .. } => (1, 2),
887            Self::BuildTuple { .. } => (1, oparg),
888            Self::Cache => (0, 0),
889            Self::Call { .. } => (1, 2 + oparg),
890            Self::CallAllocAndEnterInit => (0, 2 + oparg),
891            Self::CallBoundMethodExactArgs => (0, 2 + oparg),
892            Self::CallBoundMethodGeneral => (0, 2 + oparg),
893            Self::CallBuiltinClass => (1, 2 + oparg),
894            Self::CallBuiltinFast => (1, 2 + oparg),
895            Self::CallBuiltinFastWithKeywords => (1, 2 + oparg),
896            Self::CallBuiltinO => (1, 2 + oparg),
897            Self::CallFunctionEx => (1, 4),
898            Self::CallIntrinsic1 { .. } => (1, 1),
899            Self::CallIntrinsic2 { .. } => (1, 2),
900            Self::CallIsinstance => (1, 2 + oparg),
901            Self::CallKw { .. } => (1, 3 + oparg),
902            Self::CallKwBoundMethod => (0, 3 + oparg),
903            Self::CallKwNonPy => (1, 3 + oparg),
904            Self::CallKwPy => (0, 3 + oparg),
905            Self::CallLen => (1, 3),
906            Self::CallListAppend => (0, 3),
907            Self::CallMethodDescriptorFast => (1, 2 + oparg),
908            Self::CallMethodDescriptorFastWithKeywords => (1, 2 + oparg),
909            Self::CallMethodDescriptorNoargs => (1, 2 + oparg),
910            Self::CallMethodDescriptorO => (1, 2 + oparg),
911            Self::CallNonPyGeneral => (1, 2 + oparg),
912            Self::CallPyExactArgs => (0, 2 + oparg),
913            Self::CallPyGeneral => (0, 2 + oparg),
914            Self::CallStr1 => (1, 3),
915            Self::CallTuple1 => (1, 3),
916            Self::CallType1 => (1, 3),
917            Self::CheckEgMatch => (2, 2),
918            Self::CheckExcMatch => (2, 2),
919            Self::CleanupThrow => (2, 3),
920            Self::CompareOp { .. } => (1, 2),
921            Self::CompareOpFloat => (1, 2),
922            Self::CompareOpInt => (1, 2),
923            Self::CompareOpStr => (1, 2),
924            Self::ContainsOp { .. } => (1, 2),
925            Self::ContainsOpDict => (1, 2),
926            Self::ContainsOpSet => (1, 2),
927            Self::ConvertValue { .. } => (1, 1),
928            Self::Copy { .. } => (2 + (oparg - 1), 1 + (oparg - 1)),
929            Self::CopyFreeVars { .. } => (0, 0),
930            Self::DeleteAttr { .. } => (0, 1),
931            Self::DeleteDeref { .. } => (0, 0),
932            Self::DeleteFast { .. } => (0, 0),
933            Self::DeleteGlobal { .. } => (0, 0),
934            Self::DeleteName { .. } => (0, 0),
935            Self::DeleteSubscr => (0, 2),
936            Self::DictMerge { .. } => (4 + (oparg - 1), 5 + (oparg - 1)),
937            Self::DictUpdate { .. } => (1 + (oparg - 1), 2 + (oparg - 1)),
938            Self::EndAsyncFor => (0, 2),
939            Self::EndFor => (0, 1),
940            Self::EndSend => (1, 2),
941            Self::EnterExecutor => (0, 0),
942            Self::ExitInitCheck => (0, 1),
943            Self::ExtendedArg => (0, 0),
944            Self::ForIter { .. } => (2, 1),
945            Self::ForIterGen => (1, 1),
946            Self::ForIterList => (2, 1),
947            Self::ForIterRange => (2, 1),
948            Self::ForIterTuple => (2, 1),
949            Self::FormatSimple => (1, 1),
950            Self::FormatWithSpec => (1, 2),
951            Self::GetAIter => (1, 1),
952            Self::GetANext => (2, 1),
953            Self::GetAwaitable { .. } => (1, 1),
954            Self::GetIter => (1, 1),
955            Self::GetLen => (2, 1),
956            Self::GetYieldFromIter => (1, 1),
957            Self::ImportFrom { .. } => (2, 1),
958            Self::ImportName { .. } => (1, 2),
959            Self::InstrumentedCall => (1, 2 + oparg),
960            Self::InstrumentedCallFunctionEx => (1, 4),
961            Self::InstrumentedCallKw => (1, 3 + oparg),
962            Self::InstrumentedEndAsyncFor => (0, 2),
963            Self::InstrumentedEndFor => (1, 2),
964            Self::InstrumentedEndSend => (1, 2),
965            Self::InstrumentedForIter => (2, 1),
966            Self::InstrumentedInstruction => (0, 0),
967            Self::InstrumentedJumpBackward => (0, 0),
968            Self::InstrumentedJumpForward => (0, 0),
969            Self::InstrumentedLine => (0, 0),
970            Self::InstrumentedLoadSuperAttr => (1 + (oparg & 1), 3),
971            Self::InstrumentedNotTaken => (0, 0),
972            Self::InstrumentedPopIter => (0, 1),
973            Self::InstrumentedPopJumpIfFalse => (0, 1),
974            Self::InstrumentedPopJumpIfNone => (0, 1),
975            Self::InstrumentedPopJumpIfNotNone => (0, 1),
976            Self::InstrumentedPopJumpIfTrue => (0, 1),
977            Self::InstrumentedResume => (0, 0),
978            Self::InstrumentedReturnValue => (1, 1),
979            Self::InstrumentedYieldValue => (1, 1),
980            Self::InterpreterExit => (0, 1),
981            Self::IsOp { .. } => (1, 2),
982            Self::JumpBackward { .. } => (0, 0),
983            Self::JumpBackwardJit => (0, 0),
984            Self::JumpBackwardNoInterrupt { .. } => (0, 0),
985            Self::JumpBackwardNoJit => (0, 0),
986            Self::JumpForward { .. } => (0, 0),
987            Self::ListAppend { .. } => (1 + (oparg - 1), 2 + (oparg - 1)),
988            Self::ListExtend { .. } => (1 + (oparg - 1), 2 + (oparg - 1)),
989            Self::LoadAttr { .. } => (1 + (oparg & 1), 1),
990            Self::LoadAttrClass => (1 + (oparg & 1), 1),
991            Self::LoadAttrClassWithMetaclassCheck => (1 + (oparg & 1), 1),
992            Self::LoadAttrGetattributeOverridden => (1, 1),
993            Self::LoadAttrInstanceValue => (1 + (oparg & 1), 1),
994            Self::LoadAttrMethodLazyDict => (2, 1),
995            Self::LoadAttrMethodNoDict => (2, 1),
996            Self::LoadAttrMethodWithValues => (2, 1),
997            Self::LoadAttrModule => (1 + (oparg & 1), 1),
998            Self::LoadAttrNondescriptorNoDict => (1, 1),
999            Self::LoadAttrNondescriptorWithValues => (1, 1),
1000            Self::LoadAttrProperty => (0, 1),
1001            Self::LoadAttrSlot => (1 + (oparg & 1), 1),
1002            Self::LoadAttrWithHint => (1 + (oparg & 1), 1),
1003            Self::LoadBuildClass => (1, 0),
1004            Self::LoadCommonConstant { .. } => (1, 0),
1005            Self::LoadConst { .. } => (1, 0),
1006            Self::LoadConstImmortal => (1, 0),
1007            Self::LoadConstMortal => (1, 0),
1008            Self::LoadDeref { .. } => (1, 0),
1009            Self::LoadFast { .. } => (1, 0),
1010            Self::LoadFastAndClear { .. } => (1, 0),
1011            Self::LoadFastBorrow { .. } => (1, 0),
1012            Self::LoadFastBorrowLoadFastBorrow { .. } => (2, 0),
1013            Self::LoadFastCheck { .. } => (1, 0),
1014            Self::LoadFastLoadFast { .. } => (2, 0),
1015            Self::LoadFromDictOrDeref { .. } => (1, 1),
1016            Self::LoadFromDictOrGlobals { .. } => (1, 1),
1017            Self::LoadGlobal { .. } => (1 + (oparg & 1), 0),
1018            Self::LoadGlobalBuiltin => (1 + (oparg & 1), 0),
1019            Self::LoadGlobalModule => (1 + (oparg & 1), 0),
1020            Self::LoadLocals => (1, 0),
1021            Self::LoadName { .. } => (1, 0),
1022            Self::LoadSmallInt { .. } => (1, 0),
1023            Self::LoadSpecial { .. } => (2, 1),
1024            Self::LoadSuperAttr { .. } => (1 + (oparg & 1), 3),
1025            Self::LoadSuperAttrAttr => (1, 3),
1026            Self::LoadSuperAttrMethod => (2, 3),
1027            Self::MakeCell { .. } => (0, 0),
1028            Self::MakeFunction { .. } => (1, 1),
1029            Self::MapAdd { .. } => (1 + (oparg - 1), 3 + (oparg - 1)),
1030            Self::MatchClass { .. } => (1, 3),
1031            Self::MatchKeys { .. } => (3, 2),
1032            Self::MatchMapping => (2, 1),
1033            Self::MatchSequence => (2, 1),
1034            Self::Nop => (0, 0),
1035            Self::NotTaken => (0, 0),
1036            Self::PopExcept => (0, 1),
1037            Self::PopIter => (0, 1),
1038            Self::PopJumpIfFalse { .. } => (0, 1),
1039            Self::PopJumpIfNone { .. } => (0, 1),
1040            Self::PopJumpIfNotNone { .. } => (0, 1),
1041            Self::PopJumpIfTrue { .. } => (0, 1),
1042            Self::PopTop => (0, 1),
1043            Self::PushExcInfo => (2, 1),
1044            Self::PushNull => (1, 0),
1045            Self::RaiseVarargs { .. } => (0, oparg),
1046            Self::Reraise { .. } => (oparg, 1 + oparg),
1047            Self::Reserved => (0, 0),
1048            Self::Resume { .. } => (0, 0),
1049            Self::ResumeCheck => (0, 0),
1050            Self::ReturnGenerator => (1, 0),
1051            Self::ReturnValue => (1, 1),
1052            Self::Send { .. } => (2, 2),
1053            Self::SendGen => (1, 2),
1054            Self::SetAdd { .. } => (1 + (oparg - 1), 2 + (oparg - 1)),
1055            Self::SetFunctionAttribute { .. } => (1, 2),
1056            Self::SetUpdate { .. } => (1 + (oparg - 1), 2 + (oparg - 1)),
1057            Self::SetupAnnotations => (0, 0),
1058            Self::StoreAttr { .. } => (0, 2),
1059            Self::StoreAttrInstanceValue => (0, 2),
1060            Self::StoreAttrSlot => (0, 2),
1061            Self::StoreAttrWithHint => (0, 2),
1062            Self::StoreDeref { .. } => (0, 1),
1063            Self::StoreFast { .. } => (0, 1),
1064            Self::StoreFastLoadFast { .. } => (1, 1),
1065            Self::StoreFastStoreFast { .. } => (0, 2),
1066            Self::StoreGlobal { .. } => (0, 1),
1067            Self::StoreName { .. } => (0, 1),
1068            Self::StoreSlice => (0, 4),
1069            Self::StoreSubscr => (0, 3),
1070            Self::StoreSubscrDict => (0, 3),
1071            Self::StoreSubscrListInt => (0, 3),
1072            Self::Swap { .. } => (2 + (oparg - 2), 2 + (oparg - 2)),
1073            Self::ToBool => (1, 1),
1074            Self::ToBoolAlwaysTrue => (1, 1),
1075            Self::ToBoolBool => (1, 1),
1076            Self::ToBoolInt => (1, 1),
1077            Self::ToBoolList => (1, 1),
1078            Self::ToBoolNone => (1, 1),
1079            Self::ToBoolStr => (1, 1),
1080            Self::UnaryInvert => (1, 1),
1081            Self::UnaryNegative => (1, 1),
1082            Self::UnaryNot => (1, 1),
1083            Self::UnpackEx { .. } => (1 + (oparg & 0xFF) + (oparg >> 8), 1),
1084            Self::UnpackSequence { .. } => (oparg, 1),
1085            Self::UnpackSequenceList => (oparg, 1),
1086            Self::UnpackSequenceTuple => (oparg, 1),
1087            Self::UnpackSequenceTwoTuple => (2, 1),
1088            Self::WithExceptStart => (7, 6),
1089            Self::YieldValue { .. } => (1, 1),
1090        };
1091
1092        debug_assert!((0..=i32::MAX).contains(&pushed));
1093        debug_assert!((0..=i32::MAX).contains(&popped));
1094
1095        StackEffect::new(pushed as u32, popped as u32)
1096    }
1097
1098    #[allow(clippy::too_many_arguments)]
1099    fn fmt_dis(
1100        &self,
1101        arg: OpArg,
1102        f: &mut fmt::Formatter<'_>,
1103        ctx: &impl InstrDisplayContext,
1104        expand_code_objects: bool,
1105        pad: usize,
1106        level: usize,
1107    ) -> fmt::Result {
1108        macro_rules! w {
1109            ($variant:ident) => {
1110                write!(f, stringify!($variant))
1111            };
1112            ($variant:ident, $map:ident = $arg_marker:expr) => {{
1113                let arg = $arg_marker.get(arg);
1114                write!(f, "{:pad$}({}, {})", stringify!($variant), arg, $map(arg))
1115            }};
1116            ($variant:ident, $arg_marker:expr) => {
1117                write!(f, "{:pad$}({})", stringify!($variant), $arg_marker.get(arg))
1118            };
1119            ($variant:ident, ?$arg_marker:expr) => {
1120                write!(
1121                    f,
1122                    "{:pad$}({:?})",
1123                    stringify!($variant),
1124                    $arg_marker.get(arg)
1125                )
1126            };
1127        }
1128
1129        let varname = |var_num: oparg::VarNum| ctx.get_varname(var_num);
1130        let name = |i: u32| ctx.get_name(i as usize);
1131        let cell_name = |i: oparg::VarNum| ctx.get_localsplus_name(i);
1132
1133        let fmt_const = |op: &str,
1134                         arg: OpArg,
1135                         f: &mut fmt::Formatter<'_>,
1136                         consti: &Arg<oparg::ConstIdx>|
1137         -> fmt::Result {
1138            let value = ctx.get_constant(consti.get(arg));
1139            match value.borrow_constant() {
1140                BorrowedConstant::Code { code } if expand_code_objects => {
1141                    write!(f, "{op:pad$}({code:?}):")?;
1142                    code.display_inner(f, true, level + 1)?;
1143                    Ok(())
1144                }
1145                c => {
1146                    write!(f, "{op:pad$}(")?;
1147                    c.fmt_display(f)?;
1148                    write!(f, ")")
1149                }
1150            }
1151        };
1152
1153        match self {
1154            Self::BinarySlice => w!(BINARY_SLICE),
1155            Self::BinaryOp { op } => write!(f, "{:pad$}({})", "BINARY_OP", op.get(arg)),
1156            Self::BinaryOpInplaceAddUnicode => w!(BINARY_OP_INPLACE_ADD_UNICODE),
1157            Self::BuildList { count } => w!(BUILD_LIST, count),
1158            Self::BuildMap { count } => w!(BUILD_MAP, count),
1159            Self::BuildSet { count } => w!(BUILD_SET, count),
1160            Self::BuildSlice { argc } => w!(BUILD_SLICE, ?argc),
1161            Self::BuildString { count } => w!(BUILD_STRING, count),
1162            Self::BuildTuple { count } => w!(BUILD_TUPLE, count),
1163            Self::Call { argc } => w!(CALL, argc),
1164            Self::CallFunctionEx => w!(CALL_FUNCTION_EX),
1165            Self::CallKw { argc } => w!(CALL_KW, argc),
1166            Self::CallIntrinsic1 { func } => w!(CALL_INTRINSIC_1, ?func),
1167            Self::CallIntrinsic2 { func } => w!(CALL_INTRINSIC_2, ?func),
1168            Self::Cache => w!(CACHE),
1169            Self::CheckEgMatch => w!(CHECK_EG_MATCH),
1170            Self::CheckExcMatch => w!(CHECK_EXC_MATCH),
1171            Self::CleanupThrow => w!(CLEANUP_THROW),
1172            Self::CompareOp { opname } => w!(COMPARE_OP, ?opname),
1173            Self::ContainsOp { invert } => w!(CONTAINS_OP, ?invert),
1174            Self::ConvertValue { oparg } => write!(f, "{:pad$}{}", "CONVERT_VALUE", oparg.get(arg)),
1175            Self::Copy { i } => w!(COPY, i),
1176            Self::CopyFreeVars { n } => w!(COPY_FREE_VARS, n),
1177            Self::DeleteAttr { namei } => w!(DELETE_ATTR, name = namei),
1178            Self::DeleteDeref { i } => w!(DELETE_DEREF, cell_name = i),
1179            Self::DeleteFast { var_num } => w!(DELETE_FAST, varname = var_num),
1180            Self::DeleteGlobal { namei } => w!(DELETE_GLOBAL, name = namei),
1181            Self::DeleteName { namei } => w!(DELETE_NAME, name = namei),
1182            Self::DeleteSubscr => w!(DELETE_SUBSCR),
1183            Self::DictMerge { i } => w!(DICT_MERGE, i),
1184            Self::DictUpdate { i } => w!(DICT_UPDATE, i),
1185            Self::EndAsyncFor => w!(END_ASYNC_FOR),
1186            Self::EndSend => w!(END_SEND),
1187            Self::ExtendedArg => w!(EXTENDED_ARG, Arg::<u32>::marker()),
1188            Self::ExitInitCheck => w!(EXIT_INIT_CHECK),
1189            Self::ForIter { delta } => w!(FOR_ITER, delta),
1190            Self::FormatSimple => w!(FORMAT_SIMPLE),
1191            Self::FormatWithSpec => w!(FORMAT_WITH_SPEC),
1192            Self::GetAIter => w!(GET_AITER),
1193            Self::GetANext => w!(GET_ANEXT),
1194            Self::GetAwaitable { r#where } => w!(GET_AWAITABLE, r#where),
1195            Self::Reserved => w!(RESERVED),
1196            Self::GetIter => w!(GET_ITER),
1197            Self::GetLen => w!(GET_LEN),
1198            Self::ImportFrom { namei } => w!(IMPORT_FROM, name = namei),
1199            Self::ImportName { namei } => w!(IMPORT_NAME, name = namei),
1200            Self::InterpreterExit => w!(INTERPRETER_EXIT),
1201            Self::IsOp { invert } => w!(IS_OP, ?invert),
1202            Self::JumpBackward { delta } => w!(JUMP_BACKWARD, delta),
1203            Self::JumpBackwardNoInterrupt { delta } => w!(JUMP_BACKWARD_NO_INTERRUPT, delta),
1204            Self::JumpForward { delta } => w!(JUMP_FORWARD, delta),
1205            Self::ListAppend { i } => w!(LIST_APPEND, i),
1206            Self::ListExtend { i } => w!(LIST_EXTEND, i),
1207            Self::LoadAttr { namei } => {
1208                let oparg = namei.get(arg);
1209                let oparg_u32 = u32::from(oparg);
1210                let attr_name = name(oparg.name_idx());
1211                if oparg.is_method() {
1212                    write!(
1213                        f,
1214                        "{:pad$}({}, {}, method=true)",
1215                        "LOAD_ATTR", oparg_u32, attr_name
1216                    )
1217                } else {
1218                    write!(f, "{:pad$}({}, {})", "LOAD_ATTR", oparg_u32, attr_name)
1219                }
1220            }
1221            Self::LoadBuildClass => w!(LOAD_BUILD_CLASS),
1222            Self::LoadCommonConstant { idx } => w!(LOAD_COMMON_CONSTANT, ?idx),
1223            Self::LoadFromDictOrDeref { i } => w!(LOAD_FROM_DICT_OR_DEREF, cell_name = i),
1224            Self::LoadConst { consti } => fmt_const("LOAD_CONST", arg, f, consti),
1225            Self::LoadSmallInt { i } => w!(LOAD_SMALL_INT, i),
1226            Self::LoadDeref { i } => w!(LOAD_DEREF, cell_name = i),
1227            Self::LoadFast { var_num } => w!(LOAD_FAST, varname = var_num),
1228            Self::LoadFastAndClear { var_num } => w!(LOAD_FAST_AND_CLEAR, varname = var_num),
1229            Self::LoadFastBorrow { var_num } => w!(LOAD_FAST_BORROW, varname = var_num),
1230            Self::LoadFastCheck { var_num } => w!(LOAD_FAST_CHECK, varname = var_num),
1231            Self::LoadFastLoadFast { var_nums } => {
1232                let oparg = var_nums.get(arg);
1233                let (idx1, idx2) = oparg.indexes();
1234                let name1 = varname(idx1);
1235                let name2 = varname(idx2);
1236                write!(f, "{:pad$}({}, {})", "LOAD_FAST_LOAD_FAST", name1, name2)
1237            }
1238            Self::LoadFastBorrowLoadFastBorrow { var_nums } => {
1239                let oparg = var_nums.get(arg);
1240                let (idx1, idx2) = oparg.indexes();
1241                let name1 = varname(idx1);
1242                let name2 = varname(idx2);
1243                write!(
1244                    f,
1245                    "{:pad$}({}, {})",
1246                    "LOAD_FAST_BORROW_LOAD_FAST_BORROW", name1, name2
1247                )
1248            }
1249            Self::LoadFromDictOrGlobals { i } => w!(LOAD_FROM_DICT_OR_GLOBALS, name = i),
1250            Self::LoadGlobal { namei } => {
1251                let oparg = namei.get(arg);
1252                let name_idx = oparg >> 1;
1253                if (oparg & 1) != 0 {
1254                    write!(
1255                        f,
1256                        "{:pad$}({}, NULL + {})",
1257                        "LOAD_GLOBAL",
1258                        oparg,
1259                        name(name_idx)
1260                    )
1261                } else {
1262                    write!(f, "{:pad$}({}, {})", "LOAD_GLOBAL", oparg, name(name_idx))
1263                }
1264            }
1265            Self::LoadGlobalBuiltin => {
1266                let oparg = u32::from(arg);
1267                let name_idx = oparg >> 1;
1268                if (oparg & 1) != 0 {
1269                    write!(
1270                        f,
1271                        "{:pad$}({}, NULL + {})",
1272                        "LOAD_GLOBAL_BUILTIN",
1273                        oparg,
1274                        name(name_idx)
1275                    )
1276                } else {
1277                    write!(
1278                        f,
1279                        "{:pad$}({}, {})",
1280                        "LOAD_GLOBAL_BUILTIN",
1281                        oparg,
1282                        name(name_idx)
1283                    )
1284                }
1285            }
1286            Self::LoadGlobalModule => {
1287                let oparg = u32::from(arg);
1288                let name_idx = oparg >> 1;
1289                if (oparg & 1) != 0 {
1290                    write!(
1291                        f,
1292                        "{:pad$}({}, NULL + {})",
1293                        "LOAD_GLOBAL_MODULE",
1294                        oparg,
1295                        name(name_idx)
1296                    )
1297                } else {
1298                    write!(
1299                        f,
1300                        "{:pad$}({}, {})",
1301                        "LOAD_GLOBAL_MODULE",
1302                        oparg,
1303                        name(name_idx)
1304                    )
1305                }
1306            }
1307            Self::LoadLocals => w!(LOAD_LOCALS),
1308            Self::LoadName { namei } => w!(LOAD_NAME, name = namei),
1309            Self::LoadSpecial { method } => w!(LOAD_SPECIAL, method),
1310            Self::LoadSuperAttr { namei } => {
1311                let oparg = namei.get(arg);
1312                write!(
1313                    f,
1314                    "{:pad$}({}, {}, method={}, class={})",
1315                    "LOAD_SUPER_ATTR",
1316                    u32::from(oparg),
1317                    name(oparg.name_idx()),
1318                    oparg.is_load_method(),
1319                    oparg.has_class()
1320                )
1321            }
1322            Self::MakeCell { i } => w!(MAKE_CELL, cell_name = i),
1323            Self::MakeFunction => w!(MAKE_FUNCTION),
1324            Self::MapAdd { i } => w!(MAP_ADD, i),
1325            Self::MatchClass { count } => w!(MATCH_CLASS, count),
1326            Self::MatchKeys => w!(MATCH_KEYS),
1327            Self::MatchMapping => w!(MATCH_MAPPING),
1328            Self::MatchSequence => w!(MATCH_SEQUENCE),
1329            Self::Nop => w!(NOP),
1330            Self::NotTaken => w!(NOT_TAKEN),
1331            Self::PopExcept => w!(POP_EXCEPT),
1332            Self::PopJumpIfFalse { delta } => w!(POP_JUMP_IF_FALSE, delta),
1333            Self::PopJumpIfNone { delta } => w!(POP_JUMP_IF_NONE, delta),
1334            Self::PopJumpIfNotNone { delta } => w!(POP_JUMP_IF_NOT_NONE, delta),
1335            Self::PopJumpIfTrue { delta } => w!(POP_JUMP_IF_TRUE, delta),
1336            Self::PopTop => w!(POP_TOP),
1337            Self::EndFor => w!(END_FOR),
1338            Self::PopIter => w!(POP_ITER),
1339            Self::PushExcInfo => w!(PUSH_EXC_INFO),
1340            Self::PushNull => w!(PUSH_NULL),
1341            Self::RaiseVarargs { argc } => w!(RAISE_VARARGS, ?argc),
1342            Self::Reraise { depth } => w!(RERAISE, depth),
1343            Self::Resume { context } => w!(RESUME, context),
1344            Self::ReturnValue => w!(RETURN_VALUE),
1345            Self::ReturnGenerator => w!(RETURN_GENERATOR),
1346            Self::Send { delta } => w!(SEND, delta),
1347            Self::SetAdd { i } => w!(SET_ADD, i),
1348            Self::SetFunctionAttribute { flag } => w!(SET_FUNCTION_ATTRIBUTE, ?flag),
1349            Self::SetupAnnotations => w!(SETUP_ANNOTATIONS),
1350            Self::SetUpdate { i } => w!(SET_UPDATE, i),
1351            Self::StoreAttr { namei } => w!(STORE_ATTR, name = namei),
1352            Self::StoreDeref { i } => w!(STORE_DEREF, cell_name = i),
1353            Self::StoreFast { var_num } => w!(STORE_FAST, varname = var_num),
1354            Self::StoreFastLoadFast { var_nums } => {
1355                let oparg = var_nums.get(arg);
1356                let (store_idx, load_idx) = oparg.indexes();
1357                write!(f, "STORE_FAST_LOAD_FAST")?;
1358                write!(f, " ({}, {})", store_idx, load_idx)
1359            }
1360            Self::StoreFastStoreFast { var_nums } => {
1361                let oparg = var_nums.get(arg);
1362                let (idx1, idx2) = oparg.indexes();
1363                write!(
1364                    f,
1365                    "{:pad$}({}, {})",
1366                    "STORE_FAST_STORE_FAST",
1367                    varname(idx1),
1368                    varname(idx2)
1369                )
1370            }
1371            Self::StoreGlobal { namei } => w!(STORE_GLOBAL, name = namei),
1372            Self::StoreName { namei } => w!(STORE_NAME, name = namei),
1373            Self::StoreSlice => w!(STORE_SLICE),
1374            Self::StoreSubscr => w!(STORE_SUBSCR),
1375            Self::Swap { i } => w!(SWAP, i),
1376            Self::ToBool => w!(TO_BOOL),
1377            Self::UnpackEx { counts } => w!(UNPACK_EX, counts),
1378            Self::UnpackSequence { count } => w!(UNPACK_SEQUENCE, count),
1379            Self::WithExceptStart => w!(WITH_EXCEPT_START),
1380            Self::UnaryInvert => w!(UNARY_INVERT),
1381            Self::UnaryNegative => w!(UNARY_NEGATIVE),
1382            Self::UnaryNot => w!(UNARY_NOT),
1383            Self::YieldValue { arg } => w!(YIELD_VALUE, arg),
1384            Self::GetYieldFromIter => w!(GET_YIELD_FROM_ITER),
1385            Self::BuildTemplate => w!(BUILD_TEMPLATE),
1386            Self::BuildInterpolation { format } => w!(BUILD_INTERPOLATION, format),
1387            _ => w!(RUSTPYTHON_PLACEHOLDER),
1388        }
1389    }
1390}
1391
1392/// Instructions used by the compiler. They are not executed by the VM.
1393///
1394/// CPython 3.14.2 aligned (256-266).
1395#[derive(Clone, Copy, Debug)]
1396#[repr(u16)]
1397pub enum PseudoInstruction {
1398    // CPython 3.14.2 pseudo instructions (256-266)
1399    AnnotationsPlaceholder = 256,
1400    Jump { delta: Arg<Label> } = 257,
1401    JumpIfFalse { delta: Arg<Label> } = 258,
1402    JumpIfTrue { delta: Arg<Label> } = 259,
1403    JumpNoInterrupt { delta: Arg<Label> } = 260,
1404    LoadClosure { i: Arg<NameIdx> } = 261,
1405    PopBlock = 262,
1406    SetupCleanup { delta: Arg<Label> } = 263,
1407    SetupFinally { delta: Arg<Label> } = 264,
1408    SetupWith { delta: Arg<Label> } = 265,
1409    StoreFastMaybeNull { var_num: Arg<NameIdx> } = 266,
1410}
1411
1412const _: () = assert!(mem::size_of::<PseudoInstruction>() == 2);
1413
1414impl From<PseudoInstruction> for u16 {
1415    #[inline]
1416    fn from(ins: PseudoInstruction) -> Self {
1417        // SAFETY: there's no padding bits
1418        unsafe { mem::transmute::<PseudoInstruction, Self>(ins) }
1419    }
1420}
1421
1422impl TryFrom<u16> for PseudoInstruction {
1423    type Error = MarshalError;
1424
1425    #[inline]
1426    fn try_from(value: u16) -> Result<Self, MarshalError> {
1427        let start = u16::from(Self::AnnotationsPlaceholder);
1428        let end = u16::from(Self::StoreFastMaybeNull {
1429            var_num: Arg::marker(),
1430        });
1431
1432        if (start..=end).contains(&value) {
1433            Ok(unsafe { mem::transmute::<u16, Self>(value) })
1434        } else {
1435            Err(Self::Error::InvalidBytecode)
1436        }
1437    }
1438}
1439
1440impl PseudoInstruction {
1441    /// Returns true if this is a block push pseudo instruction
1442    /// (SETUP_FINALLY, SETUP_CLEANUP, or SETUP_WITH).
1443    pub fn is_block_push(&self) -> bool {
1444        matches!(
1445            self,
1446            Self::SetupCleanup { .. } | Self::SetupFinally { .. } | Self::SetupWith { .. }
1447        )
1448    }
1449}
1450
1451impl InstructionMetadata for PseudoInstruction {
1452    fn label_arg(&self) -> Option<Arg<Label>> {
1453        match self {
1454            Self::Jump { delta: l }
1455            | Self::JumpIfFalse { delta: l }
1456            | Self::JumpIfTrue { delta: l }
1457            | Self::JumpNoInterrupt { delta: l }
1458            | Self::SetupCleanup { delta: l }
1459            | Self::SetupFinally { delta: l }
1460            | Self::SetupWith { delta: l } => Some(*l),
1461            _ => None,
1462        }
1463    }
1464
1465    fn is_scope_exit(&self) -> bool {
1466        false
1467    }
1468
1469    fn stack_effect_info(&self, _oparg: u32) -> StackEffect {
1470        // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)`
1471        // that causes underflow errors.
1472        let _oparg = i32::try_from(_oparg).expect("oparg does not fit in an `i32`");
1473
1474        // NOTE: Please don't "simplify" expressions here (i.e. `1 + (oparg - 1)`)
1475        // as it will be harder to see diff with what CPython auto-generates
1476        let (pushed, popped) = match self {
1477            Self::AnnotationsPlaceholder => (0, 0),
1478            Self::Jump { .. } => (0, 0),
1479            Self::JumpIfFalse { .. } => (1, 1),
1480            Self::JumpIfTrue { .. } => (1, 1),
1481            Self::JumpNoInterrupt { .. } => (0, 0),
1482            Self::LoadClosure { .. } => (1, 0),
1483            Self::PopBlock => (0, 0),
1484            // Normal path effect is 0 (these are NOPs on fall-through).
1485            // Handler entry effects are computed directly in max_stackdepth().
1486            Self::SetupCleanup { .. } => (0, 0),
1487            Self::SetupFinally { .. } => (0, 0),
1488            Self::SetupWith { .. } => (0, 0),
1489            Self::StoreFastMaybeNull { .. } => (0, 1),
1490        };
1491
1492        debug_assert!((0..=i32::MAX).contains(&pushed));
1493        debug_assert!((0..=i32::MAX).contains(&popped));
1494
1495        StackEffect::new(pushed as u32, popped as u32)
1496    }
1497
1498    fn is_unconditional_jump(&self) -> bool {
1499        matches!(self, Self::Jump { .. } | Self::JumpNoInterrupt { .. })
1500    }
1501
1502    fn fmt_dis(
1503        &self,
1504        _arg: OpArg,
1505        _f: &mut fmt::Formatter<'_>,
1506        _ctx: &impl InstrDisplayContext,
1507        _expand_code_objects: bool,
1508        _pad: usize,
1509        _level: usize,
1510    ) -> fmt::Result {
1511        unimplemented!()
1512    }
1513}
1514
1515#[derive(Clone, Copy, Debug)]
1516pub enum AnyInstruction {
1517    Real(Instruction),
1518    Pseudo(PseudoInstruction),
1519}
1520
1521impl From<Instruction> for AnyInstruction {
1522    fn from(value: Instruction) -> Self {
1523        Self::Real(value)
1524    }
1525}
1526
1527impl From<PseudoInstruction> for AnyInstruction {
1528    fn from(value: PseudoInstruction) -> Self {
1529        Self::Pseudo(value)
1530    }
1531}
1532
1533impl TryFrom<u8> for AnyInstruction {
1534    type Error = MarshalError;
1535
1536    fn try_from(value: u8) -> Result<Self, Self::Error> {
1537        Ok(Instruction::try_from(value)?.into())
1538    }
1539}
1540
1541impl TryFrom<u16> for AnyInstruction {
1542    type Error = MarshalError;
1543
1544    fn try_from(value: u16) -> Result<Self, Self::Error> {
1545        match u8::try_from(value) {
1546            Ok(v) => v.try_into(),
1547            Err(_) => Ok(PseudoInstruction::try_from(value)?.into()),
1548        }
1549    }
1550}
1551
1552macro_rules! inst_either {
1553    (fn $name:ident ( &self $(, $arg:ident : $arg_ty:ty )* ) -> $ret:ty ) => {
1554        fn $name(&self $(, $arg : $arg_ty )* ) -> $ret {
1555            match self {
1556                Self::Real(op) => op.$name($($arg),*),
1557                Self::Pseudo(op) => op.$name($($arg),*),
1558            }
1559        }
1560    };
1561}
1562
1563impl InstructionMetadata for AnyInstruction {
1564    inst_either!(fn label_arg(&self) -> Option<Arg<Label>>);
1565
1566    inst_either!(fn is_unconditional_jump(&self) -> bool);
1567
1568    inst_either!(fn is_scope_exit(&self) -> bool);
1569
1570    inst_either!(fn stack_effect(&self, oparg: u32) -> i32);
1571
1572    inst_either!(fn stack_effect_info(&self, oparg: u32) -> StackEffect);
1573
1574    inst_either!(fn fmt_dis(
1575        &self,
1576        arg: OpArg,
1577        f: &mut fmt::Formatter<'_>,
1578        ctx: &impl InstrDisplayContext,
1579        expand_code_objects: bool,
1580        pad: usize,
1581        level: usize
1582    ) -> fmt::Result);
1583}
1584
1585impl AnyInstruction {
1586    /// Gets the inner value of [`Self::Real`].
1587    pub const fn real(self) -> Option<Instruction> {
1588        match self {
1589            Self::Real(ins) => Some(ins),
1590            _ => None,
1591        }
1592    }
1593
1594    /// Gets the inner value of [`Self::Pseudo`].
1595    pub const fn pseudo(self) -> Option<PseudoInstruction> {
1596        match self {
1597            Self::Pseudo(ins) => Some(ins),
1598            _ => None,
1599        }
1600    }
1601
1602    /// Same as [`Self::real`] but panics if wasn't called on [`Self::Real`].
1603    ///
1604    /// # Panics
1605    ///
1606    /// If was called on something else other than [`Self::Real`].
1607    pub const fn expect_real(self) -> Instruction {
1608        self.real()
1609            .expect("Expected Instruction::Real, found Instruction::Pseudo")
1610    }
1611
1612    /// Same as [`Self::pseudo`] but panics if wasn't called on [`Self::Pseudo`].
1613    ///
1614    /// # Panics
1615    ///
1616    /// If was called on something else other than [`Self::Pseudo`].
1617    pub const fn expect_pseudo(self) -> PseudoInstruction {
1618        self.pseudo()
1619            .expect("Expected Instruction::Pseudo, found Instruction::Real")
1620    }
1621
1622    /// Returns true if this is a block push pseudo instruction
1623    /// (SETUP_FINALLY, SETUP_CLEANUP, or SETUP_WITH).
1624    pub fn is_block_push(&self) -> bool {
1625        matches!(self, Self::Pseudo(p) if p.is_block_push())
1626    }
1627
1628    /// Returns true if this is a POP_BLOCK pseudo instruction.
1629    pub fn is_pop_block(&self) -> bool {
1630        matches!(self, Self::Pseudo(PseudoInstruction::PopBlock))
1631    }
1632}
1633
1634/// What effect the instruction has on the stack.
1635#[derive(Clone, Copy)]
1636pub struct StackEffect {
1637    /// How many items the instruction is pushing on the stack.
1638    pushed: u32,
1639    /// How many items the instruction is popping from the stack.
1640    popped: u32,
1641}
1642
1643impl StackEffect {
1644    /// Creates a new [`Self`].
1645    pub const fn new(pushed: u32, popped: u32) -> Self {
1646        Self { pushed, popped }
1647    }
1648
1649    /// Get the calculated stack effect as [`i32`].
1650    pub fn effect(self) -> i32 {
1651        self.into()
1652    }
1653
1654    /// Get the pushed count.
1655    pub const fn pushed(self) -> u32 {
1656        self.pushed
1657    }
1658
1659    /// Get the popped count.
1660    pub const fn popped(self) -> u32 {
1661        self.popped
1662    }
1663}
1664
1665impl From<StackEffect> for i32 {
1666    fn from(effect: StackEffect) -> Self {
1667        (effect.pushed() as i32) - (effect.popped() as i32)
1668    }
1669}
1670
1671pub trait InstructionMetadata {
1672    /// Gets the label stored inside this instruction, if it exists.
1673    fn label_arg(&self) -> Option<Arg<Label>>;
1674
1675    fn is_scope_exit(&self) -> bool;
1676
1677    fn is_unconditional_jump(&self) -> bool;
1678
1679    /// Stack effect info for how many items are pushed/popped from the stack,
1680    /// for this instruction.
1681    fn stack_effect_info(&self, oparg: u32) -> StackEffect;
1682
1683    /// Stack effect of [`Self::stack_effect_info`].
1684    fn stack_effect(&self, oparg: u32) -> i32 {
1685        self.stack_effect_info(oparg).effect()
1686    }
1687
1688    #[allow(clippy::too_many_arguments)]
1689    fn fmt_dis(
1690        &self,
1691        arg: OpArg,
1692        f: &mut fmt::Formatter<'_>,
1693        ctx: &impl InstrDisplayContext,
1694        expand_code_objects: bool,
1695        pad: usize,
1696        level: usize,
1697    ) -> fmt::Result;
1698
1699    fn display(&self, arg: OpArg, ctx: &impl InstrDisplayContext) -> impl fmt::Display {
1700        fmt::from_fn(move |f| self.fmt_dis(arg, f, ctx, false, 0, 0))
1701    }
1702}
1703
1704#[derive(Copy, Clone)]
1705pub struct Arg<T: OpArgType>(PhantomData<T>);
1706
1707impl<T: OpArgType> Arg<T> {
1708    #[inline]
1709    pub const fn marker() -> Self {
1710        Self(PhantomData)
1711    }
1712
1713    #[inline]
1714    pub fn new(arg: T) -> (Self, OpArg) {
1715        (Self(PhantomData), OpArg::new(arg.into()))
1716    }
1717
1718    #[inline]
1719    pub fn new_single(arg: T) -> (Self, OpArgByte)
1720    where
1721        T: Into<u8>,
1722    {
1723        (Self(PhantomData), OpArgByte::new(arg.into()))
1724    }
1725
1726    #[inline(always)]
1727    pub fn get(self, arg: OpArg) -> T {
1728        self.try_get(arg).unwrap()
1729    }
1730
1731    #[inline(always)]
1732    pub fn try_get(self, arg: OpArg) -> Result<T, MarshalError> {
1733        T::try_from(u32::from(arg)).map_err(|_| MarshalError::InvalidBytecode)
1734    }
1735
1736    /// # Safety
1737    /// T::from_op_arg(self) must succeed
1738    #[inline(always)]
1739    pub unsafe fn get_unchecked(self, arg: OpArg) -> T {
1740        // SAFETY: requirements forwarded from caller
1741        unsafe { T::try_from(u32::from(arg)).unwrap_unchecked() }
1742    }
1743}
1744
1745impl<T: OpArgType> PartialEq for Arg<T> {
1746    fn eq(&self, _: &Self) -> bool {
1747        true
1748    }
1749}
1750
1751impl<T: OpArgType> Eq for Arg<T> {}
1752
1753impl<T: OpArgType> fmt::Debug for Arg<T> {
1754    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1755        write!(f, "Arg<{}>", core::any::type_name::<T>())
1756    }
1757}