use std::ops::ControlFlow;
use crate::{
Context, JsError, JsNativeError,
vm::{
CompletionRecord,
opcode::{Operation, VaryingOperand},
},
};
#[derive(Debug, Clone, Copy)]
pub(crate) struct Throw;
impl Throw {
#[inline(always)]
pub(crate) fn operation(
value: VaryingOperand,
context: &mut Context,
) -> ControlFlow<CompletionRecord> {
let value = context.vm.get_register(value.into());
let error = JsError::from_opaque(value.clone());
context.vm.pending_exception = Some(error);
let pc = context.vm.frame().pc - 1;
if context.vm.handle_exception_at(pc) {
return ControlFlow::Continue(());
}
context.handle_throw()
}
}
impl Operation for Throw {
const NAME: &'static str = "Throw";
const INSTRUCTION: &'static str = "INST - Throw";
const COST: u8 = 6;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ReThrow;
impl ReThrow {
#[inline(always)]
pub(crate) fn operation((): (), context: &mut Context) -> ControlFlow<CompletionRecord> {
let pc = context.vm.frame().pc.saturating_sub(1);
if context.vm.handle_exception_at(pc) {
return ControlFlow::Continue(());
}
if context.vm.pending_exception.is_none() {
return context.handle_return();
}
context.handle_throw()
}
}
impl Operation for ReThrow {
const NAME: &'static str = "ReThrow";
const INSTRUCTION: &'static str = "INST - ReThrow";
const COST: u8 = 2;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Exception;
impl Exception {
#[inline(always)]
pub(crate) fn operation(
dst: VaryingOperand,
context: &mut Context,
) -> ControlFlow<CompletionRecord> {
if let Some(error) = context.vm.pending_exception.take() {
let error = error.to_opaque(context);
context.vm.set_register(dst.into(), error);
return ControlFlow::Continue(());
}
ReThrow::operation((), context)
}
}
impl Operation for Exception {
const NAME: &'static str = "Exception";
const INSTRUCTION: &'static str = "INST - Exception";
const COST: u8 = 2;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct MaybeException;
impl MaybeException {
#[inline(always)]
pub(crate) fn operation(
(has_exception, exception): (VaryingOperand, VaryingOperand),
context: &mut Context,
) {
if let Some(error) = context.vm.pending_exception.take() {
let error = error.to_opaque(context);
context.vm.set_register(exception.into(), error);
context.vm.set_register(has_exception.into(), true.into());
} else {
context.vm.set_register(has_exception.into(), false.into());
}
}
}
impl Operation for MaybeException {
const NAME: &'static str = "MaybeException";
const INSTRUCTION: &'static str = "INST - MaybeException";
const COST: u8 = 3;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowNewTypeError;
impl ThrowNewTypeError {
#[inline(always)]
pub(crate) fn operation(index: VaryingOperand, context: &mut Context) -> JsError {
let msg = context
.vm
.frame()
.code_block()
.constant_string(index.into());
let msg = msg
.to_std_string()
.expect("throw message must be an ASCII string");
JsNativeError::typ().with_message(msg).into()
}
}
impl Operation for ThrowNewTypeError {
const NAME: &'static str = "ThrowNewTypeError";
const INSTRUCTION: &'static str = "INST - ThrowNewTypeError";
const COST: u8 = 2;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowNewSyntaxError;
impl ThrowNewSyntaxError {
#[inline(always)]
pub(crate) fn operation(index: VaryingOperand, context: &mut Context) -> JsError {
let msg = context
.vm
.frame()
.code_block()
.constant_string(index.into());
let msg = msg
.to_std_string()
.expect("throw message must be an ASCII string");
JsNativeError::syntax().with_message(msg).into()
}
}
impl Operation for ThrowNewSyntaxError {
const NAME: &'static str = "ThrowNewSyntaxError";
const INSTRUCTION: &'static str = "INST - ThrowNewSyntaxError";
const COST: u8 = 2;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ThrowNewReferenceError;
impl ThrowNewReferenceError {
#[inline(always)]
pub(crate) fn operation(index: VaryingOperand, context: &mut Context) -> JsError {
let msg = context
.vm
.frame()
.code_block()
.constant_string(index.into());
let msg = msg
.to_std_string()
.expect("throw message must be an ASCII string");
JsNativeError::reference().with_message(msg).into()
}
}
impl Operation for ThrowNewReferenceError {
const NAME: &'static str = "ThrowNewReferenceError";
const INSTRUCTION: &'static str = "INST - ThrowNewReferenceError";
const COST: u8 = 2;
}