1"""Opcode definitions."""
2
3# We define all-uppercase classes, to match their opcode names:
4# pylint: disable=invalid-name
5
6HAS_CONST = 1  # references the constant table
7HAS_NAME = 2  # references the name table
8HAS_JREL = 4  # relative jump
9HAS_JABS = 8  # absolute jump
10HAS_JUNKNOWN = 16  # jumps to unknown location
11HAS_LOCAL = 32  # references the varnames table
12HAS_FREE = 64  # references "free variable" cells
13HAS_NARGS = 128  # stores number of args + kwargs
14HAS_ARGUMENT = 256  # all opcodes >= 90
15NO_NEXT = 512  # doesn't execute the following opcode
16STORE_JUMP = 1024  # only stores a jump, doesn't actually execute it
17PUSHES_BLOCK = 2048  # starts a block (while, try, finally, with, etc.)
18POPS_BLOCK = 4096  # ends a block
19
20
21class Opcode:
22  """An opcode without arguments."""
23
24  __slots__ = ("line", "index", "prev", "next", "target", "block_target",
25               "code", "annotation", "folded")
26  FLAGS = 0
27
28  def __init__(self, index, line):
29    self.index = index
30    self.line = line
31    self.target = None
32    self.code = None  # If we have a CodeType or OrderedCode parent
33    self.annotation = None
34    self.folded = None  # elided by constant folding
35
36  def at_line(self, line):
37    """Return a new opcode simliar to this one but with a different line."""
38    # Ignore the optional slots (prev, next, block_target).
39    op = Opcode(self.index, line)
40    op.target = self.target
41    op.code = self.code
42    return op
43
44  def basic_str(self):
45    """Helper function for the various __str__ formats."""
46    folded = "<<<<" if self.folded else ""
47    return "%d: %d: %s %s" % (
48        self.line, self.index, self.__class__.__name__, folded)
49
50  def __str__(self):
51    if self.annotation:
52      return "%s  # type: %s" % (self.basic_str(), self.annotation)
53    else:
54      return self.basic_str()
55
56  def __repr__(self):
57    return self.__class__.__name__
58
59  @property
60  def name(self):
61    return self.__class__.__name__
62
63  @classmethod
64  def has_const(cls):
65    return bool(cls.FLAGS & HAS_CONST)
66
67  @classmethod
68  def has_name(cls):
69    return bool(cls.FLAGS & HAS_NAME)
70
71  @classmethod
72  def has_jrel(cls):
73    return bool(cls.FLAGS & HAS_JREL)
74
75  @classmethod
76  def has_jabs(cls):
77    return bool(cls.FLAGS & HAS_JABS)
78
79  @classmethod
80  def has_junknown(cls):
81    return bool(cls.FLAGS & HAS_JUNKNOWN)
82
83  @classmethod
84  def has_jump(cls):
85    return bool(cls.FLAGS & (HAS_JREL | HAS_JABS | HAS_JUNKNOWN))
86
87  @classmethod
88  def has_local(cls):
89    return bool(cls.FLAGS & HAS_LOCAL)
90
91  @classmethod
92  def has_free(cls):
93    return bool(cls.FLAGS & HAS_FREE)
94
95  @classmethod
96  def has_nargs(cls):
97    return bool(cls.FLAGS & HAS_NARGS)
98
99  @classmethod
100  def has_argument(cls):
101    return bool(cls.FLAGS & HAS_ARGUMENT)
102
103  @classmethod
104  def no_next(cls):
105    return bool(cls.FLAGS & NO_NEXT)
106
107  @classmethod
108  def carry_on_to_next(cls):
109    return not cls.FLAGS & NO_NEXT
110
111  @classmethod
112  def store_jump(cls):
113    return bool(cls.FLAGS & STORE_JUMP)
114
115  @classmethod
116  def does_jump(cls):
117    return cls.has_jump() and not cls.store_jump()
118
119  @classmethod
120  def pushes_block(cls):
121    return bool(cls.FLAGS & PUSHES_BLOCK)
122
123  @classmethod
124  def pops_block(cls):
125    return bool(cls.FLAGS & POPS_BLOCK)
126
127  @classmethod
128  def has_arg(cls):
129    return False
130
131
132class OpcodeWithArg(Opcode):
133  """An opcode with one argument."""
134
135  __slots__ = ("arg", "pretty_arg")
136
137  def __init__(self, index, line, arg, pretty_arg):
138    super().__init__(index, line)
139    self.arg = arg
140    self.pretty_arg = pretty_arg
141
142  def __str__(self):
143    out = "%s %s" % (self.basic_str(), self.pretty_arg)
144    if self.annotation:
145      return "%s  # type: %s" % (out, self.annotation)
146    else:
147      return out
148
149  @classmethod
150  def has_arg(cls):
151    return True
152
153
154class POP_TOP(Opcode):
155  __slots__ = ()
156
157
158class ROT_TWO(Opcode):
159  __slots__ = ()
160
161
162class ROT_THREE(Opcode):
163  __slots__ = ()
164
165
166class DUP_TOP(Opcode):
167  __slots__ = ()
168
169
170class ROT_FOUR(Opcode):
171  __slots__ = ()
172
173
174class DUP_TOP_TWO(Opcode):
175  __slots__ = ()
176
177
178class NOP(Opcode):
179  __slots__ = ()
180
181
182class UNARY_POSITIVE(Opcode):
183  __slots__ = ()
184
185
186class UNARY_NEGATIVE(Opcode):
187  __slots__ = ()
188
189
190class UNARY_NOT(Opcode):
191  __slots__ = ()
192
193
194class UNARY_INVERT(Opcode):
195  __slots__ = ()
196
197
198class BINARY_MATRIX_MULTIPLY(Opcode):
199  __slots__ = ()
200
201
202class INPLACE_MATRIX_MULTIPLY(Opcode):
203  __slots__ = ()
204
205
206class BINARY_POWER(Opcode):
207  __slots__ = ()
208
209
210class BINARY_MULTIPLY(Opcode):
211  __slots__ = ()
212
213
214class BINARY_MODULO(Opcode):
215  __slots__ = ()
216
217
218class BINARY_ADD(Opcode):
219  __slots__ = ()
220
221
222class BINARY_SUBTRACT(Opcode):
223  __slots__ = ()
224
225
226class BINARY_SUBSCR(Opcode):
227  __slots__ = ()
228
229
230class BINARY_FLOOR_DIVIDE(Opcode):
231  __slots__ = ()
232
233
234class BINARY_TRUE_DIVIDE(Opcode):
235  __slots__ = ()
236
237
238class INPLACE_FLOOR_DIVIDE(Opcode):
239  __slots__ = ()
240
241
242class INPLACE_TRUE_DIVIDE(Opcode):
243  __slots__ = ()
244
245
246class GET_AITER(Opcode):
247  __slots__ = ()
248
249
250class GET_ANEXT(Opcode):
251  __slots__ = ()
252
253
254class BEFORE_ASYNC_WITH(Opcode):
255  __slots__ = ()
256
257
258class BEGIN_FINALLY(Opcode):
259  __slots__ = ()
260
261
262class END_ASYNC_FOR(Opcode):
263  # Even though dis documentation says that END_ASYNC_FOR may reraise an
264  # exception, we do not include NO_NEXT in the flags because doing so would
265  # cause the return statement for an async method to be skipped, leading to
266  # an incorrect return type.
267  # See tests/test_stdlib2:StdlibTestsFeatures.test_async_iter and
268  # tests/test_coroutine:GeneratorFeatureTest.test_async_for_pyi for tests
269  # that fail if we add NO_NEXT.
270  FLAGS = HAS_JUNKNOWN
271  __slots__ = ()
272
273
274class INPLACE_ADD(Opcode):
275  __slots__ = ()
276
277
278class INPLACE_SUBTRACT(Opcode):
279  __slots__ = ()
280
281
282class INPLACE_MULTIPLY(Opcode):
283  __slots__ = ()
284
285
286class INPLACE_MODULO(Opcode):
287  __slots__ = ()
288
289
290class STORE_SUBSCR(Opcode):
291  __slots__ = ()
292
293
294class DELETE_SUBSCR(Opcode):
295  __slots__ = ()
296
297
298class BINARY_LSHIFT(Opcode):
299  __slots__ = ()
300
301
302class BINARY_RSHIFT(Opcode):
303  __slots__ = ()
304
305
306class BINARY_AND(Opcode):
307  __slots__ = ()
308
309
310class BINARY_XOR(Opcode):
311  __slots__ = ()
312
313
314class BINARY_OR(Opcode):
315  __slots__ = ()
316
317
318class INPLACE_POWER(Opcode):
319  __slots__ = ()
320
321
322class GET_ITER(Opcode):
323  __slots__ = ()
324
325
326class GET_YIELD_FROM_ITER(Opcode):
327  __slots__ = ()
328
329
330class PRINT_EXPR(Opcode):
331  __slots__ = ()
332
333
334class LOAD_BUILD_CLASS(Opcode):
335  __slots__ = ()
336
337
338class YIELD_FROM(Opcode):
339  FLAGS = HAS_JUNKNOWN
340  __slots__ = ()
341
342
343class GET_AWAITABLE(Opcode):
344  __slots__ = ()
345
346
347class INPLACE_LSHIFT(Opcode):
348  __slots__ = ()
349
350
351class INPLACE_RSHIFT(Opcode):
352  __slots__ = ()
353
354
355class INPLACE_AND(Opcode):
356  __slots__ = ()
357
358
359class INPLACE_XOR(Opcode):
360  __slots__ = ()
361
362
363class INPLACE_OR(Opcode):
364  __slots__ = ()
365
366
367class BREAK_LOOP(Opcode):
368  FLAGS = HAS_JUNKNOWN | NO_NEXT
369  __slots__ = ()
370
371
372class WITH_CLEANUP_START(Opcode):
373  FLAGS = HAS_JUNKNOWN  # might call __exit__
374  __slots__ = ()
375
376
377class WITH_CLEANUP_FINISH(Opcode):
378  __slots__ = ()
379
380
381class RETURN_VALUE(Opcode):
382  FLAGS = HAS_JUNKNOWN | NO_NEXT
383  __slots__ = ()
384
385
386class IMPORT_STAR(Opcode):
387  __slots__ = ()
388
389
390class SETUP_ANNOTATIONS(Opcode):
391  __slots__ = ()
392
393
394class YIELD_VALUE(Opcode):
395  FLAGS = HAS_JUNKNOWN
396  __slots__ = ()
397
398
399class POP_BLOCK(Opcode):
400  FLAGS = POPS_BLOCK
401  __slots__ = ()
402
403
404class END_FINALLY(Opcode):
405  FLAGS = HAS_JUNKNOWN  # might re-raise an exception
406  __slots__ = ()
407
408
409class POP_EXCEPT(Opcode):
410  __slots__ = ()
411
412
413class STORE_NAME(OpcodeWithArg):  # Indexes into name list
414  FLAGS = HAS_NAME|HAS_ARGUMENT
415  __slots__ = ()
416
417
418class DELETE_NAME(OpcodeWithArg):  # Indexes into name list
419  FLAGS = HAS_NAME|HAS_ARGUMENT
420  __slots__ = ()
421
422
423class UNPACK_SEQUENCE(OpcodeWithArg):  # Arg: Number of tuple items
424  FLAGS = HAS_ARGUMENT
425  __slots__ = ()
426
427
428class FOR_ITER(OpcodeWithArg):
429  FLAGS = HAS_JREL|HAS_ARGUMENT
430  __slots__ = ()
431
432
433class LIST_APPEND(OpcodeWithArg):
434  FLAGS = HAS_ARGUMENT
435  __slots__ = ()
436
437
438class UNPACK_EX(OpcodeWithArg):
439  FLAGS = HAS_ARGUMENT
440  __slots__ = ()
441
442
443class STORE_ATTR(OpcodeWithArg):  # Indexes into name list
444  FLAGS = HAS_NAME|HAS_ARGUMENT
445  __slots__ = ()
446
447
448class DELETE_ATTR(OpcodeWithArg):  # Indexes into name list
449  FLAGS = HAS_NAME|HAS_ARGUMENT
450  __slots__ = ()
451
452
453class STORE_GLOBAL(OpcodeWithArg):  # Indexes into name list
454  FLAGS = HAS_NAME|HAS_ARGUMENT
455  __slots__ = ()
456
457
458class DELETE_GLOBAL(OpcodeWithArg):  # Indexes into name list
459  FLAGS = HAS_NAME|HAS_ARGUMENT
460  __slots__ = ()
461
462
463class LOAD_CONST(OpcodeWithArg):  # Arg: Index in const list
464  FLAGS = HAS_ARGUMENT|HAS_CONST
465  __slots__ = ()
466
467
468class LOAD_NAME(OpcodeWithArg):  # Arg: Index in name list
469  FLAGS = HAS_NAME|HAS_ARGUMENT
470  __slots__ = ()
471
472
473class BUILD_TUPLE(OpcodeWithArg):  # Arg: Number of tuple items
474  FLAGS = HAS_ARGUMENT
475  __slots__ = ()
476
477
478class BUILD_LIST(OpcodeWithArg):  # Arg: Number of list items
479  FLAGS = HAS_ARGUMENT
480  __slots__ = ()
481
482
483class BUILD_SET(OpcodeWithArg):  # Arg: Number of set items
484  FLAGS = HAS_ARGUMENT
485  __slots__ = ()
486
487
488class BUILD_MAP(OpcodeWithArg):  # Arg: Number of dict entries (up to 255)
489  FLAGS = HAS_ARGUMENT
490  __slots__ = ()
491
492
493class LOAD_ATTR(OpcodeWithArg):  # Arg: Index in name list
494  FLAGS = HAS_NAME|HAS_ARGUMENT
495  __slots__ = ()
496
497
498class COMPARE_OP(OpcodeWithArg):  # Arg: Comparison operator
499  FLAGS = HAS_ARGUMENT
500  __slots__ = ()
501
502
503class IMPORT_NAME(OpcodeWithArg):  # Arg: Index in name list
504  FLAGS = HAS_NAME|HAS_ARGUMENT|HAS_JUNKNOWN
505  __slots__ = ()
506
507
508class IMPORT_FROM(OpcodeWithArg):  # Arg: Index in name list
509  FLAGS = HAS_NAME|HAS_ARGUMENT
510  __slots__ = ()
511
512
513class JUMP_FORWARD(OpcodeWithArg):
514  FLAGS = HAS_JREL|HAS_ARGUMENT|NO_NEXT
515  __slots__ = ()
516
517
518class JUMP_IF_FALSE_OR_POP(OpcodeWithArg):
519  FLAGS = HAS_JABS|HAS_ARGUMENT
520  __slots__ = ()
521
522
523class JUMP_IF_TRUE_OR_POP(OpcodeWithArg):
524  FLAGS = HAS_JABS|HAS_ARGUMENT
525  __slots__ = ()
526
527
528class JUMP_ABSOLUTE(OpcodeWithArg):
529  FLAGS = HAS_JABS|HAS_ARGUMENT|NO_NEXT
530  __slots__ = ()
531
532
533class POP_JUMP_IF_FALSE(OpcodeWithArg):
534  FLAGS = HAS_JABS|HAS_ARGUMENT
535  __slots__ = ()
536
537
538class POP_JUMP_IF_TRUE(OpcodeWithArg):
539  FLAGS = HAS_JABS|HAS_ARGUMENT
540  __slots__ = ()
541
542
543class LOAD_GLOBAL(OpcodeWithArg):  # Indexes into name list
544  FLAGS = HAS_NAME|HAS_ARGUMENT
545  __slots__ = ()
546
547
548class CONTINUE_LOOP(OpcodeWithArg):  # Acts as jump
549  FLAGS = HAS_JABS|HAS_ARGUMENT|NO_NEXT
550  __slots__ = ()
551
552
553class SETUP_LOOP(OpcodeWithArg):
554  FLAGS = HAS_JREL|HAS_ARGUMENT|STORE_JUMP|PUSHES_BLOCK
555  __slots__ = ()
556
557
558class SETUP_EXCEPT(OpcodeWithArg):
559  FLAGS = HAS_JREL|HAS_ARGUMENT|STORE_JUMP|PUSHES_BLOCK
560  __slots__ = ()
561
562
563class SETUP_FINALLY(OpcodeWithArg):
564  FLAGS = HAS_JREL|HAS_ARGUMENT|STORE_JUMP|PUSHES_BLOCK
565  __slots__ = ()
566
567
568class LOAD_FAST(OpcodeWithArg):  # Loads local variable number
569  FLAGS = HAS_LOCAL|HAS_ARGUMENT
570  __slots__ = ()
571
572
573class STORE_FAST(OpcodeWithArg):  # Stores local variable number
574  FLAGS = HAS_LOCAL|HAS_ARGUMENT
575  __slots__ = ()
576
577
578class DELETE_FAST(OpcodeWithArg):  # Deletes local variable number
579  FLAGS = HAS_LOCAL|HAS_ARGUMENT
580  __slots__ = ()
581
582
583class STORE_ANNOTATION(OpcodeWithArg):
584  FLAGS = HAS_NAME|HAS_ARGUMENT
585  __slots__ = ()
586
587
588class RAISE_VARARGS(OpcodeWithArg):  # Arg: Number of raise args (1, 2, or 3)
589  FLAGS = HAS_ARGUMENT|HAS_JUNKNOWN|NO_NEXT
590  __slots__ = ()
591
592
593class CALL_FUNCTION(OpcodeWithArg):  # Arg: #args + (#kwargs << 8)
594  FLAGS = HAS_NARGS|HAS_ARGUMENT|HAS_JUNKNOWN
595  __slots__ = ()
596
597
598class MAKE_FUNCTION(OpcodeWithArg):  # Arg: Number of args with default values
599  FLAGS = HAS_ARGUMENT
600  __slots__ = ()
601
602
603class BUILD_SLICE(OpcodeWithArg):  # Arg: Number of items
604  FLAGS = HAS_ARGUMENT
605  __slots__ = ()
606
607
608class MAKE_CLOSURE(OpcodeWithArg):
609  FLAGS = HAS_ARGUMENT
610  __slots__ = ()
611
612
613class LOAD_CLOSURE(OpcodeWithArg):
614  FLAGS = HAS_FREE|HAS_ARGUMENT
615  __slots__ = ()
616
617
618class LOAD_DEREF(OpcodeWithArg):
619  FLAGS = HAS_FREE|HAS_ARGUMENT
620  __slots__ = ()
621
622
623class STORE_DEREF(OpcodeWithArg):
624  FLAGS = HAS_FREE|HAS_ARGUMENT
625  __slots__ = ()
626
627
628class DELETE_DEREF(OpcodeWithArg):
629  FLAGS = HAS_FREE|HAS_ARGUMENT
630  __slots__ = ()
631
632
633class CALL_FUNCTION_VAR(OpcodeWithArg):  # Arg: #args + (#kwargs << 8)
634  FLAGS = HAS_NARGS|HAS_ARGUMENT|HAS_JUNKNOWN
635  __slots__ = ()
636
637
638class CALL_FUNCTION_KW(OpcodeWithArg):  # Arg: #args + (#kwargs << 8)
639  FLAGS = HAS_NARGS|HAS_ARGUMENT|HAS_JUNKNOWN
640  __slots__ = ()
641
642
643class CALL_FUNCTION_VAR_KW(OpcodeWithArg):  # Arg: #args + (#kwargs << 8)
644  FLAGS = HAS_NARGS|HAS_ARGUMENT|HAS_JUNKNOWN
645  __slots__ = ()
646
647
648class CALL_FUNCTION_EX(OpcodeWithArg):  # Arg: flags
649  FLAGS = HAS_ARGUMENT
650  __slots__ = ()
651
652
653class SETUP_WITH(OpcodeWithArg):
654  FLAGS = HAS_JREL|HAS_ARGUMENT|STORE_JUMP|PUSHES_BLOCK
655  __slots__ = ()
656
657
658class EXTENDED_ARG(OpcodeWithArg):
659  FLAGS = HAS_ARGUMENT
660  __slots__ = ()
661
662
663class SET_ADD(OpcodeWithArg):
664  FLAGS = HAS_ARGUMENT
665  __slots__ = ()
666
667
668class MAP_ADD(OpcodeWithArg):
669  FLAGS = HAS_ARGUMENT
670  __slots__ = ()
671
672
673class LOAD_CLASSDEREF(OpcodeWithArg):
674  FLAGS = HAS_FREE|HAS_ARGUMENT
675  __slots__ = ()
676
677
678class BUILD_LIST_UNPACK(OpcodeWithArg):  # Arg: Number of items
679  FLAGS = HAS_ARGUMENT
680  __slots__ = ()
681
682
683class BUILD_MAP_UNPACK(OpcodeWithArg):  # Arg: Number of items
684  FLAGS = HAS_ARGUMENT
685  __slots__ = ()
686
687
688class BUILD_MAP_UNPACK_WITH_CALL(OpcodeWithArg):  # Arg: Number of items
689  FLAGS = HAS_ARGUMENT
690  __slots__ = ()
691
692
693class BUILD_TUPLE_UNPACK(OpcodeWithArg):  # Arg: Number of items
694  FLAGS = HAS_ARGUMENT
695  __slots__ = ()
696
697
698class BUILD_SET_UNPACK(OpcodeWithArg):  # Arg: Number of items
699  FLAGS = HAS_ARGUMENT
700  __slots__ = ()
701
702
703class SETUP_ASYNC_WITH(OpcodeWithArg):
704  FLAGS = HAS_JREL|HAS_ARGUMENT|STORE_JUMP|PUSHES_BLOCK
705  __slots__ = ()
706
707
708class FORMAT_VALUE(OpcodeWithArg):  # Arg: Flags
709  FLAGS = HAS_ARGUMENT
710  __slots__ = ()
711
712
713class BUILD_CONST_KEY_MAP(OpcodeWithArg):  # Arg: Number of items
714  FLAGS = HAS_ARGUMENT
715  __slots__ = ()
716
717
718class BUILD_STRING(OpcodeWithArg):  # Arg: Number of items
719  FLAGS = HAS_ARGUMENT
720  __slots__ = ()
721
722
723class BUILD_TUPLE_UNPACK_WITH_CALL(OpcodeWithArg):  # Arg: Number of items
724  FLAGS = HAS_ARGUMENT
725  __slots__ = ()
726
727
728class LOAD_METHOD(OpcodeWithArg):  # Arg: Index in name list
729  FLAGS = HAS_NAME|HAS_ARGUMENT
730  __slots__ = ()
731
732
733class CALL_METHOD(OpcodeWithArg):  # Arg: #args
734  FLAGS = HAS_NARGS|HAS_ARGUMENT|HAS_JUNKNOWN
735  __slots__ = ()
736
737
738class CALL_FINALLY(OpcodeWithArg):  # Arg: Jump offset to finally block
739  FLAGS = HAS_JREL | HAS_ARGUMENT
740  __slots__ = ()
741
742
743class POP_FINALLY(OpcodeWithArg):
744  # might re-raise an exception or jump to a finally
745  FLAGS = HAS_ARGUMENT | HAS_JUNKNOWN
746  __slots__ = ()
747
748
749class RERAISE(Opcode):
750  __slots__ = ()
751
752
753class WITH_EXCEPT_START(Opcode):
754  __slots__ = ()
755
756
757class LOAD_ASSERTION_ERROR(Opcode):
758  __slots__ = ()
759
760
761class LIST_TO_TUPLE(Opcode):
762  __slots__ = ()
763
764
765class IS_OP(OpcodeWithArg):
766  FLAGS = HAS_ARGUMENT
767  __slots__ = ()
768
769
770class CONTAINS_OP(OpcodeWithArg):
771  FLAGS = HAS_ARGUMENT
772  __slots__ = ()
773
774
775class JUMP_IF_NOT_EXC_MATCH(OpcodeWithArg):
776  FLAGS = HAS_ARGUMENT | HAS_JABS
777  __slots__ = ()
778
779
780class LIST_EXTEND(OpcodeWithArg):
781  FLAGS = HAS_ARGUMENT
782  __slots__ = ()
783
784
785class SET_UPDATE(OpcodeWithArg):
786  FLAGS = HAS_ARGUMENT
787  __slots__ = ()
788
789
790class DICT_MERGE(OpcodeWithArg):
791  FLAGS = HAS_ARGUMENT
792  __slots__ = ()
793
794
795class DICT_UPDATE(OpcodeWithArg):
796  FLAGS = HAS_ARGUMENT
797  __slots__ = ()
798
799
800class LOAD_FOLDED_CONST(OpcodeWithArg):  # A fake opcode used internally
801  FLAGS = HAS_ARGUMENT
802  __slots__ = ()
803
804  def __str__(self):
805    return self.basic_str() + " " + str(self.arg.value)
806
807
808def _overlay_mapping(mapping, new_entries):
809  ret = mapping.copy()
810  ret.update(new_entries)
811  return dict((k, v) for k, v in ret.items() if v is not None)
812
813
814python_3_5_mapping = {
815    1: POP_TOP,
816    2: ROT_TWO,
817    3: ROT_THREE,
818    4: DUP_TOP,
819    5: DUP_TOP_TWO,
820    9: NOP,
821    10: UNARY_POSITIVE,
822    11: UNARY_NEGATIVE,
823    12: UNARY_NOT,
824    15: UNARY_INVERT,
825    16: BINARY_MATRIX_MULTIPLY,
826    17: INPLACE_MATRIX_MULTIPLY,
827    19: BINARY_POWER,
828    20: BINARY_MULTIPLY,
829    22: BINARY_MODULO,
830    23: BINARY_ADD,
831    24: BINARY_SUBTRACT,
832    25: BINARY_SUBSCR,
833    26: BINARY_FLOOR_DIVIDE,
834    27: BINARY_TRUE_DIVIDE,
835    28: INPLACE_FLOOR_DIVIDE,
836    29: INPLACE_TRUE_DIVIDE,
837    50: GET_AITER,
838    51: GET_ANEXT,
839    52: BEFORE_ASYNC_WITH,
840    55: INPLACE_ADD,
841    56: INPLACE_SUBTRACT,
842    57: INPLACE_MULTIPLY,
843    59: INPLACE_MODULO,
844    60: STORE_SUBSCR,
845    61: DELETE_SUBSCR,
846    62: BINARY_LSHIFT,
847    63: BINARY_RSHIFT,
848    64: BINARY_AND,
849    65: BINARY_XOR,
850    66: BINARY_OR,
851    67: INPLACE_POWER,
852    68: GET_ITER,
853    69: GET_YIELD_FROM_ITER,
854    70: PRINT_EXPR,
855    71: LOAD_BUILD_CLASS,
856    72: YIELD_FROM,
857    73: GET_AWAITABLE,
858    75: INPLACE_LSHIFT,
859    76: INPLACE_RSHIFT,
860    77: INPLACE_AND,
861    78: INPLACE_XOR,
862    79: INPLACE_OR,
863    80: BREAK_LOOP,
864    81: WITH_CLEANUP_START,
865    82: WITH_CLEANUP_FINISH,
866    83: RETURN_VALUE,
867    84: IMPORT_STAR,
868    86: YIELD_VALUE,
869    87: POP_BLOCK,
870    88: END_FINALLY,
871    89: POP_EXCEPT,
872    90: STORE_NAME,
873    91: DELETE_NAME,
874    92: UNPACK_SEQUENCE,
875    93: FOR_ITER,
876    94: UNPACK_EX,
877    95: STORE_ATTR,
878    96: DELETE_ATTR,
879    97: STORE_GLOBAL,
880    98: DELETE_GLOBAL,
881    100: LOAD_CONST,
882    101: LOAD_NAME,
883    102: BUILD_TUPLE,
884    103: BUILD_LIST,
885    104: BUILD_SET,
886    105: BUILD_MAP,
887    106: LOAD_ATTR,
888    107: COMPARE_OP,
889    108: IMPORT_NAME,
890    109: IMPORT_FROM,
891    110: JUMP_FORWARD,
892    111: JUMP_IF_FALSE_OR_POP,
893    112: JUMP_IF_TRUE_OR_POP,
894    113: JUMP_ABSOLUTE,
895    114: POP_JUMP_IF_FALSE,
896    115: POP_JUMP_IF_TRUE,
897    116: LOAD_GLOBAL,
898    119: CONTINUE_LOOP,
899    120: SETUP_LOOP,
900    121: SETUP_EXCEPT,
901    122: SETUP_FINALLY,
902    124: LOAD_FAST,
903    125: STORE_FAST,
904    126: DELETE_FAST,
905    130: RAISE_VARARGS,
906    131: CALL_FUNCTION,
907    132: MAKE_FUNCTION,
908    133: BUILD_SLICE,
909    134: MAKE_CLOSURE,
910    135: LOAD_CLOSURE,
911    136: LOAD_DEREF,
912    137: STORE_DEREF,
913    138: DELETE_DEREF,
914    140: CALL_FUNCTION_VAR,  # removed in Python 3.6
915    141: CALL_FUNCTION_KW,
916    142: CALL_FUNCTION_VAR_KW,
917    143: SETUP_WITH,
918    144: EXTENDED_ARG,
919    145: LIST_APPEND,
920    146: SET_ADD,
921    147: MAP_ADD,
922    148: LOAD_CLASSDEREF,
923    149: BUILD_LIST_UNPACK,
924    150: BUILD_MAP_UNPACK,
925    151: BUILD_MAP_UNPACK_WITH_CALL,
926    152: BUILD_TUPLE_UNPACK,
927    153: BUILD_SET_UNPACK,
928    154: SETUP_ASYNC_WITH,
929}
930
931python_3_6_mapping = _overlay_mapping(python_3_5_mapping, {
932    85: SETUP_ANNOTATIONS,
933    127: STORE_ANNOTATION,  # removed in Python 3.7
934    140: None,
935    142: CALL_FUNCTION_EX,  # CALL_FUNCTION_VAR_KW in Python 3.5
936    155: FORMAT_VALUE,
937    156: BUILD_CONST_KEY_MAP,
938    157: BUILD_STRING,
939    158: BUILD_TUPLE_UNPACK_WITH_CALL,
940})
941
942python_3_7_mapping = _overlay_mapping(python_3_6_mapping, {
943    127: None,
944    160: LOAD_METHOD,
945    161: CALL_METHOD,
946})
947
948python_3_8_mapping = _overlay_mapping(python_3_7_mapping, {
949    6: ROT_FOUR,  # ROT_FOUR returns under a different, cooler id!
950    53: BEGIN_FINALLY,
951    54: END_ASYNC_FOR,
952    80: None,   # BREAK_LOOP was removed in 3.8
953    119: None,  # CONTINUE_LOOP was removed in 3.8
954    120: None,  # SETUP_LOOP was removed in 3.8
955    121: None,  # SETUP_EXCEPT was removed in 3.8
956    162: CALL_FINALLY,
957    163: POP_FINALLY,
958})
959
960python_3_9_mapping = _overlay_mapping(python_3_8_mapping, {
961    48: RERAISE,
962    49: WITH_EXCEPT_START,
963    53: None,  # was BEGIN_FINALLY in 3.8
964    74: LOAD_ASSERTION_ERROR,
965    81: None,  # was WITH_CLEANUP_START in 3.8
966    82: LIST_TO_TUPLE,  # was WITH_CLEANUP_FINISH in 3.8
967    88: None,  # was END_FINALLY in 3.8
968    117: IS_OP,
969    118: CONTAINS_OP,
970    121: JUMP_IF_NOT_EXC_MATCH,
971    149: None,  # was BUILD_LIST_UNPACK in 3.8
972    150: None,  # was BUILD_MAP_UNPACK in 3.8
973    151: None,  # was BUILD_MAP_UNPACK_WITH_CALL in 3.8
974    152: None,  # was BUILD_TUPLE_UNPACK in 3.8
975    153: None,  # was BUILD_SET_UNPACK in 3.8
976    158: None,  # was BUILD_TUPLE_UNPACK_WITH_CALL in 3.8
977    162: LIST_EXTEND,  # was CALL_FINALLY in 3.8
978    163: SET_UPDATE,  # was POP_FINALLY in 3.8
979    164: DICT_MERGE,
980    165: DICT_UPDATE,
981})
982
983
984class _LineNumberTableParser:
985  """State machine for decoding a Python line number array."""
986
987  def __init__(self, python_version, lnotab, firstlineno):
988    assert not len(lnotab) & 1  # lnotab always has an even number of elements
989    self.lnotab = lnotab
990    self.lineno = firstlineno
991    self.next_addr = self.lnotab[0] if self.lnotab else 0
992    self.pos = 0
993    self.python_version = python_version
994
995  def get(self, i):
996    """Get the line number for the instruction at the given position.
997
998    This does NOT allow random access. Call with incremental numbers.
999
1000    Args:
1001      i: The byte position in the bytecode. i needs to stay constant or increase
1002        between calls.
1003
1004    Returns:
1005      The line number corresponding to the position at i.
1006    """
1007    while i >= self.next_addr and self.pos < len(self.lnotab):
1008      line_diff = self.lnotab[self.pos + 1]
1009      # The Python docs have more details on this weird bit twiddling.
1010      # https://github.com/python/cpython/blob/master/Objects/lnotab_notes.txt
1011      # https://github.com/python/cpython/commit/f3914eb16d28ad9eb20fe5133d9aa83658bcc27f
1012      if self.python_version >= (3, 6) and line_diff >= 0x80:
1013        line_diff -= 0x100
1014      self.lineno += line_diff
1015
1016      self.pos += 2
1017      if self.pos < len(self.lnotab):
1018        self.next_addr += self.lnotab[self.pos]
1019    return self.lineno
1020
1021
1022def _prettyprint_arg(cls, oparg, co_consts, co_names,
1023                     co_varnames, cellvars_freevars):
1024  """Prettyprint `oparg`."""
1025  if cls.has_jrel():
1026    return oparg
1027  elif co_consts and cls.has_const():
1028    return repr(co_consts[oparg])
1029  elif co_names and cls.has_name():
1030    return co_names[oparg]
1031  elif co_varnames and cls.has_local():
1032    return co_varnames[oparg]
1033  elif cellvars_freevars and cls.has_free():
1034    return cellvars_freevars[oparg]
1035  else:
1036    return oparg
1037
1038
1039def _bytecode_reader(data, mapping):
1040  """Reads binary data from pyc files as bytecode.
1041
1042  Works with Python3.5 and below.
1043
1044  Arguments:
1045    data: The block of binary pyc code
1046    mapping: {opcode : class}
1047
1048  Yields:
1049    (start position, end position, opcode class, oparg)
1050  """
1051  assert isinstance(data, bytes)
1052  pos = 0
1053  extended_arg = 0
1054  start = 0
1055  size = len(data)
1056  while pos < size:
1057    opcode = data[pos]
1058    cls = mapping[opcode]
1059    oparg = None
1060    if cls is EXTENDED_ARG:
1061      # EXTENDED_ARG modifies the opcode after it, setting bits 16..31 of
1062      # its argument.
1063      assert not extended_arg, "two EXTENDED_ARGs in a row"
1064      extended_arg = data[pos+1] << 16 | data[pos+2] << 24
1065      bytes_read = 3
1066    elif cls.FLAGS & HAS_ARGUMENT:
1067      oparg = data[pos+1] | data[pos+2] << 8 | extended_arg
1068      extended_arg = 0
1069      bytes_read = 3
1070    else:
1071      assert not extended_arg, "EXTENDED_ARG in front of opcode without arg"
1072      extended_arg = 0
1073      bytes_read = 1
1074    # Don't yield EXTENDED_ARG; it is part of the next opcode.
1075    if cls is not EXTENDED_ARG:
1076      yield (start, pos + bytes_read, cls, oparg)
1077      start = pos + bytes_read
1078    pos += bytes_read
1079
1080
1081def _wordcode_reader(data, mapping):
1082  """Reads binary data from pyc files as wordcode.
1083
1084  Works with Python3.6 and above.
1085
1086  Arguments:
1087    data: The block of binary pyc code
1088    mapping: {opcode : class}
1089
1090  Yields:
1091    (start position, end position, opcode class, oparg)
1092  """
1093  assert isinstance(data, bytes)
1094  extended_arg = 0
1095  start = 0
1096  for pos in range(0, len(data), 2):
1097    opcode = data[pos]
1098    cls = mapping[opcode]
1099    if cls is EXTENDED_ARG:
1100      oparg = data[pos+1] | extended_arg
1101      extended_arg = oparg << 8
1102    elif cls.FLAGS & HAS_ARGUMENT:
1103      oparg = data[pos+1] | extended_arg
1104      extended_arg = 0
1105    else:
1106      oparg = None
1107      extended_arg = 0
1108    # Don't yield EXTENDED_ARG; it is part of the next opcode.
1109    if cls is not EXTENDED_ARG:
1110      yield (start, pos + 2, cls, oparg)
1111      start = pos + 2
1112
1113
1114def _dis(python_version, data, mapping, reader,
1115         co_varnames=None, co_names=None, co_consts=None, co_cellvars=None,
1116         co_freevars=None, co_lnotab=None, co_firstlineno=None):
1117  """Disassemble a string into a list of Opcode instances."""
1118  code = []
1119  if co_lnotab:
1120    lp = _LineNumberTableParser(python_version, co_lnotab, co_firstlineno)
1121  else:
1122    lp = None
1123  offset_to_index = {}
1124  if co_cellvars is not None and co_freevars is not None:
1125    cellvars_freevars = co_cellvars + co_freevars
1126  else:
1127    cellvars_freevars = None
1128  for pos, end_pos, cls, oparg in reader(data, mapping):
1129    index = len(code)
1130    offset_to_index[pos] = index
1131    if lp:
1132      line = lp.get(pos)
1133    else:
1134      # single line programs don't have co_lnotab
1135      line = co_firstlineno
1136    if oparg is not None:
1137      if cls.has_jrel():
1138        oparg += end_pos
1139      pretty = _prettyprint_arg(cls, oparg, co_consts, co_names, co_varnames,
1140                                cellvars_freevars)
1141      code.append(cls(index, line, oparg, pretty))
1142    else:
1143      code.append(cls(index, line))
1144
1145  # Map the target of jump instructions to the opcode they jump to, and fill
1146  # in "next" and "prev" pointers
1147  for i, op in enumerate(code):
1148    if op.FLAGS & (HAS_JREL | HAS_JABS):
1149      op.arg = op.pretty_arg = offset_to_index[op.arg]
1150      op.target = code[op.arg]
1151    op.prev = code[i - 1] if i > 0 else None
1152    op.next = code[i + 1] if i < len(code) - 1 else None
1153  return code
1154
1155
1156def dis(data, python_version, *args, **kwargs):
1157  """Set up version-specific arguments and call _dis()."""
1158  major, minor = python_version[0], python_version[1]
1159  assert major == 3
1160  mapping = {
1161      (3, 5): python_3_5_mapping,
1162      (3, 6): python_3_6_mapping,
1163      (3, 7): python_3_7_mapping,
1164      (3, 8): python_3_8_mapping,
1165      (3, 9): python_3_9_mapping,
1166  }[(major, minor)]
1167  reader = _wordcode_reader if (major, minor) > (3, 5) else _bytecode_reader
1168  return _dis(python_version, data, mapping, reader, *args, **kwargs)
1169
1170
1171def dis_code(code):
1172  return dis(data=code.co_code,
1173             python_version=code.python_version,
1174             co_varnames=code.co_varnames,
1175             co_names=code.co_names,
1176             co_consts=code.co_consts,
1177             co_cellvars=code.co_cellvars,
1178             co_freevars=code.co_freevars,
1179             co_lnotab=code.co_lnotab,
1180             co_firstlineno=code.co_firstlineno)
1181