mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
wasm_interp: implement store instructions
This commit is contained in:
parent
d9a8c6f64c
commit
598e62275d
2 changed files with 108 additions and 23 deletions
|
@ -1,5 +1,6 @@
|
||||||
use bumpalo::{collections::Vec, Bump};
|
use bumpalo::{collections::Vec, Bump};
|
||||||
use std::fmt::Write;
|
use std::fmt;
|
||||||
|
use std::io::Write;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use roc_wasm_module::opcodes::OpCode;
|
use roc_wasm_module::opcodes::OpCode;
|
||||||
|
@ -125,6 +126,7 @@ impl<'a> ExecutionState<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_immediate_u32(&mut self, module: &WasmModule<'a>) -> u32 {
|
fn fetch_immediate_u32(&mut self, module: &WasmModule<'a>) -> u32 {
|
||||||
|
use std::fmt::Write;
|
||||||
let x = u32::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
let x = u32::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
if let Some(debug_string) = self.debug_string.as_mut() {
|
||||||
write!(debug_string, "{}", x).unwrap();
|
write!(debug_string, "{}", x).unwrap();
|
||||||
|
@ -158,6 +160,25 @@ impl<'a> ExecutionState<'a> {
|
||||||
base_addr + offset
|
base_addr + offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_store_addr_value(&mut self, module: &WasmModule<'a>) -> (usize, Value) {
|
||||||
|
// Alignment is not used in the execution steps from the spec! Maybe it's just an optimization hint?
|
||||||
|
// https://webassembly.github.io/spec/core/exec/instructions.html#memory-instructions
|
||||||
|
// Also note: in the text format we can specify the useless `align=` but not the useful `offset=`!
|
||||||
|
let _alignment = self.fetch_immediate_u32(module);
|
||||||
|
let offset = self.fetch_immediate_u32(module);
|
||||||
|
let value = self.value_stack.pop();
|
||||||
|
let base_addr = self.value_stack.pop_u32();
|
||||||
|
let addr = (base_addr + offset) as usize;
|
||||||
|
(addr, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_debug<T: fmt::Debug>(&mut self, value: T) {
|
||||||
|
use fmt::Write;
|
||||||
|
if let Some(debug_string) = self.debug_string.as_mut() {
|
||||||
|
std::write!(debug_string, "{:?} ", value).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn execute_next_instruction(&mut self, module: &WasmModule<'a>) -> Action {
|
pub fn execute_next_instruction(&mut self, module: &WasmModule<'a>) -> Action {
|
||||||
use OpCode::*;
|
use OpCode::*;
|
||||||
|
|
||||||
|
@ -167,7 +188,7 @@ impl<'a> ExecutionState<'a> {
|
||||||
|
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
if let Some(debug_string) = self.debug_string.as_mut() {
|
||||||
debug_string.clear();
|
debug_string.clear();
|
||||||
write!(debug_string, "{:?} ", op_code).unwrap();
|
self.write_debug(op_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut action = Action::Continue;
|
let mut action = Action::Continue;
|
||||||
|
@ -354,38 +375,77 @@ impl<'a> ExecutionState<'a> {
|
||||||
let value = u32::from_le_bytes(bytes);
|
let value = u32::from_le_bytes(bytes);
|
||||||
self.value_stack.push(Value::I64(value as i64));
|
self.value_stack.push(Value::I64(value as i64));
|
||||||
}
|
}
|
||||||
I32STORE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
I32STORE => {
|
||||||
I64STORE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
F32STORE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
let unwrapped = value.unwrap_i32();
|
||||||
F64STORE => todo!("{:?} @ {:#x}", op_code, file_offset),
|
let mut target = &mut self.memory[addr..][..4];
|
||||||
I32STORE8 => todo!("{:?} @ {:#x}", op_code, file_offset),
|
target.write(&unwrapped.to_le_bytes()).unwrap();
|
||||||
I32STORE16 => todo!("{:?} @ {:#x}", op_code, file_offset),
|
}
|
||||||
I64STORE8 => todo!("{:?} @ {:#x}", op_code, file_offset),
|
I64STORE => {
|
||||||
I64STORE16 => todo!("{:?} @ {:#x}", op_code, file_offset),
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
I64STORE32 => todo!("{:?} @ {:#x}", op_code, file_offset),
|
let unwrapped = value.unwrap_i64();
|
||||||
|
let mut target = &mut self.memory[addr..][..8];
|
||||||
|
target.write(&unwrapped.to_le_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
F32STORE => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_f32();
|
||||||
|
let mut target = &mut self.memory[addr..][..4];
|
||||||
|
target.write(&unwrapped.to_le_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
F64STORE => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_f64();
|
||||||
|
let mut target = &mut self.memory[addr..][..8];
|
||||||
|
target.write(&unwrapped.to_le_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
I32STORE8 => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_i32();
|
||||||
|
let mut target = &mut self.memory[addr..][..1];
|
||||||
|
target.write(&unwrapped.to_le_bytes()[..1]).unwrap();
|
||||||
|
}
|
||||||
|
I32STORE16 => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_i32();
|
||||||
|
let mut target = &mut self.memory[addr..][..2];
|
||||||
|
target.write(&unwrapped.to_le_bytes()[..2]).unwrap();
|
||||||
|
}
|
||||||
|
I64STORE8 => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_i64();
|
||||||
|
let mut target = &mut self.memory[addr..][..1];
|
||||||
|
target.write(&unwrapped.to_le_bytes()[..1]).unwrap();
|
||||||
|
}
|
||||||
|
I64STORE16 => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_i64();
|
||||||
|
let mut target = &mut self.memory[addr..][..2];
|
||||||
|
target.write(&unwrapped.to_le_bytes()[..2]).unwrap();
|
||||||
|
}
|
||||||
|
I64STORE32 => {
|
||||||
|
let (addr, value) = self.get_store_addr_value(module);
|
||||||
|
let unwrapped = value.unwrap_i64();
|
||||||
|
let mut target = &mut self.memory[addr..][..4];
|
||||||
|
target.write(&unwrapped.to_le_bytes()[..4]).unwrap();
|
||||||
|
}
|
||||||
CURRENTMEMORY => todo!("{:?} @ {:#x}", op_code, file_offset),
|
CURRENTMEMORY => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||||
GROWMEMORY => todo!("{:?} @ {:#x}", op_code, file_offset),
|
GROWMEMORY => todo!("{:?} @ {:#x}", op_code, file_offset),
|
||||||
I32CONST => {
|
I32CONST => {
|
||||||
let value = i32::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
let value = i32::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
self.write_debug(value);
|
||||||
write!(debug_string, "{}", value).unwrap();
|
|
||||||
}
|
|
||||||
self.value_stack.push(Value::I32(value));
|
self.value_stack.push(Value::I32(value));
|
||||||
}
|
}
|
||||||
I64CONST => {
|
I64CONST => {
|
||||||
let value = i64::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
let value = i64::parse((), &module.code.bytes, &mut self.program_counter).unwrap();
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
self.write_debug(value);
|
||||||
write!(debug_string, "{}", value).unwrap();
|
|
||||||
}
|
|
||||||
self.value_stack.push(Value::I64(value));
|
self.value_stack.push(Value::I64(value));
|
||||||
}
|
}
|
||||||
F32CONST => {
|
F32CONST => {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
bytes.copy_from_slice(&module.code.bytes[self.program_counter..][..4]);
|
bytes.copy_from_slice(&module.code.bytes[self.program_counter..][..4]);
|
||||||
let value = f32::from_le_bytes(bytes);
|
let value = f32::from_le_bytes(bytes);
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
self.write_debug(value);
|
||||||
write!(debug_string, "{}", value).unwrap();
|
|
||||||
}
|
|
||||||
self.value_stack.push(Value::F32(value));
|
self.value_stack.push(Value::F32(value));
|
||||||
self.program_counter += 4;
|
self.program_counter += 4;
|
||||||
}
|
}
|
||||||
|
@ -393,9 +453,7 @@ impl<'a> ExecutionState<'a> {
|
||||||
let mut bytes = [0; 8];
|
let mut bytes = [0; 8];
|
||||||
bytes.copy_from_slice(&module.code.bytes[self.program_counter..][..8]);
|
bytes.copy_from_slice(&module.code.bytes[self.program_counter..][..8]);
|
||||||
let value = f64::from_le_bytes(bytes);
|
let value = f64::from_le_bytes(bytes);
|
||||||
if let Some(debug_string) = self.debug_string.as_mut() {
|
self.write_debug(value);
|
||||||
write!(debug_string, "{}", value).unwrap();
|
|
||||||
}
|
|
||||||
self.value_stack.push(Value::F64(value));
|
self.value_stack.push(Value::F64(value));
|
||||||
self.program_counter += 8;
|
self.program_counter += 8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -679,6 +679,33 @@ pub enum Value {
|
||||||
F64(f64),
|
F64(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn unwrap_i32(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Value::I32(x) => *x,
|
||||||
|
_ => panic!("Expected I32 but found {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unwrap_i64(&self) -> i64 {
|
||||||
|
match self {
|
||||||
|
Value::I64(x) => *x,
|
||||||
|
_ => panic!("Expected I64 but found {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unwrap_f32(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Value::F32(x) => *x,
|
||||||
|
_ => panic!("Expected F32 but found {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn unwrap_f64(&self) -> f64 {
|
||||||
|
match self {
|
||||||
|
Value::F64(x) => *x,
|
||||||
|
_ => panic!("Expected F64 but found {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Wasm memory alignment for load/store instructions.
|
/// Wasm memory alignment for load/store instructions.
|
||||||
/// Rust representation matches Wasm encoding.
|
/// Rust representation matches Wasm encoding.
|
||||||
/// It's an error to specify alignment higher than the "natural" alignment of the instruction
|
/// It's an error to specify alignment higher than the "natural" alignment of the instruction
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue