use crate::{
vm::{call_frame::AbruptCompletionRecord, opcode::Operation, CompletionType},
Context, JsResult,
};
pub(crate) struct Continue;
impl Operation for Continue {
const NAME: &'static str = "Continue";
const INSTRUCTION: &'static str = "INST - Continue";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let jump_address = context.vm.read::<u32>();
let target_address = context.vm.read::<u32>();
let mut envs_to_pop = 0;
let mut found_target = false;
for i in (0..context.vm.frame().env_stack.len()).rev() {
if found_target {
break;
}
let Some(env_entry) = context.vm.frame_mut().env_stack.get_mut(i) else {
break;
};
if (env_entry.is_finally_env() && jump_address == env_entry.start_address())
|| (jump_address == target_address && jump_address == env_entry.start_address())
{
found_target = true;
continue;
}
envs_to_pop += env_entry.env_num();
if jump_address > target_address && jump_address == env_entry.exit_address() {
found_target = true;
context.vm.frame_mut().env_stack.pop();
continue;
}
context.vm.frame_mut().env_stack.pop();
}
let env_truncation_len = context.vm.environments.len().saturating_sub(envs_to_pop);
context.vm.environments.truncate(env_truncation_len);
let new_record = AbruptCompletionRecord::new_continue().with_initial_target(target_address);
context.vm.frame_mut().abrupt_completion = Some(new_record);
context.vm.frame_mut().pc = jump_address;
Ok(CompletionType::Normal)
}
}