use crate::{
assert_validated::UnwrapValidatedExt,
core::reader::{span::Span, WasmReadable, WasmReader},
value::{FuncAddr, Ref},
value_stack::Stack,
NumType, RefType, ValType, Value,
};
pub(crate) fn run_const(
mut wasm: WasmReader,
stack: &mut Stack,
_imported_globals: (), ) {
use crate::core::reader::types::opcode::*;
loop {
let first_instr_byte = wasm.read_u8().unwrap_validated();
match first_instr_byte {
END => {
break;
}
I32_CONST => {
let constant = wasm.read_var_i32().unwrap_validated();
trace!("Constant instruction: i32.const [] -> [{constant}]");
stack.push_value(constant.into());
}
I32_ADD => {
let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let res = v1.wrapping_add(v2);
trace!("Constant instruction: i32.add [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
I32_SUB => {
let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let res = v1.wrapping_sub(v2);
trace!("Constant instruction: i32.sub [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
I32_MUL => {
let v1: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let v2: i32 = stack.pop_value(ValType::NumType(NumType::I32)).into();
let res = v1.wrapping_mul(v2);
trace!("Constant instruction: i32.mul [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
I64_CONST => {
let constant = wasm.read_var_i64().unwrap_validated();
trace!("Constant instruction: i64.const [] -> [{constant}]");
stack.push_value(constant.into());
}
I64_ADD => {
let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let res = v1.wrapping_add(v2);
trace!("Constant instruction: i64.add [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
I64_SUB => {
let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let res = v1.wrapping_sub(v2);
trace!("Constant instruction: i64.sub [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
I64_MUL => {
let v1: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let v2: i64 = stack.pop_value(ValType::NumType(NumType::I64)).into();
let res = v1.wrapping_mul(v2);
trace!("Constant instruction: i64.mul [{v1} {v2}] -> [{res}]");
stack.push_value(res.into());
}
REF_NULL => {
let reftype = RefType::read_unvalidated(&mut wasm);
stack.push_value(Value::Ref(reftype.to_null_ref()));
trace!("Instruction: ref.null '{:?}' -> [{:?}]", reftype, reftype);
}
REF_FUNC => {
let func_idx = wasm.read_var_u32().unwrap_validated() as usize;
stack.push_value(Value::Ref(Ref::Func(FuncAddr::new(Some(func_idx)))));
}
other => {
panic!("Unknown constant instruction {other:#x}, validation allowed an unimplemented instruction.");
}
}
}
}
pub(crate) fn run_const_span(
wasm: &[u8],
span: &Span,
imported_globals: (),
) -> Option<Value> {
let mut wasm = WasmReader::new(wasm);
wasm.move_start_to(*span).unwrap_validated();
let mut stack = Stack::new();
run_const(wasm, &mut stack, imported_globals);
stack.peek_unknown_value()
}