Skip to content

Commit 67aa5f1

Browse files
committed
perf: cf_scope as a stack
1 parent c502bdc commit 67aa5f1

File tree

11 files changed

+131
-110
lines changed

11 files changed

+131
-110
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"rust-analyzer.procMacro.ignored": { "napi-derive": ["napi"] },
3-
"rust-analyzer.cargo.features": ["flame"],
3+
"rust-analyzer.cargo.features": "all",
44

55
"[rust]": {
66
"editor.formatOnSave": true,

crates/jsshaker/src/analyzer/exhaustive.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl<'a> Analyzer<'a> {
8383
runner: Rc<dyn Fn(&mut Analyzer<'a>) -> Entity<'a> + 'a>,
8484
) -> Entity<'a> {
8585
self.push_cf_scope(
86-
CfScopeKind::Exhaustive(self.allocator.alloc(ExhaustiveData {
86+
CfScopeKind::Exhaustive(Box::new(ExhaustiveData {
8787
clean: true,
8888
temp_deps: drain.then(|| allocator::HashSet::new_in(self.allocator)),
8989
register_deps: register.then(|| allocator::HashSet::new_in(self.allocator)),
@@ -114,9 +114,11 @@ impl<'a> Analyzer<'a> {
114114
break;
115115
}
116116
}
117-
let id = self.pop_cf_scope();
118-
let data = self.scoping.cf.get_mut(id).exhaustive_data_mut().unwrap();
119-
if let Some(register_deps) = data.register_deps.take() {
117+
let scope = self.pop_cf_scope();
118+
let CfScopeKind::Exhaustive(data) = scope.kind else {
119+
unreachable!();
120+
};
121+
if let Some(register_deps) = data.register_deps {
120122
self.register_exhaustive_callbacks(drain, runner, register_deps);
121123
}
122124
first_ret.unwrap()

crates/jsshaker/src/analyzer/rw_tracking.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ impl<'a> Analyzer<'a> {
5252
let target_depth = self.find_first_different_cf_scope(scope);
5353
let mut registered = false;
5454
let mut tracker_dep = None;
55-
for depth in (target_depth..self.scoping.cf.stack.len()).rev() {
56-
let scope = self.scoping.cf.get_mut_from_depth(depth);
55+
for depth in (target_depth..self.scoping.cf.stack_len()).rev() {
56+
let scope = self.scoping.cf.data_at_mut(depth);
5757
if let Some(data) = scope.exhaustive_data_mut() {
5858
if data.clean
5959
&& let Some(temp_deps) = data.temp_deps.as_mut()
@@ -89,8 +89,8 @@ impl<'a> Analyzer<'a> {
8989
let mut exhaustive = false;
9090
let mut must_mark = true;
9191
let mut has_fn_scope = false;
92-
for depth in scope_depth..self.scoping.cf.stack.len() {
93-
let scope = self.scoping.cf.get_mut_from_depth(depth);
92+
for depth in scope_depth..self.scoping.cf.stack_len() {
93+
let scope = self.scoping.cf.data_at_mut(depth);
9494
has_fn_scope |= scope.kind.is_function();
9595
if let Some(data) = scope.exhaustive_data_mut() {
9696
exhaustive = true;
@@ -109,8 +109,8 @@ impl<'a> Analyzer<'a> {
109109
}
110110
if has_fn_scope {
111111
let mut non_det = false;
112-
for depth in (scope_depth..self.scoping.cf.stack.len()).rev() {
113-
let scope = self.scoping.cf.get_mut_from_depth(depth);
112+
for depth in (scope_depth..self.scoping.cf.stack_len()).rev() {
113+
let scope = self.scoping.cf.data_at_mut(depth);
114114
non_det |= scope.non_det();
115115
if let Some(data) = scope.fn_cache_tracking_data_mut() {
116116
data.track_write(target, cacheable.map(|e| (non_det, e)));

crates/jsshaker/src/builtins/react/dependencies.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,8 @@ pub fn check_dependencies<'a>(
140140
};
141141

142142
if require_rerun {
143-
for depth in 0..analyzer.scoping.cf.stack.len() {
144-
if let Some(exhaustive_data) =
145-
analyzer.scoping.cf.get_mut_from_depth(depth).exhaustive_data_mut()
146-
{
143+
for scope in analyzer.scoping.cf.iter_stack_mut() {
144+
if let Some(exhaustive_data) = scope.exhaustive_data_mut() {
147145
exhaustive_data.clean = false;
148146
break;
149147
}

crates/jsshaker/src/nodes/stmt/if_statement.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl<'a> Analyzer<'a> {
1919

2020
let mut both_exit = true;
2121
let mut exit_target_inner = 0;
22-
let mut exit_target_outer = self.scoping.cf.stack.len();
22+
let mut exit_target_outer = self.scoping.cf.stack_len();
2323
let mut acc_dep_1 = None;
2424
let mut acc_dep_2 = None;
2525

@@ -34,7 +34,7 @@ impl<'a> Analyzer<'a> {
3434
node.alternate.is_some(),
3535
);
3636
self.exec_statement(&node.consequent);
37-
let conditional_scope = self.pop_cf_scope_and_get_mut();
37+
let mut conditional_scope = self.pop_cf_scope();
3838
if let CfScopeKind::ExitBlocker(Some(stopped_exit)) = &conditional_scope.kind {
3939
exit_target_inner = exit_target_inner.max(*stopped_exit);
4040
exit_target_outer = exit_target_outer.min(*stopped_exit);
@@ -55,7 +55,7 @@ impl<'a> Analyzer<'a> {
5555
);
5656
if let Some(alternate) = &node.alternate {
5757
self.exec_statement(alternate);
58-
let conditional_scope = self.pop_cf_scope_and_get_mut();
58+
let mut conditional_scope = self.pop_cf_scope();
5959
if let CfScopeKind::ExitBlocker(Some(stopped_exit)) = &conditional_scope.kind {
6060
exit_target_inner = exit_target_inner.max(*stopped_exit);
6161
exit_target_outer = exit_target_outer.min(*stopped_exit);
@@ -72,12 +72,12 @@ impl<'a> Analyzer<'a> {
7272
let acc_dep = Some(self.dep((acc_dep_1, acc_dep_2)));
7373
if both_exit {
7474
if let Some(acc_dep) =
75-
self.exit_to_impl(exit_target_inner, self.scoping.cf.stack.len(), true, acc_dep)
75+
self.exit_to_impl(exit_target_inner, self.scoping.cf.stack_len(), true, acc_dep)
7676
{
7777
self.exit_to_impl(exit_target_outer, exit_target_inner, false, acc_dep);
7878
}
7979
} else {
80-
self.exit_to_impl(exit_target_outer, self.scoping.cf.stack.len(), false, acc_dep);
80+
self.exit_to_impl(exit_target_outer, self.scoping.cf.stack_len(), false, acc_dep);
8181
}
8282
}
8383
}

crates/jsshaker/src/scope/cf_scope.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ use oxc::{ast::ast::LabeledStatement, span::Atom};
22

33
use crate::{
44
analyzer::{Analyzer, exhaustive::ExhaustiveData},
5-
define_box_bump_idx,
5+
define_stacked_tree_idx,
66
dep::{Dep, DepCollector, DepVec},
77
utils::ast::AstKind2,
88
value::cache::FnCacheTrackingData,
99
};
1010

11-
define_box_bump_idx! {
11+
define_stacked_tree_idx! {
1212
pub struct CfScopeId;
1313
}
1414

@@ -17,14 +17,14 @@ pub enum CfScopeKind<'a> {
1717
Root,
1818
Module,
1919
Labeled(&'a LabeledStatement<'a>),
20-
Function(&'a mut FnCacheTrackingData<'a>),
20+
Function(Box<FnCacheTrackingData<'a>>),
2121
LoopBreak,
2222
LoopContinue,
2323
Switch,
2424

2525
Dependent,
2626
NonDet,
27-
Exhaustive(&'a mut ExhaustiveData<'a>),
27+
Exhaustive(Box<ExhaustiveData<'a>>),
2828
ExitBlocker(Option<usize>),
2929
}
3030

@@ -157,8 +157,8 @@ impl<'a> Analyzer<'a> {
157157
pub fn get_exec_dep(&mut self, target_depth: usize) -> (DepVec<'a>, bool) {
158158
let mut deps = self.factory.vec();
159159
let mut non_det = false;
160-
for id in target_depth..self.scoping.cf.stack.len() {
161-
let scope = self.scoping.cf.get_mut_from_depth(id);
160+
for id in target_depth..self.scoping.cf.stack_len() {
161+
let scope = self.scoping.cf.data_at_mut(id);
162162
if let Some(dep) = scope.deps.collect(self.factory) {
163163
deps.push(dep);
164164
}
@@ -168,11 +168,11 @@ impl<'a> Analyzer<'a> {
168168
}
169169

170170
pub fn exit_to(&mut self, target_depth: usize) {
171-
self.exit_to_impl(target_depth, self.scoping.cf.stack.len(), true, None);
171+
self.exit_to_impl(target_depth, self.scoping.cf.stack_len(), true, None);
172172
}
173173

174174
pub fn exit_to_not_must(&mut self, target_depth: usize) {
175-
self.exit_to_impl(target_depth, self.scoping.cf.stack.len(), false, None);
175+
self.exit_to_impl(target_depth, self.scoping.cf.stack_len(), false, None);
176176
}
177177

178178
/// `None` => Interrupted by if branch
@@ -185,8 +185,7 @@ impl<'a> Analyzer<'a> {
185185
mut acc_dep: Option<Dep<'a>>,
186186
) -> Option<Option<Dep<'a>>> {
187187
for depth in (target_depth..from_depth).rev() {
188-
let id = self.scoping.cf.stack[depth];
189-
let cf_scope = self.scoping.cf.get_mut(id);
188+
let cf_scope = self.scoping.cf.data_at_mut(depth);
190189

191190
if cf_scope.must_exited() {
192191
return Some(Some(self.factory.no_dep));
@@ -310,8 +309,7 @@ impl<'a> Analyzer<'a> {
310309
pub fn global_effect(&mut self) {
311310
let mut deps = vec![];
312311
let mut first_stage = true;
313-
for scope in self.scoping.cf.stack.iter().rev() {
314-
let scope = &mut self.scoping.cf.nodes.get_mut(*scope).data;
312+
for scope in self.scoping.cf.iter_stack_mut().rev() {
315313
if first_stage {
316314
match scope.deoptimize_state {
317315
DeoptimizeState::Never => {

crates/jsshaker/src/scope/mod.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ mod stacked_tree;
66
mod linked_tree;
77
pub mod variable_scope;
88

9-
use std::mem;
10-
119
use call_scope::CallScope;
1210
use cf_scope::CfScope;
1311
pub use cf_scope::{CfScopeId, CfScopeKind};
@@ -28,7 +26,7 @@ use crate::{
2826
pub struct Scoping<'a> {
2927
pub call: Vec<CallScope<'a>>,
3028
pub variable: LinkedTree<'a, VariableScopeId, VariableScope<'a>>,
31-
pub cf: StackedTree<'a, CfScopeId, CfScope<'a>>,
29+
pub cf: StackedTree<CfScopeId, CfScope<'a>>,
3230
pub root_cf_scope: CfScopeId,
3331
pub try_catch_depth: Option<usize>,
3432
pub current_callsite: AstKind2<'a>,
@@ -40,8 +38,8 @@ impl<'a> Scoping<'a> {
4038
let mut variable = LinkedTree::new_in(factory.allocator);
4139
let root_variable_scope =
4240
variable.push(VariableScope::new_in_with_this(factory.allocator, factory.unknown));
43-
let mut cf = StackedTree::new_in(factory.allocator);
44-
let root_cf_scope = cf.push(CfScope::new(CfScopeKind::Root, factory.vec(), false));
41+
let cf = StackedTree::new(CfScope::new(CfScopeKind::Root, factory.vec(), false));
42+
let root_cf_scope = cf.root;
4543
factory.root_cf_scope = Some(root_cf_scope);
4644
Scoping {
4745
call: vec![CallScope::new_in(
@@ -80,11 +78,11 @@ impl<'a> Analyzer<'a> {
8078
}
8179

8280
pub fn cf_scope(&self) -> &CfScope<'a> {
83-
self.scoping.cf.get_current()
81+
self.scoping.cf.current_data()
8482
}
8583

8684
pub fn cf_scope_mut(&mut self) -> &mut CfScope<'a> {
87-
self.scoping.cf.get_current_mut()
85+
self.scoping.cf.current_data_mut()
8886
}
8987

9088
pub fn variable_scope(&self) -> &VariableScope<'a> {
@@ -111,9 +109,7 @@ impl<'a> Analyzer<'a> {
111109
let old_variable_scope_stack = self.replace_variable_scope(info.func.lexical_scope);
112110
let body_variable_scope = self.push_variable_scope();
113111
let cf_scope_depth = self.push_cf_scope_with_deps(
114-
CfScopeKind::Function(
115-
self.allocator.alloc(FnCacheTrackingData::new_in(self.allocator, info)),
116-
),
112+
CfScopeKind::Function(Box::new(FnCacheTrackingData::new_in(self.allocator, info))),
117113
self.factory.vec1(info.call_dep),
118114
false,
119115
);
@@ -133,17 +129,14 @@ impl<'a> Analyzer<'a> {
133129
pub fn pop_call_scope(&mut self) -> (Entity<'a>, FnCacheTrackingData<'a>) {
134130
let scope = self.scoping.call.pop().unwrap();
135131
let ret_val = scope.ret_val(self);
136-
let cf_scope_id = self.pop_cf_scope();
137-
let cf_scope = self.scoping.cf.get_mut(cf_scope_id);
138-
let CfScopeKind::Function(tracking_data) = &mut cf_scope.kind else {
132+
let cf_scope = self.pop_cf_scope();
133+
let CfScopeKind::Function(tracking_data) = cf_scope.kind else {
139134
unreachable!();
140135
};
141-
let tracking_data = mem::take(*tracking_data);
142-
143136
self.pop_variable_scope();
144137
self.replace_variable_scope(scope.old_variable_scope);
145138
self.set_current_module(scope.old_module);
146-
(ret_val, tracking_data)
139+
(ret_val, *tracking_data)
147140
}
148141

149142
pub fn push_variable_scope(&mut self) -> VariableScopeId {
@@ -180,23 +173,18 @@ impl<'a> Analyzer<'a> {
180173
);
181174
}
182175

183-
pub fn pop_cf_scope(&mut self) -> CfScopeId {
176+
pub fn pop_cf_scope(&mut self) -> CfScope<'a> {
184177
self.scoping.cf.pop()
185178
}
186179

187180
pub fn pop_multiple_cf_scopes(&mut self, count: usize) -> Option<Dep<'a>> {
188181
let mut exec_deps = self.factory.vec();
189182
for _ in 0..count {
190-
let id = self.scoping.cf.stack.pop().unwrap();
191-
if let Some(dep) = self.scoping.cf.get_mut(id).deps.collect(self.factory) {
183+
let mut scope = self.pop_cf_scope();
184+
if let Some(dep) = scope.deps.collect(self.factory) {
192185
exec_deps.push(dep);
193186
}
194187
}
195188
if exec_deps.is_empty() { None } else { Some(self.dep(exec_deps)) }
196189
}
197-
198-
pub fn pop_cf_scope_and_get_mut(&mut self) -> &mut CfScope<'a> {
199-
let id = self.pop_cf_scope();
200-
self.scoping.cf.get_mut(id)
201-
}
202190
}

0 commit comments

Comments
 (0)