Ejemplo n.º 1
0
def check_stack_effect():
    import dis
    from xdis import IS_PYPY
    from xdis.op_imports import get_opcode_module

    if IS_PYPY:
        variant = "pypy"
    else:
        variant = ""
    opc = get_opcode_module(None, variant)
    for (
        opname,
        opcode,
    ) in opc.opmap.items():
        if opname in ("EXTENDED_ARG", "NOP"):
            continue
        xdis_args = [opcode, opc]
        dis_args = [opcode]
        if op_has_argument(opcode, opc):
            xdis_args.append(0)
            dis_args.append(0)
        if (
            PYTHON_VERSION_TRIPLE > (3, 7)
            and opcode in opc.CONDITION_OPS
            and opname
            not in (
                "JUMP_IF_FALSE_OR_POP",
                "JUMP_IF_TRUE_OR_POP",
                "POP_JUMP_IF_FALSE",
                "POP_JUMP_IF_TRUE",
                "SETUP_FINALLY",
            )
        ):
            xdis_args.append(0)
            dis_args.append(0)

        effect = xstack_effect(*xdis_args)
        check_effect = dis.stack_effect(*dis_args)
        if effect == -100:
            print(
                "%d (%s) needs adjusting; should be: should have effect %d"
                % (opcode, opname, check_effect)
            )
        elif check_effect == effect:
            pass
            # print("%d (%s) is good: effect %d" % (opcode, opname, effect))
        else:
            print(
                "%d (%s) not okay; effect %d vs %d"
                % (opcode, opname, effect, check_effect)
            )
            pass
        pass
    return
Ejemplo n.º 2
0
def lineoffsets_in_file(filename, toplevel_only=False):
    obj_path = check_object_path(filename)
    version, timestamp, magic_int, code, pypy, source_size, sip_hash = load_module(
        obj_path)
    if pypy:
        variant = "pypy"
    else:
        variant = None
    opc = get_opcode_module(version, variant)
    return LineOffsetInfo(opc, code, not toplevel_only)
    pass
Ejemplo n.º 3
0
    def __init__(self, python_version=sys.version_info, variant=VARIANT):

        if python_version >= (3, 6):
            import xdis.wordcode as xcode
        else:
            import xdis.bytecode as xcode
        self.xcode = xcode

        self.opc = opc = get_opcode_module(python_version, variant)
        self.python_version = opc.version
        self.python_version_tuple = opc.version_tuple
        self.is_pypy = variant == PYPY
        self.hasconst = opc.hasconst
        self.hasname = opc.hasname
        self.opmap = opc.opmap
        self.opname = opc.opname
        self.EXTENDED_ARG = opc.EXTENDED_ARG
        self.HAVE_ARGUMENT = opc.HAVE_ARGUMENT

        class Bytecode(_Bytecode):
            """The bytecode operations of a piece of code

            Instantiate this with a function, method, string of code, or a code object
            (as returned by compile()).

            Iterating over this yields the bytecode operations as Instruction instances.
            """
            def __init__(self, x, first_line=None, current_offset=None):
                super(Bytecode, self).__init__(x,
                                               opc=opc,
                                               first_line=first_line,
                                               current_offset=current_offset)

        self.Bytecode = Bytecode

        class Instruction(_Instruction):
            """Details for a bytecode operation

            Defined fields:
              opname - human readable name for operation
              opcode - numeric code for operation
              arg - numeric argument to operation (if any), otherwise None
              argval - resolved arg value (if known), otherwise same as arg
              argrepr - human readable description of operation argument
              offset - start index of operation within bytecode sequence
              starts_line - line started by this opcode (if any), otherwise None
              is_jump_target - True if other code jumps to here, otherwise False
            """
            def __init__(self, *args, **kwargs):
                _Instruction(*args, **kwargs)
                self.opc = opc

        self.Instruction = Instruction
