wasm_interp: implement local.get, local.set, and local.tee

This commit is contained in:
Brian Carroll 2022-11-21 23:29:08 +00:00
parent 987fcf616e
commit ff63831fd1
No known key found for this signature in database
GPG Key ID: 5C7B2EC4101703C0
3 changed files with 83 additions and 11 deletions

View File

@ -14,7 +14,7 @@ pub struct ExecutionState<'a> {
memory: Vec<'a, u8>,
#[allow(dead_code)]
call_stack: CallStack<'a>,
pub call_stack: CallStack<'a>,
pub value_stack: ValueStack<'a>,
program_counter: usize,
@ -31,6 +31,10 @@ impl<'a> ExecutionState<'a> {
}
}
fn fetch_immediate_u32(&mut self, module: &WasmModule<'a>) -> u32 {
u32::parse((), &module.code.bytes, &mut self.program_counter).unwrap()
}
pub fn execute_next_instruction(&mut self, module: &WasmModule<'a>) {
use OpCode::*;
@ -82,13 +86,19 @@ impl<'a> ExecutionState<'a> {
todo!("{:?}", op_code);
}
GETLOCAL => {
todo!("{:?}", op_code);
let index = self.fetch_immediate_u32(module);
let value = self.call_stack.get_local(index);
self.value_stack.push(value);
}
SETLOCAL => {
todo!("{:?}", op_code);
let index = self.fetch_immediate_u32(module);
let value = self.value_stack.pop();
self.call_stack.set_local(index, value);
}
TEELOCAL => {
todo!("{:?}", op_code);
let index = self.fetch_immediate_u32(module);
let value = self.value_stack.peek();
self.call_stack.set_local(index, value);
}
GETGLOBAL => {
todo!("{:?}", op_code);

View File

@ -34,6 +34,10 @@ impl<'a> ValueStack<'a> {
}
}
pub fn len(&self) -> usize {
self.is_64.len()
}
pub fn push(&mut self, value: Value) {
match value {
Value::I32(x) => {
@ -69,6 +73,14 @@ impl<'a> ValueStack<'a> {
value
}
pub fn peek(&self) -> Value {
let is_64 = self.is_64[self.is_64.len() - 1];
let is_float = self.is_float[self.is_float.len() - 1];
let size = if is_64 { 8 } else { 4 };
let bytes_idx = self.bytes.len() - size;
self.get(is_64, is_float, bytes_idx)
}
fn get(&self, is_64: bool, is_float: bool, bytes_idx: usize) -> Value {
if is_64 {
let mut b = [0; 8];

View File

@ -2,7 +2,7 @@
use bumpalo::Bump;
use roc_wasm_interp::{ExecutionState, Value};
use roc_wasm_module::{opcodes::OpCode, SerialBuffer, WasmModule};
use roc_wasm_module::{opcodes::OpCode, SerialBuffer, ValueType, WasmModule};
const DEFAULT_MEMORY_PAGES: u32 = 1;
const DEFAULT_PROGRAM_COUNTER: usize = 0;
@ -52,14 +52,64 @@ const DEFAULT_PROGRAM_COUNTER: usize = 0;
// #[test]
// fn test_select() {}
// #[test]
// fn test_getlocal() {}
#[test]
fn test_set_get_local() {
let arena = Bump::new();
let mut state = ExecutionState::new(&arena, DEFAULT_MEMORY_PAGES, DEFAULT_PROGRAM_COUNTER);
let mut module = WasmModule::new(&arena);
// #[test]
// fn test_setlocal() {}
let local_decls = [
(1, ValueType::F32),
(1, ValueType::F64),
(1, ValueType::I32),
(1, ValueType::I64),
];
state.call_stack.push_frame(0x1234, &local_decls);
// #[test]
// fn test_teelocal() {}
module.code.bytes.push(OpCode::I32CONST as u8);
module.code.bytes.encode_i32(12345);
module.code.bytes.push(OpCode::SETLOCAL as u8);
module.code.bytes.encode_u32(2);
module.code.bytes.push(OpCode::GETLOCAL as u8);
module.code.bytes.encode_u32(2);
state.execute_next_instruction(&module);
state.execute_next_instruction(&module);
state.execute_next_instruction(&module);
assert_eq!(state.value_stack.len(), 1);
assert_eq!(state.value_stack.pop(), Value::I32(12345));
}
#[test]
fn test_tee_get_local() {
let arena = Bump::new();
let mut state = ExecutionState::new(&arena, DEFAULT_MEMORY_PAGES, DEFAULT_PROGRAM_COUNTER);
let mut module = WasmModule::new(&arena);
let local_decls = [
(1, ValueType::F32),
(1, ValueType::F64),
(1, ValueType::I32),
(1, ValueType::I64),
];
state.call_stack.push_frame(0x1234, &local_decls);
module.code.bytes.push(OpCode::I32CONST as u8);
module.code.bytes.encode_i32(12345);
module.code.bytes.push(OpCode::TEELOCAL as u8);
module.code.bytes.encode_u32(2);
module.code.bytes.push(OpCode::GETLOCAL as u8);
module.code.bytes.encode_u32(2);
state.execute_next_instruction(&module);
state.execute_next_instruction(&module);
state.execute_next_instruction(&module);
assert_eq!(state.value_stack.len(), 2);
assert_eq!(state.value_stack.pop(), Value::I32(12345));
assert_eq!(state.value_stack.pop(), Value::I32(12345));
}
// #[test]
// fn test_getglobal() {}