コード例 #1
0
def _build_table_mass_assignment(state, addr, instruction):
    assignment = nodes.Assignment()

    base = instruction.A

    destination = nodes.TableElement()
    destination.key = nodes.MULTRES()
    destination.table = _build_slot(state, addr, base - 1)

    assignment.destinations.contents = [destination]
    assignment.expressions.contents = [nodes.MULTRES()]

    return assignment
コード例 #2
0
def _build_call(state, addr, instruction):
    call = nodes.FunctionCall()
    call.function = _build_slot(state, addr, instruction.A)
    call.arguments.contents = _build_call_arguments(state, addr, instruction)

    line_marked = [call]

    if instruction.opcode <= ins.CALL.opcode:
        if instruction.B == 0:
            node = nodes.Assignment()
            node.destinations.contents.append(nodes.MULTRES())
            node.expressions.contents.append(call)
        elif instruction.B == 1:
            node = call
        else:
            from_slot = instruction.A
            to_slot = instruction.A + instruction.B - 2
            node = _build_range_assignment(state, addr, from_slot, to_slot)
            node.expressions.contents.append(call)
    else:
        assert instruction.opcode <= ins.CALLT.opcode
        node = nodes.Return()
        node.returns.contents.append(call)
        line_marked.append(node)

    return node, line_marked
コード例 #3
0
def _build_call_arguments(state, addr, instruction):
    base = instruction.A
    last_argument_slot = base + instruction.CD

    is_variadic = (instruction.opcode == ins.CALLM.opcode
                   or instruction.opcode == ins.CALLMT.opcode)

    if not is_variadic:
        last_argument_slot -= 1

    arguments = []

    slot = base + 1

    # LJ_FR2 flag, required for 64-bit LuaJIT
    # To the best of my knowledge, with this flag enabled there is a empty space on the
    #  stack between the function and the arguments - when normally you would push the function
    #  onto the stack followed by arguments, like so:
    #
    # /----------
    # | 0. FUNCTION OBJ
    # | 1. ARG1
    # | 2. ARG2
    # \----------
    #
    # With the flag enabled, it would go like so
    #
    # /----------
    # | 0. FUNCTION OBJ
    # | 1. <unused, reserved for runtime>
    # | 2. ARG1
    # | 3. ARG2
    # \----------
    #
    # And thus we have to skip that bit
    #
    # (if you're curious about why it does this - it's to allow LuaJIT to store some pointers in the space
    #  usually used by the stack contents. See https://github.com/LuaJIT/LuaJIT/issues/25#issuecomment-183660706 for
    #  more information)
    if state.header.flags.fr2:
        slot += 1
        last_argument_slot += 1

    while slot <= last_argument_slot:
        argument = _build_slot(state, addr, slot)
        arguments.append(argument)
        slot += 1

    if is_variadic:
        arguments.append(nodes.MULTRES())

    return arguments
コード例 #4
0
def _build_vararg(state, addr, instruction):
    base = instruction.A
    last_slot = base + instruction.B - 2

    if last_slot < base:
        node = nodes.Assignment()
        node.destinations.contents.append(nodes.MULTRES())
        node.expressions.contents.append(nodes.Vararg())
    else:
        node = _build_range_assignment(state, addr, base, last_slot)
        node.expressions.contents.append(nodes.Vararg())

    return node
コード例 #5
0
def _build_return(state, addr, instruction):
    node = nodes.Return()

    base = instruction.A
    last_slot = base + instruction.CD - 1

    if instruction.opcode != ins.RETM.opcode:
        last_slot -= 1

    slot = base

    # Negative count for the RETM is OK
    while slot <= last_slot:
        variable = _build_slot(state, addr, slot)
        node.returns.contents.append(variable)
        slot += 1

    if instruction.opcode == ins.RETM.opcode:
        node.returns.contents.append(nodes.MULTRES())

    return node
コード例 #6
0
def _build_call_arguments(state, addr, instruction):
    base = instruction.A
    last_argument_slot = base + instruction.CD

    is_variadic = (instruction.opcode == ins.CALLM.opcode
                   or instruction.opcode == ins.CALLMT.opcode)

    if not is_variadic:
        last_argument_slot -= 1

    arguments = []

    slot = base + 1

    while slot <= last_argument_slot:
        argument = _build_slot(state, addr, slot)
        arguments.append(argument)
        slot += 1

    if is_variadic:
        arguments.append(nodes.MULTRES())

    return arguments
コード例 #7
0
def _build_call(state, addr, instruction):
    call = nodes.FunctionCall()
    call.function = _build_slot(state, addr, instruction.A)
    call.arguments.contents = _build_call_arguments(state, addr, instruction)
    call.name = _lookup_variable_name(state, addr, instruction.A)
    if gconfig.gVerbose:
        print("_build_call " + call.name)

    # CALLM Call: A, ..., A+B-2 = A(A+1, ..., A+C+MULTRES)
    # CALL Call: A, ..., A+B-2 = A(A+1, ..., A+C-1)
    if instruction.opcode <= ins.CALL.opcode:
        if instruction.B == 0:
            node = nodes.Assignment()
            node.destinations.contents.append(nodes.MULTRES())
            node.expressions.contents.append(call)
        elif instruction.B == 1:
            node = call
        # elif call.name and call.name == "class" and instruction.B == 2:
        #     class_name = _lookup_variable_name(state, addr, instruction.A+1)
        #     print("class " + class_name)
        #     assert class_name is not None
        #     node = _build_class_assignment(addr, instruction.A, class_name)
        #     node.expressions.contents.append(call)
        else:
            from_slot = instruction.A
            to_slot = instruction.A + instruction.B - 2
            node = _build_range_assignment(state, addr, from_slot, to_slot)
            node.expressions.contents.append(call)
    # CALLMT Tailcall: return A(A+1, ..., A+D+MULTRES)
    # CALLT Tailcall: return A(A+1, ..., A+D-1)
    else:
        assert instruction.opcode <= ins.CALLT.opcode
        node = nodes.Return()
        node.returns.contents.append(call)

    return node