Skip to content

Commit

Permalink
perf(transformer/arrow-function): optimize `generate_super_binding_na…
Browse files Browse the repository at this point in the history
…me` (#7312)

Optimize this function in various ways:

* Return a static `Atom` (rather than allocating into arena) if no `property`.
* Reserve capacity for `ArenaString` at start.
* Make path for unicode identifiers (very rare case) `#[cold]` and `#[inline(never)]`.
* Slightly faster uppercase conversion.
  • Loading branch information
overlookmotel committed Nov 17, 2024
1 parent 50c18c7 commit 4892875
Showing 1 changed file with 34 additions and 16 deletions.
50 changes: 34 additions & 16 deletions crates/oxc_transformer/src/common/arrow_function_converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,34 +797,52 @@ impl<'a> ArrowFunctionConverter<'a> {
)
}

/// Generate a binding name for the super method, like `_superprop_getXXX`.
/// 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 mut name = ArenaString::new_in(ctx.ast.allocator);
let start =
if is_assignment { Atom::from("superprop_set") } else { Atom::from("superprop_get") };

name.push_str("superprop_");
if is_assignment {
name.push_str("set");
} else {
name.push_str("get");
}
let Some(&first_byte) = property.as_bytes().first() else {
return start;
};

// Capitalize the first letter of the property name
if let Some(&first_byte) = property.as_bytes().first() {
if first_byte.is_ascii() {
name.push(first_byte.to_ascii_uppercase() as char);
if property.len() > 1 {
name.push_str(&property[1..]);
}
} else {
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.
if first_byte.is_ascii() {
// We know `IdentifierName`s begin with `a-z`, `A-Z`, `_` or `$` if ASCII,
// so can use a slightly cheaper conversion than `u8::to_ascii_uppercase`.
// Adapted from `u8::to_ascii_uppercase`'s implementation.
// https://godbolt.org/z/5Txa6Pv9z
#[inline]
fn ascii_ident_first_char_uppercase(b: u8) -> u8 {
const ASCII_CASE_MASK: u8 = 0b0010_0000;
let is_lower_case = b >= b'a';
b ^ (u8::from(is_lower_case) * ASCII_CASE_MASK)
}

name.push(ascii_ident_first_char_uppercase(first_byte) as char);
if property.len() > 1 {
name.push_str(&property[1..]);
}
} else {
#[cold]
#[inline(never)]
fn push_unicode(property: &str, name: &mut ArenaString) {
let mut chars = property.chars();
let first_char = chars.next().unwrap();
name.extend(first_char.to_uppercase());
name.push_str(chars.as_str());
}
push_unicode(property, &mut name);
}

ctx.ast.atom(name.into_bump_str())
Expand Down

0 comments on commit 4892875

Please sign in to comment.