mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
wasm_interp: create a block for each function and get tests working again
This commit is contained in:
parent
caedb9060b
commit
d51beb073f
6 changed files with 390 additions and 376 deletions
|
@ -1,8 +1,11 @@
|
|||
#![cfg(test)]
|
||||
|
||||
use super::{const_value, create_exported_function_no_locals, default_state};
|
||||
use crate::frame::Frame;
|
||||
use crate::{instance::Action, DefaultImportDispatcher, ImportDispatcher, Instance};
|
||||
use crate::tests::{
|
||||
const_value, create_exported_function_no_locals, create_exported_function_with_locals,
|
||||
default_state,
|
||||
};
|
||||
use crate::{DefaultImportDispatcher, ImportDispatcher, Instance};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_wasm_module::sections::{Import, ImportDesc};
|
||||
use roc_wasm_module::{
|
||||
|
@ -119,163 +122,157 @@ fn test_if_else() {
|
|||
fn test_if_else_help(condition: i32, expected: i32) {
|
||||
let arena = Bump::new();
|
||||
let mut module = WasmModule::new(&arena);
|
||||
let buf = &mut module.code.bytes;
|
||||
|
||||
buf.push(1); // one group of the given type
|
||||
buf.push(1); // one local in the group
|
||||
buf.push(ValueType::I32 as u8);
|
||||
let signature = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
let local_types = [(1, ValueType::I32)];
|
||||
create_exported_function_with_locals(&mut module, "test", signature, &local_types, |buf| {
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
// if <blocktype>
|
||||
buf.push(OpCode::IF as u8);
|
||||
buf.push(ValueType::VOID as u8);
|
||||
|
||||
// if <blocktype>
|
||||
buf.push(OpCode::IF as u8);
|
||||
buf.push(ValueType::VOID as u8);
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// else
|
||||
buf.push(OpCode::ELSE as u8);
|
||||
|
||||
// else
|
||||
buf.push(OpCode::ELSE as u8);
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// local.get 0
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.get 0
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end function
|
||||
buf.push(OpCode::END as u8);
|
||||
});
|
||||
|
||||
// end function
|
||||
buf.push(OpCode::END as u8);
|
||||
let is_debug_mode = false;
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
let result = inst.call_export("test", []).unwrap().unwrap();
|
||||
|
||||
let mut state = default_state(&arena);
|
||||
let fn_index = 0;
|
||||
let return_addr = 0x1234;
|
||||
let return_block_depth = 0;
|
||||
let arg_type_bytes = &[];
|
||||
let frame = Frame::enter(
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
arg_type_bytes,
|
||||
&buf,
|
||||
&mut state.value_stack,
|
||||
&mut state.program_counter,
|
||||
);
|
||||
state.current_frame = frame;
|
||||
|
||||
while let Ok(Action::Continue) = state.execute_next_instruction(&module) {}
|
||||
|
||||
assert_eq!(state.value_stack.pop_i32(), Ok(expected));
|
||||
assert_eq!(result, Value::I32(expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_br() {
|
||||
let start_fn_name = "test";
|
||||
let arena = Bump::new();
|
||||
let mut state = default_state(&arena);
|
||||
let mut module = WasmModule::new(&arena);
|
||||
let buf = &mut module.code.bytes;
|
||||
|
||||
// (local i32)
|
||||
buf.encode_u32(1);
|
||||
buf.encode_u32(1);
|
||||
buf.push(ValueType::I32 as u8);
|
||||
let signature = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
let local_types = [(1, ValueType::I32)];
|
||||
create_exported_function_with_locals(
|
||||
&mut module,
|
||||
start_fn_name,
|
||||
signature,
|
||||
&local_types,
|
||||
|buf| {
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// br 2 (;@1;)
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(2);
|
||||
|
||||
// br 2 (;@1;)
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(2);
|
||||
// i32.const 444
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(444);
|
||||
|
||||
// i32.const 444
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(444);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
let fn_index = 0;
|
||||
let return_addr = 0x1234;
|
||||
let return_block_depth = 0;
|
||||
let arg_type_bytes = &[];
|
||||
let frame = Frame::enter(
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
arg_type_bytes,
|
||||
&buf,
|
||||
&mut state.value_stack,
|
||||
&mut state.program_counter,
|
||||
buf.push(OpCode::END as u8);
|
||||
},
|
||||
);
|
||||
state.current_frame = frame;
|
||||
|
||||
while let Ok(Action::Continue) = state.execute_next_instruction(&module) {}
|
||||
let is_debug_mode = false;
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
let result = inst.call_export(start_fn_name, []).unwrap().unwrap();
|
||||
|
||||
assert_eq!(state.value_stack.pop(), Value::I32(111))
|
||||
assert_eq!(result, Value::I32(111))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -285,101 +282,101 @@ fn test_br_if() {
|
|||
}
|
||||
|
||||
fn test_br_if_help(condition: i32, expected: i32) {
|
||||
let start_fn_name = "test";
|
||||
let arena = Bump::new();
|
||||
let mut state = default_state(&arena);
|
||||
let mut module = WasmModule::new(&arena);
|
||||
let buf = &mut module.code.bytes;
|
||||
|
||||
// (local i32)
|
||||
buf.encode_u32(1);
|
||||
buf.encode_u32(1);
|
||||
buf.push(ValueType::I32 as u8);
|
||||
let signature = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
let local_types = [(1, ValueType::I32)];
|
||||
create_exported_function_with_locals(
|
||||
&mut module,
|
||||
start_fn_name,
|
||||
signature,
|
||||
&local_types,
|
||||
|buf| {
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
// br_if 2 (;@1;)
|
||||
buf.push(OpCode::BRIF as u8);
|
||||
buf.encode_u32(2);
|
||||
|
||||
// br_if 2 (;@1;)
|
||||
buf.push(OpCode::BRIF as u8);
|
||||
buf.encode_u32(2);
|
||||
// i32.const 444
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(444);
|
||||
|
||||
// i32.const 444
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(444);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
let fn_index = 0;
|
||||
let return_addr = 0x1234;
|
||||
let return_block_depth = 0;
|
||||
let arg_type_bytes = &[];
|
||||
let frame = Frame::enter(
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
arg_type_bytes,
|
||||
&buf,
|
||||
&mut state.value_stack,
|
||||
&mut state.program_counter,
|
||||
buf.push(OpCode::END as u8);
|
||||
},
|
||||
);
|
||||
state.current_frame = frame;
|
||||
|
||||
while let Ok(Action::Continue) = state.execute_next_instruction(&module) {}
|
||||
let is_debug_mode = true;
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
let result = inst.call_export(start_fn_name, []).unwrap().unwrap();
|
||||
|
||||
assert_eq!(state.value_stack.pop(), Value::I32(expected))
|
||||
assert_eq!(result, Value::I32(expected))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -390,106 +387,104 @@ fn test_br_table() {
|
|||
}
|
||||
|
||||
fn test_br_table_help(condition: i32, expected: i32) {
|
||||
let start_fn_name = "test";
|
||||
let arena = Bump::new();
|
||||
let mut state = default_state(&arena);
|
||||
let mut module = WasmModule::new(&arena);
|
||||
let buf = &mut module.code.bytes;
|
||||
|
||||
// (local i32)
|
||||
buf.encode_u32(1);
|
||||
buf.encode_u32(1);
|
||||
buf.push(ValueType::I32 as u8);
|
||||
let signature = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
let local_types = [(1, ValueType::I32)];
|
||||
create_exported_function_with_locals(
|
||||
&mut module,
|
||||
start_fn_name,
|
||||
signature,
|
||||
&local_types,
|
||||
|buf| {
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
|
||||
// i32.const 111
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(111);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @1
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @2
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
|
||||
// block ;; label = @3
|
||||
buf.push(OpCode::BLOCK as u8);
|
||||
buf.push(ValueType::VOID);
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
|
||||
// i32.const <condition>
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(condition);
|
||||
// br_table 0 1 2 (;@1;)
|
||||
buf.push(OpCode::BRTABLE as u8);
|
||||
buf.encode_u32(2); // number of non-fallback branches
|
||||
buf.encode_u32(0);
|
||||
buf.encode_u32(1);
|
||||
buf.encode_u32(2);
|
||||
|
||||
// br_table 0 1 2 (;@1;)
|
||||
buf.push(OpCode::BRTABLE as u8);
|
||||
buf.encode_u32(2); // number of non-fallback branches
|
||||
buf.encode_u32(0);
|
||||
buf.encode_u32(1);
|
||||
buf.encode_u32(2);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
|
||||
// i32.const 333
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(333);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// br 1
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(1);
|
||||
|
||||
// br 1
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(1);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
|
||||
// i32.const 222
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.encode_i32(222);
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.set 0
|
||||
buf.push(OpCode::SETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
// br 0
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// br 0
|
||||
buf.push(OpCode::BR as u8);
|
||||
buf.encode_u32(0);
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
// end
|
||||
buf.push(OpCode::END as u8);
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
// local.get 0)
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.encode_u32(0);
|
||||
|
||||
buf.push(OpCode::END as u8);
|
||||
|
||||
println!("{:02x?}", buf);
|
||||
|
||||
let fn_index = 0;
|
||||
let return_addr = 0x1234;
|
||||
let return_block_depth = 0;
|
||||
let arg_type_bytes = &[];
|
||||
let frame = Frame::enter(
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
arg_type_bytes,
|
||||
&buf,
|
||||
&mut state.value_stack,
|
||||
&mut state.program_counter,
|
||||
buf.push(OpCode::END as u8);
|
||||
},
|
||||
);
|
||||
state.current_frame = frame;
|
||||
|
||||
while let Ok(Action::Continue) = state.execute_next_instruction(&module) {}
|
||||
let is_debug_mode = false;
|
||||
let mut inst = Instance::for_module(
|
||||
&arena,
|
||||
&module,
|
||||
DefaultImportDispatcher::default(),
|
||||
is_debug_mode,
|
||||
)
|
||||
.unwrap();
|
||||
let result = inst.call_export(start_fn_name, []).unwrap().unwrap();
|
||||
|
||||
assert_eq!(state.value_stack.pop(), Value::I32(expected))
|
||||
assert_eq!(result, Value::I32(expected))
|
||||
}
|
||||
|
||||
struct TestDispatcher {
|
||||
|
@ -650,28 +645,22 @@ fn test_call_return_no_args() {
|
|||
#[test]
|
||||
fn test_call_return_with_args() {
|
||||
let arena = Bump::new();
|
||||
let mut state = default_state(&arena);
|
||||
let mut module = WasmModule::new(&arena);
|
||||
|
||||
// Function 0: calculate 2+2
|
||||
let func0_offset = module.code.bytes.len() as u32;
|
||||
module.code.function_offsets.push(func0_offset);
|
||||
module.add_function_signature(Signature {
|
||||
param_types: bumpalo::vec![in &arena;],
|
||||
let signature0 = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
create_exported_function_no_locals(&mut module, "two_plus_two", signature0, |buf| {
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.push(2);
|
||||
buf.push(OpCode::I32CONST as u8);
|
||||
buf.push(2);
|
||||
buf.push(OpCode::CALL as u8);
|
||||
buf.push(1);
|
||||
buf.push(OpCode::END as u8);
|
||||
});
|
||||
[
|
||||
0, // no locals
|
||||
OpCode::I32CONST as u8,
|
||||
2,
|
||||
OpCode::I32CONST as u8,
|
||||
2,
|
||||
OpCode::CALL as u8,
|
||||
1,
|
||||
OpCode::END as u8,
|
||||
]
|
||||
.serialize(&mut module.code.bytes);
|
||||
let func0_first_instruction = func0_offset + 2; // skip function length and locals length
|
||||
|
||||
// Function 1: add two numbers
|
||||
let func1_offset = module.code.bytes.len() as u32;
|
||||
|
@ -691,11 +680,24 @@ fn test_call_return_with_args() {
|
|||
]
|
||||
.serialize(&mut module.code.bytes);
|
||||
|
||||
state.program_counter = func0_first_instruction as usize;
|
||||
let signature0 = Signature {
|
||||
param_types: bumpalo::vec![in &arena; ValueType::I32, ValueType::I32],
|
||||
ret_type: Some(ValueType::I32),
|
||||
};
|
||||
create_exported_function_no_locals(&mut module, "add", signature0, |buf| {
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.push(0);
|
||||
buf.push(OpCode::GETLOCAL as u8);
|
||||
buf.push(1);
|
||||
buf.push(OpCode::I32ADD as u8);
|
||||
buf.push(OpCode::END as u8);
|
||||
});
|
||||
|
||||
while let Ok(Action::Continue) = state.execute_next_instruction(&module) {}
|
||||
let mut inst =
|
||||
Instance::for_module(&arena, &module, DefaultImportDispatcher::default(), false).unwrap();
|
||||
let result = inst.call_export("two_plus_two", []).unwrap().unwrap();
|
||||
|
||||
assert_eq!(state.value_stack.peek(), Value::I32(4));
|
||||
assert_eq!(result, Value::I32(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -769,11 +771,9 @@ fn test_call_indirect_help(table_index: u32, elem_index: u32) -> Value {
|
|||
if false {
|
||||
let mut outfile_buf = Vec::new_in(&arena);
|
||||
module.serialize(&mut outfile_buf);
|
||||
std::fs::write(
|
||||
format!("/tmp/roc/call_indirect_{}_{}.wasm", table_index, elem_index),
|
||||
outfile_buf,
|
||||
)
|
||||
.unwrap();
|
||||
let filename = format!("/tmp/roc/call_indirect_{}_{}.wasm", table_index, elem_index);
|
||||
std::fs::write(&filename, outfile_buf).unwrap();
|
||||
println!("\nWrote to {}\n", filename);
|
||||
}
|
||||
|
||||
let mut inst = Instance::for_module(
|
||||
|
@ -798,36 +798,25 @@ fn test_select() {
|
|||
fn test_select_help(first: Value, second: Value, condition: i32, expected: Value) {
|
||||
let arena = Bump::new();
|
||||
let mut module = WasmModule::new(&arena);
|
||||
let buf = &mut module.code.bytes;
|
||||
|
||||
buf.push(0); // no locals
|
||||
// Function 0: calculate 2+2
|
||||
let signature0 = Signature {
|
||||
param_types: bumpalo::vec![in &arena],
|
||||
ret_type: Some(ValueType::from(expected)),
|
||||
};
|
||||
create_exported_function_no_locals(&mut module, "test", signature0, |buf| {
|
||||
const_value(buf, first);
|
||||
const_value(buf, second);
|
||||
const_value(buf, Value::I32(condition));
|
||||
buf.push(OpCode::SELECT as u8);
|
||||
buf.push(OpCode::END as u8);
|
||||
});
|
||||
|
||||
const_value(buf, first);
|
||||
const_value(buf, second);
|
||||
const_value(buf, Value::I32(condition));
|
||||
buf.push(OpCode::SELECT as u8);
|
||||
buf.push(OpCode::END as u8);
|
||||
let mut inst =
|
||||
Instance::for_module(&arena, &module, DefaultImportDispatcher::default(), false).unwrap();
|
||||
let result = inst.call_export("test", []).unwrap().unwrap();
|
||||
|
||||
let mut inst = default_state(&arena);
|
||||
|
||||
let fn_index = 0;
|
||||
let return_addr = 0x1234;
|
||||
let return_block_depth = 0;
|
||||
let arg_type_bytes = &[];
|
||||
let frame = Frame::enter(
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
arg_type_bytes,
|
||||
&buf,
|
||||
&mut inst.value_stack,
|
||||
&mut inst.program_counter,
|
||||
);
|
||||
inst.current_frame = frame;
|
||||
|
||||
while let Ok(Action::Continue) = inst.execute_next_instruction(&module) {}
|
||||
|
||||
assert_eq!(inst.value_stack.pop(), expected);
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue