Skip to content

Commit

Permalink
test: add tests for call_indirect runtime type check, types of ifs wi…
Browse files Browse the repository at this point in the history
…thout elses, invoke methods return type order

Signed-off-by: Cem Onem <[email protected]>
  • Loading branch information
Cem Onem committed Feb 18, 2025
1 parent 150710e commit 6d5839e
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 0 deletions.
31 changes: 31 additions & 0 deletions tests/function_recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,34 @@ fn recursion_busted_stack() {
"validation incorrectly passed"
);
}

#[test_log::test]
fn multivalue_call() {
let wat = r#"
(module
(func $foo (param $x i64) (param $y i32) (param $z f32) (result i32 f32 i64)
local.get $y
local.get $z
local.get $x
)
(func $bar (export "bar") (result i32 f32 i64)
i64.const 5
i32.const 10
f32.const 42.0
call $foo
)
)
"#;
let wasm_bytes = wat::parse_str(wat).unwrap();
let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let foo_fn = instance
.get_function_by_name(DEFAULT_MODULE, "bar")
.unwrap();

assert_eq!(
(10, 42.0, 5),
instance.invoke::<(), (i32, f32, i64)>(&foo_fn, ()).unwrap()
);
}
95 changes: 95 additions & 0 deletions tests/structured_control_flow/if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,98 @@ fn recursive_fibonacci_if_else() {
assert_eq!(5, instance.invoke(&fibonacci_fn, 4).unwrap());
assert_eq!(8, instance.invoke(&fibonacci_fn, 5).unwrap());
}

#[test_log::test]
fn if_without_else_type_check1() {
let wasm_bytes = wat::parse_str(
r#"
(module
(func $empty (param $cond i32)
(if (local.get $cond) (then))
)
(export "empty" (func $empty))
)"#,
)
.unwrap();
let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let empty_fn = instance.get_function_by_index(0, 0).unwrap();

assert_eq!((), instance.invoke(&empty_fn, 1).unwrap());
assert_eq!((), instance.invoke(&empty_fn, 0).unwrap());
}

#[test_log::test]
fn if_without_else_type_check2() {
let wasm_bytes = wat::parse_str(
r#"
(module
(func $empty (param $cond i32)
(i32.const 1)
(if (param i32) (local.get $cond) (then drop))
)
(export "empty" (func $empty))
)"#,
)
.unwrap();
assert!(validate(&wasm_bytes).is_err_and(|x| x == wasm::Error::IfWithoutMatchingElse));
}

#[test_log::test]
fn if_without_else_type_check3() {
let wasm_bytes = wat::parse_str(
r#"
(module
(func $add_one_if_true (param $cond i32) (result i32)
(i32.const 5)
(if (param i32) (result i32) (local.get $cond) (then (i32.const 2) (i32.add)))
)
(export "add_one_if_true" (func $add_one_if_true))
)"#,
)
.unwrap();
let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let add_one_if_true_fn = instance.get_function_by_index(0, 0).unwrap();

assert_eq!(7, instance.invoke(&add_one_if_true_fn, 1).unwrap());
assert_eq!(5, instance.invoke(&add_one_if_true_fn, 0).unwrap());
}

#[test_log::test]
fn if_without_else_type_check4() {
let wasm_bytes = wat::parse_str(
r#"
(module
(func $do_stuff_if_true (param $cond i32) (result i32) (result i64)
(i32.const 5)
(i64.const 20)
(if (param i32) (param i64) (result i32) (result i64) (local.get $cond) (then drop (i32.const 2) (i32.add) (i64.const 42)))
)
(export "do_stuff_if_true" (func $do_stuff_if_true))
)"#,
)
.unwrap();
let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let add_one_if_true_fn = instance.get_function_by_index(0, 0).unwrap();
assert_eq!(
(7, 42),
instance
.invoke::<i32, (i32, i64)>(&add_one_if_true_fn, 1)
.unwrap()
);
assert_eq!(
(5, 20),
instance
.invoke::<i32, (i32, i64)>(&add_one_if_true_fn, 0)
.unwrap()
);
}
67 changes: 67 additions & 0 deletions tests/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,73 @@ fn table_get_set_test() {
}
}

#[test_log::test]
fn call_indirect_type_check() {
let wat = r#"
(module
;; duplicate same type for different ids to make sure types themselves are compared
;; during call_indirect, not type ids
(type $type_1 (func (param i32) (result i32)))
(type $type_2 (func (param i32) (result i32)))
(type $type_3 (func (param i32) (result i32)))
(func $add_one_func (type $type_1) (param $x i32) (result i32)
local.get $x
i32.const 1
i32.add
)
(func $mul_two_func (type $type_2) (param $x i32) (result i32)
local.get $x
i32.const 2
i32.mul
)
(table funcref (elem $add_one_func $mul_two_func))
(func $call_function (param $value i32) (param $index i32) (result i32)
local.get $value
local.get $index
call_indirect 0 (type $type_3)
)
(export "call_function" (func $call_function))
)
"#;
let wasm_bytes = wat::parse_str(wat).unwrap();
let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

let call_fn = instance
.get_function_by_name(DEFAULT_MODULE, "call_function")
.unwrap();

assert_eq!(
4,
instance
.invoke::<(i32, i32), i32>(&call_fn, (3, 0))
.unwrap()
);
assert_eq!(
6,
instance
.invoke::<(i32, i32), i32>(&call_fn, (5, 0))
.unwrap()
);
assert_eq!(
6,
instance
.invoke::<(i32, i32), i32>(&call_fn, (3, 1))
.unwrap()
);
assert_eq!(
10,
instance
.invoke::<(i32, i32), i32>(&call_fn, (5, 1))
.unwrap()
);
}

// (assert_malformed
// (module quote "(table 0x1_0000_0000 funcref)")
// "i32 constant out of range"
Expand Down

0 comments on commit 6d5839e

Please sign in to comment.