From 44fd962fbbb384fe91da2cf92e18b880d854bc02 Mon Sep 17 00:00:00 2001 From: overlookmotel <557937+overlookmotel@users.noreply.github.com> Date: Sun, 17 Nov 2024 10:49:17 +0000 Subject: [PATCH] perf(transformer/arrow-functions): move arguments transform checks to aid inlining (#7322) Move the cheap "does arguments need to be transformed" checks introduced in #7321 into `enter_identifier_reference` and `enter_binding_identifier`, and mark those methods `#[inline]`. These hot paths can then usually execute without a function call. This wins back the other half of the perf hit of #7234. --- .../src/common/arrow_function_converter.rs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/crates/oxc_transformer/src/common/arrow_function_converter.rs b/crates/oxc_transformer/src/common/arrow_function_converter.rs index e1b80ff69c4c5..46cfe3d7a6a4e 100644 --- a/crates/oxc_transformer/src/common/arrow_function_converter.rs +++ b/crates/oxc_transformer/src/common/arrow_function_converter.rs @@ -368,20 +368,34 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { } } + // `#[inline]` because this is a hot path + #[inline] fn enter_identifier_reference( &mut self, ident: &mut IdentifierReference<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.transform_identifier_reference_for_arguments(ident, ctx); + // Do this check here rather than in `transform_identifier_reference_for_arguments` + // so that the fast path for "no transform required" doesn't require a function call + let arguments_needs_transform = *self.arguments_needs_transform_stack.last(); + if arguments_needs_transform { + self.transform_identifier_reference_for_arguments(ident, ctx); + } } + // `#[inline]` because this is a hot path + #[inline] fn enter_binding_identifier( &mut self, ident: &mut BindingIdentifier<'a>, ctx: &mut TraverseCtx<'a>, ) { - self.transform_binding_identifier_for_arguments(ident, ctx); + // Do this check here rather than in `transform_binding_identifier_for_arguments` + // so that the fast path for "no transform required" doesn't require a function call + let arguments_needs_transform = *self.arguments_needs_transform_stack.last(); + if arguments_needs_transform { + self.transform_binding_identifier_for_arguments(ident, ctx); + } } } @@ -907,8 +921,7 @@ impl<'a> ArrowFunctionConverter<'a> { ident: &mut IdentifierReference<'a>, ctx: &mut TraverseCtx<'a>, ) { - let arguments_needs_transform = *self.arguments_needs_transform_stack.last(); - if !arguments_needs_transform || &ident.name != "arguments" { + if &ident.name != "arguments" { return; } @@ -952,11 +965,9 @@ impl<'a> ArrowFunctionConverter<'a> { ident: &mut BindingIdentifier<'a>, ctx: &mut TraverseCtx<'a>, ) { - let arguments_needs_transform = *self.arguments_needs_transform_stack.last(); - if !arguments_needs_transform - || ctx.current_scope_flags().is_strict_mode() // `arguments` is not allowed to be defined in strict mode - || &ident.name != "arguments" - { + // `arguments` is not allowed to be defined in strict mode. + // Check if strict mode first to avoid the more expensive string comparison check if possible. + if ctx.current_scope_flags().is_strict_mode() || &ident.name != "arguments" { return; }