Esempio n. 1
0
def iXX_trunc_usX_fXX_op(config: Configuration) -> None:
    """
    Common logic function for the TRUNC opcodes which convert a float to an
    integer
    """
    instruction = cast(Truncate, config.current_instruction)

    value = config.pop_f32()

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

    if numpy.isnan(value) or numpy.isinf(value):
        raise Trap(f"Truncation is undefined for {value}")
    else:
        trunc_value = int(numpy.trunc(value))

        if instruction.signed:
            s_lower_bound, s_upper_bound = instruction.valtype.signed_bounds
            if trunc_value < s_lower_bound or trunc_value > s_upper_bound:
                raise Trap(
                    f"Truncation is undefined for {value}. Result outside of s32 "
                    "range.")

            result = instruction.valtype.from_signed(
                instruction.valtype.signed_type(trunc_value))
        else:
            u_lower_bound, u_upper_bound = instruction.valtype.bounds
            if trunc_value < u_lower_bound or trunc_value > u_upper_bound:
                raise Trap(
                    f"Truncation is undefined for {value}. Result outside of s32 "
                    "range.")
            result = instruction.valtype.value(trunc_value)

        config.push_operand(result)
Esempio n. 2
0
def _setup_function_invocation(config: Configuration,
                               function_address: FunctionAddress,
                               function_args: Tuple[TValue, ...]) -> None:
    """
    Helper function for invoking a function by the function's address.
    """
    function = config.store.funcs[function_address]

    if len(function_args) != len(function.type.params):
        raise TypeError(
            f"Wrong number of arguments. Expected {len(function.type.params)} "
            f"Got {len(function_args)}")

    if isinstance(function, FunctionInstance):
        locals = [valtype.zero for valtype in function.code.locals]
        frame = Frame(
            module=function.module,
            locals=list(function_args) + locals,
            # TODO: do we need this wrapping anymore?
            instructions=Block.wrap_with_end(function.type.results,
                                             function.code.body),
            arity=len(function.type.results),
        )
        config.push_frame(frame)
    elif isinstance(function, HostFunction):
        ret = function.hostcode(config, function_args)
        if len(ret) > 1:
            raise Exception("Invariant")
        elif ret:
            config.push_operand(ret[0])
    else:
        raise Exception("Invariant: unreachable code path")
Esempio n. 3
0
def iXX_divs_op(config: Configuration) -> None:
    """
    Common logic function for the integer DIVS opcodes
    """
    instruction = cast(BinOp, config.current_instruction)
    b, a = config.pop2_u32()

    b_s = instruction.valtype.to_signed(b)
    a_s = instruction.valtype.to_signed(a)
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", instruction.opcode.text, a_s, b_s)

    if b == 0:
        raise Trap('DIVISION BY ZERO')

    raw_result = abs(int(a_s)) // abs(int(b_s))
    _, upper_bound = instruction.valtype.signed_bounds

    if raw_result > upper_bound:
        raise Trap('UNDEFINED')

    if (a_s < 0) is not (b_s < 0):
        signed_result = instruction.valtype.signed_type(-1 * raw_result)
    else:
        signed_result = instruction.valtype.signed_type(raw_result)

    result = instruction.valtype.from_signed(signed_result)

    config.push_operand(result)
Esempio n. 4
0
def const_op(config: Configuration) -> None:
    """
    Common logic function for the various CONST opcodes.
    """
    instruction = cast(TConst, config.current_instruction)
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", instruction.opcode.text, instruction)

    config.push_operand(instruction.value)
Esempio n. 5
0
def f32demote_op(config: Configuration) -> None:
    """
    Logic function for the F32_DEMOTE_F64 opcode
    """
    value = config.pop_f64()

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

    config.push_operand(numpy.float32(value))
Esempio n. 6
0
def ixor_op(config: Configuration) -> None:
    """
    Common logic function for the integer XOR opcodes
    """
    b, a = config.pop2_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    config.push_operand(a ^ b)
Esempio n. 7
0
def iwrap64_op(config: Configuration) -> None:
    """
    Logic function for the I32_WRAP_I64 opcode
    """
    value = config.pop_u64()

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

    config.push_operand(numpy.uint32(value))
Esempio n. 8
0
def get_local_op(config: Configuration) -> None:
    """
    Logic functin for the GET_LOCAL opcode.
    """
    instruction = cast(LocalOp, config.current_instruction)
    if config.enable_logic_fn_logging:
        logger.debug("%s()", instruction.opcode.text)

    value = config.frame_locals[instruction.local_idx]
    config.push_operand(value)
