opcode_312rust.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. """
  2. RustPython 3.12 bytecode opcodes
  3. """
  4. #FIXME: this needs a lot of going over.
  5. from typing import Dict, List, Optional, Tuple
  6. import xdis.opcodes.opcode_313 as opcode_313
  7. from xdis.opcodes.base import (
  8. binary_op,
  9. compare_op,
  10. const_op,
  11. def_op,
  12. finalize_opcodes,
  13. free_op,
  14. init_opdata,
  15. jrel_op,
  16. local_op,
  17. name_op,
  18. store_op,
  19. unary_op,
  20. update_pj3,
  21. )
  22. from xdis.opcodes.format.extended import extended_format_binary_op
  23. from xdis.opcodes.opcode_312 import opcode_arg_fmt312, opcode_extended_fmt312
  24. version_tuple = (3, 12)
  25. python_implementation = "RustPython"
  26. # oppush[op] => number of stack entries pushed
  27. oppush: List[int] = [0] * 256
  28. # oppop[op] => number of stack entries popped
  29. oppop: List[int] = [0] * 256
  30. # opmap[opcode_name] => opcode_number
  31. opmap: Dict[str, int] = {}
  32. ## pseudo opcodes (used in the compiler) mapped to the values
  33. ## they can become in the actual code.
  34. _pseudo_ops = {}
  35. _nb_ops = [
  36. ("NB_ADD", "+"),
  37. ("NB_AND", "&"),
  38. ("NB_FLOOR_DIVIDE", "//"),
  39. ("NB_LSHIFT", "<<"),
  40. ("NB_MATRIX_MULTIPLY", "@"),
  41. ("NB_MULTIPLY", "*"),
  42. ("NB_REMAINDER", "%"),
  43. ("NB_OR", "|"),
  44. ("NB_POWER", "**"),
  45. ("NB_RSHIFT", ">>"),
  46. ("NB_SUBTRACT", "-"),
  47. ("NB_TRUE_DIVIDE", "/"),
  48. ("NB_XOR", "^"),
  49. ("NB_INPLACE_ADD", "+="),
  50. ("NB_INPLACE_AND", "&="),
  51. ("NB_INPLACE_FLOOR_DIVIDE", "//="),
  52. ("NB_INPLACE_LSHIFT", "<<="),
  53. ("NB_INPLACE_MATRIX_MULTIPLY", "@="),
  54. ("NB_INPLACE_MULTIPLY", "*="),
  55. ("NB_INPLACE_REMAINDER", "%="),
  56. ("NB_INPLACE_OR", "|="),
  57. ("NB_INPLACE_POWER", "**="),
  58. ("NB_INPLACE_RSHIFT", ">>="),
  59. ("NB_INPLACE_SUBTRACT", "-="),
  60. ("NB_INPLACE_TRUE_DIVIDE", "/="),
  61. ("NB_INPLACE_XOR", "^="),
  62. ]
  63. hasexc = []
  64. loc = locals()
  65. init_opdata(loc, opcode_313, version_tuple)
  66. oplists = [
  67. loc["hasarg"],
  68. loc["hasconst"],
  69. loc["hasname"],
  70. loc["hasjrel"],
  71. loc["hasjabs"],
  72. loc["haslocal"],
  73. loc["hascompare"],
  74. loc["hasfree"],
  75. loc["hasexc"],
  76. ]
  77. def pseudo_op(name: str, op: int, real_ops: list):
  78. def_op(loc, name, op)
  79. _pseudo_ops[name] = real_ops
  80. # add the pseudo opcode to the lists its targets are in
  81. for oplist in oplists:
  82. res = [opmap[rop] in oplist for rop in real_ops]
  83. if any(res):
  84. # FIXME: for some reason JUMP_FORWARD appears to be
  85. # listed as a free op. It isn't.
  86. # if not all(res):
  87. # breakpoint()
  88. # assert all(res)
  89. oplist.append(op)
  90. # fmt: off
  91. # OP NAME OPCODE POP PUSH
  92. #----------------------------------------------------------
  93. def_op(loc, "CACHE", 0, 0, 0)
  94. def_op(loc, "POP_TOP", 1, 1, 0)
  95. def_op(loc, "PUSH_NULL", 2, 0 , 1)
  96. def_op(loc, "NOP", 9, 0, 0)
  97. unary_op(loc, "UNARY_POSITIVE", 10)
  98. unary_op(loc, "UNARY_NEGATIVE", 11)
  99. unary_op(loc, "UNARY_NOT", 12)
  100. unary_op(loc, "UNARY_INVERT", 15)
  101. binary_op(loc, "BINARY_SUBSCR", 25)
  102. binary_op(loc, "BINARY_SLICE", 26)
  103. store_op(loc, "STORE_SLICE", 27, 4, 0)
  104. def_op(loc, "GET_LEN", 30, 0, 1)
  105. def_op(loc, "MATCH_MAPPING", 31, 0, 1)
  106. def_op(loc, "MATCH_SEQUENCE", 32, 0, 1)
  107. def_op(loc, "MATCH_KEYS", 33, 0, 2)
  108. jrel_op(loc, "PUSH_EXC_INFO", 35, 0, 1)
  109. def_op(loc, "CHECK_EXC_MATCH", 36)
  110. jrel_op(loc, "CHECK_EG_MATCH", 37, 0, 0)
  111. # FIXME: fill in
  112. def_op(loc, "WITH_EXCEPT_START", 49)
  113. def_op(loc, "GET_AITER", 50)
  114. def_op(loc, "GET_ANEXT", 51)
  115. def_op(loc, "BEFORE_ASYNC_WITH", 52)
  116. def_op(loc, "BEFORE_WITH", 53)
  117. def_op(loc, "END_ASYNC_FOR", 54)
  118. def_op(loc, "CLEANUP_THROW", 55)
  119. def_op(loc, "STORE_SUBSCR", 60)
  120. def_op(loc, "DELETE_SUBSCR", 61)
  121. # TODO: RUSTPYTHON
  122. # Delete below def_op after updating coroutines.py
  123. def_op(loc, "YIELD_FROM", 72)
  124. def_op(loc, "GET_ITER", 68)
  125. def_op(loc, "GET_YIELD_FROM_ITER", 69)
  126. def_op(loc, "PRINT_EXPR", 70)
  127. def_op(loc, "LOAD_BUILD_CLASS", 71)
  128. def_op(loc, "LOAD_ASSERTION_ERROR", 74)
  129. def_op(loc, "RETURN_GENERATOR", 75)
  130. def_op(loc, "LIST_TO_TUPLE", 82)
  131. def_op(loc, "RETURN_VALUE", 83)
  132. def_op(loc, "IMPORT_STAR", 84)
  133. def_op(loc, "SETUP_ANNOTATIONS", 85)
  134. def_op(loc, "ASYNC_GEN_WRAP", 87)
  135. def_op(loc, "PREP_RERAISE_STAR", 88)
  136. def_op(loc, "POP_EXCEPT", 89)
  137. HAVE_ARGUMENT = 90 # real opcodes from here have an argument:
  138. name_op(loc, "STORE_NAME", 90) # Index in name list
  139. name_op(loc, "DELETE_NAME", 91) # ""
  140. def_op(loc, "UNPACK_SEQUENCE", 92) # Number of tuple items
  141. jrel_op(loc, "FOR_ITER", 93)
  142. def_op(loc, "UNPACK_EX", 94)
  143. name_op(loc, "STORE_ATTR", 95) # Index in name list
  144. name_op(loc, "DELETE_ATTR", 96) # ""
  145. name_op(loc, "STORE_GLOBAL", 97) # ""
  146. name_op(loc, "DELETE_GLOBAL", 98) # ""
  147. def_op(loc, "SWAP", 99, 0, 0)
  148. # Operand is in const list
  149. const_op(loc, "LOAD_CONST", 100, 0, 1)
  150. name_op(loc, "LOAD_NAME", 101) # Index in name list
  151. def_op(loc, "BUILD_TUPLE", 102) # Number of tuple items
  152. def_op(loc, "BUILD_LIST", 103) # Number of list items
  153. def_op(loc, "BUILD_SET", 104) # Number of set items
  154. def_op(loc, "BUILD_MAP", 105) # Number of dict entries
  155. name_op(loc, "LOAD_ATTR", 106) # Index in name list
  156. compare_op(loc, "COMPARE_OP", 107, 2, 1) # Comparison operator
  157. name_op(loc, "IMPORT_NAME", 108) # Index in name list
  158. name_op(loc, "IMPORT_FROM", 109) # Index in name list
  159. jrel_op(loc, "JUMP_FORWARD", 110) # Number of words to skip
  160. jrel_op(loc, "JUMP_IF_FALSE_OR_POP", 111) # Number of words to skip
  161. jrel_op(loc, "JUMP_IF_TRUE_OR_POP", 112) # ""
  162. jrel_op(loc, "POP_JUMP_IF_FALSE", 114)
  163. jrel_op(loc, "POP_JUMP_IF_TRUE", 115)
  164. name_op(loc, "LOAD_GLOBAL", 116) # Index in name list
  165. def_op(loc, "IS_OP", 117)
  166. def_op(loc, "CONTAINS_OP", 118)
  167. def_op(loc, "RERAISE", 119, 3, 0)
  168. def_op(loc, "COPY", 120)
  169. def_op(loc, "BINARY_OP", 122)
  170. jrel_op(loc, "SEND", 123) # Number of bytes to skip
  171. local_op(loc, "LOAD_FAST", 124, 0, 1) # Local variable number
  172. loc["nullaryloadop"].add(124)
  173. store_op(loc, "STORE_FAST", 125, 1, 0, is_type="local") # Local variable
  174. local_op(loc, "DELETE_FAST", 126, 0, 0) # Local variable number is in operand
  175. def_op(loc , "LOAD_FAST_CHECK" , 127, 0, 1)
  176. local_op(loc, "LOAD_FAST_CHECK", 127) # Local variable number
  177. jrel_op(loc, "POP_JUMP_IF_NOT_NONE", 128)
  178. jrel_op(loc, "POP_JUMP_IF_NONE", 129)
  179. def_op(loc, "RAISE_VARARGS", 130) # Number of raise arguments (1, 2, or 3)
  180. def_op(loc, "GET_AWAITABLE", 131)
  181. def_op(loc, "MAKE_FUNCTION", 132) # Flags
  182. def_op(loc, "BUILD_SLICE", 133) # Number of items
  183. jrel_op(loc, "JUMP_BACKWARD_NO_INTERRUPT", 134) # Number of words to skip (backwards)
  184. free_op(loc, "MAKE_CELL", 135, 0, 0)
  185. free_op(loc, "LOAD_CLOSURE", 136)
  186. free_op(loc, "LOAD_DEREF", 137, 0, 1)
  187. loc["nullaryop"].add(137)
  188. loc["nullaryloadop"].add(137)
  189. store_op(loc, "STORE_DEREF", 138, 1, 0, is_type="free")
  190. free_op(loc, "DELETE_DEREF", 139, 0, 0)
  191. jrel_op(loc, "JUMP_BACKWARD", 140) # Number of words to skip (backwards)
  192. def_op(loc, "CALL_FUNCTION_EX", 142) # Flags
  193. def_op(loc, "EXTENDED_ARG", 144)
  194. EXTENDED_ARG = 144
  195. def_op(loc, "LIST_APPEND", 145)
  196. def_op(loc, "SET_ADD", 146)
  197. def_op(loc, "MAP_ADD", 147)
  198. free_op(loc, "LOAD_CLASSDEREF", 148)
  199. def_op(loc, "COPY_FREE_VARS", 149)
  200. def_op(loc, "YIELD_VALUE", 150)
  201. # This must be kept in sync with deepfreeze.py
  202. # resume, acts like a nop
  203. def_op(loc, "RESUME", 151, 0, 0)
  204. def_op(loc, "MATCH_CLASS", 152)
  205. def_op(loc, "FORMAT_VALUE", 155)
  206. def_op(loc, "BUILD_CONST_KEY_MAP", 156)
  207. def_op(loc, "BUILD_STRING", 157)
  208. def_op(loc, "LIST_EXTEND", 162)
  209. def_op(loc, "SET_UPDATE", 163)
  210. def_op(loc, "DICT_MERGE", 164)
  211. def_op(loc, "DICT_UPDATE", 165)
  212. def_op(loc, "CALL", 171)
  213. const_op(loc, "KW_NAMES", 172)
  214. loc["hasarg"].extend([op for op in opmap.values() if op >= HAVE_ARGUMENT])
  215. MIN_PSEUDO_OPCODE = 256
  216. pseudo_op("SETUP_FINALLY", 256, ["NOP"])
  217. hasexc.append(256)
  218. pseudo_op("SETUP_CLEANUP", 257, ["NOP"])
  219. hasexc.append(257)
  220. pseudo_op("SETUP_WITH", 258, ["NOP"])
  221. hasexc.append(258)
  222. pseudo_op("POP_BLOCK", 259, ["NOP"])
  223. pseudo_op("JUMP", 260, ["JUMP_FORWARD", "JUMP_BACKWARD"])
  224. pseudo_op("JUMP_NO_INTERRUPT", 261, ["JUMP_FORWARD", "JUMP_BACKWARD_NO_INTERRUPT"])
  225. pseudo_op("LOAD_METHOD", 262, ["LOAD_ATTR"])
  226. # fmt: on
  227. MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1
  228. # extend opcodes to cover pseudo ops
  229. opname = [f"<{op!r}>" for op in range(MAX_PSEUDO_OPCODE + 1)]
  230. opname.extend([f"<{i}>" for i in range(256, 267)])
  231. oppop.extend([0] * 11)
  232. oppush.extend([0] * 11)
  233. for op, i in opmap.items():
  234. opname[i] = op
  235. _specializations = {
  236. "BINARY_OP": [
  237. "BINARY_OP_ADAPTIVE",
  238. "BINARY_OP_ADD_FLOAT",
  239. "BINARY_OP_ADD_INT",
  240. "BINARY_OP_ADD_UNICODE",
  241. "BINARY_OP_INPLACE_ADD_UNICODE",
  242. "BINARY_OP_MULTIPLY_FLOAT",
  243. "BINARY_OP_MULTIPLY_INT",
  244. "BINARY_OP_SUBTRACT_FLOAT",
  245. "BINARY_OP_SUBTRACT_INT",
  246. ],
  247. "BINARY_SUBSCR": [
  248. "BINARY_SUBSCR_ADAPTIVE",
  249. "BINARY_SUBSCR_DICT",
  250. "BINARY_SUBSCR_GETITEM",
  251. "BINARY_SUBSCR_LIST_INT",
  252. "BINARY_SUBSCR_TUPLE_INT",
  253. ],
  254. "CALL": [
  255. "CALL_ADAPTIVE",
  256. "CALL_PY_EXACT_ARGS",
  257. "CALL_PY_WITH_DEFAULTS",
  258. "CALL_BOUND_METHOD_EXACT_ARGS",
  259. "CALL_BUILTIN_CLASS",
  260. "CALL_BUILTIN_FAST_WITH_KEYWORDS",
  261. "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
  262. "CALL_NO_KW_BUILTIN_FAST",
  263. "CALL_NO_KW_BUILTIN_O",
  264. "CALL_NO_KW_ISINSTANCE",
  265. "CALL_NO_KW_LEN",
  266. "CALL_NO_KW_LIST_APPEND",
  267. "CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
  268. "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS",
  269. "CALL_NO_KW_METHOD_DESCRIPTOR_O",
  270. "CALL_NO_KW_STR_1",
  271. "CALL_NO_KW_TUPLE_1",
  272. "CALL_NO_KW_TYPE_1",
  273. ],
  274. "COMPARE_OP": [
  275. "COMPARE_OP_ADAPTIVE",
  276. "COMPARE_OP_FLOAT_JUMP",
  277. "COMPARE_OP_INT_JUMP",
  278. "COMPARE_OP_STR_JUMP",
  279. ],
  280. "EXTENDED_ARG": [
  281. "EXTENDED_ARG_QUICK",
  282. ],
  283. "FOR_ITER": [
  284. "FOR_ITER_ADAPTIVE",
  285. "FOR_ITER_LIST",
  286. "FOR_ITER_RANGE",
  287. ],
  288. "JUMP_BACKWARD": [
  289. "JUMP_BACKWARD_QUICK",
  290. ],
  291. "LOAD_ATTR": [
  292. "LOAD_ATTR_ADAPTIVE",
  293. # These potentially push [NULL, bound method] onto the stack.
  294. "LOAD_ATTR_CLASS",
  295. "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
  296. "LOAD_ATTR_INSTANCE_VALUE",
  297. "LOAD_ATTR_MODULE",
  298. "LOAD_ATTR_PROPERTY",
  299. "LOAD_ATTR_SLOT",
  300. "LOAD_ATTR_WITH_HINT",
  301. # These will always push [unbound method, self] onto the stack.
  302. "LOAD_ATTR_METHOD_LAZY_DICT",
  303. "LOAD_ATTR_METHOD_NO_DICT",
  304. "LOAD_ATTR_METHOD_WITH_DICT",
  305. "LOAD_ATTR_METHOD_WITH_VALUES",
  306. ],
  307. "LOAD_CONST": [
  308. "LOAD_CONST__LOAD_FAST",
  309. ],
  310. "LOAD_FAST": [
  311. "LOAD_FAST__LOAD_CONST",
  312. "LOAD_FAST__LOAD_FAST",
  313. ],
  314. "LOAD_GLOBAL": [
  315. "LOAD_GLOBAL_ADAPTIVE",
  316. "LOAD_GLOBAL_BUILTIN",
  317. "LOAD_GLOBAL_MODULE",
  318. ],
  319. "RESUME": [
  320. "RESUME_QUICK",
  321. ],
  322. "STORE_ATTR": [
  323. "STORE_ATTR_ADAPTIVE",
  324. "STORE_ATTR_INSTANCE_VALUE",
  325. "STORE_ATTR_SLOT",
  326. "STORE_ATTR_WITH_HINT",
  327. ],
  328. "STORE_FAST": [
  329. "STORE_FAST__LOAD_FAST",
  330. "STORE_FAST__STORE_FAST",
  331. ],
  332. "STORE_SUBSCR": [
  333. "STORE_SUBSCR_ADAPTIVE",
  334. "STORE_SUBSCR_DICT",
  335. "STORE_SUBSCR_LIST_INT",
  336. ],
  337. "UNPACK_SEQUENCE": [
  338. "UNPACK_SEQUENCE_ADAPTIVE",
  339. "UNPACK_SEQUENCE_LIST",
  340. "UNPACK_SEQUENCE_TUPLE",
  341. "UNPACK_SEQUENCE_TWO_TUPLE",
  342. ],
  343. }
  344. _specialized_instructions = [
  345. opcode for family in _specializations.values() for opcode in family
  346. ]
  347. _specialization_stats = [
  348. "success",
  349. "failure",
  350. "hit",
  351. "deferred",
  352. "miss",
  353. "deopt",
  354. ]
  355. _cache_format = {
  356. "LOAD_GLOBAL": {
  357. "counter": 1,
  358. "index": 1,
  359. "module_keys_version": 2,
  360. "builtin_keys_version": 1,
  361. },
  362. "BINARY_OP": {
  363. "counter": 1,
  364. },
  365. "UNPACK_SEQUENCE": {
  366. "counter": 1,
  367. },
  368. "COMPARE_OP": {
  369. "counter": 1,
  370. "mask": 1,
  371. },
  372. "BINARY_SUBSCR": {
  373. "counter": 1,
  374. "type_version": 2,
  375. "func_version": 1,
  376. },
  377. "FOR_ITER": {
  378. "counter": 1,
  379. },
  380. "LOAD_ATTR": {
  381. "counter": 1,
  382. "version": 2,
  383. "keys_version": 2,
  384. "descr": 4,
  385. },
  386. "STORE_ATTR": {
  387. "counter": 1,
  388. "version": 2,
  389. "index": 1,
  390. },
  391. "CALL": {
  392. "counter": 1,
  393. "func_version": 2,
  394. "min_args": 1,
  395. },
  396. "STORE_SUBSCR": {
  397. "counter": 1,
  398. },
  399. }
  400. _inline_cache_entries = [
  401. sum(_cache_format.get(opname[opcode], {}).values()) for opcode in range(256)
  402. ]
  403. def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]:
  404. opname = _nb_ops[instructions[0].argval][1]
  405. if opname == "%":
  406. opname = "%%"
  407. elif opname == "%=":
  408. opname = "%%="
  409. return extended_format_binary_op(opc, instructions, f"%s {opname} %s")
  410. pcode_extended_fmt312rust = opcode_extended_fmt312.copy()
  411. opcode_arg_fmt = opcode_arg_fmt12rust = opcode_arg_fmt312.copy()
  412. ### update arg formatting
  413. opcode_extended_fmt = opcode_extended_fmt312rust = {
  414. **opcode_extended_fmt312,
  415. **{
  416. "BINARY_OP": extended_format_BINARY_OP,
  417. },
  418. }
  419. from xdis.opcodes.opcode_311 import findlinestarts
  420. update_pj3(globals(), loc)
  421. finalize_opcodes(loc)