diff --git a/src/runner.rs b/src/runner.rs index 5a9ec84..2d7c53a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1109,11 +1109,7 @@ impl FunctionContext { .map(RuntimeValue::default) .collect::>(); - // TODO: Replace with extend. - for local in locals { - value_stack.push(local) - .map_err(|_| TrapKind::StackOverflow)?; - } + value_stack.extend(&locals)?; self.is_initialized = true; Ok(()) @@ -1263,8 +1259,78 @@ impl ValueStack { Ok(()) } + #[inline] + fn extend(&mut self, values: &[RuntimeValue]) -> Result<(), TrapKind> { + let avail_len = self.buf.len() - self.sp; + let to_copy_len = values.len(); + + if to_copy_len <= avail_len { + self.buf[self.sp..(self.sp+to_copy_len)].copy_from_slice(&values[..to_copy_len]); + self.sp += to_copy_len; + Ok(()) + } else { + Err(TrapKind::StackOverflow) + } + } + #[inline] fn len(&self) -> usize { self.sp } } + +#[cfg(test)] +mod tests { + use super::ValueStack; + use value::RuntimeValue; + + #[test] + fn test_stack_extend() { + let mut stack = ValueStack::with_limit(5); + let values = vec![ + RuntimeValue::I32(1), + RuntimeValue::I32(2), + RuntimeValue::I32(3), + RuntimeValue::I32(4), + RuntimeValue::I32(5) + ]; + + assert!(stack.extend(&values).is_ok()); + assert_eq!(stack.len(), 5); + + assert!(stack.push(RuntimeValue::I32(6)).is_err()); + + // check each elements + assert_eq!(stack.pop(), RuntimeValue::I32(5)); + assert_eq!(stack.pop(), RuntimeValue::I32(4)); + assert_eq!(stack.pop(), RuntimeValue::I32(3)); + assert_eq!(stack.pop(), RuntimeValue::I32(2)); + assert_eq!(stack.pop(), RuntimeValue::I32(1)); + + assert_eq!(stack.len(), 0); + } + + #[test] + fn test_stack_extend_overflow() { + let mut stack = ValueStack::with_limit(4); + let values = vec![ + RuntimeValue::I32(1), + RuntimeValue::I32(2), + RuntimeValue::I32(3), + RuntimeValue::I32(4), + RuntimeValue::I32(5) + ]; + + assert!(stack.extend(&values).is_err()); + assert_eq!(stack.len(), 0); + + assert!(stack.push(RuntimeValue::I32(6)).is_ok()); + + assert_eq!(stack.len(), 1); + + // check each elements + assert_eq!(stack.pop(), RuntimeValue::I32(6)); + + assert_eq!(stack.len(), 0); + } +}