diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index f9dba8a601..5013bbb0e7 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -259,7 +259,7 @@ impl CodeBlock { /// Returns an empty `String` if no operands are present. #[cfg(any(feature = "trace", feature = "flowgraph"))] pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { - let opcode: Opcode = self.bytecode[*pc].try_into().expect("invalid opcode"); + let opcode: Opcode = self.bytecode[*pc].into(); *pc += size_of::(); match opcode { Opcode::SetFunctionName => { @@ -557,6 +557,62 @@ impl CodeBlock { | Opcode::PopPrivateEnvironment | Opcode::ImportCall | Opcode::Nop => String::new(), + Opcode::Reserved1 + | Opcode::Reserved2 + | Opcode::Reserved3 + | Opcode::Reserved4 + | Opcode::Reserved5 + | Opcode::Reserved6 + | Opcode::Reserved7 + | Opcode::Reserved8 + | Opcode::Reserved9 + | Opcode::Reserved10 + | Opcode::Reserved11 + | Opcode::Reserved12 + | Opcode::Reserved13 + | Opcode::Reserved14 + | Opcode::Reserved15 + | Opcode::Reserved16 + | Opcode::Reserved17 + | Opcode::Reserved18 + | Opcode::Reserved19 + | Opcode::Reserved20 + | Opcode::Reserved21 + | Opcode::Reserved22 + | Opcode::Reserved23 + | Opcode::Reserved24 + | Opcode::Reserved25 + | Opcode::Reserved26 + | Opcode::Reserved27 + | Opcode::Reserved28 + | Opcode::Reserved29 + | Opcode::Reserved30 + | Opcode::Reserved31 + | Opcode::Reserved32 + | Opcode::Reserved33 + | Opcode::Reserved34 + | Opcode::Reserved35 + | Opcode::Reserved36 + | Opcode::Reserved37 + | Opcode::Reserved38 + | Opcode::Reserved39 + | Opcode::Reserved40 + | Opcode::Reserved41 + | Opcode::Reserved42 + | Opcode::Reserved43 + | Opcode::Reserved44 + | Opcode::Reserved45 + | Opcode::Reserved46 + | Opcode::Reserved47 + | Opcode::Reserved48 + | Opcode::Reserved49 + | Opcode::Reserved50 + | Opcode::Reserved51 + | Opcode::Reserved52 + | Opcode::Reserved53 + | Opcode::Reserved54 + | Opcode::Reserved55 + | Opcode::Reserved56 => unreachable!("Reserved opcodes are unrechable"), } } } @@ -579,7 +635,7 @@ impl ToInternedString for CodeBlock { let mut pc = 0; let mut count = 0; while pc < self.bytecode.len() { - let opcode: Opcode = self.bytecode[pc].try_into().expect("invalid opcode"); + let opcode: Opcode = self.bytecode[pc].into(); let opcode = opcode.as_str(); let previous_pc = pc; let operands = self.instruction_operands(&mut pc, interner); diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index 35ab5b4f41..4bca8be4f1 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -32,7 +32,7 @@ impl CodeBlock { let mut pc = 0; while pc < self.bytecode.len() { - let opcode: Opcode = self.bytecode[pc].try_into().expect("invalid opcode"); + let opcode: Opcode = self.bytecode[pc].into(); let opcode_str = opcode.as_str(); let previous_pc = pc; @@ -622,6 +622,62 @@ impl CodeBlock { returns.push(previous_pc); } } + Opcode::Reserved1 + | Opcode::Reserved2 + | Opcode::Reserved3 + | Opcode::Reserved4 + | Opcode::Reserved5 + | Opcode::Reserved6 + | Opcode::Reserved7 + | Opcode::Reserved8 + | Opcode::Reserved9 + | Opcode::Reserved10 + | Opcode::Reserved11 + | Opcode::Reserved12 + | Opcode::Reserved13 + | Opcode::Reserved14 + | Opcode::Reserved15 + | Opcode::Reserved16 + | Opcode::Reserved17 + | Opcode::Reserved18 + | Opcode::Reserved19 + | Opcode::Reserved20 + | Opcode::Reserved21 + | Opcode::Reserved22 + | Opcode::Reserved23 + | Opcode::Reserved24 + | Opcode::Reserved25 + | Opcode::Reserved26 + | Opcode::Reserved27 + | Opcode::Reserved28 + | Opcode::Reserved29 + | Opcode::Reserved30 + | Opcode::Reserved31 + | Opcode::Reserved32 + | Opcode::Reserved33 + | Opcode::Reserved34 + | Opcode::Reserved35 + | Opcode::Reserved36 + | Opcode::Reserved37 + | Opcode::Reserved38 + | Opcode::Reserved39 + | Opcode::Reserved40 + | Opcode::Reserved41 + | Opcode::Reserved42 + | Opcode::Reserved43 + | Opcode::Reserved44 + | Opcode::Reserved45 + | Opcode::Reserved46 + | Opcode::Reserved47 + | Opcode::Reserved48 + | Opcode::Reserved49 + | Opcode::Reserved50 + | Opcode::Reserved51 + | Opcode::Reserved52 + | Opcode::Reserved53 + | Opcode::Reserved54 + | Opcode::Reserved55 + | Opcode::Reserved56 => unreachable!("Reserved opcodes are unrechable"), } } diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 0fcce8ad75..50d91ba76a 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -16,7 +16,7 @@ use crate::{ use boa_gc::{custom_trace, Finalize, Gc, Trace}; use boa_profiler::Profiler; -use std::{convert::TryInto, mem::size_of}; +use std::mem::size_of; #[cfg(feature = "trace")] use boa_interner::ToInternedString; @@ -160,10 +160,12 @@ impl Context<'_> { fn execute_instruction(&mut self) -> JsResult { let opcode: Opcode = { let _timer = Profiler::global().start_event("Opcode retrieval", "vm"); - let opcode = self.vm.frame().code_block.bytecode[self.vm.frame().pc as usize] - .try_into() - .expect("could not convert code at PC to opcode"); - self.vm.frame_mut().pc += 1; + + let frame = self.vm.frame_mut(); + + let pc = frame.pc; + let opcode = Opcode::from(frame.code_block.bytecode[pc as usize]); + frame.pc += 1; opcode }; diff --git a/boa_engine/src/vm/opcode/mod.rs b/boa_engine/src/vm/opcode/mod.rs index 4dd00b2a5e..a4827bbfbc 100644 --- a/boa_engine/src/vm/opcode/mod.rs +++ b/boa_engine/src/vm/opcode/mod.rs @@ -1,8 +1,6 @@ /// The opcodes of the vm. use crate::{vm::CompletionType, Context, JsResult}; -use num_enum::TryFromPrimitive; - // Operation modules mod await_stm; mod binary_ops; @@ -92,12 +90,15 @@ pub(crate) use unary_ops::*; pub(crate) use value::*; macro_rules! generate_impl { + ( name $name:ident ) => { $name }; + ( name $name:ident => $mapping:ident ) => { $mapping }; + ( $(#[$outer:meta])* pub enum $Type:ident { $( $(#[$inner:ident $($args:tt)*])* - $Variant:ident $(= $index:expr)* + $Variant:ident $(=> $mapping:ident)? $(= $index:expr)* ),* $(,)? } @@ -111,22 +112,24 @@ macro_rules! generate_impl { ),* } - impl $Type { - - /// Create opcode from `u8` byte. - /// - /// # Safety - /// - /// Does not check if `u8` type is a valid `Opcode`. - #[must_use] - pub unsafe fn from_raw(value: u8) -> Self { - // Safety: - // The caller is responsible for ensuring that the value is a valid opcode. - unsafe { std::mem::transmute(value) } + impl From for Opcode { + #[inline] + #[allow(non_upper_case_globals)] + fn from(value: u8) -> Self { + $( + const $Variant: u8 = Opcode::$Variant as u8; + )* + match value { + $($Variant => Self::$Variant),* + } } + } + + impl $Type { + const MAX: usize = 2usize.pow(8); - const NAMES: &[&'static str] = &[ - $($Variant::NAME),* + const NAMES: [&'static str; Self::MAX] = [ + $( $mapping)?)>::NAME),* ]; /// Name of this opcode. @@ -135,8 +138,8 @@ macro_rules! generate_impl { Self::NAMES[self as usize] } - const INSTRUCTIONS: &[&'static str] = &[ - $($Variant::INSTRUCTION),* + const INSTRUCTIONS: [&'static str; Self::MAX] = [ + $( $mapping)?)>::INSTRUCTION),* ]; /// Name of the profiler event for this opcode. @@ -145,8 +148,8 @@ macro_rules! generate_impl { Self::INSTRUCTIONS[self as usize] } - const EXECUTE_FNS: &[fn(&mut Context<'_>) -> JsResult] = &[ - $($Variant::execute),* + const EXECUTE_FNS: [fn(&mut Context<'_>) -> JsResult; Self::MAX] = [ + $( $mapping)?)>::execute),* ]; pub(super) fn execute(self, context: &mut Context<'_>) -> JsResult { @@ -170,7 +173,7 @@ pub(crate) trait Operation { } generate_impl! { - #[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum Opcode { /// Pop the top value from the stack. @@ -1655,9 +1658,120 @@ generate_impl! { /// Operands: /// /// Stack: **=>** - // Safety: Must be last in the list since, we use this for range checking - // in `TryFrom` impl. Nop, + + /// Reserved [`Opcode`]. + Reserved1 => Reserved, + /// Reserved [`Opcode`]. + Reserved2 => Reserved, + /// Reserved [`Opcode`]. + Reserved3 => Reserved, + /// Reserved [`Opcode`]. + Reserved4 => Reserved, + /// Reserved [`Opcode`]. + Reserved5 => Reserved, + /// Reserved [`Opcode`]. + Reserved6 => Reserved, + /// Reserved [`Opcode`]. + Reserved7 => Reserved, + /// Reserved [`Opcode`]. + Reserved8 => Reserved, + /// Reserved [`Opcode`]. + Reserved9 => Reserved, + /// Reserved [`Opcode`]. + Reserved10 => Reserved, + /// Reserved [`Opcode`]. + Reserved11 => Reserved, + /// Reserved [`Opcode`]. + Reserved12 => Reserved, + /// Reserved [`Opcode`]. + Reserved13 => Reserved, + /// Reserved [`Opcode`]. + Reserved14 => Reserved, + /// Reserved [`Opcode`]. + Reserved15 => Reserved, + /// Reserved [`Opcode`]. + Reserved16 => Reserved, + /// Reserved [`Opcode`]. + Reserved17 => Reserved, + /// Reserved [`Opcode`]. + Reserved18 => Reserved, + /// Reserved [`Opcode`]. + Reserved19 => Reserved, + /// Reserved [`Opcode`]. + Reserved20 => Reserved, + /// Reserved [`Opcode`]. + Reserved21 => Reserved, + /// Reserved [`Opcode`]. + Reserved22 => Reserved, + /// Reserved [`Opcode`]. + Reserved23 => Reserved, + /// Reserved [`Opcode`]. + Reserved24 => Reserved, + /// Reserved [`Opcode`]. + Reserved25 => Reserved, + /// Reserved [`Opcode`]. + Reserved26 => Reserved, + /// Reserved [`Opcode`]. + Reserved27 => Reserved, + /// Reserved [`Opcode`]. + Reserved28 => Reserved, + /// Reserved [`Opcode`]. + Reserved29 => Reserved, + /// Reserved [`Opcode`]. + Reserved30 => Reserved, + /// Reserved [`Opcode`]. + Reserved31 => Reserved, + /// Reserved [`Opcode`]. + Reserved32 => Reserved, + /// Reserved [`Opcode`]. + Reserved33 => Reserved, + /// Reserved [`Opcode`]. + Reserved34 => Reserved, + /// Reserved [`Opcode`]. + Reserved35 => Reserved, + /// Reserved [`Opcode`]. + Reserved36 => Reserved, + /// Reserved [`Opcode`]. + Reserved37 => Reserved, + /// Reserved [`Opcode`]. + Reserved38 => Reserved, + /// Reserved [`Opcode`]. + Reserved39 => Reserved, + /// Reserved [`Opcode`]. + Reserved40 => Reserved, + /// Reserved [`Opcode`]. + Reserved41 => Reserved, + /// Reserved [`Opcode`]. + Reserved42 => Reserved, + /// Reserved [`Opcode`]. + Reserved43 => Reserved, + /// Reserved [`Opcode`]. + Reserved44 => Reserved, + /// Reserved [`Opcode`]. + Reserved45 => Reserved, + /// Reserved [`Opcode`]. + Reserved46 => Reserved, + /// Reserved [`Opcode`]. + Reserved47 => Reserved, + /// Reserved [`Opcode`]. + Reserved48 => Reserved, + /// Reserved [`Opcode`]. + Reserved49 => Reserved, + /// Reserved [`Opcode`]. + Reserved50 => Reserved, + /// Reserved [`Opcode`]. + Reserved51 => Reserved, + /// Reserved [`Opcode`]. + Reserved52 => Reserved, + /// Reserved [`Opcode`]. + Reserved53 => Reserved, + /// Reserved [`Opcode`]. + Reserved54 => Reserved, + /// Reserved [`Opcode`]. + Reserved55 => Reserved, + /// Reserved [`Opcode`]. + Reserved56 => Reserved, } } diff --git a/boa_engine/src/vm/opcode/nop/mod.rs b/boa_engine/src/vm/opcode/nop/mod.rs index bffc2fbb41..881902b9b7 100644 --- a/boa_engine/src/vm/opcode/nop/mod.rs +++ b/boa_engine/src/vm/opcode/nop/mod.rs @@ -18,3 +18,19 @@ impl Operation for Nop { Ok(CompletionType::Normal) } } + +/// `Reserved` implements the Opcode Operation for `Opcode::Reserved` +/// +/// Operation: +/// - Panics, this should be unreachable. +#[derive(Debug, Clone, Copy)] +pub(crate) struct Reserved; + +impl Operation for Reserved { + const NAME: &'static str = "Reserved"; + const INSTRUCTION: &'static str = "INST - Reserved"; + + fn execute(_: &mut Context<'_>) -> JsResult { + unreachable!("Reserved opcodes are unreachable!") + } +}