swc_ecma_transforms_base/
perf.rs

1use 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    /// Invoked after visiting each statements.
29    ///
30    /// Implementor should not delete/prepend to `stmts`.
31    fn after_one_stmt(&mut self, stmts: &mut Vec<Stmt>);
32
33    /// Invoked after visiting each statements.
34    ///
35    /// Implementor should not delete/prepend to `stmts`.
36    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}