From 93b8e86446275e76c9f83766b97440e983f0808e Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Wed, 16 Apr 2025 08:41:43 +0000 Subject: [PATCH] perf(parser): use `ArenaVec` to store decorators (#10437) No performance changes show in the `CodeSpeed` because we don't have a benchmark that includes decorators. According to convention, we always store child/leaf ASTs used for building ASTs in an arena to avoid extra allocations. We have got many performances from this kind of change, so I think it is good! --- crates/oxc_parser/src/cursor.rs | 5 ++--- crates/oxc_parser/src/lib.rs | 2 +- crates/oxc_parser/src/state.rs | 15 +++++++++++++-- crates/oxc_parser/src/ts/statement.rs | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/oxc_parser/src/cursor.rs b/crates/oxc_parser/src/cursor.rs index f0e9690d07a1a..8c9a94de605ee 100644 --- a/crates/oxc_parser/src/cursor.rs +++ b/crates/oxc_parser/src/cursor.rs @@ -1,6 +1,6 @@ //! Code related to navigating `Token`s from the lexer -use oxc_allocator::Vec; +use oxc_allocator::{TakeIn, Vec}; use oxc_ast::ast::{Decorator, RegExpFlags}; use oxc_diagnostics::Result; use oxc_span::{GetSpan, Span}; @@ -327,8 +327,7 @@ impl<'a> ParserImpl<'a> { } pub(crate) fn consume_decorators(&mut self) -> Vec<'a, Decorator<'a>> { - let decorators = std::mem::take(&mut self.state.decorators); - self.ast.vec_from_iter(decorators) + self.state.decorators.take_in(self.ast.allocator) } pub(crate) fn parse_normal_list( diff --git a/crates/oxc_parser/src/lib.rs b/crates/oxc_parser/src/lib.rs index 9f61703da3c4b..f5fcf0df88e04 100644 --- a/crates/oxc_parser/src/lib.rs +++ b/crates/oxc_parser/src/lib.rs @@ -410,7 +410,7 @@ impl<'a> ParserImpl<'a> { errors: vec![], token: Token::default(), prev_token_end: 0, - state: ParserState::default(), + state: ParserState::new(allocator), ctx: Self::default_context(source_type, options), ast: AstBuilder::new(allocator), module_record_builder: ModuleRecordBuilder::new(allocator), diff --git a/crates/oxc_parser/src/state.rs b/crates/oxc_parser/src/state.rs index e82dcbbcecb87..cea1292b56d86 100644 --- a/crates/oxc_parser/src/state.rs +++ b/crates/oxc_parser/src/state.rs @@ -1,13 +1,13 @@ use rustc_hash::{FxHashMap, FxHashSet}; +use oxc_allocator::{Allocator, Vec as ArenaVec}; use oxc_ast::ast::{AssignmentExpression, Decorator}; use oxc_span::Span; -#[derive(Default)] pub struct ParserState<'a> { pub not_parenthesized_arrow: FxHashSet, - pub decorators: Vec>, + pub decorators: ArenaVec<'a, Decorator<'a>>, /// Temporary storage for `CoverInitializedName` `({ foo = bar })`. /// Keyed by `ObjectProperty`'s span.start. @@ -19,3 +19,14 @@ pub struct ParserState<'a> { /// Valued by position of the trailing_comma. pub trailing_commas: FxHashMap, } + +impl<'a> ParserState<'a> { + pub fn new(allocator: &'a Allocator) -> Self { + Self { + not_parenthesized_arrow: FxHashSet::default(), + decorators: ArenaVec::new_in(allocator), + cover_initialized_name: FxHashMap::default(), + trailing_commas: FxHashMap::default(), + } + } +} diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 8f626143e5030..6d0143ed4cc5f 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -491,7 +491,7 @@ impl<'a> ParserImpl<'a> { return Ok(()); } - let mut decorators = vec![]; + let mut decorators = self.ast.vec(); while self.at(Kind::At) { let decorator = self.parse_decorator()?; decorators.push(decorator);