diff --git a/xdis/codetype/code312rust.py b/xdis/codetype/code312rust.py new file mode 100644 index 00000000..e937770a --- /dev/null +++ b/xdis/codetype/code312rust.py @@ -0,0 +1,82 @@ +# (C) Copyright 2025 by Rocky Bernstein +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from dataclasses import dataclass +from typing import Any, Dict, Tuple, Union + +from xdis.codetype.code311 import Code311 + + +@dataclass +class SourceLocation: + # 1-based integer line number + line_number: int + # column offset in line: 1-based int (constructed from a zero-indexed stored value) + column_offset: int + + +class Code312Rust(Code311): + """Class for a RustPython 3.12 code object used when a Python + interpreter is not RustPython 3.12 but working on RustPython 3.12 bytecode. It + also functions as an object that can be used to build or write a + Python3 code object, since we allow mutable structures. + + When done mutating, call method to_native(). + + For convenience in generating code objects, fields like + `co_consts`, co_names which are (immutable) tuples in the end-result can be stored + instead as (mutable) lists. Likewise, the line number table `co_lnotab` + can be stored as a simple list of offset, line_number tuples. + + """ + def __init__( + self, + co_argcount: int, + co_posonlyargcount: int, + co_kwonlyargcount: int, + co_stacksize: int, + co_flags: int, + co_code: bytes, + co_consts: tuple, + co_names: tuple[str], + co_varnames: tuple[str], + co_filename: str, + co_name: str, + co_firstlineno: int, + co_freevars: tuple, + co_cellvars: tuple, + version_triple: Tuple[int, int, int], + locations: tuple, + collection_order: Dict[Union[set, frozenset, dict], Tuple[Any]] = {}, + ) -> None: + self.co_argcount = co_argcount + self.co_posonlyargcount = co_posonlyargcount + self.co_kwonlyargcount = co_kwonlyargcount + self.co_lnotab={} # FIXME: compute this from locations. + self.co_stacksize = co_stacksize + self.co_flags = co_flags + self.co_code = co_code + self.co_consts = co_consts + self.co_names = co_names + self.co_varnames = co_varnames + self.co_filename = co_filename + self.co_name = co_name + self.co_firstlineno = co_firstlineno # None if 0 in serialized form + self.co_cellvars = co_cellvars + self.co_freevars= co_freevars + self.co_collection_order = collection_order + self.version_triple = version_triple + self.locations = locations diff --git a/xdis/codetype/code313rust.py b/xdis/codetype/code313rust.py index 0833aed8..c4ba5b67 100644 --- a/xdis/codetype/code313rust.py +++ b/xdis/codetype/code313rust.py @@ -82,7 +82,6 @@ def __init__( self.co_linetable = co_linetable self.co_qualname = co_qualname self.co_cellvars = co_cellvars - self.co_linetable = co_linetable self.co_freevars= co_freevars self.co_exceptiontable = co_exceptiontable self.co_collection_order = collection_order diff --git a/xdis/cross_dis.py b/xdis/cross_dis.py index 80c41357..5c34a2b4 100644 --- a/xdis/cross_dis.py +++ b/xdis/cross_dis.py @@ -170,7 +170,7 @@ def findlinestarts(code, dup_lines: bool = False): Generate pairs (offset, lineno) as described in Python/compile.c. """ - if hasattr(code, "co_lines"): + if hasattr(code, "co_lines") and hasattr(code, "co_linetable"): # Taken from 3.10 findlinestarts lastline = None for start, _, line in code.co_lines(): @@ -325,7 +325,7 @@ def format_code_info( lines.append("# Keyword-only arguments: %s" % co.co_kwonlyargcount) pos_argc = co.co_argcount - if version_tuple >= (1, 3): + if hasattr(co, "co_nlocals"): lines.append("# Number of locals: %s" % co.co_nlocals) if version_tuple >= (1, 5): lines.append("# Stack size: %s" % co.co_stacksize) diff --git a/xdis/load.py b/xdis/load.py index 168293fd..75fcfaf3 100644 --- a/xdis/load.py +++ b/xdis/load.py @@ -228,10 +228,24 @@ def load_module_from_file_object( magic = fp.read(4) magic_int = magic2int(magic) + if magic_int == 3531: + # this magic int is used for both 3.12 and 3.13Rust! + # Disambiguate using the fact that CPython 3.13 stores 0xe3 + # "c" | 0x80 at offoset 0x10 while RustPython uses "c" (no 0x80). + fp.seek(0x10) + code_type = fp.read(1) + if code_type == b'c': + # Is RustPython 3.13 using CPython's 3.12 magic number. + magic_int = 35310 + else: + assert code_type == b'\xe3', "Expecting magic int 3531 to have a code type b'0x63 or b'0x33' at offset 0x10" + fp.seek(0x04) + # For reasons I don't understand, PyPy 3.2 stores a magic # of '0'... The two values below are for Python 2.x and 3.x respectively if magic[0:1] in ["0", b"0"]: magic = int2magic(3180 + 7) + magic_int = magic2int(magic) try: # FIXME: use the internal routine below @@ -245,10 +259,7 @@ def load_module_from_file_object( else: raise ImportError(f"Bad magic number: '{magic}'") - if magic_int in [2657, 22138] + list( - RUSTPYTHON_MAGICS - ) + list(JYTHON_MAGICS): - version = magicint2version.get(magic_int, "") + version = magic_int2tuple(magic_int) if magic_int in INTERIM_MAGIC_INTS: raise ImportError( @@ -268,8 +279,6 @@ def load_module_from_file_object( try: my_magic_int = PYTHON_MAGIC_INT - magic_int = magic2int(magic) - version = magic_int2tuple(magic_int) timestamp = None source_size = None diff --git a/xdis/magics.py b/xdis/magics.py index ee3f5baf..d2744596 100755 --- a/xdis/magics.py +++ b/xdis/magics.py @@ -47,11 +47,13 @@ # See below for mapping to version numbers. PYPY3_MAGICS = (48, 64, 112, 160, 192, 240, 244, 256, 320, 336, 384, 416) +# Rust Magics is a git commit number! RUSTPYTHON_MAGICS = ( 12641, # RustPython 3.12 - 12897, # RustPython 3.12 + 12897, # RustPython 3.12.0 0.4.0 13413, # RustPython 3.13 - 24881, # RustPython 3.13 + 24881, # RustPython 3.13 0.4.0 + 35310, # RustPython 3.13 0.4.0 later version! Actually 3531 is stored in file ) # A list of interim Python version magic numbers used, but were not @@ -515,7 +517,7 @@ def __by_version(magic_versions: Dict[bytes, str]) -> dict: add_magic_from_int(3512, "3.12a2c") add_magic_from_int(3513, "3.12a4a") add_magic_from_int(3514, "3.12a4b") -add_magic_from_int(3515, "3.12a5a") +# add_magic_from_int(3515, "3.12a5a") # Rust Python 3.13 0.40 uses this too! add_magic_from_int(3516, "3.12a5b") add_magic_from_int(3517, "3.12a5c") add_magic_from_int(3518, "3.12a6a") @@ -695,9 +697,12 @@ def __by_version(magic_versions: Dict[bytes, str]) -> dict: add_magic_from_int(416, "3.11.13PyPy") # PyPy 3.11.13 or pypy3.11-7.3.20 add_magic_from_int(12641, "3.12.0a.rust") # RustPython 3.12.0 -add_magic_from_int(12897, "3.13.0b.rust") # RustPython 3.12.0 +add_magic_from_int(12897, "3.12.0.rust") # RustPython 3.12.0 0.4.0 add_magic_from_int(13413, "3.13.0a.rust") # RustPython 3.13.0 -add_magic_from_int(24881, "3.13.0b.rust") # RustPython 3.13.0 +add_magic_from_int(24881, "3.13.0b.rust") # RustPython 3.13.0 0.4.0 + +# Actually we should add 3531, but that already means CPython 3.12! +add_magic_from_int(35310, "3.13.1.rust") # RustPython 3.13.0 0.4.0 # Graal Python. Graal uses its own JVM-ish CPython bytecode, not # true CPython or PyPy bytecode. diff --git a/xdis/op_imports.py b/xdis/op_imports.py index 3b044542..51541b7f 100644 --- a/xdis/op_imports.py +++ b/xdis/op_imports.py @@ -60,8 +60,10 @@ opcode_311pypy, opcode_312, opcode_313, - opcode_313rust, opcode_314, + opcode_3531rust, + opcode_12897rust, + opcode_24481rust, ) from xdis.opcodes.opcode_graal import ( opcode_38graal, @@ -187,10 +189,12 @@ 3.11: opcode_311, "3.12.7Graal": opcode_312graal, # this right? "3.12.8Graal": opcode_312graal, # this right? + "3.12.0Rust": opcode_12897rust, "3.12.0rc2": opcode_312, "3.12.0": opcode_312, "3.13.0rc3": opcode_313, - "3.13.0Rust": opcode_313rust, + "3.13.0Rust": opcode_24481rust, + "3.13.1Rust": opcode_3531rust, "3.14b3": opcode_314, "3.14.0": opcode_314, "3.14": opcode_314, @@ -211,7 +215,7 @@ def get_opcode_module(version_info: Tuple[int, ...], implementation: PythonImple if vers_str not in canonic_python_version: vers_str = version_tuple_to_str(version_info[:2]) - if implementation != PythonImplementation.CPython: + if str(implementation) != str(PythonImplementation.CPython): vers_str += str(implementation) return op_imports[canonic_python_version[vers_str]] @@ -330,4 +334,4 @@ def remap_opcodes(op_obj, alternate_opmap): if __name__ == "__main__": from version_info import PYTHON_IMPLEMENTATION, PYTHON_VERSION_TRIPLE - print(get_opcode_module(PYTHON_VERSION_TRIPLE, PYTHON_IMPLEMENTATION)) + print(get_opcode_module(PYTHON_VERSION_TRIPLE[:2], PYTHON_IMPLEMENTATION)) diff --git a/xdis/opcodes/__init__.py b/xdis/opcodes/__init__.py index 9a987866..0737617a 100644 --- a/xdis/opcodes/__init__.py +++ b/xdis/opcodes/__init__.py @@ -68,7 +68,7 @@ opcode_310pypy, opcode_311pypy, ) -from xdis.opcodes.opcode_rust import opcode_313rust # opcode_312rust, +from xdis.opcodes.opcode_rust import opcode_3531rust, opcode_12897rust, opcode_24481rust # from xdis.opcodes.opcode_graal import ( # opcode_310graal, @@ -78,7 +78,6 @@ # ) - __all__ = [ "opcode_10", "opcode_11", @@ -123,9 +122,8 @@ "opcode_39pypy", # "opcode_310graal", # "opcode_311graal", - # "opcode_312graal", - "opcode_38graal", # "opcode_312rust", - "opcode_313rust", - + "opcode_3531rust", + "opcode_12897rust", + "opcode_24481rust", ] diff --git a/xdis/opcodes/opcode_rust/base.py b/xdis/opcodes/opcode_rust/base.py new file mode 100644 index 00000000..2aa72aea --- /dev/null +++ b/xdis/opcodes/opcode_rust/base.py @@ -0,0 +1,374 @@ +# (C) Copyright 2025 by Rocky Bernstein +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +""" +Common routines for entering and classifying rust opcodes. Inspired by, +limited by, and somewhat compatible with the corresponding +Python opcode.py structures +""" + +from xdis.opcodes.base import ( + VARYING_STACK_INT, + binary_op, + call_op, + compare_op, + conditional_op, + const_op, + def_op, + free_op, + init_opdata, + jabs_op, + jrel_op, + local_op, + name_op, + nargs_op, + store_op, + ternary_op, + unary_op, + varargs_op, +) + +# RustPython compare operation enumerations are different from CPythons +# From bytecode.rs: +# be intentional with bits so that we can do eval_ord with just a bitwise and +# bits: | Equal | Greater | Less | + +cmp_op = ( + "==", # 0 + "<", # 1 + ">", # 2 + "!=", # 3 + "==", # 4 + ">", # 5 + "<=", # 5 + ">=", # 6 +) + +test_op = ( + "in", # 0 + "not-in", # 1 + "is", # 2 + "is-not", # 3 + "exception-match", # 4 +) + +def init_opdata_rust(loc, from_mod, version_tuple) -> None: + """Sets up a number of the structures found in Python's + opcode.py. Python opcode.py routines assign attributes to modules. + In order to do this in a modular way here, the local dictionary + for the module is passed. + """ + init_opdata(loc, from_mod, version_tuple, False) + loc["cmp_op"] = cmp_op + +def inc_opcode(loc): + loc["_opcode"] += 1 + +def binary_op_graal(loc: dict, name: str, pop: int = 2, push: int = 1) -> None: + """ + Put opcode in the class of instructions that are binary operations. + """ + binary_op(loc, name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def call_op_graal( + loc: dict, name: str, pop: int = -2, push: int = 1, fallthrough: bool=True +) -> None: + """ + Put opcode in the class of instructions that perform calls. + """ + call_op(loc, name, loc["_opcode"], pop, push, fallthrough) + inc_opcode(loc) + + +def compare_op_graal(loc: dict, name: str, pop: int = 2, push: int = 1) -> None: + compare_op(loc, name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def conditional_op_graal(loc: dict, name: str) -> None: + conditional_op(loc, name, loc["_opcode"]) + inc_opcode(loc) + + +def const_op_graal(loc: dict, name: str, pop: int = 0, push: int = 1) -> None: + const_op(loc, name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def def_op_graal( + loc: dict, + op_name: str, + pop: int = -2, + push: int = -2, + fallthrough: bool = True, +) -> None: + def_op(loc, op_name, loc["_opcode"], pop, push, fallthrough) + inc_opcode(loc) + + +def free_op_graal(loc: dict, op_name: str, pop: int = 0, push: int = 1) -> None: + free_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def jabs_op_graal( + loc: dict, + op_name: str, + pop: int = 0, + push: int = 0, + conditional: bool = False, + fallthrough: bool = True, +) -> None: + """ + Put opcode in the class of instructions that can perform an absolute jump. + """ + jabs_op(loc, op_name, loc["_opcode"], pop, push, conditional, fallthrough) + inc_opcode(loc) + + +def jrel_op_graal(loc, op_name: str, pop: int=0, push: int=0, conditional=False, fallthrough=True) -> None: + """ + Put opcode in the class of instructions that can perform a relative jump. + """ + jrel_op(loc, op_name, loc["_opcode"], pop, push, conditional, fallthrough) + inc_opcode(loc) + + +def local_op_graal(loc, op_name, pop=0, push=1) -> None: + local_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def name_op_graal(loc: dict, op_name, pop=-2, push=-2) -> None: + """ + Put opcode in the class of instructions that index into the "name" table. + """ + name_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def nargs_op_graal( + loc, op_name: str, pop: int = -2, push: int = -1, fallthrough=True +) -> None: + """ + Put opcode in the class of instructions that have a variable number of (or *n*) arguments + """ + nargs_op(loc, op_name, loc["_opcode"], pop, push, fallthrough) + inc_opcode(loc) + + +def store_op_graal(loc: dict, op_name: str, pop=0, push=1, is_type="def") -> None: + store_op(loc, op_name, loc["_opcode"], pop, push, is_type) + inc_opcode(loc) + + +def ternary_op_graal(loc: dict, op_name: str, pop: int = 3, push: int = 1) -> None: + """ + Put opcode in the class of instructions that are ternary operations. + """ + ternary_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def unary_op_graal(loc, op_name: str, pop: int=1, push: int=1) -> None: + unary_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + +def varargs_op_graal(loc, op_name, pop: int=-1, push: int=1) -> None: + varargs_op(loc, op_name, loc["_opcode"], pop, push) + inc_opcode(loc) + + + +# See RustPython/compiler/core/src/bytecode.rs Instruction +# fmt: off + +def make_opcodes(loc: dict, magic_int: int): + # OP NAME POP PUSH + #---------------------------------------------------------- + def_op_graal(loc, "NOP", 0, 0) + name_op_graal(loc, "IMPORT_NAME") + def_op_graal(loc, "IMPORT_NAMELESS", 0, 1) + name_op_graal(loc, "IMPORT_FROM") + + local_op_graal(loc, "LOAD_FAST") + name_op_graal(loc, "LOAD_NAME") + name_op_graal(loc, "LOAD_GLOBAL") + free_op_graal(loc, "LOAD_DEREF") + + def_op_graal(loc, "LOAD_CLASS_DEREF") + + store_op_graal(loc, "STORE_FAST", 1, 0, is_type="local") # Local variable + store_op_graal(loc, "STORE_LOCAL", 0) + name_op_graal(loc, "STORE_GLOBAL") # "" + store_op_graal(loc, "STORE_DEREF", 1, 0, is_type="free") + + local_op_graal(loc, "DELETE_FAST", 0, 0) # Local variable number is in operand + local_op_graal(loc, "DELETE_LOCAL", 0, 0) + name_op_graal(loc, "DELETE_GLOBAL") # "" + free_op_graal(loc, "DELETE_DEREF", 0, 0) + free_op_graal(loc, "LOAD_CLOSURE") + binary_op_graal(loc, "BINARY_SUBSCR") + + def_op_graal(loc, "STORE_SUBSCR", 0, 0) + def_op_graal(loc, "DELETE_SUBSCR", 0, 0) + name_op_graal(loc, "STORE_ATTR") # Index in name list + name_op_graal(loc, "DELETE_ATTR") # "" + + # Operand is in const list + const_op_graal(loc, "LOAD_CONST", 0, 1) + unary_op_graal(loc, "UNARY_OP", 1, 1) + binary_op_graal(loc, "BINARY_OP") + binary_op_graal(loc, "BINARY_OP_INPLACE") + if magic_int in (12897,): + name_op_graal(loc, "LOAD_ATTR") + compare_op_graal(loc, "TEST_OP", 2, 1) # test operator + if magic_int in (24881,): + def_op_graal(loc, "COPY") + binary_op_graal(loc, "BINARY_SUBCR") + compare_op_graal(loc, "COMPARE_OP", 2, 1) # Comparison operator + if magic_int in (24881,): + def_op_graal(loc, "SWAP", 1, 1) + def_op_graal(loc, "POP_TOP", 1, 0) + if magic_int in (24881,): + def_op_graal(loc, "TO_BOOL", 1, 1) + def_op_graal(loc, "Unknown1") + def_op_graal(loc, "ROT_TWO", 2, 2) + def_op_graal(loc, "ROT_THREE", 3, 3) + def_op_graal(loc, "DUP_TOP", 0, 1) + def_op_graal(loc, "Duplicate2") + def_op_graal(loc, "GET_ITER") + + if magic_int in (24881,): + def_op_graal(loc, "GetLen") + call_op_graal(loc, "CallIntrinsic1") + call_op_graal(loc, "CallIntrinsic2") + def_op_graal(loc, "CONTINUE_LOOP") + def_op_graal(loc, "BREAK_LOOP") + + # In contrast to CPython and others Rust does not seem to use relative jumps, + # but only absolute jumps. + jabs_op_graal(loc, "JUMP") # Number of words to skip + + jabs_op_graal(loc, "POP_JUMP_IF_TRUE") + jabs_op_graal(loc, "POP_JUMP_IF_FALSE") + jabs_op_graal(loc, "JUMP_IF_TRUE_OR_POP") # Number of words to skip + jabs_op_graal(loc, "JUMP_IF_FALSE_OR_POP") # " + + nargs_op_graal(loc, "MAKE_FUNCTION", VARYING_STACK_INT) # Flags + + if magic_int in (24881,): + def_op_graal(loc, "SET_FUNCTION_ATTR") + + call_op_graal(loc, "CALL_FUNCTION") + call_op_graal(loc, "CALL_FUNCTION_KW") + call_op_graal(loc, "CALL_FUNCTION_EX") # Flags + def_op_graal(loc, "LOAD_METHOD") + call_op_graal(loc, "CALL_METHOD") + call_op_graal(loc, "CALL_METHOD_KW") + call_op_graal(loc, "CALL_METHOD_EX") + + jabs_op_graal(loc, "FOR_ITER") + def_op_graal(loc, "RETURN_VALUE") + const_op_graal(loc, "RETURN_CONST") + def_op_graal(loc, "YIELD") + def_op_graal(loc, "YIELD_FROM") + if magic_int in (24881,): + def_op_graal(loc, "RESUME", 0, 0) + + def_op_graal(loc, "SETUP_ANNOTATIONS") + jabs_op_graal(loc, "SETUP_LOOP", 0, 0, conditional=True) + def_op_graal(loc, "SETUP_FINALLY", 0, 1) + + if magic_int in (12897,): + def_op_graal(loc, "EnterFinally") + def_op_graal(loc, "EndFinally") + + if magic_int in (24881,): + def_op_graal(loc, "GET_YIELD_FROM_ITER") + def_op_graal(loc, "SETUP_EXCEPT") + def_op_graal(loc, "SETUP_WITH") + def_op_graal(loc, "SETUP_CLEANUP") + def_op_graal(loc, "WithCleanupStart") + if magic_int in (24881,): + def_op_graal(loc, "WithCleanupFinish") + + def_op_graal(loc, "POP_BLOCK") + def_op_graal(loc, "RAISE") + + if magic_int in (24881,): + def_op_graal(loc, "LIST_TO_TUPLE") + + if magic_int in (12897,): + varargs_op_graal(loc, "BUILD_STRING", 1, VARYING_STACK_INT) # Number of tuple items + + varargs_op_graal(loc, "BUILD_TUPLE", 1, VARYING_STACK_INT) # Number of tuple items + + if magic_int in (12897,): + varargs_op_graal(loc, "BUILD_TUPLE_UNPACK", 1, VARYING_STACK_INT) # Number of tuple items + + if magic_int in (24881,): + varargs_op_graal(loc, "BUILD_TUPLE_FROM_TUPLES", 1, VARYING_STACK_INT) # Number of tuple items + varargs_op_graal(loc, "BUILD_TUPLE_FROM_ITER", 1, VARYING_STACK_INT) # Number of tuple items + varargs_op_graal(loc, "BUILD_LIST", VARYING_STACK_INT) # Number of list items + + if magic_int in (12897,): + varargs_op_graal(loc, "BUILD_LIST_UNPACK", 1, VARYING_STACK_INT) # Number of list items + if magic_int in (24881,): + varargs_op_graal(loc, "BUILD_LIST_FROM_TUPLES", 1, VARYING_STACK_INT) # Number of list items + varargs_op_graal(loc, "BUILD_SET", 1, VARYING_STACK_INT) # Number of set items + if magic_int in (12897,): + varargs_op_graal(loc, "BUILD_SET", 1, VARYING_STACK_INT) # Number of set items + if magic_int in (24881,): + varargs_op_graal(loc, "BUILD_SET_FROM_TUPLES", 1, VARYING_STACK_INT) # Number of list items + varargs_op_graal(loc, "BUILD_MAP", 1, VARYING_STACK_INT) # Number of dict entries + varargs_op_graal(loc, "BUILD_MAP_FOR_CALL", 1, VARYING_STACK_INT) # Number of dict entries + varargs_op_graal(loc, "DICT_UPDATE") # Number of dict entries + def_op_graal(loc, "BUILD_SLICE") + def_op_graal(loc, "LIST_APPEND") + def_op_graal(loc, "SET_ADD") + def_op_graal(loc, "MAP_ADD") + def_op_graal(loc, "PRINT_EXPR") + def_op_graal(loc, "LOAD_BUILD_CLASS") + varargs_op_graal(loc, "UNPACK_SEQUENCE", 1, VARYING_STACK_INT) # Number of tuple items + def_op_graal(loc, "UNPACK_EX", VARYING_STACK_INT, VARYING_STACK_INT) + def_op_graal(loc, "FORMAT_VALUE", VARYING_STACK_INT, VARYING_STACK_INT) + def_op_graal(loc, "POP_EXCEPT") + def_op_graal(loc, "REVERSE") + def_op_graal(loc, "GET_AWAITABLE") + + if magic_int in (12897,): + def_op_graal(loc, "BeforeAsyncWith") + def_op_graal(loc, "SetupAsyncWith") + def_op_graal(loc, "GET_AITER", 0, 1) + def_op_graal(loc, "GET_ANEXT") + def_op_graal(loc, "EndAsyncFor") + + if magic_int in (24881,): + def_op_graal(loc, "END_ASYNC_FOR") + def_op_graal(loc, "MATCH_MAPPING") + def_op_graal(loc, "MATCH_SEQUENCE") + def_op_graal(loc, "MATCH_CLASS") + + def_op_graal(loc, "EXTENDED_ARG") + + if magic_int in (12897,): + def_op_graal(loc, "TypeVar") + def_op_graal(loc, "TypeVarWithBound") + def_op_graal(loc, "TypeVarWithConstraint") + def_op_graal(loc, "TypeAlias") diff --git a/xdis/opcodes/opcode_rust/opcode_12897rust.py b/xdis/opcodes/opcode_rust/opcode_12897rust.py new file mode 100644 index 00000000..d80635a7 --- /dev/null +++ b/xdis/opcodes/opcode_rust/opcode_12897rust.py @@ -0,0 +1,147 @@ +# (C) Copyright 2025 by Rocky Bernstein +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +""" +RustPython 3.12.0 bytecode opcodes for version 0.40. There are other Rust 3.12 with different opcodes! +""" + +#FIXME: this needs a lot of going over. + +from typing import Dict, List, Optional, Tuple + +import xdis.opcodes.opcode_3x.opcode_311 as opcode_311 + +# import xdis.opcodes.opcode_313 as opcode_313 +from xdis.opcodes.base import finalize_opcodes, update_pj3 +from xdis.opcodes.format.extended import extended_format_binary_op +from xdis.opcodes.opcode_3x.opcode_313 import opcode_arg_fmt313, opcode_extended_fmt313 +from xdis.opcodes.opcode_rust.base import init_opdata_rust, make_opcodes +from xdis.version_info import PythonImplementation + +_opcode = 0 +version_tuple = (3, 12, 0) +python_implementation = PythonImplementation("RustPython") + +# oppush[op] => number of stack entries pushed +oppush: List[int] = [0] * 256 + +# oppop[op] => number of stack entries popped +oppop: List[int] = [0] * 256 + +# opmap[opcode_name] => opcode_number +opmap: Dict[str, int] = {} + +## pseudo opcodes (used in the compiler) mapped to the values +## they can become in the actual code. +_pseudo_ops = {} + +_nb_ops = [ + ("NB_ADD", "+"), + ("NB_AND", "&"), + ("NB_FLOOR_DIVIDE", "//"), + ("NB_LSHIFT", "<<"), + ("NB_MATRIX_MULTIPLY", "@"), + ("NB_MULTIPLY", "*"), + ("NB_REMAINDER", "%"), + ("NB_OR", "|"), + ("NB_POWER", "**"), + ("NB_RSHIFT", ">>"), + ("NB_SUBTRACT", "-"), + ("NB_TRUE_DIVIDE", "/"), + ("NB_XOR", "^"), + ("NB_INPLACE_ADD", "+="), + ("NB_INPLACE_AND", "&="), + ("NB_INPLACE_FLOOR_DIVIDE", "//="), + ("NB_INPLACE_LSHIFT", "<<="), + ("NB_INPLACE_MATRIX_MULTIPLY", "@="), + ("NB_INPLACE_MULTIPLY", "*="), + ("NB_INPLACE_REMAINDER", "%="), + ("NB_INPLACE_OR", "|="), + ("NB_INPLACE_POWER", "**="), + ("NB_INPLACE_RSHIFT", ">>="), + ("NB_INPLACE_SUBTRACT", "-="), + ("NB_INPLACE_TRUE_DIVIDE", "/="), + ("NB_INPLACE_XOR", "^="), +] + +hasexc = [] + +loc = locals() + +init_opdata_rust(loc, from_mod=None, version_tuple=version_tuple) + +loc["opname"].extend([f"<{i}>" for i in range(256, 267)]) +loc["oppop"].extend([0] * 11) +loc["oppush"].extend([0] * 11) + +hasarg = [] +hasconst = [] +hasname = [] +hasjrel = [] +hasjabs = [] +haslocal = [] +hascompare = [] +hasfree = [] +hasexc = [] + +oplists = [ + loc["hasarg"], + loc["hasconst"], + loc["hasname"], + loc["hasjrel"], + loc["hasjabs"], + loc["haslocal"], + loc["hascompare"], + loc["hasfree"], + loc["hasexc"], +] + +# add new table "hasjump" +loc.update({"hasjump": []}) +loc["hasjrel"] = loc["hasjump"] + +make_opcodes(loc, 12897) +EXTENDED_ARG = 103 + +# fmt: on + +# for i in range(105): +# print(f"%3d {loc['opname'][i]}" % i) + +findlinestarts = opcode_311.findlinestarts + +def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]: + opname = _nb_ops[instructions[0].argval][1] + if opname == "%": + opname = "%%" + elif opname == "%=": + opname = "%%=" + return extended_format_binary_op(opc, instructions, f"%s {opname} %s") + + +opcode_extended_fmt313rust = {} +opcode_arg_fmt = opcode_arg_fmt13rust = {} + +### update arg formatting +opcode_extended_fmt = opcode_extended_fmt312rust = { + **opcode_extended_fmt313, + **{ + "BINARY_OP": extended_format_BINARY_OP, + }, +} + + +update_pj3(globals(), loc, is_rust=True) +finalize_opcodes(loc) diff --git a/xdis/opcodes/opcode_rust/opcode_24481rust.py b/xdis/opcodes/opcode_rust/opcode_24481rust.py new file mode 100644 index 00000000..6d38657b --- /dev/null +++ b/xdis/opcodes/opcode_rust/opcode_24481rust.py @@ -0,0 +1,318 @@ +# (C) Copyright 2025 by Rocky Bernstein +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +""" +RustPython 3.13 bytecode opcodes for version 0.40. There are other Rust 3.13 with different opcodes! +""" + +#FIXME: this needs a lot of going over. + +from typing import Dict, List, Optional, Tuple + +import xdis.opcodes.opcode_3x.opcode_311 as opcode_311 + +# import xdis.opcodes.opcode_313 as opcode_313 +from xdis.opcodes.base import finalize_opcodes, update_pj3 +from xdis.opcodes.format.extended import extended_format_binary_op +from xdis.opcodes.opcode_3x.opcode_313 import opcode_arg_fmt313, opcode_extended_fmt313 +from xdis.opcodes.opcode_rust.base import init_opdata_rust, make_opcodes +from xdis.version_info import PythonImplementation + +_opcode = 0 +version_tuple = (3, 13) +python_implementation = PythonImplementation("RustPython") + +# oppush[op] => number of stack entries pushed +oppush: List[int] = [0] * 256 + +# oppop[op] => number of stack entries popped +oppop: List[int] = [0] * 256 + +# opmap[opcode_name] => opcode_number +opmap: Dict[str, int] = {} + +## pseudo opcodes (used in the compiler) mapped to the values +## they can become in the actual code. +_pseudo_ops = {} + +_nb_ops = [ + ("NB_ADD", "+"), + ("NB_AND", "&"), + ("NB_FLOOR_DIVIDE", "//"), + ("NB_LSHIFT", "<<"), + ("NB_MATRIX_MULTIPLY", "@"), + ("NB_MULTIPLY", "*"), + ("NB_REMAINDER", "%"), + ("NB_OR", "|"), + ("NB_POWER", "**"), + ("NB_RSHIFT", ">>"), + ("NB_SUBTRACT", "-"), + ("NB_TRUE_DIVIDE", "/"), + ("NB_XOR", "^"), + ("NB_INPLACE_ADD", "+="), + ("NB_INPLACE_AND", "&="), + ("NB_INPLACE_FLOOR_DIVIDE", "//="), + ("NB_INPLACE_LSHIFT", "<<="), + ("NB_INPLACE_MATRIX_MULTIPLY", "@="), + ("NB_INPLACE_MULTIPLY", "*="), + ("NB_INPLACE_REMAINDER", "%="), + ("NB_INPLACE_OR", "|="), + ("NB_INPLACE_POWER", "**="), + ("NB_INPLACE_RSHIFT", ">>="), + ("NB_INPLACE_SUBTRACT", "-="), + ("NB_INPLACE_TRUE_DIVIDE", "/="), + ("NB_INPLACE_XOR", "^="), +] + +hasexc = [] + +loc = locals() + +init_opdata_rust(loc, from_mod=None, version_tuple=version_tuple) + +loc["opname"].extend([f"<{i}>" for i in range(256, 267)]) +loc["oppop"].extend([0] * 11) +loc["oppush"].extend([0] * 11) + +hasarg = [] +hasconst = [] +hasname = [] +hasjrel = [] +hasjabs = [] +haslocal = [] +hascompare = [] +hasfree = [] +hasexc = [] + +oplists = [ + loc["hasarg"], + loc["hasconst"], + loc["hasname"], + loc["hasjrel"], + loc["hasjabs"], + loc["haslocal"], + loc["hascompare"], + loc["hasfree"], + loc["hasexc"], +] + +# add new table "hasjump" +loc.update({"hasjump": []}) +loc["hasjrel"] = loc["hasjump"] + +make_opcodes(loc, 24881) +EXTENDED_ARG = 103 + +# fmt: on + +# for i in range(105): +# print(f"%3d {loc['opname'][i]}" % i) + +_specializations = { + "BINARY_OP": [ + "BINARY_OP_ADAPTIVE", + "BINARY_OP_ADD_FLOAT", + "BINARY_OP_ADD_INT", + "BINARY_OP_ADD_UNICODE", + "BINARY_OP_INPLACE_ADD_UNICODE", + "BINARY_OP_MULTIPLY_FLOAT", + "BINARY_OP_MULTIPLY_INT", + "BINARY_OP_SUBTRACT_FLOAT", + "BINARY_OP_SUBTRACT_INT", + ], + "BINARY_SUBSCR": [ + "BINARY_SUBSCR_ADAPTIVE", + "BINARY_SUBSCR_DICT", + "BINARY_SUBSCR_GETITEM", + "BINARY_SUBSCR_LIST_INT", + "BINARY_SUBSCR_TUPLE_INT", + ], + "CALL": [ + "CALL_ADAPTIVE", + "CALL_PY_EXACT_ARGS", + "CALL_PY_WITH_DEFAULTS", + "CALL_BOUND_METHOD_EXACT_ARGS", + "CALL_BUILTIN_CLASS", + "CALL_BUILTIN_FAST_WITH_KEYWORDS", + "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + "CALL_NO_KW_BUILTIN_FAST", + "CALL_NO_KW_BUILTIN_O", + "CALL_NO_KW_ISINSTANCE", + "CALL_NO_KW_LEN", + "CALL_NO_KW_LIST_APPEND", + "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + "CALL_NO_KW_METHOD_DESCRIPTOR_O", + "CALL_NO_KW_STR_1", + "CALL_NO_KW_TUPLE_1", + "CALL_NO_KW_TYPE_1", + ], + "COMPARE_OP": [ + "COMPARE_OP_ADAPTIVE", + "COMPARE_OP_FLOAT_JUMP", + "COMPARE_OP_INT_JUMP", + "COMPARE_OP_STR_JUMP", + ], + "EXTENDED_ARG": [ + "EXTENDED_ARG_QUICK", + ], + "FOR_ITER": [ + "FOR_ITER_ADAPTIVE", + "FOR_ITER_LIST", + "FOR_ITER_RANGE", + ], + "JUMP_BACKWARD": [ + "JUMP_BACKWARD_QUICK", + ], + "LOAD_ATTR": [ + "LOAD_ATTR_ADAPTIVE", + # These potentially push [NULL, bound method] onto the stack. + "LOAD_ATTR_CLASS", + "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + "LOAD_ATTR_INSTANCE_VALUE", + "LOAD_ATTR_MODULE", + "LOAD_ATTR_PROPERTY", + "LOAD_ATTR_SLOT", + "LOAD_ATTR_WITH_HINT", + # These will always push [unbound method, self] onto the stack. + "LOAD_ATTR_METHOD_LAZY_DICT", + "LOAD_ATTR_METHOD_NO_DICT", + "LOAD_ATTR_METHOD_WITH_DICT", + "LOAD_ATTR_METHOD_WITH_VALUES", + ], + "LOAD_CONST": [ + "LOAD_CONST__LOAD_FAST", + ], + "LOAD_FAST": [ + "LOAD_FAST__LOAD_CONST", + "LOAD_FAST__LOAD_FAST", + ], + "LOAD_GLOBAL": [ + "LOAD_GLOBAL_ADAPTIVE", + "LOAD_GLOBAL_BUILTIN", + "LOAD_GLOBAL_MODULE", + ], + "RESUME": [ + "RESUME_QUICK", + ], + "STORE_ATTR": [ + "STORE_ATTR_ADAPTIVE", + "STORE_ATTR_INSTANCE_VALUE", + "STORE_ATTR_SLOT", + "STORE_ATTR_WITH_HINT", + ], + "STORE_FAST": [ + "STORE_FAST__LOAD_FAST", + "STORE_FAST__STORE_FAST", + ], + "STORE_SUBSCR": [ + "STORE_SUBSCR_ADAPTIVE", + "STORE_SUBSCR_DICT", + "STORE_SUBSCR_LIST_INT", + ], + "UNPACK_SEQUENCE": [ + "UNPACK_SEQUENCE_ADAPTIVE", + "UNPACK_SEQUENCE_LIST", + "UNPACK_SEQUENCE_TUPLE", + "UNPACK_SEQUENCE_TWO_TUPLE", + ], +} +_specialized_instructions = [ + opcode for family in _specializations.values() for opcode in family +] +_specialization_stats = [ + "success", + "failure", + "hit", + "deferred", + "miss", + "deopt", +] + +_cache_format = { + "LOAD_GLOBAL": { + "counter": 1, + "index": 1, + "module_keys_version": 2, + "builtin_keys_version": 1, + }, + "BINARY_OP": { + "counter": 1, + }, + "UNPACK_SEQUENCE": { + "counter": 1, + }, + "COMPARE_OP": { + "counter": 1, + "mask": 1, + }, + "BINARY_SUBSCR": { + "counter": 1, + "type_version": 2, + "func_version": 1, + }, + "FOR_ITER": { + "counter": 1, + }, + "LOAD_ATTR": { + "counter": 1, + "version": 2, + "keys_version": 2, + "descr": 4, + }, + "STORE_ATTR": { + "counter": 1, + "version": 2, + "index": 1, + }, + "CALL": { + "counter": 1, + "func_version": 2, + "min_args": 1, + }, + "STORE_SUBSCR": { + "counter": 1, + }, +} + +_inline_cache_entries = [ + sum(_cache_format.get(opname[opcode], {}).values()) for opcode in range(256) +] + +findlinestarts = opcode_311.findlinestarts + +def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]: + opname = _nb_ops[instructions[0].argval][1] + if opname == "%": + opname = "%%" + elif opname == "%=": + opname = "%%=" + return extended_format_binary_op(opc, instructions, f"%s {opname} %s") + + +opcode_extended_fmt313rust = {} +opcode_arg_fmt = opcode_arg_fmt13rust = {} + +### update arg formatting +opcode_extended_fmt = opcode_extended_fmt312rust = { + **opcode_extended_fmt313, + **{ + "BINARY_OP": extended_format_BINARY_OP, + }, +} + + +update_pj3(globals(), loc, is_rust=True) +finalize_opcodes(loc) diff --git a/xdis/opcodes/opcode_rust/opcode_312rust.py b/xdis/opcodes/opcode_rust/opcode_312rust.py deleted file mode 100644 index 7ec564bf..00000000 --- a/xdis/opcodes/opcode_rust/opcode_312rust.py +++ /dev/null @@ -1,515 +0,0 @@ -# (C) Copyright 2019-2023, 2025 by Rocky Bernstein -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -""" -RustPython 3.12 bytecode opcodes. -""" - -#FIXME: this needs a lot of going over. - -from typing import Dict, List, Optional, Tuple - -from xdis.opcodes.base import ( - VARYING_STACK_INT, - binary_op, - call_op, - compare_op, - const_op, - def_op, - finalize_opcodes, - free_op, - init_opdata, - jrel_op, - local_op, - name_op, - nargs_op, - store_op, - unary_op, - update_pj3, - varargs_op, -) -from xdis.opcodes.format.extended import extended_format_binary_op -from xdis.opcodes.opcode_3x.opcode_312 import opcode_arg_fmt312, opcode_extended_fmt312 -from xdis.version_info import PythonImplementation - -version_tuple = (3, 12) -python_implementation = PythonImplementation("RustPython") - -# oppush[op] => number of stack entries pushed -oppush: List[int] = [0] * 256 - -# oppop[op] => number of stack entries popped -oppop: List[int] = [0] * 256 - -# opmap[opcode_name] => opcode_number -opmap: Dict[str, int] = {} - -## pseudo opcodes (used in the compiler) mapped to the values -## they can become in the actual code. -_pseudo_ops = {} - -_nb_ops = [ - ("NB_ADD", "+"), - ("NB_AND", "&"), - ("NB_FLOOR_DIVIDE", "//"), - ("NB_LSHIFT", "<<"), - ("NB_MATRIX_MULTIPLY", "@"), - ("NB_MULTIPLY", "*"), - ("NB_REMAINDER", "%"), - ("NB_OR", "|"), - ("NB_POWER", "**"), - ("NB_RSHIFT", ">>"), - ("NB_SUBTRACT", "-"), - ("NB_TRUE_DIVIDE", "/"), - ("NB_XOR", "^"), - ("NB_INPLACE_ADD", "+="), - ("NB_INPLACE_AND", "&="), - ("NB_INPLACE_FLOOR_DIVIDE", "//="), - ("NB_INPLACE_LSHIFT", "<<="), - ("NB_INPLACE_MATRIX_MULTIPLY", "@="), - ("NB_INPLACE_MULTIPLY", "*="), - ("NB_INPLACE_REMAINDER", "%="), - ("NB_INPLACE_OR", "|="), - ("NB_INPLACE_POWER", "**="), - ("NB_INPLACE_RSHIFT", ">>="), - ("NB_INPLACE_SUBTRACT", "-="), - ("NB_INPLACE_TRUE_DIVIDE", "/="), - ("NB_INPLACE_XOR", "^="), -] - -hasexc = [] - -loc = locals() - -init_opdata(loc, None, version_tuple) - -hasarg = [] -hasconst = [] -hasname = [] -hasjrel = [] -hasjabs = [] -haslocal = [] -hascompare = [] -hasfree = [] -hasexc = [] - -oplists = [ - loc["hasarg"], - loc["hasconst"], - loc["hasname"], - loc["hasjrel"], - loc["hasjabs"], - loc["haslocal"], - loc["hascompare"], - loc["hasfree"], - loc["hasexc"], -] - - -def pseudo_op(name: str, op: int, real_ops: list): - def_op(loc, name, op) - _pseudo_ops[name] = real_ops - # add the pseudo opcode to the lists its targets are in - for oplist in oplists: - res = [opmap[rop] in oplist for rop in real_ops] - if any(res): - # FIXME: for some reason JUMP_FORWARD appears to be - # listed as a free op. It isn't. - # if not all(res): - # breakpoint() - # assert all(res) - oplist.append(op) - - -# See RustPython/compiler/core/src/bytecode.rs Instruction -# fmt: off - -# OP NAME OPCODE POP PUSH -#---------------------------------------------------------- -def_op(loc, "CACHE", 0, 0, 0) -def_op(loc, "POP_TOP", 1, 1, 0) -def_op(loc, "PUSH_NULL", 2, 0 , 1) - -def_op(loc, "NOP", 9, 0, 0) -unary_op(loc, "UNARY_POSITIVE", 10) -unary_op(loc, "UNARY_NEGATIVE", 11) -unary_op(loc, "UNARY_NOT", 12) - -unary_op(loc, "UNARY_INVERT", 15) - -binary_op(loc, "BINARY_SUBSCR", 25) -binary_op(loc, "BINARY_SLICE", 26) -store_op(loc, "STORE_SLICE", 27, 4, 0) - -def_op(loc, "GET_LEN", 30, 0, 1) -def_op(loc, "MATCH_MAPPING", 31, 0, 1) -def_op(loc, "MATCH_SEQUENCE", 32, 0, 1) -def_op(loc, "MATCH_KEYS", 33, 0, 2) - -jrel_op(loc, "PUSH_EXC_INFO", 35, 0, 1) -def_op(loc, "CHECK_EXC_MATCH", 36) -jrel_op(loc, "CHECK_EG_MATCH", 37, 0, 0) - -# FIXME: fill in -def_op(loc, "WITH_EXCEPT_START", 49) -def_op(loc, "GET_AITER", 50) -def_op(loc, "GET_ANEXT", 51) -def_op(loc, "BEFORE_ASYNC_WITH", 52) -def_op(loc, "BEFORE_WITH", 53) -def_op(loc, "END_ASYNC_FOR", 54) -def_op(loc, "CLEANUP_THROW", 55) - -def_op(loc, "STORE_SUBSCR", 60) -def_op(loc, "DELETE_SUBSCR", 61) - -# TODO: RUSTPYTHON -# Delete below def_op after updating coroutines.py -def_op(loc, "YIELD_FROM", 72) - -def_op(loc, "GET_ITER", 68) -def_op(loc, "GET_YIELD_FROM_ITER", 69) -def_op(loc, "PRINT_EXPR", 70) -def_op(loc, "LOAD_BUILD_CLASS", 71) - -def_op(loc, "LOAD_ASSERTION_ERROR", 74) -def_op(loc, "RETURN_GENERATOR", 75) - -def_op(loc, "LIST_TO_TUPLE", 82) -def_op(loc, "RETURN_VALUE", 83) -def_op(loc, "IMPORT_STAR", 84) -def_op(loc, "SETUP_ANNOTATIONS", 85) - -def_op(loc, "ASYNC_GEN_WRAP", 87) -def_op(loc, "PREP_RERAISE_STAR", 88) -def_op(loc, "POP_EXCEPT", 89) - -HAVE_ARGUMENT = 90 # real opcodes from here have an argument: - -name_op(loc, "STORE_NAME", 90) # Index in name list -name_op(loc, "DELETE_NAME", 91) # "" -varargs_op(loc, "UNPACK_SEQUENCE", 92, 1, VARYING_STACK_INT) # Number of tuple items -jrel_op(loc, "FOR_ITER", 93) -def_op(loc, "UNPACK_EX", 94, VARYING_STACK_INT, VARYING_STACK_INT) -name_op(loc, "STORE_ATTR", 95) # Index in name list -name_op(loc, "DELETE_ATTR", 96) # "" -name_op(loc, "STORE_GLOBAL", 97) # "" -name_op(loc, "DELETE_GLOBAL", 98) # "" - -def_op(loc, "SWAP", 99, 0, 0) - -# Operand is in const list -const_op(loc, "LOAD_CONST", 100, 0, 1) - -name_op(loc, "LOAD_NAME", 101) # Index in name list -def_op(loc, "BUILD_TUPLE", 102) # Number of tuple items -def_op(loc, "BUILD_LIST", 103) # Number of list items -def_op(loc, "BUILD_SET", 104) # Number of set items -def_op(loc, "BUILD_MAP", 105) # Number of dict entries -name_op(loc, "LOAD_ATTR", 106) # Index in name list -compare_op(loc, "COMPARE_OP", 107, 2, 1) # Comparison operator -name_op(loc, "IMPORT_NAME", 108) # Index in name list -name_op(loc, "IMPORT_FROM", 109) # Index in name list -jrel_op(loc, "JUMP_FORWARD", 110) # Number of words to skip -jrel_op(loc, "JUMP_IF_FALSE_OR_POP", 111) # Number of words to skip -jrel_op(loc, "JUMP_IF_TRUE_OR_POP", 112) # "" -jrel_op(loc, "POP_JUMP_IF_FALSE", 114) -jrel_op(loc, "POP_JUMP_IF_TRUE", 115) -name_op(loc, "LOAD_GLOBAL", 116) # Index in name list -def_op(loc, "IS_OP", 117) -def_op(loc, "CONTAINS_OP", 118) -def_op(loc, "RERAISE", 119, 3, 0) -def_op(loc, "COPY", 120) -def_op(loc, "BINARY_OP", 122) -jrel_op(loc, "SEND", 123) # Number of bytes to skip -local_op(loc, "LOAD_FAST", 124, 0, 1) # Local variable number -loc["nullaryloadop"].add(124) -store_op(loc, "STORE_FAST", 125, 1, 0, is_type="local") # Local variable -local_op(loc, "DELETE_FAST", 126, 0, 0) # Local variable number is in operand -def_op(loc , "LOAD_FAST_CHECK" , 127, 0, 1) -local_op(loc, "LOAD_FAST_CHECK", 127) # Local variable number -jrel_op(loc, "POP_JUMP_IF_NOT_NONE", 128) -jrel_op(loc, "POP_JUMP_IF_NONE", 129) -def_op(loc, "RAISE_VARARGS", 130) # Number of raise arguments (1, 2, or 3) -def_op(loc, "GET_AWAITABLE", 131) -nargs_op(loc, "MAKE_FUNCTION", 132, VARYING_STACK_INT, 1) # Flags -def_op(loc, "BUILD_SLICE", 133) # Number of items -jrel_op(loc, "JUMP_BACKWARD_NO_INTERRUPT", 134) # Number of words to skip (backwards) -free_op(loc, "MAKE_CELL", 135, 0, 0) -free_op(loc, "LOAD_CLOSURE", 136) -free_op(loc, "LOAD_DEREF", 137, 0, 1) -loc["nullaryop"].add(137) -loc["nullaryloadop"].add(137) -store_op(loc, "STORE_DEREF", 138, 1, 0, is_type="free") -free_op(loc, "DELETE_DEREF", 139, 0, 0) -jrel_op(loc, "JUMP_BACKWARD", 140) # Number of words to skip (backwards) - -call_op(loc, "CALL_FUNCTION_EX", 142) # Flags - -def_op(loc, "EXTENDED_ARG", 144) -EXTENDED_ARG = 144 -def_op(loc, "LIST_APPEND", 145) -def_op(loc, "SET_ADD", 146) -def_op(loc, "MAP_ADD", 147) -free_op(loc, "LOAD_CLASSDEREF", 148) -def_op(loc, "COPY_FREE_VARS", 149) -def_op(loc, "YIELD_VALUE", 150) - -# This must be kept in sync with deepfreeze.py -# resume, acts like a nop -def_op(loc, "RESUME", 151, 0, 0) - -def_op(loc, "MATCH_CLASS", 152) - -def_op(loc, "FORMAT_VALUE", 155) -def_op(loc, "BUILD_CONST_KEY_MAP", 156) -def_op(loc, "BUILD_STRING", 157) - -def_op(loc, "LIST_EXTEND", 162) -def_op(loc, "SET_UPDATE", 163) -def_op(loc, "DICT_MERGE", 164) -def_op(loc, "DICT_UPDATE", 165) - -def_op(loc, "CALL", 171) -const_op(loc, "KW_NAMES", 172) - - -loc["hasarg"].extend([op for op in opmap.values() if op >= HAVE_ARGUMENT]) - -MIN_PSEUDO_OPCODE = 256 - -pseudo_op("SETUP_FINALLY", 256, ["NOP"]) -hasexc.append(256) -pseudo_op("SETUP_CLEANUP", 257, ["NOP"]) -hasexc.append(257) -pseudo_op("SETUP_WITH", 258, ["NOP"]) -hasexc.append(258) -pseudo_op("POP_BLOCK", 259, ["NOP"]) - -pseudo_op("JUMP", 260, ["JUMP_FORWARD", "JUMP_BACKWARD"]) -pseudo_op("JUMP_NO_INTERRUPT", 261, ["JUMP_FORWARD", "JUMP_BACKWARD_NO_INTERRUPT"]) - -pseudo_op("LOAD_METHOD", 262, ["LOAD_ATTR"]) - -# fmt: on - -MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1 - -# extend opcodes to cover pseudo ops - -opname = [f"<{op!r}>" for op in range(MAX_PSEUDO_OPCODE + 1)] -opname.extend([f"<{i}>" for i in range(256, 267)]) -oppop.extend([0] * 11) -oppush.extend([0] * 11) - -for op, i in opmap.items(): - opname[i] = op - - -_specializations = { - "BINARY_OP": [ - "BINARY_OP_ADAPTIVE", - "BINARY_OP_ADD_FLOAT", - "BINARY_OP_ADD_INT", - "BINARY_OP_ADD_UNICODE", - "BINARY_OP_INPLACE_ADD_UNICODE", - "BINARY_OP_MULTIPLY_FLOAT", - "BINARY_OP_MULTIPLY_INT", - "BINARY_OP_SUBTRACT_FLOAT", - "BINARY_OP_SUBTRACT_INT", - ], - "BINARY_SUBSCR": [ - "BINARY_SUBSCR_ADAPTIVE", - "BINARY_SUBSCR_DICT", - "BINARY_SUBSCR_GETITEM", - "BINARY_SUBSCR_LIST_INT", - "BINARY_SUBSCR_TUPLE_INT", - ], - "CALL": [ - "CALL_ADAPTIVE", - "CALL_PY_EXACT_ARGS", - "CALL_PY_WITH_DEFAULTS", - "CALL_BOUND_METHOD_EXACT_ARGS", - "CALL_BUILTIN_CLASS", - "CALL_BUILTIN_FAST_WITH_KEYWORDS", - "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", - "CALL_NO_KW_BUILTIN_FAST", - "CALL_NO_KW_BUILTIN_O", - "CALL_NO_KW_ISINSTANCE", - "CALL_NO_KW_LEN", - "CALL_NO_KW_LIST_APPEND", - "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", - "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - "CALL_NO_KW_METHOD_DESCRIPTOR_O", - "CALL_NO_KW_STR_1", - "CALL_NO_KW_TUPLE_1", - "CALL_NO_KW_TYPE_1", - ], - "COMPARE_OP": [ - "COMPARE_OP_ADAPTIVE", - "COMPARE_OP_FLOAT_JUMP", - "COMPARE_OP_INT_JUMP", - "COMPARE_OP_STR_JUMP", - ], - "EXTENDED_ARG": [ - "EXTENDED_ARG_QUICK", - ], - "FOR_ITER": [ - "FOR_ITER_ADAPTIVE", - "FOR_ITER_LIST", - "FOR_ITER_RANGE", - ], - "JUMP_BACKWARD": [ - "JUMP_BACKWARD_QUICK", - ], - "LOAD_ATTR": [ - "LOAD_ATTR_ADAPTIVE", - # These potentially push [NULL, bound method] onto the stack. - "LOAD_ATTR_CLASS", - "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - "LOAD_ATTR_INSTANCE_VALUE", - "LOAD_ATTR_MODULE", - "LOAD_ATTR_PROPERTY", - "LOAD_ATTR_SLOT", - "LOAD_ATTR_WITH_HINT", - # These will always push [unbound method, self] onto the stack. - "LOAD_ATTR_METHOD_LAZY_DICT", - "LOAD_ATTR_METHOD_NO_DICT", - "LOAD_ATTR_METHOD_WITH_DICT", - "LOAD_ATTR_METHOD_WITH_VALUES", - ], - "LOAD_CONST": [ - "LOAD_CONST__LOAD_FAST", - ], - "LOAD_FAST": [ - "LOAD_FAST__LOAD_CONST", - "LOAD_FAST__LOAD_FAST", - ], - "LOAD_GLOBAL": [ - "LOAD_GLOBAL_ADAPTIVE", - "LOAD_GLOBAL_BUILTIN", - "LOAD_GLOBAL_MODULE", - ], - "RESUME": [ - "RESUME_QUICK", - ], - "STORE_ATTR": [ - "STORE_ATTR_ADAPTIVE", - "STORE_ATTR_INSTANCE_VALUE", - "STORE_ATTR_SLOT", - "STORE_ATTR_WITH_HINT", - ], - "STORE_FAST": [ - "STORE_FAST__LOAD_FAST", - "STORE_FAST__STORE_FAST", - ], - "STORE_SUBSCR": [ - "STORE_SUBSCR_ADAPTIVE", - "STORE_SUBSCR_DICT", - "STORE_SUBSCR_LIST_INT", - ], - "UNPACK_SEQUENCE": [ - "UNPACK_SEQUENCE_ADAPTIVE", - "UNPACK_SEQUENCE_LIST", - "UNPACK_SEQUENCE_TUPLE", - "UNPACK_SEQUENCE_TWO_TUPLE", - ], -} -_specialized_instructions = [ - opcode for family in _specializations.values() for opcode in family -] -_specialization_stats = [ - "success", - "failure", - "hit", - "deferred", - "miss", - "deopt", -] - -_cache_format = { - "LOAD_GLOBAL": { - "counter": 1, - "index": 1, - "module_keys_version": 2, - "builtin_keys_version": 1, - }, - "BINARY_OP": { - "counter": 1, - }, - "UNPACK_SEQUENCE": { - "counter": 1, - }, - "COMPARE_OP": { - "counter": 1, - "mask": 1, - }, - "BINARY_SUBSCR": { - "counter": 1, - "type_version": 2, - "func_version": 1, - }, - "FOR_ITER": { - "counter": 1, - }, - "LOAD_ATTR": { - "counter": 1, - "version": 2, - "keys_version": 2, - "descr": 4, - }, - "STORE_ATTR": { - "counter": 1, - "version": 2, - "index": 1, - }, - "CALL": { - "counter": 1, - "func_version": 2, - "min_args": 1, - }, - "STORE_SUBSCR": { - "counter": 1, - }, -} - -_inline_cache_entries = [ - sum(_cache_format.get(opname[opcode], {}).values()) for opcode in range(256) -] - - -def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]: - opname = _nb_ops[instructions[0].argval][1] - if opname == "%": - opname = "%%" - elif opname == "%=": - opname = "%%=" - return extended_format_binary_op(opc, instructions, f"%s {opname} %s") - - -pcode_extended_fmt312rust = opcode_extended_fmt312.copy() -opcode_arg_fmt = opcode_arg_fmt12rust = opcode_arg_fmt312.copy() - -### update arg formatting -opcode_extended_fmt = opcode_extended_fmt312rust = { - **opcode_extended_fmt312, - **{ - "BINARY_OP": extended_format_BINARY_OP, - }, -} - -from xdis.opcodes.opcode_311 import findlinestarts - -update_pj3(globals(), loc) -finalize_opcodes(loc) diff --git a/xdis/opcodes/opcode_rust/opcode_313rust.py b/xdis/opcodes/opcode_rust/opcode_3531rust.py similarity index 58% rename from xdis/opcodes/opcode_rust/opcode_313rust.py rename to xdis/opcodes/opcode_rust/opcode_3531rust.py index 4ac7e332..2806ef32 100644 --- a/xdis/opcodes/opcode_rust/opcode_313rust.py +++ b/xdis/opcodes/opcode_rust/opcode_3531rust.py @@ -34,6 +34,7 @@ finalize_opcodes, free_op, init_opdata, + jabs_op, jrel_op, local_op, name_op, @@ -45,10 +46,11 @@ ) from xdis.opcodes.format.extended import extended_format_binary_op from xdis.opcodes.opcode_3x.opcode_313 import opcode_arg_fmt313, opcode_extended_fmt313 +from xdis.opcodes.opcode_rust.base import cmp_op as cmp_op_rust from xdis.version_info import PythonImplementation -version_tuple = (3, 13) python_implementation = PythonImplementation("RustPython") +version_tuple = (3, 13) # oppush[op] => number of stack entries pushed oppush: List[int] = [0] * 256 @@ -97,6 +99,8 @@ loc = locals() init_opdata(loc, from_mod=None, version_tuple=version_tuple) +# Change cmp_op set in init_opdata to be Rust's version of this. +cmp_op = cmp_op_rust loc["opname"].extend([f"<{i}>" for i in range(256, 267)]) loc["oppop"].extend([0] * 11) @@ -148,129 +152,133 @@ def pseudo_op(name: str, op: int, real_ops: list): # OP NAME OPCODE POP PUSH #---------------------------------------------------------- -def_op(loc, "NOP", 0, 0, 0) -name_op(loc, "IMPORT_NAME", 1) -def_op(loc, "IMPORT_NAMELESS", 2, 0, 1) -name_op(loc, "IMPORT_FROM", 3) - -local_op(loc, "LOAD_FAST", 4) -name_op(loc, "LOAD_NAME", 5) -name_op(loc, "LOAD_GLOBAL", 6) -free_op(loc, "LOAD_DEREF", 7) -loc["nullaryop"].add(7) -loc["nullaryloadop"].add(7) - -def_op(loc, "LOAD_CLASS_DEREF", 8) - -store_op(loc, "STORE_FAST", 9, 1, 0, is_type="local") # Local variable -store_op(loc, "STORE_LOCAL", 10, 4, 0) -name_op(loc, "STORE_GLOBAL", 11) # "" -store_op(loc, "STORE_DEREF", 12, 1, 0, is_type="free") - -local_op(loc, "DELETE_FAST", 13, 0, 0) # Local variable number is in operand -local_op(loc, "DELETE_LOCAL", 14, 0, 0) -name_op(loc, "DELETE_GLOBAL", 15) # "" -free_op(loc, "DELETE_DEREF", 16, 0, 0) - -free_op(loc, "LOAD_CLOSURE", 17) -binary_op(loc, "BINARY_SUBSCR", 18) - -def_op(loc, "STORE_SUBSCR", 19, 0, 0) -def_op(loc, "DELETE_SUBSCR", 20, 0, 0) -name_op(loc, "STORE_ATTR", 21) # Index in name list -name_op(loc, "DELETE_ATTR", 22) # "" - -# Operand is in const list -const_op(loc, "LOAD_CONST", 23, 0, 1) -unary_op(loc, "UNARY_OP", 24, 1, 1) -binary_op(loc, "BINARY_OP", 25, 1, 1) -binary_op(loc, "BINARY_OP_INPLACE", 26, 1, 1) -binary_op(loc, "BINARY_SUBCR", 27, 1, 1) -name_op(loc, "LOAD_ATTR", 28) # Index in name list -compare_op(loc, "TEST_OP", 29, 2, 1) # test operator -compare_op(loc, "COMPARE_OP", 30, 2, 1) # Comparison operator -def_op(loc, "SWAP", 31, 1, 1) -def_op(loc, "TO_BOOL", 132, 1, 1) -def_op(loc, "POP_TOP", 32, 1, 0) -def_op(loc, "ROT_TWO", 35, 2, 2) -def_op(loc, "ROT_THREE", 36, 3, 3) -def_op(loc, "DUP_TOP", 37, 0, 1) -def_op(loc, "GET_ITER", 39) - -jrel_op(loc, "JUMP", 45) # Number of words to skip -jrel_op(loc, "POP_JUMP_IF_TRUE", 46) -jrel_op(loc, "POP_JUMP_IF_FALSE", 47) -jrel_op(loc, "JUMP_IF_TRUE_OR_POP", 48) # Number of words to skip -jrel_op(loc, "JUMP_IF_FALSE_OR_POP", 49) # " - -nargs_op(loc, "MAKE_FUNCTION", 50, VARYING_STACK_INT) # Flags -def_op(loc, "SET_FUNCTION_ATTR", 51) - -call_op(loc, "CALL_FUNCTION", 52) -call_op(loc, "CALL_FUNCTION_KW", 53) -call_op(loc, "CALL_FUNCTION_EX", 54) # Flags -def_op(loc, "LOAD_METHOD", 55) -call_op(loc, "CALL_METHOD", 56) -call_op(loc, "CALL_METHOD_KW", 57) -call_op(loc, "CALL_METHOD_EX", 58) - -jrel_op(loc, "FOR_ITER", 59) -def_op(loc, "RETURN_VALUE", 60) -const_op(loc, "RETURN_CONST", 61) -def_op(loc, "YIELD", 62) -def_op(loc, "YIELD_FROM", 63) -def_op(loc, "RESUME", 64, 0, 0) - -def_op(loc, "SETUP_ANNOTATIONS", 65) -jrel_op(loc, "SETUP_LOOP", 66, 0, 0, conditional=True) -def_op(loc, "SETUP_FINALLY", 67, 0, 1) - -jrel_op(loc, "PUSH_EXC_INFO", 235, 0, 1) -def_op(loc, "CHECK_EXC_MATCH", 236) -jrel_op(loc, "CHECK_EG_MATCH", 237, 0, 0) - -# FIXME: fill in -def_op(loc, "WITH_EXCEPT_START", 249) -def_op(loc, "BEFORE_ASYNC_WITH", 252) -def_op(loc, "BEFORE_WITH", 253) -def_op(loc, "END_ASYNC_FOR", 254) -def_op(loc, "CLEANUP_THROW", 255) - -def_op(loc, "GET_YIELD_FROM_ITER", 69) -def_op(loc, "SETUP_WITH", 71) - -def_op(loc, "POP_BLOCK", 74) -def_op(loc, "RAISE", 75) - -def_op(loc, "LIST_TO_TUPLE", 82) - -varargs_op(loc, "BUILD_TUPLE", 77, 1, VARYING_STACK_INT) # Number of tuple items -varargs_op(loc, "BUILD_TUPLE_FROM_TUPLES", 78, 1, VARYING_STACK_INT) # Number of tuple items -varargs_op(loc, "BUILD_TUPLE_FROM_ITER", 79, 1, VARYING_STACK_INT) # Number of tuple items -varargs_op(loc, "BUILD_LIST", 80, 1, VARYING_STACK_INT) # Number of list items -varargs_op(loc, "BUILD_LIST_FROM_TUPLES", 81, 1, VARYING_STACK_INT) # Number of list items -varargs_op(loc, "BUILD_SET", 82, 1, VARYING_STACK_INT) # Number of set items -varargs_op(loc, "BUILD_SET_FROM_TUPLES", 83, 1, VARYING_STACK_INT) # Number of list items -varargs_op(loc, "BUILD_MAP", 84, 1, VARYING_STACK_INT) # Number of dict entries -varargs_op(loc, "BUILD_MAP_FOR_CALL", 85, 1, VARYING_STACK_INT) # Number of dict entries -varargs_op(loc, "DICT_UPDATE", 86) # Number of dict entries -def_op(loc, "BUILD_SLICE", 87) -def_op(loc, "LIST_APPEND", 88) -def_op(loc, "SET_ADD", 89) -def_op(loc, "MAP_ADD", 90) -def_op(loc, "PRINT_EXPR", 91) -def_op(loc, "LOAD_BUILD_CLASS", 92) -varargs_op(loc, "UNPACK_SEQUENCE", 93, 1, VARYING_STACK_INT) # Number of tuple items -def_op(loc, "UNPACK_EX", 94, VARYING_STACK_INT, VARYING_STACK_INT) -def_op(loc, "FORMAT_VALUE", 95, VARYING_STACK_INT, VARYING_STACK_INT) -def_op(loc, "POP_EXCEPT", 96) -def_op(loc, "REVERSE", 97) -def_op(loc, "GET_AWAITABLE", 98) -def_op(loc, "END_ASYNC_FOR", 99) -def_op(loc, "MATCH_MAPPING", 100) -def_op(loc, "MATCH_SEQUENCE", 101) -def_op(loc, "MATCH_CLASS", 102) -def_op(loc, "EXTENDED_ARG", 103) +def_op(loc, "BEFORE_ASYNC_WITH", 0) +binary_op(loc, "BINARY_OP", 1, 1, 1) +binary_op(loc, "BINARY_SUBSCR", 2) +jabs_op(loc, "BREAK_LOOP", 3, 0, 0) +varargs_op(loc, "BUILD_LIST_FROM_TUPLES", 4, 1, VARYING_STACK_INT) # Number of list items +varargs_op(loc, "BUILD_LIST", 5, 1, VARYING_STACK_INT) # Number of list items +varargs_op(loc, "BUILD_MAP_FOR_CALL", 6, 1, VARYING_STACK_INT) # Number of dict entries +varargs_op(loc, "BUILD_MAP", 7, 1, VARYING_STACK_INT) # Number of dict entries +varargs_op(loc, "BUILD_SET_FROM_TUPLES", 8, 1, VARYING_STACK_INT) # Number of list items +varargs_op(loc, "BUILD_SET", 9, 1, VARYING_STACK_INT) # Number of set items +def_op(loc, "BUILD_SLICE", 10) +varargs_op(loc, "BUILD_STRING", 11, VARYING_STACK_INT) # Number of tuple items +varargs_op(loc, "BUILD_TUPLE_FROM_ITER", 12, 1, VARYING_STACK_INT) # Number of tuple items +varargs_op(loc, "BUILD_TUPLE_FROM_TUPLES", 13, 1, VARYING_STACK_INT) # Number of tuple items +varargs_op(loc, "BUILD_TUPLE", 14, 1, VARYING_STACK_INT) # Number of tuple items + +call_op(loc, "CALL_FUNCTION_EX", 15) # Flags +call_op(loc, "CALL_FUNCTION_KW", 16) +call_op(loc, "CALL_FUNCTION", 17) +call_op(loc, "CallIntrinsic1", 18) +call_op(loc, "CallIntrinsic2", 19) +call_op(loc, "CALL_METHOD_EX", 20) +call_op(loc, "CALL_METHOD_KW", 21) +call_op(loc, "CALL_METHOD", 22) +jrel_op(loc, "CHECK_EG_MATCH", 23, 0, 0) +compare_op(loc, "COMPARE_OP", 24, 2, 1) # Comparison operator +compare_op(loc, "CONTAINS_OP", 25, 2, 1) +jabs_op(loc, "CONTINUE_LOOP", 26, 2, 1) +def_op(loc, "ConvertValue", 27, 0, 0) +def_op(loc, "COPY", 28, 0, 0) + +name_op(loc, "DELETE_ATTR", 29) # Local variable number is in operand +free_op(loc, "DELETE_DEREF", 30, 0, 0) +local_op(loc, "DELETE_FAST", 31, 0, 0) # Local variable number is in operand +name_op(loc, "DELETE_GLOBAL", 32) # "" +local_op(loc, "DELETE_LOCAL", 33, 0, 0) +def_op(loc, "DELETE_SUBSCR", 34, 0, 0) +varargs_op(loc, "DICT_UPDATE", 35) # Number of dict entries + +def_op(loc, "END_ASYNC_FOR", 36) +def_op(loc, "END_FINALLY", 37) +def_op(loc, "EnterFinally", 38) +def_op(loc, "EXTENDED_ARG", 39) + +jabs_op(loc, "FOR_ITER", 40) +def_op(loc, "FormatSimple", 41, VARYING_STACK_INT, VARYING_STACK_INT) +def_op(loc, "FormatWithSpec", 42, VARYING_STACK_INT, VARYING_STACK_INT) +def_op(loc, "GET_AITER", 43) +def_op(loc, "GET_ANEXT", 44) +def_op(loc, "GET_AWAITABLE", 45) +def_op(loc, "GET_ITER", 46) +def_op(loc, "GetLen", 47) + + +name_op(loc, "IMPORT_FROM", 48) +name_op(loc, "IMPORT_NAME", 49) +def_op(loc, "IsOp", 50, 0, 1) + +jabs_op(loc, "JUMP_IF_FALSE_OR_POP", 51) # " +jabs_op(loc, "JumpIfNotExcMatch", 52) # Number of words to skip +jabs_op(loc, "JUMP_IF_TRUE_OR_POP", 53) # Number of words to skip +jabs_op(loc, "JUMP", 54) # Number of words to skip + +def_op(loc, "LIST_APPEND", 55) +name_op(loc, "LOAD_ATTR", 56) # Index in name list +def_op(loc, "LOAD_BUILD_CLASS", 57) +def_op(loc, "LOAD_CLASS_DEREF", 59) +free_op(loc, "LOAD_CLOSURE", 59) +const_op(loc, "LOAD_CONST", 60, 0, 1) +free_op(loc, "LOAD_DEREF", 61) +local_op(loc, "LOAD_FAST", 62) +name_op(loc, "LOAD_GLOBAL", 63) +def_op(loc, "LOAD_METHOD", 64) +name_op(loc, "LOAD_NAME", 65) + +nargs_op(loc, "MAKE_FUNCTION", 66, VARYING_STACK_INT) # Flags +def_op(loc, "MAP_ADD", 67) +def_op(loc, "MATCH_CLASS", 68) +def_op(loc, "MATCH_KEYS", 69) +def_op(loc, "MATCH_MAPPING", 70) +def_op(loc, "MATCH_SEQUENCE", 71) + +def_op(loc, "NOP", 72, 0, 0) + +def_op(loc, "POP_BLOCK", 73) +def_op(loc, "POP_EXCEPT", 74) +jabs_op(loc, "POP_JUMP_IF_FALSE", 75) +jabs_op(loc, "POP_JUMP_IF_TRUE", 76) +def_op(loc, "POP_TOP", 77, 1, 0) + +def_op(loc, "RAISE", 78) +def_op(loc, "RESUME", 79, 0, 0) +const_op(loc, "RETURN_CONST", 80) +def_op(loc, "RETURN_VALUE", 81) +def_op(loc, "REVERSE", 82) + +def_op(loc, "SET_ADD", 83) +def_op(loc, "SET_FUNCTION_ATTR", 84) +def_op(loc, "SETUP_ANNOTATION", 85) +def_op(loc, "SETUP_ASYNC_WITH", 86, 0, 1) +def_op(loc, "SETUP_EXCEPT", 87) +jabs_op(loc, "SETUP_FINALLY", 88) +jabs_op(loc, "SETUP_LOOP", 89) +jabs_op(loc, "SETUP_WITHP", 90) +name_op(loc, "STORE_ATTR", 91) # Index in name list +store_op(loc, "STORE_DEREF", 92, 1, 0, is_type="free") +store_op(loc, "STORE_FAST", 93, 1, 0, is_type="local") # Local variable +name_op(loc, "STORE_GLOBAL", 94) # "" +store_op(loc, "STORE_LOCAL", 95, 4, 0) +def_op(loc, "STORE_SUBSCR", 96, 0, 0) +binary_op(loc, "SUBCRIPT", 97) +def_op(loc, "SWAP", 98, 1, 1) + +compare_op(loc, "TEST_OP", 99, 2, 1) # test operator +def_op(loc, "TO_BOOL", 100, 1, 1) + +unary_op(loc, "UNARY_OP", 101, 1, 1) +def_op(loc, "UNPACK_EX", 102, VARYING_STACK_INT, VARYING_STACK_INT) +varargs_op(loc, "UNPACK_SEQUENCE", 103, 1, VARYING_STACK_INT) # Number of tuple items + +def_op(loc, "WithCleanupFinish", 104) +def_op(loc, "WithCleanupStart", 105) + +def_op(loc, "YIELD", 106) +def_op(loc, "YIELD_FROM", 107) + + EXTENDED_ARG = 103 # fmt: on diff --git a/xdis/unmarsh_rust.py b/xdis/unmarsh_rust.py index 52babac2..08e4ab33 100644 --- a/xdis/unmarsh_rust.py +++ b/xdis/unmarsh_rust.py @@ -26,6 +26,7 @@ from typing import Any, Dict, List, Tuple, Union +from xdis.codetype.code312rust import Code312Rust from xdis.codetype.code313rust import Code313Rust, SourceLocation from xdis.magics import magic_int2tuple from xdis.unmarshal import ( @@ -162,7 +163,7 @@ def t_code_rust(self, save_ref, bytes_for_s: bool = False) -> Code313Rust: instr_count = self.read_int32() co_code = self.read_slice(instr_count * 2) - # instructions = [int(co_code[i]) for i in range(len(co_code))] # debug + instructions = [int(co_code[i]) for i in range(len(co_code))] # debug # read locations loc_count = self.read_int32() @@ -198,19 +199,18 @@ def t_code_rust(self, save_ref, bytes_for_s: bool = False) -> Code313Rust: obj_name_len = self.read_int32() obj_name = self.read_string(obj_name_len, False) - qualname_len = self.read_int32() - co_qualname = self.read_string(qualname_len, False) + if self.magic_int in (24881, 35310): + qualname_len = self.read_int32() + co_qualname = self.read_string(qualname_len, False) - cell2arg = None - if self.magic_int not in (12897,): - cell2arg_len = self.read_int32() - if cell2arg_len != 0: - cell2arg = [] - for _ in range(cell2arg_len): - raw = self.read_int32() - # convert raw (u32) to signed i32 - signed = raw if raw < (1 << 31) else raw - (1 << 32) - cell2arg.append(signed) + cell2arg_len = self.read_int32() + if cell2arg_len != 0: + cell2arg = [] + for _ in range(cell2arg_len): + raw = self.read_int32() + # convert raw (u32) to signed i32 + signed = raw if raw < (1 << 31) else raw - (1 << 32) + cell2arg.append(signed) # constants const_count = self.read_int32() @@ -235,38 +235,55 @@ def read_names(): co_freevars = read_names() co_nlocals = 0 - if self.magic_int not in (12897,): + if self.magic_int in (24881, 35310): linetable_len = self.read_int32() co_linetable = self.read_slice(linetable_len) exceptiontable_len = self.read_int32() co_exceptiontable = self.read_slice(exceptiontable_len) + return Code313Rust( + co_argcount=arg_count, + co_posonlyargcount=posonlyarg_count, + co_kwonlyargcount=kwonlyarg_count, + co_nlocals=co_nlocals, + co_stacksize=max_stackdepth, + co_flags=flags, + co_code=co_code, + co_consts=tuple(constants), + co_names=co_names, + co_varnames=co_varnames, + co_filename=source_path, + co_name=obj_name, + co_qualname=co_qualname, + co_firstlineno=first_line_number, + co_linetable=co_linetable, + co_freevars=co_freevars, + co_cellvars=co_cellvars, + co_exceptiontable=co_exceptiontable, + version_triple=self.version_triple, + locations=tuple(locations), + ) + else: - co_linetable = b'' - co_exceptiontable = b'' - - return Code313Rust( - co_argcount=arg_count, - co_posonlyargcount=posonlyarg_count, - co_kwonlyargcount=kwonlyarg_count, - co_nlocals=co_nlocals, - co_stacksize=max_stackdepth, - co_flags=flags, - co_code=co_code, - co_consts=tuple(constants), - co_names=co_names, - co_varnames=co_varnames, - co_filename=source_path, - co_name=obj_name, - co_qualname=co_qualname, - co_firstlineno=first_line_number, - co_linetable=co_linetable, - co_freevars=co_freevars, - co_cellvars=co_cellvars, - co_exceptiontable=co_exceptiontable, - version_triple=self.version_triple, - locations=tuple(locations), - ) + return Code312Rust( + co_argcount=arg_count, + co_posonlyargcount=posonlyarg_count, + co_kwonlyargcount=kwonlyarg_count, + co_stacksize=max_stackdepth, + co_flags=flags, + co_code=co_code, + co_consts=tuple(constants), + co_names=co_names, + co_varnames=co_varnames, + co_filename=source_path, + co_name=obj_name, + co_firstlineno=first_line_number, + co_freevars=co_freevars, + co_cellvars=co_cellvars, + version_triple=self.version_triple, + locations=tuple(locations), + ) + def t_bigint(self, save_ref: bool=False, bytes_for_s: bool=False):