Browse Source

Use opcode table rather than match (#2501)

`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).
pull/2509/head
Choongwoo Han 2 years ago
parent
commit
ab2e6e1ab3
  1. 36
      boa_engine/src/vm/opcode/mod.rs

36
boa_engine/src/vm/opcode/mod.rs

@ -98,7 +98,7 @@ macro_rules! generate_impl {
pub enum $Type:ident {
$(
$(#[$inner:ident $($args:tt)*])*
$Variant:ident
$Variant:ident $(= $index:expr)*
),*
$(,)?
}
@ -108,7 +108,7 @@ macro_rules! generate_impl {
pub enum $Type {
$(
$(#[$inner $($args)*])*
$Variant
$Variant $(= $index)*
),*
}
@ -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)
}
}
};
@ -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.
///

Loading…
Cancel
Save