Ejemplo n.º 4
0
    def __init__(self, python_version=sys.version_info, variant=VARIANT):

        if python_version >= (3, 6):
            import xdis.wordcode as xcode
        else:
            import xdis.bytecode as xcode
        self.xcode = xcode

        self.opc = opc = get_opcode_module(python_version, variant)
        self.python_version = opc.version
        self.is_pypy = variant == PYPY
        self.hasconst = opc.hasconst
        self.hasname = opc.hasname
        self.opmap = opc.opmap
        self.opname = opc.opname
        self.EXTENDED_ARG = opc.EXTENDED_ARG
        self.HAVE_ARGUMENT = opc.HAVE_ARGUMENT

        class Bytecode(_Bytecode):
            """The bytecode operations of a piece of code

            Instantiate this with a function, method, string of code, or a code object
            (as returned by compile()).

            Iterating over this yields the bytecode operations as Instruction instances.
            """
            def __init__(self, x, first_line=None, current_offset=None):
                super(Bytecode, self).__init__(x, opc=opc, first_line=first_line,
                                               current_offset=current_offset)
        self.Bytecode = Bytecode

        class Instruction(_Instruction):
            """Details for a bytecode operation

               Defined fields:
                 opname - human readable name for operation
                 opcode - numeric code for operation
                 arg - numeric argument to operation (if any), otherwise None
                 argval - resolved arg value (if known), otherwise same as arg
                 argrepr - human readable description of operation argument
                 offset - start index of operation within bytecode sequence
                 starts_line - line started by this opcode (if any), otherwise None
                 is_jump_target - True if other code jumps to here, otherwise False
            """

            def __init__(self, *args, **kwargs):
                _Instruction(*args, **kwargs)
                self.opc = opc
        self.Instruction = Instruction
