opcode_37.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # (C) Copyright 2016-2017, 2019-2021, 2023-2024
  2. # by Rocky Bernstein
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. """
  18. CPython 3.7 bytecode opcodes
  19. This is like Python 3.7's opcode.py with some classification
  20. of stack usage and information for formatting instructions.
  21. """
  22. from typing import Optional, Tuple
  23. import xdis.opcodes.opcode_36 as opcode_36
  24. from xdis.opcodes.base import (
  25. call_op,
  26. def_op,
  27. finalize_opcodes,
  28. init_opdata,
  29. jrel_op,
  30. name_op,
  31. rm_op,
  32. update_pj3,
  33. )
  34. from xdis.opcodes.format.extended import (
  35. extended_format_CALL_METHOD,
  36. get_instruction_arg,
  37. )
  38. from xdis.opcodes.opcode_36 import (
  39. format_CALL_FUNCTION,
  40. opcode_arg_fmt36,
  41. opcode_extended_fmt36,
  42. )
  43. version_tuple = (3, 7)
  44. python_implementation = "CPython"
  45. loc = locals()
  46. init_opdata(loc, opcode_36, version_tuple)
  47. ### Opcodes that have changed drastically ####
  48. # BUILD_MAP_UNPACK_WITH_CALL oparg
  49. # oparg is the number of unpacked mappings which no longer limited by
  50. # 255. As in BUILD_MAP_UNPACK.The location of the function is `oparg +
  51. # 2`.
  52. # CALL_FUNCTION oparg
  53. # oparg is the number of positional arguments on the stack which no
  54. # longer limited by 255.
  55. # CALL_FUNCTION_KW oparg
  56. # This is a different opcode from before, with the name of a similar
  57. # opcode as before. It s like CALL_FUNCTION but values of keyword
  58. # arguments are pushed on the stack after values of positional
  59. # arguments, and then a constant tuple of keyword names is pushed on
  60. # the top of the stack. *oparg* is the sum of numbers of positional
  61. # and keyword arguments. The number of keyword arguments is
  62. # determined by the length of the tuple of keyword names.
  63. # CALL_FUNCTION_EX** takes 2 to 3 arguments on the stack: the
  64. # function, the tuple of positional arguments, and optionally the dict
  65. # of keyword arguments if bit 0 of *oparg* is 1.
  66. # MAKE_FUNCTION oparg
  67. # This is a different opcode from before.
  68. # The tuple of default values for positional-or-keyword parameters,
  69. # the dict of default values for keyword-only parameters, the dict of
  70. # annotations and the closure are pushed on the stack if corresponding
  71. # bit (0-3) is set. They are followed by the code object and the
  72. # qualified name of the function.
  73. # These are removed since 3.6...
  74. # and STORE_ANNOTATION introduced in 3.6!
  75. rm_op(loc, "STORE_ANNOTATION", 127)
  76. # fmt: off
  77. # These have a changed stack effect since 3.6
  78. # OP NAME OPCODE POP PUSH
  79. #---------------------------------------------------------------
  80. def_op(loc, "WITH_CLEANUP_START", 81, 0, 2)
  81. def_op(loc, "WITH_CLEANUP_FINISH", 82, 3, 0)
  82. def_op(loc, "END_FINALLY", 88, 6, 0)
  83. def_op(loc, "POP_EXCEPT", 89, 3, 0) # Pops last 3 values
  84. jrel_op(loc, "SETUP_WITH", 143, 0, 6)
  85. jrel_op(loc, "SETUP_ASYNC_WITH", 154, 0, 5)
  86. # These are new since Python 3.7
  87. name_op(loc, "LOAD_METHOD", 160, 0, 1)
  88. call_op(loc, "CALL_METHOD", 161, -2, 1)
  89. format_MAKE_FUNCTION_36 = opcode_36.format_MAKE_FUNCTION_36
  90. format_value_flags = opcode_36.format_value_flags
  91. # fmt: on
  92. def extended_format_LOAD_METHOD(opc, instructions: list) -> Tuple[str, Optional[int]]:
  93. instr1 = instructions[1]
  94. if instr1.tos_str or instr1.opcode in opc.nullaryloadop:
  95. base = get_instruction_arg(instr1)
  96. return (
  97. f"{base}.{instructions[0].argrepr}",
  98. instr1.start_offset,
  99. )
  100. return "", None
  101. def extended_format_RAISE_VARARGS(opc, instructions) -> Tuple[Optional[str], int]:
  102. raise_inst = instructions[0]
  103. assert raise_inst.opname == "RAISE_VARARGS"
  104. argc = raise_inst.argval
  105. start_offset = raise_inst.start_offset
  106. if argc == 0:
  107. return "reraise", start_offset
  108. elif argc == 1:
  109. exception_name_inst = instructions[1]
  110. start_offset = exception_name_inst.start_offset
  111. exception_name = (
  112. exception_name_inst.tos_str
  113. if exception_name_inst.tos_str
  114. else exception_name_inst.argrepr
  115. )
  116. if exception_name is not None:
  117. return f"raise {exception_name}()", start_offset
  118. return format_RAISE_VARARGS(raise_inst.argval), start_offset
  119. def format_RAISE_VARARGS(argc) -> str | None:
  120. assert 0 <= argc <= 2
  121. if argc == 0:
  122. return "reraise"
  123. elif argc == 1:
  124. return "exception instance"
  125. elif argc == 2:
  126. return "exception instance with __cause__"
  127. opcode_arg_fmt = opcode_arg_fmt37 = {
  128. **opcode_arg_fmt36,
  129. **{"CALL_METHOD": format_CALL_FUNCTION, "RAISE_VARARGS": format_RAISE_VARARGS},
  130. }
  131. opcode_extended_fmt = opcode_extended_fmt37 = {
  132. **opcode_extended_fmt36,
  133. **{
  134. "CALL_METHOD": extended_format_CALL_METHOD,
  135. "LOAD_METHOD": extended_format_LOAD_METHOD,
  136. "RAISE_VARARGS": extended_format_RAISE_VARARGS,
  137. },
  138. }
  139. update_pj3(globals(), loc)
  140. finalize_opcodes(loc)