Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(es/parser): Reduce allocations for raw while lexing numbers #9056

Merged
merged 2 commits into from
Jun 15, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 55 additions & 41 deletions crates/swc_ecma_parser/src/lexer/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ impl<'a> Lexer<'a> {
let starts_with_zero = self.cur().unwrap() == '0';

// Use read_number_no_dot to support long numbers.
let (val, s, mut raw, not_octal) = self.read_number_no_dot_as_str::<10>()?;
let (val, s, not_octal) = self.read_number_no_dot_as_str::<10>()?;

if self.eat(b'n') {
raw.push('n');
let end = self.cur_pos();
let raw = unsafe {
// Safety: We got both start and end position from `self.input`
self.input.slice(start, end)
};

return Ok(Either::Right((
Box::new(s.into_value()),
self.atoms.atom(&*raw),
self.atoms.atom(raw),
)));
}

Expand All @@ -80,9 +84,16 @@ impl<'a> Lexer<'a> {
// e.g. `000` is octal
if start.0 != self.last_pos().0 - 1 {
// `-1` is utf 8 length of `0`

let end = self.cur_pos();
let raw = unsafe {
// Safety: We got both start and end position from `self.input`
self.input.slice(start, end)
};
let raw = self.atoms.atom(raw);
return self
.make_legacy_octal(start, 0f64)
.map(|value| Either::Left((value, self.atoms.atom(&*raw))));
.map(|value| Either::Left((value, raw)));
}
} else {
// strict mode hates non-zero decimals starting with zero.
Expand All @@ -109,9 +120,16 @@ impl<'a> Lexer<'a> {
panic!("failed to parse {} into float using BigInt", val_str)
});

let end = self.cur_pos();
let raw = unsafe {
// Safety: We got both start and end position from `self.input`
self.input.slice(start, end)
};
let raw = self.atoms.atom(raw);

return self
.make_legacy_octal(start, val)
.map(|value| Either::Left((value, self.atoms.atom(&*raw))));
.map(|value| Either::Left((value, raw)));
}
}
}
Expand Down Expand Up @@ -234,41 +252,43 @@ impl<'a> Lexer<'a> {
);
debug_assert_eq!(self.cur(), Some('0'));

self.with_buf(|l, buf| {
l.bump();

buf.push('0');
let start = self.cur_pos();

let c = match l.input.cur() {
Some(c) => {
l.bump();
self.bump();

c
}
_ => {
unreachable!();
}
};

buf.push(c);
match self.input.cur() {
Some(..) => {
self.bump();
}
_ => {
unreachable!();
}
}

let (val, s, raw, _) = l.read_number_no_dot_as_str::<RADIX>()?;
let (val, s, _) = self.read_number_no_dot_as_str::<RADIX>()?;

buf.push_str(&raw);
if self.eat(b'n') {
let end = self.cur_pos();
let raw = unsafe {
// Safety: We got both start and end position from `self.input`
self.input.slice(start, end)
};

if l.eat(b'n') {
buf.push('n');
return Ok(Either::Right((
Box::new(s.into_value()),
self.atoms.atom(raw),
)));
}

return Ok(Either::Right((
Box::new(s.into_value()),
l.atoms.atom(&**buf),
)));
}
self.ensure_not_ident()?;

l.ensure_not_ident()?;
let end = self.cur_pos();
let raw = unsafe {
// Safety: We got both start and end position from `self.input`
self.input.slice(start, end)
};

Ok(Either::Left((val, l.atoms.atom(&**buf))))
})
Ok(Either::Left((val, self.atoms.atom(raw))))
}

/// This can read long integers like
Expand Down Expand Up @@ -302,11 +322,10 @@ impl<'a> Lexer<'a> {
/// This can read long integers like
/// "13612536612375123612312312312312312312312".
///
///
/// Returned bool is `true` is there was `8` or `9`.
/// - Returned `bool` is `true` is there was `8` or `9`.
fn read_number_no_dot_as_str<const RADIX: u8>(
&mut self,
) -> LexResult<(f64, LazyBigInt<RADIX>, SmartString<LazyCompact>, bool)> {
) -> LexResult<(f64, LazyBigInt<RADIX>, bool)> {
debug_assert!(
RADIX == 2 || RADIX == 8 || RADIX == 10 || RADIX == 16,
"radix for read_number_no_dot should be one of 2, 8, 10, 16, but got {}",
Expand Down Expand Up @@ -344,12 +363,7 @@ impl<'a> Lexer<'a> {
.expect("failed to parse float using BigInt")
.to_f64()
.expect("failed to parse float using BigInt");
Ok((
parsed_float,
LazyBigInt::new(raw_number_str),
raw_str,
non_octal,
))
Ok((parsed_float, LazyBigInt::new(raw_number_str), non_octal))
}

/// Ensure that ident cannot directly follow numbers.
Expand Down
Loading