Exemple #1
0
def call_indirect_op(config: Configuration) -> None:
    """
    Logic function for the CALL_INDIRECT opcode
    """
    instruction = cast(CallIndirect, config.current_instruction)

    if config.enable_logic_fn_logging:
        logger.debug("%s()", instruction.opcode.text)

    table_address = config.frame_module.table_addrs[0]
    table = config.store.tables[table_address]
    function_type = config.frame_module.types[instruction.type_idx]

    element_idx = config.pop_u32()

    if len(table.elem) <= element_idx:
        raise Trap(
            "Element index out of table range: {element_idx} > {len(table.elem)}"
        )

    function_address = table.elem[element_idx]

    if function_address is None:
        raise Trap("Table element at index {element_idx} is empty")

    function = config.store.funcs[int(function_address)]

    if function.type != function_type:
        raise Trap(
            "Function type mismatch.  Expected {function_type}.  Got {function.type}"
        )

    _setup_call(config, function_address)
Exemple #2
0
def store_op(config: Configuration) -> None:
    """
    Logic function for the various *STORE* memory opcodes.
    """
    instruction = cast(MemoryOp, config.current_instruction)
    if config.enable_logic_fn_logging:
        logger.debug("%s()", instruction.opcode.text)

    memarg = instruction.memarg

    memory_address = config.frame_module.memory_addrs[0]
    mem = config.store.mems[memory_address]

    value = config.pop_operand()

    base_offset = config.pop_u32()
    memory_location = numpy.uint32(base_offset + memarg.offset)

    # TODO: update this section to use the `ValType.pack_bytes` API
    if instruction.valtype.is_integer_type:
        wrapped_value = instruction.memory_bit_size.wrap_type(value)
        encoded_value = wrapped_value.tobytes()
    elif instruction.valtype.is_float_type:
        encoded_value = value.tobytes()
    else:
        raise Exception("Invariant")

    assert len(encoded_value) == instruction.memory_bit_size.value // 8
    mem.write(memory_location, encoded_value)
Exemple #3
0
def i64extend_usX_op(config: Configuration) -> None:
    """
    Common logic function for the EXTEND opcodes
    """
    instruction = cast(Extend, config.current_instruction)

    value = config.pop_u32()

    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", instruction.opcode.text, value)

    if instruction.signed:
        signed_value = instruction.from_valtype.to_signed(value)
        result = instruction.valtype.from_signed(signed_value)
    else:
        result = instruction.valtype.value(value)

    config.push_operand(result)
Exemple #4
0
def memory_grow_op(config: Configuration) -> None:
    """
    Logic function for the MEMORY_GROW opcode
    """
    if config.enable_logic_fn_logging:
        logger.debug("%s()", config.current_instruction.opcode.text)

    memory_address = config.frame_module.memory_addrs[0]
    mem = config.store.mems[memory_address]
    current_num_pages = mem.num_pages
    num_pages = config.pop_u32()

    try:
        mem.grow(num_pages)
    except ValidationError:
        config.push_operand(constants.INT32_NEGATIVE_ONE)
    else:
        config.push_operand(current_num_pages)
Exemple #5
0
def load_op(config: Configuration) -> None:
    """
    Logic function for the various *LOAD* memory opcodes.
    """
    instruction = cast(MemoryOp, config.current_instruction)
    if config.enable_logic_fn_logging:
        logger.debug("%s()", instruction.opcode.text)

    memarg = instruction.memarg

    memory_address = config.frame_module.memory_addrs[0]
    mem = config.store.mems[memory_address]

    base_offset = config.pop_u32()
    with no_overflow():
        try:
            memory_location = base_offset + memarg.offset
        except FloatingPointError:
            raise Trap(
                "Memory locatin exceeds u32 bounds: {int(base_offset) + memarg.offset"
            )

    value_bit_width = instruction.memory_bit_size.value
    value_byte_width = value_bit_width // constants.BYTE_SIZE

    raw_bytes = mem.read(memory_location, value_byte_width)

    if instruction.valtype.is_integer_type:
        raw_value = instruction.memory_bit_size.unpack_int_bytes(
            raw_bytes,
            bool(instruction.signed),
        )

        if instruction.signed:
            config.push_operand(instruction.valtype.from_signed(raw_value))
        else:
            config.push_operand(instruction.valtype.value(raw_value))
    elif instruction.valtype.is_float_type:
        value = instruction.valtype.unpack_float_bytes(raw_bytes)
        config.push_operand(value)
    else:
        raise Exception("Invariant")