Skip to content

Commit

Permalink
lazy_static deref on lexer creation
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Feb 11, 2024
1 parent 6f47865 commit e0f12dd
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 18 deletions.
35 changes: 19 additions & 16 deletions crates/oxc_parser/src/lexer/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,9 @@ impl<'a> Lexer<'a> {

fn skip_multi_line_comment_after_line_break(&mut self, pos: SourcePosition) -> Kind {
// Can use `memchr` here as only searching for 1 pattern.
// Cache `Finder` instance, as there's a significant cost to creating one.
// `Finder::new` isn't a const function, so can't make it a `static`.
// `lazy_static!` has a cost each time it's deref-ed (but less cost than `Finder::new`).
// Creating a `Finder` unconditionally in `Lexer::new` to use for the whole file is fastest for
// files which do contain multi-line comments, but imposes pointless cost on files that don't.
// So best trade-off is calling `Finder::new` only once globally, and then deref-ing the
// lazy static only once when it's first used in a file, and then caching it.
if self.multi_line_comment_end_finder.is_none() {
lazy_static! {
static ref FINDER: Finder<'static> = Finder::new("*/");
}
self.multi_line_comment_end_finder = Some(&*FINDER);
}
let finder = self.multi_line_comment_end_finder.unwrap();

// `Finder` is created in `Lexer::new` using function below.
let remaining = self.source.str_from_pos_to_end(pos).as_bytes();
if let Some(index) = finder.find(remaining) {
if let Some(index) = self.multi_line_comment_end_finder.find(remaining) {
// SAFETY: `pos + index + 2` is end of `*/`, so a valid `SourcePosition`
self.source.set_position(unsafe { pos.add(index + 2) });
self.trivia_builder.add_multi_line_comment(self.token.start, self.offset());
Expand All @@ -173,6 +159,23 @@ impl<'a> Lexer<'a> {
}
}

/// Create `memchr` Finder for end of multi-line comment.
/// This is called by `Lexer::new`.
/// Creating a `Finder` on each call to `skip_multi_line_comment_after_line_break` has a
/// significant performance impact. `Finder::new` isn't a const function, so can't make it
/// a `static`, and `lazy_static!` also imposes a cost each time it's deref-ed.
/// So the slightly weird but fastest solution is to:
/// * Create `Finder` only once globally with `lazy_static!`.
/// * Deref the lazy static only once when `Lexer` is created.
/// * Re-use same `Finder` throughout the Lexer pass.
#[inline]
pub(super) fn create_multi_line_comment_end_finder() -> &'static Finder<'static> {
lazy_static! {
static ref FINDER: Finder<'static> = Finder::new("*/");
}
&FINDER
}

/// Section 12.5 Hashbang Comments
pub(super) fn read_hashbang_comment(&mut self) -> Kind {
while let Some(c) = self.next_char().as_ref() {
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub struct Lexer<'a> {
pub escaped_templates: FxHashMap<u32, Option<&'a str>>,

/// `memchr` Finder for end of multi-line comments. Created lazily when first used.
multi_line_comment_end_finder: Option<&'static memchr::memmem::Finder<'static>>,
multi_line_comment_end_finder: &'static memchr::memmem::Finder<'static>,
}

#[allow(clippy::unused_self)]
Expand Down Expand Up @@ -127,7 +127,7 @@ impl<'a> Lexer<'a> {
trivia_builder: TriviaBuilder::default(),
escaped_strings: FxHashMap::default(),
escaped_templates: FxHashMap::default(),
multi_line_comment_end_finder: None,
multi_line_comment_end_finder: Self::create_multi_line_comment_end_finder(),
}
}

Expand Down

0 comments on commit e0f12dd

Please sign in to comment.