perf(minifier): use oxc_data_structures::stack::Stack for ClassSymbolsStack#14029
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
CodSpeed Instrumentation Performance ReportMerging #14029 will not alter performanceComparing Summary
Footnotes |
a1476b3 to
57f5fd6
Compare
c5758c6 to
3c3cdb2
Compare
There was a problem hiding this comment.
I don't think the clear call should be required. From what I can see, the stack is filled and then emptied again during traversal, so it should be always be empty by exit_program anyway (and therefore still empty in the next enter_program call).
The pattern we generally use with stacks in transformer is:
struct SomeTransform {
stack: Stack<ThingName>,
}
impl<'a> Traverse<'a> for SomeTransform {
fn enter_program(&mut self, program: &mut Program, ctx: &mut TraverseCtx<'a>) {
// Nothing to do. `stack` is always empty here.
}
fn enter_thing(&mut self, thing: &mut Thing<'a>, ctx: &mut TraverseCtx<'a> {
self.stack.push(thing.name);
}
fn exit_thing(&mut self, thing: &mut Thing<'a>, ctx: &mut TraverseCtx<'a> {
self.stack.pop().unwrap();
// Or, if logic is simple enough that it's clear
// there's no possibility of mismatched push-pop calls
// unsafe { self.stack.pop_unchecked() };
}
#[inline] // Because it's a noop in release mode
fn exit_program(&mut self, program: &mut Program, ctx: &mut TraverseCtx<'a>) {
debug_assert!(self.stack.is_empty());
}
}This debug_assert! approach has the advantage of making sure that every push is followed by a corresponding pop, and the stack doesn't get out of sync with traversal.
You may find that oxc_data_structures::stack::NonEmptyStack is cheaper than Stack. That has really cheap last and last_mut methods. Downside is you have to provide a dummy first entry when creating the NonEmptyStack, but if MinifierState is being used over and over, that's a 1-off cost.
Feel free not to take these suggestions into account. Just wanted to let you know the patterns we've found work well with the stack types, in case it's useful.
|
Ah, true, |
57f5fd6 to
ac9e89b
Compare
3c3cdb2 to
5f62088
Compare
ac9e89b to
a1091e9
Compare
|
Changed to |
5f62088 to
8274783
Compare
a1091e9 to
4906b11
Compare
Merge activity
|
…sStack (#14029) Changed `ClassSymbolsStack` to `Stack` from normal `Vec`.
8274783 to
0fe4d95
Compare
4906b11 to
c0ef5f3
Compare
Added `Stack::clear` for #14029.

Changed
ClassSymbolsStacktoStackfrom normalVec.