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#[derive(Clone, Copy, Debug)]
23#[repr(u8)]
24pub enum Instruction {
25 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, 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, 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 BinaryOp {
72 op: Arg<BinaryOperator>,
73 } = 44,
74 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, 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 Resume {
307 context: Arg<oparg::ResumeContext>,
308 } = 128,
309 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,
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, }
417
418const _: () = assert!(mem::size_of::<Instruction>() == 1);
419
420impl From<Instruction> for u8 {
421 #[inline]
422 fn from(ins: Instruction) -> Self {
423 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 let cpython_start = u8::from(Self::Cache);
435 let cpython_end = u8::from(Self::YieldValue { arg: Arg::marker() });
436
437 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 pub const fn is_instrumented(self) -> bool {
466 self.to_base().is_some()
467 || matches!(self, Self::InstrumentedLine | Self::InstrumentedInstruction)
468 }
469
470 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 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 pub const fn deopt(self) -> Option<Self> {
562 Some(match self {
563 Self::ResumeCheck => Self::Resume {
565 context: Arg::marker(),
566 },
567 Self::LoadConstMortal | Self::LoadConstImmortal => Self::LoadConst {
569 consti: Arg::marker(),
570 },
571 Self::ToBoolAlwaysTrue
573 | Self::ToBoolBool
574 | Self::ToBoolInt
575 | Self::ToBoolList
576 | Self::ToBoolNone
577 | Self::ToBoolStr => Self::ToBool,
578 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 Self::StoreSubscrDict | Self::StoreSubscrListInt => Self::StoreSubscr,
596 Self::SendGen => Self::Send {
598 delta: Arg::marker(),
599 },
600 Self::UnpackSequenceTwoTuple | Self::UnpackSequenceTuple | Self::UnpackSequenceList => {
602 Self::UnpackSequence {
603 count: Arg::marker(),
604 }
605 }
606 Self::StoreAttrInstanceValue | Self::StoreAttrSlot | Self::StoreAttrWithHint => {
608 Self::StoreAttr {
609 namei: Arg::marker(),
610 }
611 }
612 Self::LoadGlobalModule | Self::LoadGlobalBuiltin => Self::LoadGlobal {
614 namei: Arg::marker(),
615 },
616 Self::LoadSuperAttrAttr | Self::LoadSuperAttrMethod => Self::LoadSuperAttr {
618 namei: Arg::marker(),
619 },
620 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 Self::CompareOpFloat | Self::CompareOpInt | Self::CompareOpStr => Self::CompareOp {
638 opname: Arg::marker(),
639 },
640 Self::ContainsOpSet | Self::ContainsOpDict => Self::ContainsOp {
642 invert: Arg::marker(),
643 },
644 Self::JumpBackwardNoJit | Self::JumpBackwardJit => Self::JumpBackward {
646 delta: Arg::marker(),
647 },
648 Self::ForIterList | Self::ForIterTuple | Self::ForIterRange | Self::ForIterGen => {
650 Self::ForIter {
651 delta: Arg::marker(),
652 }
653 }
654 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 Self::CallKwBoundMethod | Self::CallKwPy | Self::CallKwNonPy => Self::CallKw {
679 argc: Arg::marker(),
680 },
681 _ => return None,
682 })
683 }
684
685 pub const fn deoptimize(self) -> Self {
687 match self.deopt() {
688 Some(v) => v,
689 None => {
690 match self.to_base() {
692 Some(v) => v,
693 None => self,
694 }
695 }
696 }
697 }
698
699 pub const fn cache_entries(self) -> usize {
702 match self {
703 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 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 Self::LoadGlobal { .. }
739 | Self::LoadGlobalBuiltin
740 | Self::LoadGlobalModule
741 | Self::StoreAttr { .. }
742 | Self::StoreAttrInstanceValue
743 | Self::StoreAttrSlot
744 | Self::StoreAttrWithHint => 4,
745
746 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 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 _ => 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 let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`");
859
860 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#[derive(Clone, Copy, Debug)]
1396#[repr(u16)]
1397pub enum PseudoInstruction {
1398 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 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 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 let _oparg = i32::try_from(_oparg).expect("oparg does not fit in an `i32`");
1473
1474 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 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 pub const fn real(self) -> Option<Instruction> {
1588 match self {
1589 Self::Real(ins) => Some(ins),
1590 _ => None,
1591 }
1592 }
1593
1594 pub const fn pseudo(self) -> Option<PseudoInstruction> {
1596 match self {
1597 Self::Pseudo(ins) => Some(ins),
1598 _ => None,
1599 }
1600 }
1601
1602 pub const fn expect_real(self) -> Instruction {
1608 self.real()
1609 .expect("Expected Instruction::Real, found Instruction::Pseudo")
1610 }
1611
1612 pub const fn expect_pseudo(self) -> PseudoInstruction {
1618 self.pseudo()
1619 .expect("Expected Instruction::Pseudo, found Instruction::Real")
1620 }
1621
1622 pub fn is_block_push(&self) -> bool {
1625 matches!(self, Self::Pseudo(p) if p.is_block_push())
1626 }
1627
1628 pub fn is_pop_block(&self) -> bool {
1630 matches!(self, Self::Pseudo(PseudoInstruction::PopBlock))
1631 }
1632}
1633
1634#[derive(Clone, Copy)]
1636pub struct StackEffect {
1637 pushed: u32,
1639 popped: u32,
1641}
1642
1643impl StackEffect {
1644 pub const fn new(pushed: u32, popped: u32) -> Self {
1646 Self { pushed, popped }
1647 }
1648
1649 pub fn effect(self) -> i32 {
1651 self.into()
1652 }
1653
1654 pub const fn pushed(self) -> u32 {
1656 self.pushed
1657 }
1658
1659 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 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 fn stack_effect_info(&self, oparg: u32) -> StackEffect;
1682
1683 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 #[inline(always)]
1739 pub unsafe fn get_unchecked(self, arg: OpArg) -> T {
1740 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}