Remove tag from runtime value
This commit is contained in:
parent
1c04be64f8
commit
68e447ce28
443
src/runner.rs
443
src/runner.rs
|
@ -10,8 +10,8 @@ use module::ModuleRef;
|
||||||
use memory::MemoryRef;
|
use memory::MemoryRef;
|
||||||
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
||||||
use value::{
|
use value::{
|
||||||
RuntimeValue, FromRuntimeValue, WrapInto, TryTruncateInto, ExtendInto,
|
ArithmeticOps, ExtendInto, Float, FromRuntimeValueInternal, Integer, LittleEndianConvert,
|
||||||
ArithmeticOps, Integer, Float, LittleEndianConvert, TransmuteInto,
|
RuntimeValue, RuntimeValueInternal, TransmuteInto, TryTruncateInto, WrapInto,
|
||||||
};
|
};
|
||||||
use host::Externals;
|
use host::Externals;
|
||||||
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
|
||||||
|
@ -78,13 +78,12 @@ pub struct Interpreter {
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn new(func: &FuncRef, args: &[RuntimeValue]) -> Result<Interpreter, Trap> {
|
pub fn new(func: &FuncRef, args: &[RuntimeValue]) -> Result<Interpreter, Trap> {
|
||||||
let mut value_stack = ValueStack::with_limit(DEFAULT_VALUE_STACK_LIMIT);
|
let mut value_stack = ValueStack::with_limit(DEFAULT_VALUE_STACK_LIMIT);
|
||||||
for arg in args {
|
for &arg in args {
|
||||||
value_stack
|
let arg = arg.into();
|
||||||
.push(*arg)
|
value_stack.push(arg).map_err(
|
||||||
.map_err(
|
|
||||||
// There is not enough space for pushing initial arguments.
|
// There is not enough space for pushing initial arguments.
|
||||||
// Weird, but bail out anyway.
|
// Weird, but bail out anyway.
|
||||||
|_| Trap::from(TrapKind::StackOverflow)
|
|_| Trap::from(TrapKind::StackOverflow),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +112,9 @@ impl Interpreter {
|
||||||
self.state = InterpreterState::Started;
|
self.state = InterpreterState::Started;
|
||||||
self.run_interpreter_loop(externals)?;
|
self.run_interpreter_loop(externals)?;
|
||||||
|
|
||||||
let opt_return_value = self.return_type.map(|_vt| {
|
let opt_return_value = self
|
||||||
self.value_stack.pop()
|
.return_type
|
||||||
});
|
.map(|vt| self.value_stack.pop().with_type(vt));
|
||||||
|
|
||||||
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
||||||
assert!(self.value_stack.len() == 0);
|
assert!(self.value_stack.len() == 0);
|
||||||
|
@ -131,25 +130,18 @@ impl Interpreter {
|
||||||
|
|
||||||
let mut resumable_state = InterpreterState::Started;
|
let mut resumable_state = InterpreterState::Started;
|
||||||
swap(&mut self.state, &mut resumable_state);
|
swap(&mut self.state, &mut resumable_state);
|
||||||
let expected_ty = match resumable_state {
|
|
||||||
InterpreterState::Resumable(ty) => ty,
|
|
||||||
_ => unreachable!("Resumable arm is checked above is_resumable; qed"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let value_ty = return_val.as_ref().map(|val| val.value_type());
|
|
||||||
if value_ty != expected_ty {
|
|
||||||
return Err(TrapKind::UnexpectedSignature.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(return_val) = return_val {
|
if let Some(return_val) = return_val {
|
||||||
self.value_stack.push(return_val).map_err(Trap::new)?;
|
self.value_stack
|
||||||
|
.push(return_val.into())
|
||||||
|
.map_err(Trap::new)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_interpreter_loop(externals)?;
|
self.run_interpreter_loop(externals)?;
|
||||||
|
|
||||||
let opt_return_value = self.return_type.map(|_vt| {
|
let opt_return_value = self
|
||||||
self.value_stack.pop()
|
.return_type
|
||||||
});
|
.map(|vt| self.value_stack.pop().with_type(vt));
|
||||||
|
|
||||||
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
// Ensure that stack is empty after the execution. This is guaranteed by the validation properties.
|
||||||
assert!(self.value_stack.len() == 0);
|
assert!(self.value_stack.len() == 0);
|
||||||
|
@ -222,7 +214,9 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(return_val) = return_val {
|
if let Some(return_val) = return_val {
|
||||||
self.value_stack.push(return_val).map_err(Trap::new)?;
|
self.value_stack
|
||||||
|
.push(return_val.into())
|
||||||
|
.map_err(Trap::new)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,8 +305,8 @@ impl Interpreter {
|
||||||
|
|
||||||
&isa::Instruction::I32Const(val) => self.run_const(val.into()),
|
&isa::Instruction::I32Const(val) => self.run_const(val.into()),
|
||||||
&isa::Instruction::I64Const(val) => self.run_const(val.into()),
|
&isa::Instruction::I64Const(val) => self.run_const(val.into()),
|
||||||
&isa::Instruction::F32Const(val) => self.run_const(RuntimeValue::decode_f32(val)),
|
&isa::Instruction::F32Const(val) => self.run_const(val.into()),
|
||||||
&isa::Instruction::F64Const(val) => self.run_const(RuntimeValue::decode_f64(val)),
|
&isa::Instruction::F64Const(val) => self.run_const(val.into()),
|
||||||
|
|
||||||
&isa::Instruction::I32Eqz => self.run_eqz::<i32>(),
|
&isa::Instruction::I32Eqz => self.run_eqz::<i32>(),
|
||||||
&isa::Instruction::I32Eq => self.run_eq::<i32>(),
|
&isa::Instruction::I32Eq => self.run_eq::<i32>(),
|
||||||
|
@ -545,9 +539,7 @@ impl Interpreter {
|
||||||
.value_stack
|
.value_stack
|
||||||
.pop_triple();
|
.pop_triple();
|
||||||
|
|
||||||
let condition = right
|
let condition = <_>::from_runtime_value_internal(right);
|
||||||
.try_into()
|
|
||||||
.expect("Due to validation stack top should be I32");
|
|
||||||
let val = if condition { left } else { mid };
|
let val = if condition { left } else { mid };
|
||||||
self.value_stack.push(val)?;
|
self.value_stack.push(val)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
|
@ -586,7 +578,7 @@ impl Interpreter {
|
||||||
.global_by_index(index)
|
.global_by_index(index)
|
||||||
.expect("Due to validation global should exists");
|
.expect("Due to validation global should exists");
|
||||||
let val = global.get();
|
let val = global.get();
|
||||||
self.value_stack.push(val)?;
|
self.value_stack.push(val.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,20 +594,23 @@ impl Interpreter {
|
||||||
.module()
|
.module()
|
||||||
.global_by_index(index)
|
.global_by_index(index)
|
||||||
.expect("Due to validation global should exists");
|
.expect("Due to validation global should exists");
|
||||||
global.set(val).expect("Due to validation set to a global should succeed");
|
global
|
||||||
|
.set(val.with_type(global.value_type()))
|
||||||
|
.expect("Due to validation set to a global should succeed");
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_load<T>(
|
||||||
where RuntimeValue: From<T>, T: LittleEndianConvert {
|
&mut self,
|
||||||
let raw_address = self
|
context: &mut FunctionContext,
|
||||||
.value_stack
|
offset: u32,
|
||||||
.pop_as();
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
let address =
|
where
|
||||||
effective_address(
|
RuntimeValueInternal: From<T>,
|
||||||
offset,
|
T: LittleEndianConvert,
|
||||||
raw_address,
|
{
|
||||||
)?;
|
let raw_address = self.value_stack.pop_as();
|
||||||
|
let address = effective_address(offset, raw_address)?;
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
|
@ -625,16 +620,18 @@ impl Interpreter {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_load_extend<T, U>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_load_extend<T, U>(
|
||||||
where T: ExtendInto<U>, RuntimeValue: From<U>, T: LittleEndianConvert {
|
&mut self,
|
||||||
let raw_address = self
|
context: &mut FunctionContext,
|
||||||
.value_stack
|
offset: u32,
|
||||||
.pop_as();
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
let address =
|
where
|
||||||
effective_address(
|
T: ExtendInto<U>,
|
||||||
offset,
|
RuntimeValueInternal: From<U>,
|
||||||
raw_address,
|
T: LittleEndianConvert,
|
||||||
)?;
|
{
|
||||||
|
let raw_address = self.value_stack.pop_as();
|
||||||
|
let address = effective_address(offset, raw_address)?;
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
|
@ -648,19 +645,18 @@ impl Interpreter {
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_store<T>(&mut self, context: &mut FunctionContext, offset: u32) -> Result<InstructionOutcome, TrapKind>
|
fn run_store<T>(
|
||||||
where T: FromRuntimeValue, T: LittleEndianConvert {
|
&mut self,
|
||||||
let stack_value = self
|
context: &mut FunctionContext,
|
||||||
.value_stack
|
offset: u32,
|
||||||
.pop_as::<T>();
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
let raw_address = self
|
where
|
||||||
.value_stack
|
T: FromRuntimeValueInternal,
|
||||||
.pop_as::<u32>();
|
T: LittleEndianConvert,
|
||||||
let address =
|
{
|
||||||
effective_address(
|
let stack_value = self.value_stack.pop_as::<T>();
|
||||||
offset,
|
let raw_address = self.value_stack.pop_as::<u32>();
|
||||||
raw_address,
|
let address = effective_address(offset, raw_address)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
let m = context
|
let m = context
|
||||||
.memory()
|
.memory()
|
||||||
|
@ -676,15 +672,11 @@ impl Interpreter {
|
||||||
offset: u32,
|
offset: u32,
|
||||||
) -> Result<InstructionOutcome, TrapKind>
|
) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValueInternal,
|
||||||
T: WrapInto<U>,
|
T: WrapInto<U>,
|
||||||
U: LittleEndianConvert,
|
U: LittleEndianConvert,
|
||||||
{
|
{
|
||||||
let stack_value: T = self
|
let stack_value: T = <_>::from_runtime_value_internal(self.value_stack.pop());
|
||||||
.value_stack
|
|
||||||
.pop()
|
|
||||||
.try_into()
|
|
||||||
.expect("Due to validation value should be of proper type");
|
|
||||||
let stack_value = stack_value.wrap_into();
|
let stack_value = stack_value.wrap_into();
|
||||||
let raw_address = self
|
let raw_address = self
|
||||||
.value_stack
|
.value_stack
|
||||||
|
@ -707,9 +699,7 @@ impl Interpreter {
|
||||||
.memory()
|
.memory()
|
||||||
.expect("Due to validation memory should exists");
|
.expect("Due to validation memory should exists");
|
||||||
let s = m.current_size().0;
|
let s = m.current_size().0;
|
||||||
self
|
self.value_stack.push(RuntimeValueInternal(s as _))?;
|
||||||
.value_stack
|
|
||||||
.push(RuntimeValue::I32(s as i32))?;
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,83 +714,93 @@ impl Interpreter {
|
||||||
Ok(Pages(new_size)) => new_size as u32,
|
Ok(Pages(new_size)) => new_size as u32,
|
||||||
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
Err(_) => u32::MAX, // Returns -1 (or 0xFFFFFFFF) in case of error.
|
||||||
};
|
};
|
||||||
self
|
self.value_stack.push(RuntimeValueInternal(m as _))?;
|
||||||
.value_stack
|
|
||||||
.push(RuntimeValue::I32(m as i32))?;
|
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_const(&mut self, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
|
fn run_const(&mut self, val: RuntimeValue) -> Result<InstructionOutcome, TrapKind> {
|
||||||
self
|
self
|
||||||
.value_stack
|
.value_stack
|
||||||
.push(val)
|
.push(val.into())
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
.map(|_| InstructionOutcome::RunNextInstruction)
|
.map(|_| InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_relop<T, F>(&mut self, f: F) -> Result<InstructionOutcome, TrapKind>
|
fn run_relop<T, F>(&mut self, f: F) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValueInternal,
|
||||||
F: FnOnce(T, T) -> bool,
|
F: FnOnce(T, T) -> bool,
|
||||||
{
|
{
|
||||||
let (left, right) = self
|
let (left, right) = self
|
||||||
.value_stack
|
.value_stack
|
||||||
.pop_pair_as::<T>();
|
.pop_pair_as::<T>();
|
||||||
let v = if f(left, right) {
|
let v = if f(left, right) {
|
||||||
RuntimeValue::I32(1)
|
RuntimeValueInternal(1)
|
||||||
} else {
|
} else {
|
||||||
RuntimeValue::I32(0)
|
RuntimeValueInternal(0)
|
||||||
};
|
};
|
||||||
self.value_stack.push(v)?;
|
self.value_stack.push(v)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eqz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_eqz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue, T: PartialEq<T> + Default {
|
where
|
||||||
let v = self
|
T: FromRuntimeValueInternal,
|
||||||
.value_stack
|
T: PartialEq<T> + Default,
|
||||||
.pop_as::<T>();
|
{
|
||||||
let v = RuntimeValue::I32(if v == Default::default() { 1 } else { 0 });
|
let v = self.value_stack.pop_as::<T>();
|
||||||
|
let v = RuntimeValueInternal(if v == Default::default() { 1 } else { 0 });
|
||||||
self.value_stack.push(v)?;
|
self.value_stack.push(v)?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_eq<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_eq<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialEq<T>
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialEq<T>,
|
||||||
{
|
{
|
||||||
self.run_relop(|left: T, right: T| left == right)
|
self.run_relop(|left: T, right: T| left == right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ne<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_ne<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialEq<T> {
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialEq<T>,
|
||||||
|
{
|
||||||
self.run_relop(|left: T, right: T| left != right)
|
self.run_relop(|left: T, right: T| left != right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_lt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialOrd<T> {
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialOrd<T>,
|
||||||
|
{
|
||||||
self.run_relop(|left: T, right: T| left < right)
|
self.run_relop(|left: T, right: T| left < right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_gt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialOrd<T> {
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialOrd<T>,
|
||||||
|
{
|
||||||
self.run_relop(|left: T, right: T| left > right)
|
self.run_relop(|left: T, right: T| left > right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_lte<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_lte<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialOrd<T> {
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialOrd<T>,
|
||||||
|
{
|
||||||
self.run_relop(|left: T, right: T| left <= right)
|
self.run_relop(|left: T, right: T| left <= right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_gte<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_gte<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where T: FromRuntimeValue + PartialOrd<T> {
|
where
|
||||||
|
T: FromRuntimeValueInternal + PartialOrd<T>,
|
||||||
|
{
|
||||||
self.run_relop(|left: T, right: T| left >= right)
|
self.run_relop(|left: T, right: T| left >= right)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_unop<T, U, F>(&mut self, f: F) -> Result<InstructionOutcome, TrapKind>
|
fn run_unop<T, U, F>(&mut self, f: F) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
F: FnOnce(T) -> U,
|
F: FnOnce(T) -> U,
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValueInternal,
|
||||||
RuntimeValue: From<U>
|
RuntimeValueInternal: From<U>,
|
||||||
{
|
{
|
||||||
let v = self
|
let v = self
|
||||||
.value_stack
|
.value_stack
|
||||||
|
@ -811,55 +811,69 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_clz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_clz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Integer<T> + FromRuntimeValueInternal,
|
||||||
|
{
|
||||||
self.run_unop(|v: T| v.leading_zeros())
|
self.run_unop(|v: T| v.leading_zeros())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ctz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_ctz<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Integer<T> + FromRuntimeValueInternal,
|
||||||
|
{
|
||||||
self.run_unop(|v: T| v.trailing_zeros())
|
self.run_unop(|v: T| v.trailing_zeros())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_popcnt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_popcnt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Integer<T> + FromRuntimeValueInternal,
|
||||||
|
{
|
||||||
self.run_unop(|v: T| v.count_ones())
|
self.run_unop(|v: T| v.count_ones())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_add<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_add<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: ArithmeticOps<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.add(right);
|
let v = left.add(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sub<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_sub<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: ArithmeticOps<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.sub(right);
|
let v = left.sub(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mul<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_mul<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: ArithmeticOps<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: ArithmeticOps<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.mul(right);
|
let v = left.mul(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_div<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_div<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ArithmeticOps<U> + TransmuteInto<T> {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: TransmuteInto<U> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
U: ArithmeticOps<U> + TransmuteInto<T>,
|
||||||
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let (left, right) = (left.transmute_into(), right.transmute_into());
|
let (left, right) = (left.transmute_into(), right.transmute_into());
|
||||||
let v = left.div(right)?;
|
let v = left.div(right)?;
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
|
@ -868,10 +882,12 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rem<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_rem<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: Integer<U> + TransmuteInto<T> {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: TransmuteInto<U> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
U: Integer<U> + TransmuteInto<T>,
|
||||||
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let (left, right) = (left.transmute_into(), right.transmute_into());
|
let (left, right) = (left.transmute_into(), right.transmute_into());
|
||||||
let v = left.rem(right)?;
|
let v = left.rem(right)?;
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
|
@ -880,50 +896,57 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_and<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitAnd>::Output>, T: ops::BitAnd<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<<T as ops::BitAnd>::Output>,
|
||||||
.value_stack
|
T: ops::BitAnd<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.bitand(right);
|
let v = left.bitand(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_or<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_or<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitOr>::Output>, T: ops::BitOr<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<<T as ops::BitOr>::Output>,
|
||||||
.value_stack
|
T: ops::BitOr<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.bitor(right);
|
let v = left.bitor(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_xor<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_xor<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::BitXor>::Output>, T: ops::BitXor<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<<T as ops::BitXor>::Output>,
|
||||||
.value_stack
|
T: ops::BitXor<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.bitxor(right);
|
let v = left.bitxor(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shl<T>(&mut self, mask: T) -> Result<InstructionOutcome, TrapKind>
|
fn run_shl<T>(&mut self, mask: T) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<<T as ops::Shl<T>>::Output>, T: ops::Shl<T> + ops::BitAnd<T, Output=T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<<T as ops::Shl<T>>::Output>,
|
||||||
.value_stack
|
T: ops::Shl<T> + ops::BitAnd<T, Output = T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.shl(right & mask);
|
let v = left.shl(right & mask);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shr<T, U>(&mut self, mask: U) -> Result<InstructionOutcome, TrapKind>
|
fn run_shr<T, U>(&mut self, mask: U) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: TransmuteInto<U> + FromRuntimeValue, U: ops::Shr<U> + ops::BitAnd<U, Output=U>, <U as ops::Shr<U>>::Output: TransmuteInto<T> {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: TransmuteInto<U> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
U: ops::Shr<U> + ops::BitAnd<U, Output = U>,
|
||||||
|
<U as ops::Shr<U>>::Output: TransmuteInto<T>,
|
||||||
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let (left, right) = (left.transmute_into(), right.transmute_into());
|
let (left, right) = (left.transmute_into(), right.transmute_into());
|
||||||
let v = left.shr(right & mask);
|
let v = left.shr(right & mask);
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
|
@ -932,17 +955,20 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotl<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotl<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: Integer<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.rotl(right);
|
let v = left.rotl(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_rotr<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_rotr<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Integer<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Integer<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
let (left, right) = self
|
let (left, right) = self
|
||||||
.value_stack
|
.value_stack
|
||||||
|
@ -953,51 +979,65 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_abs<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_abs<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.abs())
|
self.run_unop(|v: T| v.abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_neg<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_neg<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<<T as ops::Neg>::Output>,
|
RuntimeValueInternal: From<<T as ops::Neg>::Output>,
|
||||||
T: ops::Neg + FromRuntimeValue
|
T: ops::Neg + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.neg())
|
self.run_unop(|v: T| v.neg())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_ceil<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_ceil<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.ceil())
|
self.run_unop(|v: T| v.ceil())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_floor<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_floor<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.floor())
|
self.run_unop(|v: T| v.floor())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_trunc<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.trunc())
|
self.run_unop(|v: T| v.trunc())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_nearest<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_nearest<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.nearest())
|
self.run_unop(|v: T| v.nearest())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sqrt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_sqrt<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
self.run_unop(|v: T| v.sqrt())
|
self.run_unop(|v: T| v.sqrt())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_min<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_min<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue
|
where
|
||||||
|
RuntimeValueInternal: From<T>,
|
||||||
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
let (left, right) = self
|
let (left, right) = self
|
||||||
.value_stack
|
.value_stack
|
||||||
|
@ -1008,35 +1048,42 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_max<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_max<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.max(right);
|
let v = left.max(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_copysign<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_copysign<T>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<T>, T: Float<T> + FromRuntimeValue {
|
where
|
||||||
let (left, right) = self
|
RuntimeValueInternal: From<T>,
|
||||||
.value_stack
|
T: Float<T> + FromRuntimeValueInternal,
|
||||||
.pop_pair_as::<T>();
|
{
|
||||||
|
let (left, right) = self.value_stack.pop_pair_as::<T>();
|
||||||
let v = left.copysign(right);
|
let v = left.copysign(right);
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_wrap<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_wrap<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<U>, T: WrapInto<U> + FromRuntimeValue {
|
where
|
||||||
|
RuntimeValueInternal: From<U>,
|
||||||
|
T: WrapInto<U> + FromRuntimeValueInternal,
|
||||||
|
{
|
||||||
self.run_unop(|v: T| v.wrap_into())
|
self.run_unop(|v: T| v.wrap_into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_trunc_to_int<T, U, V>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_trunc_to_int<T, U, V>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where RuntimeValue: From<V>, T: TryTruncateInto<U, TrapKind> + FromRuntimeValue, U: TransmuteInto<V>, {
|
where
|
||||||
let v = self
|
RuntimeValueInternal: From<V>,
|
||||||
.value_stack
|
T: TryTruncateInto<U, TrapKind> + FromRuntimeValueInternal,
|
||||||
.pop_as::<T>();
|
U: TransmuteInto<V>,
|
||||||
|
{
|
||||||
|
let v = self.value_stack.pop_as::<T>();
|
||||||
|
|
||||||
v.try_truncate_into()
|
v.try_truncate_into()
|
||||||
.map(|v| v.transmute_into())
|
.map(|v| v.transmute_into())
|
||||||
|
@ -1046,11 +1093,11 @@ impl Interpreter {
|
||||||
|
|
||||||
fn run_extend<T, U, V>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_extend<T, U, V>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<V>, T: ExtendInto<U> + FromRuntimeValue, U: TransmuteInto<V>
|
RuntimeValueInternal: From<V>,
|
||||||
|
T: ExtendInto<U> + FromRuntimeValueInternal,
|
||||||
|
U: TransmuteInto<V>,
|
||||||
{
|
{
|
||||||
let v = self
|
let v = self.value_stack.pop_as::<T>();
|
||||||
.value_stack
|
|
||||||
.pop_as::<T>();
|
|
||||||
|
|
||||||
let v = v.extend_into().transmute_into();
|
let v = v.extend_into().transmute_into();
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
|
@ -1060,11 +1107,11 @@ impl Interpreter {
|
||||||
|
|
||||||
fn run_reinterpret<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
fn run_reinterpret<T, U>(&mut self) -> Result<InstructionOutcome, TrapKind>
|
||||||
where
|
where
|
||||||
RuntimeValue: From<U>, T: FromRuntimeValue, T: TransmuteInto<U>
|
RuntimeValueInternal: From<U>,
|
||||||
|
T: FromRuntimeValueInternal,
|
||||||
|
T: TransmuteInto<U>,
|
||||||
{
|
{
|
||||||
let v = self
|
let v = self.value_stack.pop_as::<T>();
|
||||||
.value_stack
|
|
||||||
.pop_as::<T>();
|
|
||||||
|
|
||||||
let v = v.transmute_into();
|
let v = v.transmute_into();
|
||||||
self.value_stack.push(v.into())?;
|
self.value_stack.push(v.into())?;
|
||||||
|
@ -1108,11 +1155,11 @@ impl FunctionContext {
|
||||||
pub fn initialize(&mut self, locals: &[Local], value_stack: &mut ValueStack) -> Result<(), TrapKind> {
|
pub fn initialize(&mut self, locals: &[Local], value_stack: &mut ValueStack) -> Result<(), TrapKind> {
|
||||||
debug_assert!(!self.is_initialized);
|
debug_assert!(!self.is_initialized);
|
||||||
|
|
||||||
let locals = locals.iter()
|
let num_locals = locals
|
||||||
.flat_map(|l| repeat(l.value_type()).take(l.count() as usize))
|
.iter()
|
||||||
.map(::types::ValueType::from_elements)
|
.map(|l| l.count() as usize)
|
||||||
.map(RuntimeValue::default)
|
.sum();
|
||||||
.collect::<Vec<_>>();
|
let locals = vec![Default::default(); num_locals];
|
||||||
|
|
||||||
// TODO: Replace with extend.
|
// TODO: Replace with extend.
|
||||||
for local in locals {
|
for local in locals {
|
||||||
|
@ -1150,14 +1197,14 @@ fn prepare_function_args(
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
caller_stack: &mut ValueStack,
|
caller_stack: &mut ValueStack,
|
||||||
) -> Vec<RuntimeValue> {
|
) -> Vec<RuntimeValue> {
|
||||||
let mut args = signature
|
let mut out = signature
|
||||||
.params()
|
.params()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|_| caller_stack.pop())
|
.rev()
|
||||||
|
.map(|¶m_ty| caller_stack.pop().with_type(param_ty))
|
||||||
.collect::<Vec<RuntimeValue>>();
|
.collect::<Vec<RuntimeValue>>();
|
||||||
args.reverse();
|
out.reverse();
|
||||||
check_function_args(signature, &args).expect("Due to validation arguments should match");
|
out
|
||||||
args
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Trap> {
|
pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Trap> {
|
||||||
|
@ -1179,7 +1226,7 @@ pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Resu
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ValueStack {
|
struct ValueStack {
|
||||||
buf: Box<[RuntimeValue]>,
|
buf: Box<[RuntimeValueInternal]>,
|
||||||
/// Index of the first free place in the stack.
|
/// Index of the first free place in the stack.
|
||||||
sp: usize,
|
sp: usize,
|
||||||
}
|
}
|
||||||
|
@ -1187,7 +1234,7 @@ struct ValueStack {
|
||||||
impl ValueStack {
|
impl ValueStack {
|
||||||
fn with_limit(limit: usize) -> ValueStack {
|
fn with_limit(limit: usize) -> ValueStack {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
buf.resize(limit, RuntimeValue::I32(0));
|
buf.resize(limit, RuntimeValueInternal(0));
|
||||||
|
|
||||||
ValueStack {
|
ValueStack {
|
||||||
buf: buf.into_boxed_slice(),
|
buf: buf.into_boxed_slice(),
|
||||||
|
@ -1209,16 +1256,17 @@ impl ValueStack {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop_as<T>(&mut self) -> T
|
fn pop_as<T>(&mut self) -> T
|
||||||
where
|
where
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
value.try_into().expect("Due to validation stack top's type should match")
|
|
||||||
|
T::from_runtime_value_internal(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop_pair_as<T>(&mut self) -> (T, T)
|
fn pop_pair_as<T>(&mut self) -> (T, T)
|
||||||
where
|
where
|
||||||
T: FromRuntimeValue,
|
T: FromRuntimeValueInternal,
|
||||||
{
|
{
|
||||||
let right = self.pop_as();
|
let right = self.pop_as();
|
||||||
let left = self.pop_as();
|
let left = self.pop_as();
|
||||||
|
@ -1226,7 +1274,13 @@ impl ValueStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop_triple(&mut self) -> (RuntimeValue, RuntimeValue, RuntimeValue) {
|
fn pop_triple(
|
||||||
|
&mut self,
|
||||||
|
) -> (
|
||||||
|
RuntimeValueInternal,
|
||||||
|
RuntimeValueInternal,
|
||||||
|
RuntimeValueInternal,
|
||||||
|
) {
|
||||||
let right = self.pop();
|
let right = self.pop();
|
||||||
let mid = self.pop();
|
let mid = self.pop();
|
||||||
let left = self.pop();
|
let left = self.pop();
|
||||||
|
@ -1234,28 +1288,31 @@ impl ValueStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn top(&self) -> &RuntimeValue {
|
fn top(&self) -> &RuntimeValueInternal {
|
||||||
self.pick(1)
|
self.pick(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick(&self, depth: usize) -> &RuntimeValue {
|
fn pick(&self, depth: usize) -> &RuntimeValueInternal {
|
||||||
&self.buf[self.sp - depth]
|
&self.buf[self.sp - depth]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pick_mut(&mut self, depth: usize) -> &mut RuntimeValue {
|
fn pick_mut(&mut self, depth: usize) -> &mut RuntimeValueInternal {
|
||||||
&mut self.buf[self.sp - depth]
|
&mut self.buf[self.sp - depth]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pop(&mut self) -> RuntimeValue {
|
fn pop(&mut self) -> RuntimeValueInternal {
|
||||||
self.sp -= 1;
|
self.sp -= 1;
|
||||||
self.buf[self.sp]
|
self.buf[self.sp]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push(&mut self, value: RuntimeValue) -> Result<(), TrapKind> {
|
fn push(&mut self, value: RuntimeValueInternal) -> Result<(), TrapKind> {
|
||||||
let cell = self.buf.get_mut(self.sp).ok_or_else(|| TrapKind::StackOverflow)?;
|
let cell = self
|
||||||
|
.buf
|
||||||
|
.get_mut(self.sp)
|
||||||
|
.ok_or_else(|| TrapKind::StackOverflow)?;
|
||||||
*cell = value;
|
*cell = value;
|
||||||
self.sp += 1;
|
self.sp += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
107
src/value.rs
107
src/value.rs
|
@ -27,6 +27,93 @@ pub enum RuntimeValue {
|
||||||
F64(F64),
|
F64(F64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||||
|
pub(crate) struct RuntimeValueInternal(pub u64);
|
||||||
|
|
||||||
|
impl RuntimeValueInternal {
|
||||||
|
pub fn with_type(self, ty: ValueType) -> RuntimeValue {
|
||||||
|
match ty {
|
||||||
|
ValueType::I32 => RuntimeValue::I32(<_>::from_runtime_value_internal(self)),
|
||||||
|
ValueType::I64 => RuntimeValue::I64(<_>::from_runtime_value_internal(self)),
|
||||||
|
ValueType::F32 => RuntimeValue::F32(<_>::from_runtime_value_internal(self)),
|
||||||
|
ValueType::F64 => RuntimeValue::F64(<_>::from_runtime_value_internal(self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait FromRuntimeValueInternal
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
fn from_runtime_value_internal(val: RuntimeValueInternal) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_runtime_value_internal {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl FromRuntimeValueInternal for $t {
|
||||||
|
fn from_runtime_value_internal(
|
||||||
|
RuntimeValueInternal(val): RuntimeValueInternal,
|
||||||
|
) -> Self {
|
||||||
|
val as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$t> for RuntimeValueInternal {
|
||||||
|
fn from(other: $t) -> Self {
|
||||||
|
RuntimeValueInternal(other as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_runtime_value_internal_float {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl FromRuntimeValueInternal for $t {
|
||||||
|
fn from_runtime_value_internal(
|
||||||
|
RuntimeValueInternal(val): RuntimeValueInternal,
|
||||||
|
) -> Self {
|
||||||
|
<$t>::from_bits(val as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$t> for RuntimeValueInternal {
|
||||||
|
fn from(other: $t) -> Self {
|
||||||
|
RuntimeValueInternal(other.to_bits() as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_runtime_value_internal!(i8, u8, i16, u16, i32, u32, i64, u64);
|
||||||
|
impl_from_runtime_value_internal_float!(f32, f64, F32, F64);
|
||||||
|
|
||||||
|
impl From<bool> for RuntimeValueInternal {
|
||||||
|
fn from(other: bool) -> Self {
|
||||||
|
(if other { 1 } else { 0 }).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromRuntimeValueInternal for bool {
|
||||||
|
fn from_runtime_value_internal(RuntimeValueInternal(val): RuntimeValueInternal) -> Self {
|
||||||
|
val != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RuntimeValue> for RuntimeValueInternal {
|
||||||
|
fn from(other: RuntimeValue) -> Self {
|
||||||
|
match other {
|
||||||
|
RuntimeValue::I32(val) => val.into(),
|
||||||
|
RuntimeValue::I64(val) => val.into(),
|
||||||
|
RuntimeValue::F32(val) => val.into(),
|
||||||
|
RuntimeValue::F64(val) => val.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait for creating value from a [`RuntimeValue`].
|
/// Trait for creating value from a [`RuntimeValue`].
|
||||||
///
|
///
|
||||||
/// Typically each implementation can create a value from the specific type.
|
/// Typically each implementation can create a value from the specific type.
|
||||||
|
@ -132,12 +219,12 @@ pub trait Float<T>: ArithmeticOps<T> {
|
||||||
|
|
||||||
impl RuntimeValue {
|
impl RuntimeValue {
|
||||||
/// Creates new default value of given type.
|
/// Creates new default value of given type.
|
||||||
pub fn default(value_type: ::types::ValueType) -> Self {
|
pub fn default(value_type: ValueType) -> Self {
|
||||||
match value_type {
|
match value_type {
|
||||||
::types::ValueType::I32 => RuntimeValue::I32(0),
|
ValueType::I32 => RuntimeValue::I32(0),
|
||||||
::types::ValueType::I64 => RuntimeValue::I64(0),
|
ValueType::I64 => RuntimeValue::I64(0),
|
||||||
::types::ValueType::F32 => RuntimeValue::F32(0f32.into()),
|
ValueType::F32 => RuntimeValue::F32(0f32.into()),
|
||||||
::types::ValueType::F64 => RuntimeValue::F64(0f64.into()),
|
ValueType::F64 => RuntimeValue::F64(0f64.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +239,12 @@ impl RuntimeValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get variable type for this value.
|
/// Get variable type for this value.
|
||||||
pub fn value_type(&self) -> ::types::ValueType {
|
pub fn value_type(&self) -> ValueType {
|
||||||
match *self {
|
match *self {
|
||||||
RuntimeValue::I32(_) => ::types::ValueType::I32,
|
RuntimeValue::I32(_) => ValueType::I32,
|
||||||
RuntimeValue::I64(_) => ::types::ValueType::I64,
|
RuntimeValue::I64(_) => ValueType::I64,
|
||||||
RuntimeValue::F32(_) => ::types::ValueType::F32,
|
RuntimeValue::F32(_) => ValueType::F32,
|
||||||
RuntimeValue::F64(_) => ::types::ValueType::F64,
|
RuntimeValue::F64(_) => ValueType::F64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue