mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(parser): remove const generic param from finish_next_inner (#19684)
Replace const generic param from `finish_next_inner`.
```diff
- fn finish_next_inner<const REPLACE_SAME_START: bool>(&mut self, kind: Kind) -> Token {
+ fn finish_next_inner(&mut self, kind: Kind, mode: FinishTokenMode) -> Token {
```
The function is marked `#[inline(always)]` to ensure that `mode` can be statically known from each call site and acts as a const.
The perf improvement (5%-8% on `parser_tokens` benchmarks) surprised me. Turns out it's the result of the `#[inline(always)]` (see #19694 which made that change in isolation).
Aside from the perf improvement, it's easier to read, and may reduce compile time a bit (as this function is inlined into many call sites).
This commit is contained in:
1 parent
7d7d0b0d8e
commit
b5d98457e2
1 file changed
+24
-10
@@ -65,6 +65,14 @@ pub enum LexerContext {
|
||||
JsxAttributeValue,
|
||||
}
|
||||
|
||||
/// Action to take when finishing a token.
|
||||
/// Passed to [`Lexer::finish_next_inner`].
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
enum FinishTokenMode {
|
||||
Push,
|
||||
Replace,
|
||||
}
|
||||
|
||||
pub struct Lexer<'a, C: Config> {
|
||||
allocator: &'a Allocator,
|
||||
|
||||
@@ -271,26 +279,32 @@ impl<'a, C: Config> Lexer<'a, C> {
|
||||
|
||||
#[inline]
|
||||
fn finish_next(&mut self, kind: Kind) -> Token {
|
||||
self.finish_next_inner::<false>(kind)
|
||||
self.finish_next_inner(kind, FinishTokenMode::Push)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finish_next_retokenized(&mut self, kind: Kind) -> Token {
|
||||
self.finish_next_inner::<true>(kind)
|
||||
self.finish_next_inner(kind, FinishTokenMode::Replace)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finish_next_inner<const REPLACE_SAME_START: bool>(&mut self, kind: Kind) -> Token {
|
||||
// `#[inline(always)]` to ensure is inlined into `finish_next` and `finish_next_retokenized`,
|
||||
// so that `mode` is statically known
|
||||
#[expect(clippy::inline_always)]
|
||||
#[inline(always)]
|
||||
fn finish_next_inner(&mut self, kind: Kind, mode: FinishTokenMode) -> Token {
|
||||
self.token.set_kind(kind);
|
||||
self.token.set_end(self.offset());
|
||||
let token = self.token;
|
||||
if self.config.tokens() && !matches!(token.kind(), Kind::Eof | Kind::HashbangComment) {
|
||||
if REPLACE_SAME_START {
|
||||
debug_assert!(self.tokens.last().is_some_and(|last| last.start() == token.start()));
|
||||
let last = self.tokens.last_mut().unwrap();
|
||||
*last = token;
|
||||
} else {
|
||||
self.tokens.push(token);
|
||||
match mode {
|
||||
FinishTokenMode::Push => self.tokens.push(token),
|
||||
FinishTokenMode::Replace => {
|
||||
debug_assert!(
|
||||
self.tokens.last().is_some_and(|last| last.start() == token.start())
|
||||
);
|
||||
let last = self.tokens.last_mut().unwrap();
|
||||
*last = token;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.trivia_builder.handle_token(token);
|
||||
|
||||
Reference in new issue
Block a user