use crate::{
error::JsNativeError,
vm::{opcode::Operation, CompletionType},
Context, JsResult,
};
#[derive(Debug, Clone, Copy)]
pub(crate) struct New;
impl Operation for New {
const NAME: &'static str = "New";
const INSTRUCTION: &'static str = "INST - New";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() {
return Err(JsNativeError::runtime_limit()
.with_message(format!(
"Maximum recursion limit {} exceeded",
context.vm.runtime_limits.recursion_limit()
))
.into());
}
if context.vm.runtime_limits.stack_size_limit() <= context.vm.stack.len() {
return Err(JsNativeError::runtime_limit()
.with_message("Maximum call stack size exceeded")
.into());
}
let argument_count = context.vm.read::<u32>();
let mut arguments = Vec::with_capacity(argument_count as usize);
for _ in 0..argument_count {
arguments.push(context.vm.pop());
}
arguments.reverse();
let func = context.vm.pop();
let result = func
.as_constructor()
.ok_or_else(|| {
JsNativeError::typ()
.with_message("not a constructor")
.into()
})
.and_then(|cons| cons.__construct__(&arguments, cons, context))?;
context.vm.push(result);
Ok(CompletionType::Normal)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct NewSpread;
impl Operation for NewSpread {
const NAME: &'static str = "NewSpread";
const INSTRUCTION: &'static str = "INST - NewSpread";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
if context.vm.runtime_limits.recursion_limit() <= context.vm.frames.len() {
return Err(JsNativeError::runtime_limit()
.with_message(format!(
"Maximum recursion limit {} exceeded",
context.vm.runtime_limits.recursion_limit()
))
.into());
}
if context.vm.runtime_limits.stack_size_limit() <= context.vm.stack.len() {
return Err(JsNativeError::runtime_limit()
.with_message("Maximum call stack size exceeded")
.into());
}
let arguments_array = context.vm.pop();
let arguments_array_object = arguments_array
.as_object()
.expect("arguments array in call spread function must be an object");
let arguments = arguments_array_object
.borrow()
.properties()
.dense_indexed_properties()
.expect("arguments array in call spread function must be dense")
.clone();
let func = context.vm.pop();
let result = func
.as_constructor()
.ok_or_else(|| {
JsNativeError::typ()
.with_message("not a constructor")
.into()
})
.and_then(|cons| cons.__construct__(&arguments, cons, context))?;
context.vm.push(result);
Ok(CompletionType::Normal)
}
}