wasmi 0.36.0

WebAssembly interpreter
Documentation
use super::*;

use crate::{core::ValType, engine::bytecode::GlobalIdx};
use core::fmt::Display;
use wasm_type::WasmTy;

fn test_reg<T>()
where
    T: WasmTy + Default,
    DisplayWasm<T>: Display,
{
    let ty = T::NAME;
    let display_value = DisplayWasm::from(T::default());
    let wasm = format!(
        r#"
        (module
            (global $g (mut {ty}) ({ty}.const {display_value}))
            (func (param $value {ty})
                local.get $value
                global.set $g
            )
        )
    "#,
    );
    TranslationTest::from_wat(&wasm)
        .expect_func_instrs([
            Instruction::global_set(GlobalIdx::from(0), Register::from_i16(0)),
            Instruction::Return,
        ])
        .run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn reg() {
    test_reg::<i32>();
    test_reg::<i64>();
    test_reg::<f32>();
    test_reg::<f64>();
}

fn test_imm<T>(value: T)
where
    T: WasmTy + Default,
    DisplayWasm<T>: Display,
{
    let display_ty = DisplayValueType::from(T::VALUE_TYPE);
    let display_value = DisplayWasm::from(value);
    let wasm = format!(
        r#"
        (module
            (global $g (mut {display_ty}) ({display_ty}.const {display_value}))
            (func (param $value {display_ty})
                {display_ty}.const {display_value}
                global.set $g
            )
        )
    "#,
    );
    TranslationTest::from_wat(&wasm)
        .expect_func(
            ExpectedFunc::new([
                Instruction::global_set(GlobalIdx::from(0), Register::from_i16(-1)),
                Instruction::Return,
            ])
            .consts([value]),
        )
        .run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn imm() {
    test_imm::<i32>(i32::from(i16::MAX) + 1);
    test_imm::<i32>(i32::from(i16::MIN) - 1);
    test_imm::<i64>(i64::from(i16::MAX) + 1);
    test_imm::<i64>(i64::from(i16::MIN) - 1);
    test_imm::<f32>(0.0);
    test_imm::<f32>(-1.0);
    test_imm::<f64>(0.0);
    test_imm::<f64>(-1.0);
}

fn test_i32imm16(value: i32) {
    let display_ty = DisplayValueType::from(ValType::I32);
    let display_value = DisplayWasm::from(value);
    let wasm = format!(
        r#"
        (module
            (global $g (mut {display_ty}) ({display_ty}.const {display_value}))
            (func (param $value {display_ty})
                {display_ty}.const {display_value}
                global.set $g
            )
        )
    "#,
    );
    let imm16 = <Const16<i32>>::try_from(value)
        .unwrap_or_else(|_| panic!("cannot convert `value` to 16-bit encoding: {value}"));
    TranslationTest::from_wat(&wasm)
        .expect_func_instrs([
            Instruction::global_set_i32imm16(GlobalIdx::from(0), imm16),
            Instruction::Return,
        ])
        .run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn i32imm16() {
    test_i32imm16(0);
    test_i32imm16(1);
    test_i32imm16(-1);
    test_i32imm16(i32::from(i16::MAX));
    test_i32imm16(i32::from(i16::MIN));
}

fn test_i64imm16(value: i64) {
    let display_ty = DisplayValueType::from(ValType::I64);
    let display_value = DisplayWasm::from(value);
    let wasm = format!(
        r#"
        (module
            (global $g (mut {display_ty}) ({display_ty}.const {display_value}))
            (func (param $value {display_ty})
                {display_ty}.const {display_value}
                global.set $g
            )
        )
    "#,
    );
    let imm16 = <Const16<i64>>::try_from(value)
        .unwrap_or_else(|_| panic!("cannot convert `value` to 16-bit encoding: {value}"));
    TranslationTest::from_wat(&wasm)
        .expect_func_instrs([
            Instruction::global_set_i64imm16(GlobalIdx::from(0), imm16),
            Instruction::Return,
        ])
        .run()
}

#[test]
#[cfg_attr(miri, ignore)]
fn i64imm16() {
    test_i64imm16(0);
    test_i64imm16(1);
    test_i64imm16(-1);
    test_i64imm16(i64::from(i16::MAX));
    test_i64imm16(i64::from(i16::MIN));
}