| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- # (C) Copyright 2018-2019, 2021-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.
- """Facilitates for importing Python opcode maps for a given Python version"""
- import copy
- import sys
- from xdis.magics import canonic_python_version
- from xdis.opcodes import (
- opcode_10,
- opcode_11,
- opcode_12,
- opcode_13,
- opcode_14,
- opcode_15,
- opcode_16,
- opcode_20,
- opcode_21,
- opcode_22,
- opcode_23,
- opcode_24,
- opcode_25,
- opcode_26,
- opcode_26pypy,
- opcode_27,
- opcode_27pypy,
- opcode_30,
- opcode_31,
- opcode_32,
- opcode_32pypy,
- opcode_33,
- opcode_33pypy,
- opcode_34,
- opcode_35,
- opcode_35pypy,
- opcode_36,
- opcode_36pypy,
- opcode_37,
- opcode_37pypy,
- opcode_38,
- opcode_38pypy,
- opcode_39,
- opcode_39pypy,
- opcode_310,
- opcode_310pypy,
- opcode_311,
- opcode_311pypy,
- opcode_312,
- opcode_313,
- opcode_314,
- )
- from xdis.version_info import IS_PYPY, version_tuple_to_str
- # FIXME
- op_imports = {
- 1.0: opcode_10,
- "1.0": opcode_10,
- 1.1: opcode_11,
- "1.1": opcode_11,
- 1.2: opcode_12,
- "1.2": opcode_12,
- 1.3: opcode_13,
- "1.3": opcode_13,
- 1.4: opcode_14,
- "1.4": opcode_14,
- 1.5: opcode_15,
- "1.5": opcode_15,
- 1.6: opcode_16,
- "1.6": opcode_16,
- "2.0": opcode_20,
- 2.0: opcode_20,
- "2.1": opcode_21,
- 2.1: opcode_21,
- "2.2": opcode_22,
- 2.2: opcode_22,
- "2.3a0": opcode_23,
- 2.3: opcode_23,
- "2.4b1": opcode_24,
- 2.4: opcode_24,
- "2.5c2": opcode_25,
- 2.5: opcode_25,
- "2.5.0dropbox": opcode_25,
- "2.6a1": opcode_26,
- "2.6pypy": opcode_26pypy,
- 2.6: opcode_26,
- "2.7": opcode_27,
- 2.7: opcode_27,
- "2.7.18candidate1": opcode_27,
- "2.7pypy": opcode_27pypy,
- "2.7.12pypy": opcode_27pypy,
- "3.0": opcode_30,
- 3.0: opcode_30,
- "3.0a5": opcode_30,
- "3.1": opcode_31,
- "3.1a0+": opcode_31,
- 3.1: opcode_31,
- "3.2": opcode_32,
- "3.2a2": opcode_32,
- 3.2: opcode_32,
- "3.2pypy": opcode_32pypy,
- "3.3a4": opcode_33,
- 3.3: opcode_33,
- "3.3pypy": opcode_33pypy,
- "3.4": opcode_34,
- "3.4rc2": opcode_34,
- 3.4: opcode_34,
- "3.5": opcode_35,
- "3.5pypy": opcode_35pypy,
- "3.5.1": opcode_35,
- "3.5.2": opcode_35,
- "3.5.3": opcode_35,
- "3.5.4": opcode_35,
- 3.5: opcode_35,
- "3.6rc1": opcode_36,
- 3.6: opcode_36,
- "3.6pypy": opcode_36pypy,
- "3.6.1pypy": opcode_36pypy,
- "3.7.0beta3": opcode_37,
- "3.7.0.beta3": opcode_37,
- "3.7.0": opcode_37,
- "3.7pypy": opcode_37pypy,
- 3.7: opcode_37,
- "3.8.0alpha0": opcode_38,
- "3.8.0a0": opcode_38,
- "3.8.0a3+": opcode_38,
- "3.8.0alpha3": opcode_38,
- "3.8.0beta2": opcode_38,
- "3.8.0rc1+": opcode_38,
- "3.8.0candidate1": opcode_38,
- "3.8": opcode_38,
- "3.8pypy": opcode_38pypy,
- "3.8.0pypy": opcode_38pypy,
- "3.8.12pypy": opcode_38pypy,
- "3.8.13pypy": opcode_38pypy,
- "3.8.14pypy": opcode_38pypy,
- "3.8.15pypy": opcode_38pypy,
- "3.8.16pypy": opcode_38pypy,
- "3.8.17pypy": opcode_38pypy,
- "3.9.0alpha1": opcode_39,
- "3.9.0alpha2": opcode_39,
- "3.9.0beta5": opcode_39,
- "3.9": opcode_39,
- "3.9pypy": opcode_39pypy,
- "3.9.15pypy": opcode_39pypy,
- "3.9.16pypy": opcode_39pypy,
- "3.9.17pypy": opcode_39pypy,
- "3.9.18pypy": opcode_39pypy,
- 3.9: opcode_39,
- "3.10.0rc2": opcode_310,
- "3.10.b1": opcode_310,
- "3.10": opcode_310,
- "3.10pypy": opcode_310pypy,
- "3.10.12pypy": opcode_310pypy,
- "3.11": opcode_311,
- "3.11.0": opcode_311,
- "3.11.1": opcode_311,
- "3.11.2": opcode_311,
- "3.11.3": opcode_311,
- "3.11.4": opcode_311,
- "3.11.5": opcode_311,
- "3.11a7e": opcode_311,
- "3.11.13pypy": opcode_311pypy,
- 3.11: opcode_311,
- "3.12.0rc2": opcode_312,
- "3.12.0": opcode_312,
- "3.13.0rc3": opcode_313,
- "3.14b3": opcode_314,
- "3.14.0": opcode_314,
- "3.14": opcode_314,
- "3.14rc3": opcode_314,
- 3.14: opcode_314,
- }
- for k, v in canonic_python_version.items():
- if v in op_imports:
- op_imports[k] = op_imports[v]
- def get_opcode_module(version_info=None, variant=None):
- if version_info is None:
- version_info = sys.version_info
- if variant is None and IS_PYPY:
- variant = "pypy"
- pass
- pass
- elif isinstance(version_info, float):
- int_vers = int(version_info * 10)
- version_info = [int_vers // 10, int_vers % 10]
- vers_str = version_tuple_to_str(version_info)
- if len(version_info) > 3 and version_info[3] != "final":
- vers_str += version_tuple_to_str(version_info, start=3)
- if vers_str not in canonic_python_version:
- vers_str = version_tuple_to_str(version_info[:2])
- if variant is None:
- try:
- import platform
- variant = platform.python_implementation()
- if platform in ("Jython", "Pyston"):
- vers_str += variant
- pass
- except ImportError:
- # Python may be too old, e.g. < 2.6 or implementation may
- # just not have the ``platform`` attribute.
- pass
- elif variant != "Graal":
- vers_str += variant
- return op_imports[canonic_python_version[vers_str]]
- def remap_opcodes(op_obj, alternate_opmap):
- # All these lists are 255 in length, with index, ``i``, corresponding to opcode ``i``
- if hasattr(op_obj, "REMAPPED") and op_obj.REMAPPED:
- return op_obj
- positional_opcode_lists = [
- "opname", # Opcode's name
- "oppop", # How many items this opcode pops off the stack
- "oppush", # How many items this opcode pushes onto the stack
- ]
- # These lists contain all the opcodes that fit a certain description
- categorized_opcode_lists = [
- "hascompare",
- "hascondition",
- "hasconst",
- "hasfree",
- "hasjabs",
- "hasjrel",
- "haslocal",
- "hasname",
- "hasnargs",
- "hasvargs",
- "nofollow",
- ]
- new_opmap = copy.deepcopy(op_obj.opmap)
- new_lists = {}
- for list_name in positional_opcode_lists:
- if hasattr(op_obj, list_name):
- new_lists[list_name] = copy.deepcopy(getattr(op_obj, list_name))
- for list_name in categorized_opcode_lists:
- if hasattr(op_obj, list_name):
- new_lists[list_name] = copy.deepcopy(getattr(op_obj, list_name))
- new_frozensets = {}
- for i in dir(op_obj):
- item = getattr(op_obj, i)
- if isinstance(item, frozenset):
- item = list(item)
- new_frozensets[i] = copy.deepcopy(item)
- opcodes_with_args = {}
- for opname, opcode in op_obj.opmap.items():
- if opcode >= op_obj.HAVE_ARGUMENT:
- opcodes_with_args[opname] = opcode
- for opname, alt_opcode in alternate_opmap.items():
- if opname not in op_obj.opmap:
- raise KeyError(
- "The opname {} was not found in Python's original opmap for version {}".format(
- opname, op_obj.version
- )
- )
- else:
- original_opcode = op_obj.opmap[opname]
- new_opmap[opname] = alt_opcode
- if original_opcode == alt_opcode:
- continue
- if hasattr(op_obj, opname):
- setattr(op_obj, opname, alt_opcode)
- for list_name in positional_opcode_lists:
- if not hasattr(op_obj, list_name):
- continue
- new_opcode_list = new_lists[list_name]
- original_list = getattr(op_obj, list_name)
- new_opcode_list[alt_opcode] = original_list[original_opcode]
- for list_name in categorized_opcode_lists:
- if not hasattr(op_obj, list_name):
- continue
- new_opcode_list = new_lists[list_name]
- original_list = getattr(op_obj, list_name)
- if original_opcode in original_list:
- new_opcode_list[original_list.index(original_opcode)] = alt_opcode
- for set_name, frozen_set_list in new_frozensets.items():
- if original_opcode in getattr(op_obj, set_name):
- idx = list(getattr(op_obj, set_name)).index(original_opcode)
- frozen_set_list[idx] = alt_opcode
- new_opcodes_with_args = {}
- for opname in opcodes_with_args.keys():
- new_opcodes_with_args[opname] = new_opmap[opname]
- lowest_opcode_with_arg = min(new_opcodes_with_args.values())
- setattr(op_obj, "HAVE_ARGUMENT", lowest_opcode_with_arg)
- if hasattr(op_obj, "PJIF"):
- if hasattr(op_obj, "POP_JUMP_IF_FALSE") and "POP_JUMP_IF_FALSE" in new_opmap:
- # 2.7 and later
- setattr(op_obj, "PJIF", new_opmap["POP_JUMP_IF_FALSE"])
- if hasattr(op_obj, "JUMP_IF_FALSE") and "JUMP_IF_FALSE" in new_opmap:
- setattr(op_obj, "PJIF", new_opmap["JUMP_IF_FALSE"])
- if hasattr(op_obj, "PJIT"):
- if hasattr(op_obj, "POP_JUMP_IF_TRUE") and "POP_JUMP_IF_TRUE" in new_opmap:
- # 2.7 and later
- setattr(op_obj, "PJIT", new_opmap["POP_JUMP_IF_TRUE"])
- if hasattr(op_obj, "JUMP_IF_TRUE") and "JUMP_IF_TRUE" in new_opmap:
- setattr(op_obj, "PJIT", new_opmap["JUMP_IF_TRUE"])
- for new_list_name, new_list in new_lists.items():
- setattr(op_obj, new_list_name, new_list)
- for new_frozenset_name, new_frozenset in new_frozensets.items():
- setattr(op_obj, new_frozenset_name, frozenset(new_frozenset))
- setattr(op_obj, "opmap", new_opmap)
- setattr(op_obj, "REMAPPED", True)
- return op_obj
- if __name__ == "__main__":
- print(get_opcode_module())
|