roc/crates/wasm_interp/src/value_stack.rs
2022-11-21 19:54:48 +00:00

88 lines
2.8 KiB
Rust

use bitvec::vec::BitVec;
use bumpalo::collections::Vec;
use std::fmt::Debug;
use crate::Value;
/// Memory-efficient Struct-of-Arrays storage for the value stack.
/// Pack the values and their types as densely as possible,
/// to get better cache usage, at the expense of some extra logic.
struct ValueStack<'a> {
bytes: Vec<'a, u8>,
is_float: BitVec,
is_64: BitVec,
}
impl<'a> ValueStack<'a> {
pub fn push(&mut self, value: Value) {
match value {
Value::I32(x) => {
self.bytes.extend_from_slice(&x.to_ne_bytes());
self.is_float.push(false);
self.is_64.push(false);
}
Value::I64(x) => {
self.bytes.extend_from_slice(&x.to_ne_bytes());
self.is_float.push(false);
self.is_64.push(true);
}
Value::F32(x) => {
self.bytes.extend_from_slice(&x.to_ne_bytes());
self.is_float.push(true);
self.is_64.push(false);
}
Value::F64(x) => {
self.bytes.extend_from_slice(&x.to_ne_bytes());
self.is_float.push(true);
self.is_64.push(true);
}
}
}
pub fn pop(&mut self) -> Value {
let is_64 = self.is_64.pop().unwrap();
let is_float = self.is_float.pop().unwrap();
let size = if is_64 { 8 } else { 4 };
let bytes_idx = self.bytes.len() - size;
let value = self.get(is_64, is_float, bytes_idx);
self.bytes.truncate(size);
value
}
fn get(&self, is_64: bool, is_float: bool, bytes_idx: usize) -> Value {
if is_64 {
let mut b = [0; 8];
b.copy_from_slice(&self.bytes[bytes_idx..][..8]);
if is_float {
Value::F64(f64::from_ne_bytes(b))
} else {
Value::I64(i64::from_ne_bytes(b))
}
} else {
let mut b = [0; 4];
b.copy_from_slice(&self.bytes[bytes_idx..][..4]);
if is_float {
Value::F32(f32::from_ne_bytes(b))
} else {
Value::I32(i32::from_ne_bytes(b))
}
}
}
}
impl Debug for ValueStack<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[")?;
let mut index = 0;
assert_eq!(self.is_64.len(), self.is_float.len());
let iter_64 = self.is_64.iter().by_vals();
let iter_float = self.is_float.iter().by_vals();
for (is_64, is_float) in iter_64.zip(iter_float) {
let value = self.get(is_64, is_float, index);
index += if is_64 { 8 } else { 4 };
value.fmt(f)?;
write!(f, ", ")?;
}
write!(f, "]")
}
}