swc_ecma_transforms_base/
perf.rs1use swc_common::util::move_map::MoveMap;
2#[cfg(feature = "concurrent")]
3use swc_common::{errors::HANDLER, GLOBALS};
4use swc_ecma_ast::*;
5pub use swc_ecma_utils::parallel::*;
6use swc_ecma_visit::{Fold, FoldWith, Visit, VisitMut, VisitMutWith, VisitWith};
7
8#[cfg(feature = "concurrent")]
9use crate::helpers::Helpers;
10#[cfg(feature = "concurrent")]
11use crate::helpers::HELPERS;
12
13pub trait Check: Visit + Default {
14 fn should_handle(&self) -> bool;
15}
16
17pub fn should_work<C, T>(n: &T) -> bool
18where
19 C: Check,
20 T: VisitWith<C>,
21{
22 let mut checker = C::default();
23 n.visit_with(&mut checker);
24 checker.should_handle()
25}
26
27pub trait ParExplode: Parallel {
28 fn after_one_stmt(&mut self, stmts: &mut Vec<Stmt>);
32
33 fn after_one_module_item(&mut self, stmts: &mut Vec<ModuleItem>);
37}
38
39pub trait ParVisit: Visit + Parallel {
40 fn visit_par<N>(&mut self, threshold: usize, nodes: &[N])
41 where
42 N: Send + Sync + VisitWith<Self>;
43}
44
45#[cfg(feature = "concurrent")]
46impl<T> ParVisit for T
47where
48 T: Visit + Parallel,
49{
50 fn visit_par<N>(&mut self, threshold: usize, nodes: &[N])
51 where
52 N: Send + Sync + VisitWith<Self>,
53 {
54 if nodes.len() >= threshold {
55 HELPERS.with(|helpers| {
56 let helpers = helpers.data();
57
58 HANDLER.with(|handler| {
59 self.maybe_par(threshold, nodes, |visitor, node| {
60 let helpers = Helpers::from_data(helpers);
61 HELPERS.set(&helpers, || {
62 HANDLER.set(handler, || {
63 node.visit_with(visitor);
64 });
65 });
66 });
67 })
68 });
69 return;
70 }
71
72 for n in nodes {
73 n.visit_with(self);
74 }
75 }
76}
77
78pub trait ParVisitMut: VisitMut + Parallel {
79 fn visit_mut_par<N>(&mut self, threshold: usize, nodes: &mut [N])
80 where
81 N: Send + Sync + VisitMutWith<Self>;
82}
83
84#[cfg(feature = "concurrent")]
85impl<T> ParVisitMut for T
86where
87 T: VisitMut + Parallel,
88{
89 fn visit_mut_par<N>(&mut self, threshold: usize, nodes: &mut [N])
90 where
91 N: Send + Sync + VisitMutWith<Self>,
92 {
93 if nodes.len() >= threshold {
94 HELPERS.with(|helpers| {
95 let helpers = helpers.data();
96
97 HANDLER.with(|handler| {
98 self.maybe_par(threshold, nodes, |visitor, node| {
99 let helpers = Helpers::from_data(helpers);
100 HELPERS.set(&helpers, || {
101 HANDLER.set(handler, || {
102 node.visit_mut_with(visitor);
103 });
104 });
105 });
106 })
107 });
108
109 return;
110 }
111
112 for n in nodes {
113 n.visit_mut_with(self);
114 }
115 }
116}
117
118pub trait ParFold: Fold + Parallel {
119 fn fold_par<N>(&mut self, threshold: usize, nodes: Vec<N>) -> Vec<N>
120 where
121 N: Send + Sync + FoldWith<Self>;
122}
123
124#[cfg(feature = "concurrent")]
125impl<T> ParFold for T
126where
127 T: Fold + Parallel,
128{
129 fn fold_par<N>(&mut self, threshold: usize, nodes: Vec<N>) -> Vec<N>
130 where
131 N: Send + Sync + FoldWith<Self>,
132 {
133 if nodes.len() >= threshold {
134 use par_iter::prelude::*;
135
136 let (visitor, nodes) = GLOBALS.with(|globals| {
137 HELPERS.with(|helpers| {
138 let helpers = helpers.data();
139 HANDLER.with(|handler| {
140 nodes
141 .into_par_iter()
142 .map(|node| {
143 let helpers = Helpers::from_data(helpers);
144 GLOBALS.set(globals, || {
145 HELPERS.set(&helpers, || {
146 HANDLER.set(handler, || {
147 let mut visitor = Parallel::create(&*self);
148 let node = node.fold_with(&mut visitor);
149
150 (visitor, node)
151 })
152 })
153 })
154 })
155 .fold(
156 || (Parallel::create(&*self), Vec::new()),
157 |mut a, b| {
158 Parallel::merge(&mut a.0, b.0);
159
160 a.1.push(b.1);
161
162 a
163 },
164 )
165 .reduce(
166 || (Parallel::create(&*self), Vec::new()),
167 |mut a, b| {
168 Parallel::merge(&mut a.0, b.0);
169
170 a.1.extend(b.1);
171
172 a
173 },
174 )
175 })
176 })
177 });
178
179 Parallel::merge(self, visitor);
180
181 return nodes;
182 }
183
184 nodes.move_map(|n| n.fold_with(self))
185 }
186}
187
188#[cfg(not(feature = "concurrent"))]
189impl<T> ParVisit for T
190where
191 T: Visit + Parallel,
192{
193 fn visit_par<N>(&mut self, _: usize, nodes: &[N])
194 where
195 N: Send + Sync + VisitWith<Self>,
196 {
197 for n in nodes {
198 n.visit_with(self);
199 }
200 }
201}
202
203#[cfg(not(feature = "concurrent"))]
204impl<T> ParVisitMut for T
205where
206 T: VisitMut + Parallel,
207{
208 fn visit_mut_par<N>(&mut self, _: usize, nodes: &mut [N])
209 where
210 N: Send + Sync + VisitMutWith<Self>,
211 {
212 for n in nodes {
213 n.visit_mut_with(self);
214 }
215 }
216}
217
218#[cfg(not(feature = "concurrent"))]
219impl<T> ParFold for T
220where
221 T: Fold + Parallel,
222{
223 fn fold_par<N>(&mut self, _: usize, nodes: Vec<N>) -> Vec<N>
224 where
225 N: Send + Sync + FoldWith<Self>,
226 {
227 nodes.move_map(|n| n.fold_with(self))
228 }
229}