Ejemplo n.º 5
0
Archivo: vm.py Proyecto: rocky/x-python
    def __init__(
        self,
        python_version=PYTHON_VERSION,
        is_pypy=IS_PYPY,
        vmtest_testing=False,
        format_instruction_func=format_instruction,
    ):
        # The call stack of frames.
        self.frames = []
        # The current frame.
        self.frame = None
        self.return_value = None
        self.last_exception = None
        self.last_traceback_limit = None
        self.last_traceback = None
        self.version = python_version
        self.is_pypy = is_pypy
        self.format_instruction = format_instruction_func

        # FIXME: until we figure out how to fix up test/vmtest.el
        # This changes how we report a VMRuntime error.
        self.vmtest_testing = vmtest_testing

        # Like sys.exc_info() tuple
        self.last_exception = None

        # Sometimes we need a native function (e.g. for method lookup), but
        # most of the time we want a VM function defined in pyobj.
        # This maps between the two.
        self.fn2native = {}

        self.in_exception_processing = False

        # This is somewhat hoaky:
        # Give byteop routines a way to raise an error, without having
        # to import this file. We import from from byteops.
        # Alternatively, VMError could be
        # pulled out of this file
        self.PyVMError = PyVMError

        int_vers = int(python_version * 10)
        version_info = (int_vers // 10, int_vers % 10)
        variant = "pypy" if is_pypy else None
        self.opc = get_opcode_module(version_info, variant)
        self.byteop = get_byteop(self, python_version, is_pypy)
Ejemplo n.º 6
0
def test_inst_size():
    if (PYTHON_VERSION_TRIPLE[:2] == (3, 6)) and not IS_PYPY:
        opc = get_opcode_module(sys.version_info)
        bytecode_obj = Bytecode(extended_arg_fn36, opc)
        instructions = list(bytecode_obj.get_instructions(extended_arg_fn36))

        inst1 = instructions[1]
        assert inst1.opname == 'EXTENDED_ARG'
        assert inst1.argval == 0

        inst2 = instructions[2]
        assert inst2.opname == 'POP_JUMP_IF_FALSE'
        assert inst2.has_extended_arg == True
        assert inst2.inst_size == 4

        # for inst in instructions:
        #     print(inst)
    else:
        assert True
Ejemplo n.º 7
0
def test_inst_jumps():
    if (sys.version_info >= (2, 7)):
        variant = 'pypy' if IS_PYPY else None
        opc = get_opcode_module(sys.version_info, variant)
        bytecode_obj = Bytecode(extended_arg_fn36, opc)
        instructions = list(bytecode_obj.get_instructions(loop))
        seen_pjif = False
        seen_ja = False
        for inst in instructions:
            if inst.opname == "POP_JUMP_IF_FALSE":
                assert inst.is_jump()
                seen_pjif = True
            elif inst.opname == "JUMP_ABSOLUTE":
                assert inst.is_jump()
                assert not inst.jumps_forward()
                seen_ja = True
                pass
            pass
        assert seen_pjif
        assert seen_ja
Ejemplo n.º 8
0
def test_inst_size():
    if (sys.version_info == (3, 6)):
        variant = 'pypy' if IS_PYPY else None
        opc = get_opcode_module(sys.version_info, variant)
        bytecode_obj = Bytecode(extended_arg_fn36, opc)
        instructions = list(bytecode_obj.get_instructions(extended_arg_fn36))

        inst1 = instructions[1]
        assert inst1.opname == 'EXTENDED_ARG'
        assert inst1.argval == 0

        inst2 = instructions[2]
        assert inst2.opname == 'POP_JUMP_IF_FALSE'
        assert inst2.has_extended_arg == True
        assert inst2.inst_size == 4

        # for inst in instructions:
        #     print(inst)
    else:
        assert True
Ejemplo n.º 9
0
def test_inst_size():
    if (sys.version_info == (3,6)):
        variant = 'pypy' if IS_PYPY else None
        opc = get_opcode_module(sys.version_info, variant)
        bytecode_obj = Bytecode(extended_arg_fn36, opc)
        instructions = list(bytecode_obj.get_instructions(extended_arg_fn36))

        inst1 = instructions[1]
        assert inst1.opname == 'EXTENDED_ARG'
        assert inst1.argval == 0

        inst2 = instructions[2]
        assert inst2.opname == 'POP_JUMP_IF_FALSE'
        assert inst2.has_extended_arg == True
        assert inst2.inst_size == 4

        # for inst in instructions:
        #     print(inst)
    else:
        assert True
Ejemplo n.º 10
0
def test_inst_jumps():
    if (sys.version_info >= (2, 7)):
        variant = 'pypy' if IS_PYPY else None
        opc = get_opcode_module(sys.version_info, variant)
        bytecode_obj = Bytecode(extended_arg_fn36, opc)
        instructions = list(bytecode_obj.get_instructions(loop))
        seen_pjif = False
        seen_ja = False
        for inst in instructions:
            if inst.opname == "POP_JUMP_IF_FALSE":
                assert inst.is_jump()
                seen_pjif = True
            elif inst.opname == "JUMP_ABSOLUTE":
                assert inst.is_jump()
                assert not inst.jumps_forward()
                seen_ja = True
                pass
            pass
        assert seen_pjif
        # Python 3.10 code generation is more efficient and doesn't
        # and removes a JUMP_ABSOLUTE.
        if PYTHON_VERSION_TRIPLE < (3, 10):
            assert seen_ja
def test_stack_effect_vs_dis():

    if xdis.PYTHON_VERSION < 3.4 or xdis.IS_PYPY:
        # TODO figure out some other kind if internal checks to tod.
        print("Skipped for now - need to figure out how to test")
        return

    def test_one(xdis_args, dis_args, has_arg):
        effect = xstack_effect(*xdis_args)
        check_effect = dis.stack_effect(*dis_args)
        assert effect != -100, (
            "%d (%s) needs adjusting; should be: should have effect %d" %
            (opcode, opname, check_effect))
        if has_arg:
            op_val = "with operand %d" % dis_args[1]
        else:
            op_val = ""

        assert check_effect == effect, (
            "%d (%s) %s not okay; effect %d vs %d" %
            (opcode, opname, op_val, effect, check_effect))
        print("%d (%s) is good: effect %d" % (opcode, opname, effect))

    if xdis.IS_PYPY:
        variant = "pypy"
    else:
        variant = ""
    opc = get_opcode_module(None, variant)
    for opname, opcode, in opc.opmap.items():
        if opname in ("EXTENDED_ARG", "NOP"):
            continue
        xdis_args = [opcode, opc]
        dis_args = [opcode]

        # TODO: if opcode takes an argument, we should vary the arg and try
        # values in addition to 0 as done below.
        if op_has_argument(opcode, opc):
            xdis_args.append(0)
            dis_args.append(0)
            has_arg = True
        else:
            has_arg = False

        if (xdis.PYTHON_VERSION > 3.7 and opcode in opc.CONDITION_OPS
                and opname not in (
                    "JUMP_IF_FALSE_OR_POP",
                    "JUMP_IF_TRUE_OR_POP",
                    "POP_JUMP_IF_FALSE",
                    "POP_JUMP_IF_TRUE",
                    "SETUP_FINALLY",
                )):
            xdis_args.append(0)
            dis_args.append(0)

        if has_arg:
            for i in range(0, 3):
                dis_args[1] = xdis_args[2] = i
                test_one(xdis_args, dis_args, has_arg)
                pass
            pass
        else:
            test_one(xdis_args, dis_args, has_arg)
        pass
    return
Ejemplo n.º 12
0
def test_findlabels():
    code = findlabels.__code__.co_code
    opc = get_opcode_module()
    assert findlabels(code, opc) == findlabels_std(code)
Ejemplo n.º 13
0
        effect = xstack_effect(*xdis_args)
        check_effect = dis.stack_effect(*dis_args)
        if effect == -100:
            print(
                "%d (%s) needs adjusting; should be: should have effect %d"
                % (opcode, opname, check_effect)
            )
        elif check_effect == effect:
            pass
            # print("%d (%s) is good: effect %d" % (opcode, opname, effect))
        else:
            print(
                "%d (%s) not okay; effect %d vs %d"
                % (opcode, opname, effect, check_effect)
            )
            pass
        pass
    return


if __name__ == "__main__":
    from dis import findlabels as findlabels_std

    code = findlabels.__code__.co_code
    from xdis.op_imports import get_opcode_module

    opc = get_opcode_module()
    assert findlabels(code, opc) == findlabels_std(code)
    if PYTHON_VERSION_TRIPLE >= (3, 4):
        check_stack_effect()
Ejemplo n.º 14
0
    def __init__(self, version=PYTHON_VERSION_TRIPLE, is_pypy=IS_PYPY):
        global end_bb
        end_bb = 0
        self.bb_list = []
        self.exit_block = None

        version = version[:2]

        self.opcode = opcode = get_opcode_module(version)

        self.EXCEPT_INSTRUCTIONS = set([opcode.opmap["POP_TOP"]])
        self.FINALLY_INSTRUCTIONS = set([opcode.opmap["SETUP_FINALLY"]])
        self.FOR_INSTRUCTIONS = set([opcode.opmap["FOR_ITER"]])
        self.JABS_INSTRUCTIONS = set(opcode.hasjabs)
        self.JREL_INSTRUCTIONS = set(opcode.hasjrel)
        self.JUMP_INSTRUCTIONS = self.JABS_INSTRUCTIONS | self.JREL_INSTRUCTIONS
        self.JUMP_UNCONDITONAL = set(
            [opcode.opmap["JUMP_ABSOLUTE"], opcode.opmap["JUMP_FORWARD"]]
        )

        self.POP_BLOCK_INSTRUCTIONS = set([opcode.opmap["POP_BLOCK"]])
        self.RETURN_INSTRUCTIONS = set([opcode.opmap["RETURN_VALUE"]])

        # These instructions don't appear in all version of Python
        self.BREAK_INSTRUCTIONS = set()
        self.END_FINALLY_INSTRUCTIONS = set()
        self.LOOP_INSTRUCTIONS = set()
        self.TRY_INSTRUCTIONS = set()
        self.END_FINALLY_INSTRUCTIONS = set()
        self.LOOP_INSTRUCTIONS = set()
        self.TRY_INSTRUCTIONS = set()

        if version < (3, 10):
            if version < (3, 8):
                self.BREAK_INSTRUCTIONS = set([opcode.opmap["BREAK_LOOP"]])
                self.LOOP_INSTRUCTIONS = set([opcode.opmap["SETUP_LOOP"]])
                self.TRY_INSTRUCTIONS = set([opcode.opmap["SETUP_EXCEPT"]])
            elif version < (3, 9):
                # FIXME: add WITH_EXCEPT_START
                self.END_FINALLY_INSTRUCTIONS = set([opcode.opmap["END_FINALLY"]])
                pass

        else:
            self.EXCEPT_INSTRUCTIONS = set([opcode.opmap["RAISE_VARARGS"]])

        if version >= (2, 6):
            self.JUMP_CONDITONAL = set(
                [
                    opcode.opmap["POP_JUMP_IF_FALSE"],
                    opcode.opmap["POP_JUMP_IF_TRUE"],
                    opcode.opmap["JUMP_IF_FALSE_OR_POP"],
                    opcode.opmap["JUMP_IF_TRUE_OR_POP"],
                ]
            )
            self.NOFOLLOW_INSTRUCTIONS = set(
                [
                    opcode.opmap["RETURN_VALUE"],
                    opcode.opmap["YIELD_VALUE"],
                    opcode.opmap["RAISE_VARARGS"],
                ]
            )

        # ??
        #                                   opcode.opmap['YIELD_VALUE'],
        #                                   opcode.opmap['RAISE_VARARGS']])

        if not PYTHON3:
            if version in ((2, 6), (2, 7)):
                # We classify intructions into various categories (even though
                # many of the below contain just one instruction). This can
                # isolate us from instruction changes in Python.
                # The classifications are used in setting basic block flag bits
                self.JUMP_UNCONDITONAL = set(
                    [opcode.opmap["JUMP_ABSOLUTE"], opcode.opmap["JUMP_FORWARD"]]
                )
Ejemplo n.º 15
0
opcodes, supplying a custom file to dump the dis to) across python versions, for
example:

    import xdis.std as dis

    # works in Python 2 and 3
    for op in dis.Bytecode('for i in range(10): pass'):
        print(op)

"""

from xdis.op_imports import get_opcode_module

# hasconst, hasname, etc. are used from the outside. Set them.
__g = globals()
opcodes = get_opcode_module()
for field in "hasconst hasname opmap opname EXTENDED_ARG HAVE_ARGUMENT".split(
):
    __g[field] = getattr(opcodes, field)

# std
import sys
# local
from xdis import PYTHON_VERSION, IS_PYPY
from xdis.bytecode import (
    Bytecode as _Bytecode,
    Instruction as _Instruction,
)
if PYTHON_VERSION >= 3.6:
    import xdis.wordcode as xcode
else: