Skip to content

Commit

Permalink
perf(transformer/arrow-function): super method binding names lazily
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Nov 16, 2024
1 parent d51e25a commit 0cb33fa
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/oxc_transformer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ oxc_syntax = { workspace = true, features = ["to_js_string"] }
oxc_traverse = { workspace = true }

base64 = { workspace = true }
compact_str = { workspace = true }
cow-utils = { workspace = true }
dashmap = { workspace = true }
indexmap = { workspace = true }
Expand Down
74 changes: 41 additions & 33 deletions crates/oxc_transformer/src/common/arrow_function_converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@
//! The Implementation based on
//! <https://github.com/babel/babel/blob/d20b314c14533ab86351ecf6ca6b7296b66a57b3/packages/babel-traverse/src/path/conversion.ts#L170-L247>
use compact_str::CompactString;
use rustc_hash::{FxHashMap, FxHashSet};

use oxc_allocator::{Box as ArenaBox, String as ArenaString, Vec as ArenaVec};
use oxc_allocator::{Box as ArenaBox, Vec as ArenaVec};
use oxc_ast::{ast::*, NONE};
use oxc_data_structures::stack::SparseStack;
use oxc_semantic::{ReferenceFlags, SymbolId};
Expand Down Expand Up @@ -120,16 +121,20 @@ struct SuperMethodInfo<'a> {
super_expr: Expression<'a>,
/// If it is true, the method should accept a prop parameter.
is_computed: bool,
/// If it is true, the method should accept a value parameter.
is_assignment: bool,
}

#[derive(Default)]
struct SuperMethods<'a> {
getters: FxHashMap<&'a str, SuperMethodInfo<'a>>,
setters: FxHashMap<&'a str, SuperMethodInfo<'a>>,
}

pub struct ArrowFunctionConverter<'a> {
mode: ArrowFunctionConverterMode,
this_var_stack: SparseStack<BoundIdentifier<'a>>,
arguments_var_stack: SparseStack<BoundIdentifier<'a>>,
renamed_arguments_symbol_ids: FxHashSet<SymbolId>,
super_methods: Option<FxHashMap<Atom<'a>, SuperMethodInfo<'a>>>,
super_methods: Option<SuperMethods<'a>>,
}

impl<'a> ArrowFunctionConverter<'a> {
Expand Down Expand Up @@ -187,7 +192,7 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> {
self.arguments_var_stack.push(None);
if self.is_async_only() && func.r#async && Self::is_class_method_like_ancestor(ctx.parent())
{
self.super_methods = Some(FxHashMap::default());
self.super_methods = Some(SuperMethods::default());
}
}

Expand Down Expand Up @@ -594,16 +599,14 @@ impl<'a> ArrowFunctionConverter<'a> {
}
};

let binding_name = Self::generate_super_binding_name(assign_value.is_some(), property, ctx);
let super_info = super_methods.entry(binding_name.clone()).or_insert_with(|| {
let is_assignment = assign_value.is_some();
let methods =
if is_assignment { &mut super_methods.setters } else { &mut super_methods.getters };
let super_info = methods.entry(property).or_insert_with(|| {
let binding_name = Self::generate_super_binding_name(is_assignment, property);
let binding = ctx
.generate_uid_in_current_scope(&binding_name, SymbolFlags::FunctionScopedVariable);
SuperMethodInfo {
binding,
super_expr: init,
is_computed: argument.is_some(),
is_assignment: assign_value.is_some(),
}
SuperMethodInfo { binding, super_expr: init, is_computed: argument.is_some() }
});

let callee = super_info.binding.create_read_expression(ctx);
Expand Down Expand Up @@ -722,10 +725,10 @@ impl<'a> ArrowFunctionConverter<'a> {
fn generate_super_method(
target_scope_id: ScopeId,
super_method: SuperMethodInfo<'a>,
is_assignment: bool,
ctx: &mut TraverseCtx<'a>,
) -> VariableDeclarator<'a> {
let SuperMethodInfo { binding, super_expr: mut init, is_computed, is_assignment } =
super_method;
let SuperMethodInfo { binding, super_expr: mut init, is_computed } = super_method;

Self::adjust_binding_scope(target_scope_id, &binding, ctx);
let scope_id =
Expand Down Expand Up @@ -798,22 +801,17 @@ impl<'a> ArrowFunctionConverter<'a> {
}

/// Generate a binding name for the super method, like `superprop_getXXX`.
fn generate_super_binding_name(
is_assignment: bool,
property: &str,
ctx: &TraverseCtx<'a>,
) -> Atom<'a> {
let start =
if is_assignment { Atom::from("superprop_set") } else { Atom::from("superprop_get") };
fn generate_super_binding_name(is_assignment: bool, property: &str) -> CompactString {
let mut name = if is_assignment {
CompactString::const_new("superprop_set")
} else {
CompactString::const_new("superprop_get")
};

let Some(&first_byte) = property.as_bytes().first() else {
return start;
return name;
};

let mut name =
ArenaString::with_capacity_in(start.len() + property.len(), ctx.ast.allocator);
name.push_str(start.as_str());

// Capitalize the first letter of the property name.
// Fast path for ASCII (very common case).
// TODO(improve-on-babel): We could just use format `superprop_get_prop` and avoid capitalizing.
Expand All @@ -836,7 +834,7 @@ impl<'a> ArrowFunctionConverter<'a> {
} else {
#[cold]
#[inline(never)]
fn push_unicode(property: &str, name: &mut ArenaString) {
fn push_unicode(property: &str, name: &mut CompactString) {
let mut chars = property.chars();
let first_char = chars.next().unwrap();
name.extend(first_char.to_uppercase());
Expand All @@ -845,7 +843,7 @@ impl<'a> ArrowFunctionConverter<'a> {
push_unicode(property, &mut name);
}

ctx.ast.atom(name.into_bump_str())
name
}

/// Whether to transform the `arguments` identifier.
Expand Down Expand Up @@ -1013,7 +1011,9 @@ impl<'a> ArrowFunctionConverter<'a> {
let is_class_method_like = Self::is_class_method_like_ancestor(ctx.parent());
let declarations_count = usize::from(arguments.is_some())
+ if is_class_method_like {
self.super_methods.as_ref().map_or(0, FxHashMap::len)
self.super_methods.as_ref().map_or(0, |super_methods| {
super_methods.getters.len() + super_methods.setters.len()
})
} else {
0
}
Expand All @@ -1030,11 +1030,19 @@ impl<'a> ArrowFunctionConverter<'a> {
declarations.push(arguments);
}

// `_superprop_getSomething = () => super.getSomething;`
// `_superprop_getSomething = () => super.something;`
// `_superprop_setSomething = (_prop, _value) => super[_prop] = _value;`
if is_class_method_like {
if let Some(super_methods) = self.super_methods.as_mut() {
declarations.extend(super_methods.drain().map(|(_, super_method)| {
Self::generate_super_method(target_scope_id, super_method, ctx)
let methods = super_methods
.getters
.drain()
.map(|(_, super_method)| (super_method, false))
.chain(
super_methods.setters.drain().map(|(_, super_method)| (super_method, true)),
);
declarations.extend(methods.map(|(super_method, is_assignment)| {
Self::generate_super_method(target_scope_id, super_method, is_assignment, ctx)
}));
}
}
Expand Down

0 comments on commit 0cb33fa

Please sign in to comment.