Skip to content

Commit

Permalink
feat: loop validation/execution
Browse files Browse the repository at this point in the history
Signed-off-by: Cem Onem <[email protected]>
  • Loading branch information
Cem Onem committed Dec 6, 2024
1 parent 616410f commit 032a136
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/execution/interpreter_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub(super) fn run<H: HookSet>(
wasm.read_var_u32().unwrap_validated();
do_sidetable_control_transfer(&mut wasm, stack, &mut stp, current_sidetable);
}
BLOCK => {
BLOCK | LOOP => {
BlockType::read_unvalidated(&mut wasm);
}
RETURN => {
Expand Down
11 changes: 7 additions & 4 deletions src/validation/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,12 @@ fn read_instructions(
stack.assert_push_ctrl(label_info, block_ty)?;
}
LOOP => {
todo!("implement loop");
let block_ty = BlockType::read(wasm)?.as_func_type(fn_types)?;
let label_info = LabelInfo::Loop {
ip: wasm.pc,
stp: sidetable.len(),
};
stack.assert_push_ctrl(label_info, block_ty)?;
}
IF => {
todo!("implement if");
Expand Down Expand Up @@ -259,9 +264,7 @@ fn read_instructions(
LabelInfo::If { .. } => {
todo!("implement if");
}
LabelInfo::Loop { .. } => {
todo!("implement loop");
}
LabelInfo::Loop { .. } => (),
LabelInfo::Func { stps_to_backpatch } => {
// same as blocks, except jump just before the end instr, not after it
// the last end instruction will handle the return to callee during execution
Expand Down
69 changes: 69 additions & 0 deletions tests/structured_control_flow/loop.rs
Original file line number Diff line number Diff line change
@@ -1 +1,70 @@
use wasm::{validate, RuntimeInstance};

const FIBONACCI_WITH_LOOP_AND_BR_IF: &str = r#"
(module
(func $fibonacci (param $n i32) (result i32)
(local $prev i32)
(local $curr i32)
(local $counter i32)
i32.const 0
local.set $prev
i32.const 1
local.set $curr
local.get $n
i32.const 1
i32.add
local.set $counter
block $exit
loop $loop
local.get $counter
i32.const 1
i32.le_s
br_if $exit
local.get $curr
local.get $curr
local.get $prev
i32.add
local.set $curr
local.set $prev
local.get $counter
i32.const 1
i32.sub
local.set $counter
br $loop
drop
drop
drop
end $loop
end $exit
local.get $curr
)
(export "fibonacci" (func $fibonacci))
)"#;

#[test_log::test]
fn fibonacci_with_loop_and_br_if() {
let wasm_bytes = wat::parse_str(FIBONACCI_WITH_LOOP_AND_BR_IF).unwrap();

let validation_info = validate(&wasm_bytes).expect("validation failed");
let mut instance = RuntimeInstance::new(&validation_info).expect("instantiation failed");

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

assert_eq!(1, instance.invoke(&fibonacci_fn, -5).unwrap());
assert_eq!(1, instance.invoke(&fibonacci_fn, 0).unwrap());
assert_eq!(1, instance.invoke(&fibonacci_fn, 1).unwrap());
assert_eq!(2, instance.invoke(&fibonacci_fn, 2).unwrap());
assert_eq!(3, instance.invoke(&fibonacci_fn, 3).unwrap());
assert_eq!(5, instance.invoke(&fibonacci_fn, 4).unwrap());
assert_eq!(8, instance.invoke(&fibonacci_fn, 5).unwrap());
}

0 comments on commit 032a136

Please sign in to comment.