mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
wasm_interp: Don't panic when setting a local variable
This commit is contained in:
parent
9d912a6cc7
commit
1b126d3b58
2 changed files with 15 additions and 13 deletions
|
@ -6,7 +6,7 @@ use roc_wasm_module::{parse::Parse, Value, ValueType, WasmModule};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
|
||||||
use crate::{pc_to_fn_index, ValueStack};
|
use crate::{pc_to_fn_index, type_from_flags_f_64, Error, ValueStack};
|
||||||
|
|
||||||
/// Struct-of-Arrays storage for the call stack.
|
/// Struct-of-Arrays storage for the call stack.
|
||||||
/// Type info is packed to avoid wasting space on padding.
|
/// Type info is packed to avoid wasting space on padding.
|
||||||
|
@ -130,32 +130,34 @@ impl<'a> CallStack<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_local(&mut self, local_index: u32, value: Value) {
|
pub(crate) fn set_local(&mut self, local_index: u32, value: Value) -> Result<(), Error> {
|
||||||
let type_check_ok = self.set_local_help(local_index, value);
|
let expected_type = self.set_local_help(local_index, value);
|
||||||
debug_assert!(type_check_ok);
|
let actual_type = ValueType::from(value);
|
||||||
|
if actual_type == expected_type {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::ValueStackType(expected_type, actual_type))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_local_help(&mut self, local_index: u32, value: Value) -> bool {
|
fn set_local_help(&mut self, local_index: u32, value: Value) -> ValueType {
|
||||||
let frame_offset = *self.frame_offsets.last().unwrap();
|
let frame_offset = *self.frame_offsets.last().unwrap();
|
||||||
let index = (frame_offset + local_index) as usize;
|
let index = (frame_offset + local_index) as usize;
|
||||||
match value {
|
match value {
|
||||||
Value::I32(x) => {
|
Value::I32(x) => {
|
||||||
self.locals_data[index] = u64::from_ne_bytes((x as i64).to_ne_bytes());
|
self.locals_data[index] = u64::from_ne_bytes((x as i64).to_ne_bytes());
|
||||||
!self.is_64[index] && !self.is_float[index]
|
|
||||||
}
|
}
|
||||||
Value::I64(x) => {
|
Value::I64(x) => {
|
||||||
self.locals_data[index] = u64::from_ne_bytes((x).to_ne_bytes());
|
self.locals_data[index] = u64::from_ne_bytes((x).to_ne_bytes());
|
||||||
!self.is_float[index] && self.is_64[index]
|
|
||||||
}
|
}
|
||||||
Value::F32(x) => {
|
Value::F32(x) => {
|
||||||
self.locals_data[index] = x.to_bits() as u64;
|
self.locals_data[index] = x.to_bits() as u64;
|
||||||
self.is_float[index] && !self.is_64[index]
|
|
||||||
}
|
}
|
||||||
Value::F64(x) => {
|
Value::F64(x) => {
|
||||||
self.locals_data[index] = x.to_bits();
|
self.locals_data[index] = x.to_bits();
|
||||||
self.is_float[index] && self.is_64[index]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type_from_flags_f_64(self.is_float[index], self.is_64[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_stack_base(&self) -> u32 {
|
pub fn value_stack_base(&self) -> u32 {
|
||||||
|
@ -283,7 +285,7 @@ mod tests {
|
||||||
const RETURN_ADDR: u32 = 0x12345;
|
const RETURN_ADDR: u32 = 0x12345;
|
||||||
|
|
||||||
fn test_get_set(call_stack: &mut CallStack<'_>, index: u32, value: Value) {
|
fn test_get_set(call_stack: &mut CallStack<'_>, index: u32, value: Value) {
|
||||||
call_stack.set_local(index, value);
|
call_stack.set_local(index, value).unwrap();
|
||||||
assert_eq!(call_stack.get_local(index), value);
|
assert_eq!(call_stack.get_local(index), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -601,12 +601,12 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
|
||||||
SETLOCAL => {
|
SETLOCAL => {
|
||||||
let index = self.fetch_immediate_u32(module);
|
let index = self.fetch_immediate_u32(module);
|
||||||
let value = self.value_stack.pop();
|
let value = self.value_stack.pop();
|
||||||
self.call_stack.set_local(index, value);
|
self.call_stack.set_local(index, value)?;
|
||||||
}
|
}
|
||||||
TEELOCAL => {
|
TEELOCAL => {
|
||||||
let index = self.fetch_immediate_u32(module);
|
let index = self.fetch_immediate_u32(module);
|
||||||
let value = self.value_stack.peek();
|
let value = self.value_stack.peek();
|
||||||
self.call_stack.set_local(index, value);
|
self.call_stack.set_local(index, value)?;
|
||||||
}
|
}
|
||||||
GETGLOBAL => {
|
GETGLOBAL => {
|
||||||
let index = self.fetch_immediate_u32(module);
|
let index = self.fetch_immediate_u32(module);
|
||||||
|
@ -1523,7 +1523,7 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
|
||||||
if let Some(debug_string) = &self.debug_string {
|
if let Some(debug_string) = &self.debug_string {
|
||||||
let base = self.call_stack.value_stack_base();
|
let base = self.call_stack.value_stack_base();
|
||||||
let slice = self.value_stack.get_slice(base as usize);
|
let slice = self.value_stack.get_slice(base as usize);
|
||||||
eprintln!("{:#07x} {:17} {:?}", file_offset, debug_string, slice);
|
eprintln!("{:06x} {:17} {:?}", file_offset, debug_string, slice);
|
||||||
if op_code == RETURN || (op_code == END && implicit_return) {
|
if op_code == RETURN || (op_code == END && implicit_return) {
|
||||||
let fn_index = pc_to_fn_index(self.program_counter, module);
|
let fn_index = pc_to_fn_index(self.program_counter, module);
|
||||||
eprintln!("returning to function {}\n", fn_index);
|
eprintln!("returning to function {}\n", fn_index);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue