From e3e439dba638cd631560d2eb0c2b0ec4db288e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Mon, 6 Nov 2023 14:28:30 +0900 Subject: [PATCH] perf(es/parser): Improve performance (#8224) **Description:** Small things --- Cargo.lock | 1 + crates/swc_common/src/input.rs | 1 + crates/swc_ecma_parser/Cargo.toml | 1 + crates/swc_ecma_parser/src/lexer/util.rs | 58 +++++++++++++--------- crates/swc_ecma_parser/src/parser/input.rs | 32 ++++-------- 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aef70d528ff..6621f73b451 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4530,6 +4530,7 @@ version = "0.141.10" dependencies = [ "criterion", "either", + "new_debug_unreachable", "num-bigint", "num-traits", "phf 0.11.2", diff --git a/crates/swc_common/src/input.rs b/crates/swc_common/src/input.rs index b08277c4cab..2a649d5d0d2 100644 --- a/crates/swc_common/src/input.rs +++ b/crates/swc_common/src/input.rs @@ -136,6 +136,7 @@ impl<'a> Input for StringInput<'a> { ret } + #[inline] fn uncons_while(&mut self, mut pred: F) -> &str where F: FnMut(char) -> bool, diff --git a/crates/swc_ecma_parser/Cargo.toml b/crates/swc_ecma_parser/Cargo.toml index 1a206d01c6c..dfdef0d9f9d 100644 --- a/crates/swc_ecma_parser/Cargo.toml +++ b/crates/swc_ecma_parser/Cargo.toml @@ -38,6 +38,7 @@ swc_common = { version = "0.33.3", path = "../swc_common" } swc_ecma_ast = { version = "0.110.4", path = "../swc_ecma_ast" } swc_ecma_visit = { version = "0.96.4", path = "../swc_ecma_visit", optional = true } phf = { version = "0.11.2", features = ["macros"] } +new_debug_unreachable = "1.0.4" [target.'cfg(not(any(target_arch = "wasm32", target_arch = "arm")))'.dependencies] stacker = { version = "0.1.15", optional = true } diff --git a/crates/swc_ecma_parser/src/lexer/util.rs b/crates/swc_ecma_parser/src/lexer/util.rs index 6fe5b3d3eb1..e765e8402b3 100644 --- a/crates/swc_ecma_parser/src/lexer/util.rs +++ b/crates/swc_ecma_parser/src/lexer/util.rs @@ -188,6 +188,7 @@ impl<'a> Lexer<'a> { /// Skip comments or whitespaces. /// /// See https://tc39.github.io/ecma262/#sec-white-space + #[inline(never)] pub(super) fn skip_space(&mut self) -> LexResult<()> { loop { let (offset, newline) = { @@ -310,29 +311,7 @@ impl<'a> Lexer<'a> { is_for_next = false; } - if let Some(comments) = self.comments_buffer.as_mut() { - let src = unsafe { - // Safety: We got slice_start and end from self.input so those are valid. - self.input.slice(slice_start, end) - }; - let s = &src[..src.len() - 2]; - let cmt = Comment { - kind: CommentKind::Block, - span: Span::new(start, end, SyntaxContext::empty()), - text: s.into(), - }; - - let _ = self.input.peek(); - if is_for_next { - comments.push_pending_leading(cmt); - } else { - comments.push(BufferedComment { - kind: BufferedCommentKind::Trailing, - pos: self.state.prev_hi, - comment: cmt, - }); - } - } + self.store_comment(is_for_next, start, end, slice_start); return Ok(()); } @@ -346,6 +325,39 @@ impl<'a> Lexer<'a> { self.error(start, SyntaxError::UnterminatedBlockComment)? } + + #[inline(never)] + fn store_comment( + &mut self, + is_for_next: bool, + start: BytePos, + end: BytePos, + slice_start: BytePos, + ) { + if let Some(comments) = self.comments_buffer.as_mut() { + let src = unsafe { + // Safety: We got slice_start and end from self.input so those are valid. + self.input.slice(slice_start, end) + }; + let s = &src[..src.len() - 2]; + let cmt = Comment { + kind: CommentKind::Block, + span: Span::new(start, end, SyntaxContext::empty()), + text: s.into(), + }; + + let _ = self.input.peek(); + if is_for_next { + comments.push_pending_leading(cmt); + } else { + comments.push(BufferedComment { + kind: BufferedCommentKind::Trailing, + pos: self.state.prev_hi, + comment: cmt, + }); + } + } + } } /// Implemented for `char`. diff --git a/crates/swc_ecma_parser/src/parser/input.rs b/crates/swc_ecma_parser/src/parser/input.rs index e0c46b735fe..a97ad77cf67 100644 --- a/crates/swc_ecma_parser/src/parser/input.rs +++ b/crates/swc_ecma_parser/src/parser/input.rs @@ -1,5 +1,6 @@ use std::{cell::RefCell, mem, mem::take, rc::Rc}; +use debug_unreachable::debug_unreachable; use lexer::TokenContexts; use swc_common::{BytePos, Span}; @@ -299,18 +300,6 @@ impl Buffer { }); } - #[inline(never)] - fn bump_inner(&mut self) { - let prev = self.cur.take(); - self.prev_span = match prev { - Some(TokenAndSpan { span, .. }) => span, - _ => self.prev_span, - }; - - // If we have peeked a token, take it instead of calling lexer.next() - self.cur = self.next.take().or_else(|| self.iter.next()); - } - #[allow(dead_code)] pub fn cur_debug(&self) -> Option<&Token> { self.cur.as_ref().map(|it| &it.token) @@ -327,18 +316,14 @@ impl Buffer { /// Returns current token. pub fn bump(&mut self) -> Token { - #[cold] - #[inline(never)] - fn invalid_state() -> ! { - unreachable!( - "Current token is `None`. Parser should not call bump() without knowing current \ - token" - ) - } - let prev = match self.cur.take() { Some(t) => t, - None => invalid_state(), + None => unsafe { + debug_unreachable!( + "Current token is `None`. Parser should not call bump() without knowing \ + current token" + ) + }, }; self.prev_span = prev.span; @@ -388,7 +373,8 @@ impl Buffer { #[inline] pub fn cur(&mut self) -> Option<&Token> { if self.cur.is_none() { - self.bump_inner(); + // If we have peeked a token, take it instead of calling lexer.next() + self.cur = self.next.take().or_else(|| self.iter.next()); } match &self.cur {