Skip to content

Commit

Permalink
Use opcode table rather than match (#2501)
Browse files Browse the repository at this point in the history
`execute_instruction` is heavily used. After decoding an opcode, `match` is used to find a proper `execute` function for the opcode. But, the `match` may not be able to be optimized into a table jump by rust compiler, so it may use multiple branches to find the function. When I tested with a toy program, only `enum -> &'static str` case was optimized to use a table while `enum -> function call` uses multiple branches. ([gotbolt](https://rust.godbolt.org/z/1rzK5vj6f))

This change makes the opcode to use a table explicitly. It improves the benchmark score of Richards by 1-2% (22.8 -> 23.2).
  • Loading branch information
tunz committed Dec 26, 2022
1 parent 3bf5de2 commit a197f5c
Showing 1 changed file with 18 additions and 18 deletions.
36 changes: 18 additions & 18 deletions boa_engine/src/vm/opcode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ macro_rules! generate_impl {
pub enum $Type:ident {
$(
$(#[$inner:ident $($args:tt)*])*
$Variant:ident
$Variant:ident $(= $index:expr)*
),*
$(,)?
}
Expand All @@ -108,7 +108,7 @@ macro_rules! generate_impl {
pub enum $Type {
$(
$(#[$inner $($args)*])*
$Variant
$Variant $(= $index)*
),*
}

Expand All @@ -126,32 +126,32 @@ macro_rules! generate_impl {
unsafe { std::mem::transmute(value) }
}

const NAMES: &[&'static str] = &[
$($Variant::NAME),*
];

/// Name of this opcode.
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
$(
Self::$Variant => $Variant::NAME
),*
}
Self::NAMES[self as usize]
}

const INSTRUCTIONS: &[&'static str] = &[
$($Variant::INSTRUCTION),*
];

/// Name of the profiler event for this opcode.
#[must_use]
pub const fn as_instruction_str(self) -> &'static str {
match self {
$(
Self::$Variant => $Variant::INSTRUCTION
),*
}
Self::INSTRUCTIONS[self as usize]
}

const EXECUTE_FNS: &[fn(&mut Context) -> JsResult<ShouldExit>] = &[
$($Variant::execute),*
];

pub(super) fn execute(self, context: &mut Context) -> JsResult<ShouldExit> {
match self {
$(
Self::$Variant => $Variant::execute(context)
),*
}
Self::EXECUTE_FNS[self as usize](context)
}
}
};
Expand Down Expand Up @@ -179,7 +179,7 @@ generate_impl! {
/// Operands:
///
/// Stack: value **=>**
Pop,
Pop = 0,

/// Pop the top value from the stack if the last try block has thrown a value.
///
Expand Down

0 comments on commit a197f5c

Please sign in to comment.