Esempio n. 9
0
def get_global_op(config: Configuration) -> None:
    """
    Logic functin for the GET_GLOBAL opcode.
    """
    instruction = cast(GlobalOp, config.current_instruction)
    if config.enable_logic_fn_logging:
        logger.debug("%s()", instruction.opcode.text)

    global_address = config.frame_module.global_addrs[instruction.global_idx]
    global_ = config.store.globals[global_address]
    config.push_operand(global_.value)
Esempio n. 10
0
def memory_size_op(config: Configuration) -> None:
    """
    Logic function for the MEMORY_SIZE 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]
    size = numpy.uint32(len(mem.data) // constants.PAGE_SIZE_64K)
    config.push_operand(size)
Esempio n. 11
0
def iXX_mul_op(config: Configuration) -> None:
    """
    Common logic function for the integer MUL opcodes
    """
    b, a = config.pop2_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    with allow_overflow():
        config.push_operand(a * b)
Esempio n. 12
0
def fadd_op(config: Configuration) -> None:
    """
    Common logic function for the float ADD opcodes
    """
    b, a = config.pop2_f64()

    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    with allow_multiple(over=True, invalid=True):
        config.push_operand(a + b)
Esempio n. 13
0
def idivu_op(config: Configuration) -> None:
    """
    Common logic function for the integer DIVU opcodes
    """
    b, a = config.pop2_u32()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    if b == 0:
        raise Trap('DIVISION BY ZERO')
    config.push_operand(a // b)
Esempio n. 14
0
def ieqz_op(config: Configuration) -> None:
    """
    Common logic function for the integer EQZ opcodes
    """
    value = config.pop_operand()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", config.current_instruction.opcode.text, value)

    if value == 0:
        config.push_operand(constants.U32_ONE)
    else:
        config.push_operand(constants.U32_ZERO)
Esempio n. 15
0
def ne_op(config: Configuration) -> None:
    """
    Common logic function for all NE opcodes
    """
    b, a = config.pop2_operands()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    if a == b:
        config.push_operand(constants.U32_ZERO)
    else:
        config.push_operand(constants.U32_ONE)
Esempio n. 16
0
def select_op(config: Configuration) -> None:
    """
    Logic functin for the SELECT opcode.
    """
    if config.enable_logic_fn_logging:
        logger.debug("%s()", config.current_instruction.opcode.text)

    a, b, c = config.pop3_operands()

    if a:
        config.push_operand(c)
    else:
        config.push_operand(b)
Esempio n. 17
0
def XXX_reinterpret_XXX_op(config: Configuration) -> None:
    """
    Common logic function for the REINTERPRET opcodes
    """
    instruction = cast(Convert, config.current_instruction)

    value = config.pop_f32()

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

    config.push_operand(
        numpy.frombuffer(value.data, instruction.valtype.value)[0])
Esempio n. 18
0
def iXX_shl_op(config: Configuration) -> None:
    """
    Common logic function for the integer SHL opcodes
    """
    instruction = cast(BinOp, config.current_instruction)
    b, a = config.pop2_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", instruction.opcode.text, a, b)

    shift_amount = int(b % instruction.valtype.bit_size.value)
    raw_result = int(a) << shift_amount
    mod = instruction.valtype.mod
    config.push_operand(instruction.valtype.value(raw_result % mod))
Esempio n. 19
0
def fneg_op(config: Configuration) -> None:
    """
    Common logic function for the float NEG opcodes
    """
    instruction = cast(UnOp, config.current_instruction)

    value = config.pop_f64()

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

    negated_value = _negate_float(value)

    config.push_operand(negated_value)
Esempio n. 20
0
def fsqrt_op(config: Configuration) -> None:
    """
    Common logic function for the float SQRT opcodes
    """
    instruction = cast(UnOp, config.current_instruction)

    value = config.pop_f64()

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

    if numpy.isnan(value):
        with allow_invalid():
            config.push_operand(numpy.sqrt(value))
    elif value == 0:
        # TODO: this block and the subsequent _is_negative block are in
        # inverted order in the spec, indicating that the proper response here
        # should potentially be `nan` for the case of `sqrt(-0.0)` but the spec
        # tests assert that is not correct.
        # f32.wasm: line 2419
        config.push_operand(value)
    elif _is_negative(value):
        config.push_operand(instruction.valtype.nan)
    else:
        config.push_operand(numpy.sqrt(value))
Esempio n. 21
0
def ipopcnt_op(config: Configuration) -> None:
    """
    Common logic function for the integer POPCNT opcodes
    """
    instruction = cast(UnOp, config.current_instruction)
    value = config.pop_operand()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", instruction.opcode.text, value)

    if value == 0:
        config.push_operand(instruction.valtype.zero)
    else:
        config.push_operand(
            instruction.valtype.value(bin(int(value)).count('1')))
Esempio n. 22
0
def iXX_clz_op(config: Configuration) -> None:
    """
    Common logic function for the integer CLZ opcodes
    """
    instruction = cast(TestOp, config.current_instruction)
    value = config.pop_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", instruction.opcode.text, value)

    bit_size = instruction.valtype.bit_size.value
    if value == 0:
        config.push_operand(instruction.valtype.value(bit_size))
    else:
        config.push_operand(
            instruction.valtype.value(bit_size - int(value).bit_length()))
Esempio n. 23
0
def iXX_ges_op(config: Configuration) -> None:
    """
    Common logic function for the integer GES opcodes
    """
    instruction = cast(RelOp, config.current_instruction)
    b, a = config.pop2_u64()
    b_s = instruction.valtype.to_signed(b)
    a_s = instruction.valtype.to_signed(a)
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", instruction.opcode.text, a_s, b_s)

    if a_s >= b_s:
        config.push_operand(constants.U32_ONE)
    else:
        config.push_operand(constants.U32_ZERO)
Esempio n. 24
0
def iXX_ctz_op(config: Configuration) -> None:
    """
    Common logic function for the integer CTZ opcodes
    """
    instruction = cast(TestOp, config.current_instruction)
    value = config.pop_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s)", instruction.opcode.text, value)

    if value == 0:
        config.push_operand(
            instruction.valtype.value(instruction.valtype.bit_size.value))
    else:
        as_bin = bin(int(value))
        _, _, zeros = as_bin.rpartition('1')
        config.push_operand(instruction.valtype.value(len(zeros)))
Esempio n. 25
0
def fcopysign_op(config: Configuration) -> None:
    """
    Common logic function for the float COPYSIGN opcodes
    """
    b, a = config.pop2_f64()

    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", config.current_instruction.opcode.text, a,
                     b)

    a_is_negative = _is_negative(a)
    b_is_negative = _is_negative(b)

    if a_is_negative is b_is_negative:
        config.push_operand(a)
    else:
        config.push_operand(_negate_float(a))
Esempio n. 26
0
def fXX_convert_usX_iXX_op(config: Configuration) -> None:
    """
    Common logic function for the CONVERT opcodes
    """
    instruction = cast(Convert, config.current_instruction)

    base_value = config.pop_u64()

    if instruction.signed:
        value = instruction.from_valtype.to_signed(base_value)
    else:
        value = base_value

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

    config.push_operand(instruction.valtype.to_float(value))
Esempio n. 27
0
def iXX_rotr_op(config: Configuration) -> None:
    """
    Common logic function for the integer ROTR opcodes
    """
    instruction = cast(BinOp, config.current_instruction)
    b, a = config.pop2_u64()

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

    bit_size = instruction.valtype.bit_size.value
    shift_size = int(b % bit_size)
    lower = int(a) >> shift_size
    upper = int(a) << int(bit_size - shift_size)
    result = (upper | lower) % instruction.valtype.mod

    config.push_operand(instruction.valtype.value(result))
Esempio n. 28
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)
Esempio n. 29
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)
Esempio n. 30
0
def iXX_rems_op(config: Configuration) -> None:
    """
    Common logic function for the integer REMS opcodes
    """
    instruction = cast(BinOp, config.current_instruction)
    b, a = config.pop2_u64()
    if config.enable_logic_fn_logging:
        logger.debug("%s(%s, %s)", instruction.opcode.text, a, b)

    if b == 0:
        raise Trap('DIVISION BY ZERO')

    b_s = instruction.valtype.to_signed(b)
    a_s = instruction.valtype.to_signed(a)

    raw_result = numpy.abs(a_s) % numpy.abs(b_s)
    result = -1 * raw_result if a_s < 0 else raw_result

    config.push_operand(instruction.valtype.value(result))