util.py 文件源码

python
阅读 19 收藏 0 点赞 0 评论 0

项目:Vanstein 作者: SunDwarf 项目源码 文件源码
def get_instruction_index_by_offset(ctx: _VSContext, instruction: dis.Instruction) -> int:
    """
    Returns the index of an instruction (i.e ctx.instructions[I]) when given an offset to jump to.

    This is useful for when implementing an operator such as JUMP_FORWARD or SETUP_*.

    :param ctx: The context in which this is currently executing.
    :param instruction: The instruction to use.
    :return: The instruction index.
    """

    if PY36:
        # In CPython 3.6 and above, bytecode instructions are 2 bytes wide, all the time.
        # That means the offset can be divided by two and added to the instruction pointer.
        return ctx.instruction_pointer + (instruction.arg / 2)
    else:
        # This is a bit trickier.

        # However, we can use some known constants.
        # Opcodes with a code more than 90 have arguments, which means that they are length 3 (opcode + argv[0, 1])
        # We can loop over the instructions, check their opcode, and then check if the opcode is more than 90.
        # If it is, add 3 to our local raw pointer, because it has an argument, and 1 to the offset.
        # If it isn't, then only add 1 to our local raw pointer, but 1 to the offset again.
        # Once we've looped over these, we can then check if our local pointer is equal to the arg (NOT ARGVAL) of
        # the current instruction.
        # When it is, that means the instruction we're looking for is the current one, and we set the exception
        # pointer to our offset.

        # We have to special case arg = 1 on 3.5 and below.
        if instruction.arg == 1:
            return ctx.instruction_pointer + 1

        local_pointer = 0
        offset = 0
        for ins in ctx.instructions[ctx.instruction_pointer:]:
            if ins.opcode >= dis.HAVE_ARGUMENT:
                local_pointer += 3
            else:
                local_pointer += 1

            offset += 1

            if local_pointer == instruction.arg:
                # We've reached the right instruction.
                break
        else:
            raise SystemError("Could not find instruction at '{}'".format(instruction.argval))

        # The new instruction pointer is the current one + the offset we just calculated.
        return ctx.instruction_pointer + offset
评论列表
文章目录


问题


面经


文章

微信
公众号

扫码关注公众号