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