Skip to content

Commit bfdd1c2

Browse files
committed
Basical design work is done
1 parent 08fc0e8 commit bfdd1c2

File tree

4 files changed

+108
-19
lines changed

4 files changed

+108
-19
lines changed

ecmascript/optimizer/src/ast.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,67 @@
1+
use swc_common::Mark;
2+
use swc_common::Span;
3+
use swc_common::GLOBALS;
14
use swc_ecma_ast::*;
25
use swc_ecma_visit::noop_visit_mut_type;
36
use swc_ecma_visit::VisitMut;
47
use swc_ecma_visit::VisitMutWith;
58

69
/// Make every statements `identifiable` by marking all spans.
710
///
8-
/// This requires [swc_common::GLOBALS] to be set.
11+
/// This requires [swc_common::GLOBALS] to be set and same instance of
12+
/// [swc_common::Globals] should be used for [prepare] and [clean].
913
pub(crate) fn prepare(m: &mut Module) {
10-
m.visit_mut_with(&mut Preparer)
14+
debug_assert!(
15+
GLOBALS.is_set(),
16+
"swc_common::GLOBALS should be set before calling optimizer::ast::prepare"
17+
);
18+
19+
m.visit_mut_with(&mut MarkModifier { remove_mode: false })
20+
}
21+
22+
/// Make every statements `identifiable` by marking all spans.
23+
///
24+
/// This requires [swc_common::GLOBALS] to be set and same instance of
25+
/// [swc_common::Globals] should be used for [prepare] and [clean].
26+
pub(crate) fn clean_up(m: &mut Module) {
27+
debug_assert!(
28+
GLOBALS.is_set(),
29+
"swc_common::GLOBALS should be set before calling optimizer::ast::clean_up"
30+
);
31+
32+
m.visit_mut_with(&mut MarkModifier { remove_mode: true })
1133
}
1234

13-
struct Preparer;
35+
/// This struct applies a mark to or remove the mark from all useful span nodes.
36+
///
37+
/// This is shared between marking process and removing process to ensure that
38+
/// we only remove marks applied by this pass.
39+
struct MarkModifier {
40+
remove_mode: bool,
41+
}
1442

15-
impl VisitMut for Preparer {
43+
impl VisitMut for MarkModifier {
1644
noop_visit_mut_type!();
1745

46+
fn visit_mut_span(&mut self, span: &mut Span) {
47+
if self.remove_mode {
48+
let mark = span.remove_mark();
49+
debug_assert_eq!(
50+
mark.parent(),
51+
Mark::root(),
52+
"optimizer::ast::clean_up should be only called for prepared modules, which is \
53+
created by calling optimizer::ast::prepare"
54+
);
55+
} else {
56+
let mark = Mark::fresh(Mark::root());
57+
*span = span.apply_mark(mark);
58+
}
59+
}
60+
61+
/// Noop. This is required for correctness, as simply marking everything
62+
/// breaks span hygiene.
63+
fn visit_mut_ident(&mut self, _: &mut Ident) {}
64+
1865
/// Noop. This is performance optimization.
1966
fn visit_mut_lit(&mut self, _: &mut Lit) {}
2067
}

ecmascript/optimizer/src/control_flow_graph/mod.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@ use crate::block_id::BlockId;
66
use crate::block_id::BlockIdGenerator;
77
use crate::mutations::Mutations;
88
use fxhash::FxHashMap;
9+
use petgraph::graphmap::DiGraphMap;
910
use std::cell::RefCell;
1011
use std::mem::take;
1112
use std::rc::Rc;
1213
use swc_ecma_ast::*;
1314
use swc_ecma_utils::Id;
1415

15-
pub mod traversal;
16+
pub(crate) mod traversal;
17+
18+
/// Actual `control flow` part of the control flow graph.
19+
///
20+
/// This type is used instead of hashmap to reduce work related to implementing
21+
/// visitors/
22+
pub(crate) type BlockGraph<'cfg> = DiGraphMap<BlockId, Vec<JumpCond<'cfg>>>;
1623

1724
/// This struct is required for optimizaiotn.
1825
#[derive(Debug)]
@@ -21,7 +28,7 @@ pub struct ControlFlowGraph<'cfg> {
2128

2229
blocks: FxHashMap<BlockId, Block<'cfg>>,
2330

24-
next: FxHashMap<BlockId, Vec<(BlockId, JumpCond<'cfg>)>>,
31+
next: BlockGraph<'cfg>,
2532
start: BlockId,
2633

2734
exprs: Vec<ExprData<'cfg>>,
@@ -69,17 +76,11 @@ impl<'cfg> ControlFlowGraph<'cfg> {
6976
mutations: Default::default(),
7077
}
7178
}
72-
73-
pub fn apply(self, to: &mut Module) {
74-
assert_eq!(to.body.len(), self.module_items.len());
75-
76-
self.mutations.apply(to);
77-
}
7879
}
7980
#[derive(Debug)]
8081
struct Analyzer<'cfg, 'a> {
8182
blocks: FxHashMap<BlockId, Block<'cfg>>,
82-
next: FxHashMap<BlockId, Vec<(BlockId, JumpCond<'cfg>)>>,
83+
next: BlockGraph<'cfg>,
8384
exprs: Vec<ExprData<'cfg>>,
8485
id_gen: Rc<RefCell<BlockIdGenerator>>,
8586
cur_id: BlockId,
@@ -157,7 +158,11 @@ impl<'cfg> Analyzer<'cfg, '_> {
157158

158159
self.cur_id = self.id_gen.borrow_mut().generate();
159160

160-
self.next.entry(from).or_default().push((to, cond));
161+
if let Some(edge) = self.next.edge_weight_mut(from, to) {
162+
edge.push(cond);
163+
} else {
164+
self.next.add_edge(from, to, vec![cond]);
165+
}
161166
}
162167

163168
fn jump_cond(&mut self, test: ExprData<'cfg>, to: BlockId, if_true: bool) {

ecmascript/optimizer/src/control_flow_graph/traversal.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
use super::ControlFlowGraph;
12
use crate::basic_block::Block;
23
use crate::basic_block::JumpCond;
34
use crate::block_id::BlockId;
4-
55
pub(crate) trait Visitor<'cfg> {
66
fn visit_block(
77
&mut self,
@@ -11,3 +11,11 @@ pub(crate) trait Visitor<'cfg> {
1111
) {
1212
}
1313
}
14+
15+
impl<'cfg> ControlFlowGraph<'cfg> {
16+
pub(crate) fn traverse<V>(&mut self, v: &mut V)
17+
where
18+
V: Visitor<'cfg>,
19+
{
20+
}
21+
}

ecmascript/optimizer/src/lib.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
1+
use crate::ast::clean_up;
2+
use crate::ast::prepare;
3+
use crate::control_flow_graph::ControlFlowGraph;
4+
use crate::dce::remove_dead_code;
5+
use swc_ecma_ast::*;
6+
17
mod ast;
2-
pub mod basic_block;
3-
pub mod block_id;
4-
pub mod control_flow_graph;
5-
pub mod dce;
8+
mod basic_block;
9+
mod block_id;
10+
mod control_flow_graph;
11+
mod dce;
612
mod mutations;
13+
14+
#[derive(Debug, Clone, Copy)]
15+
pub struct OptimizerConfig {
16+
pub dce: bool,
17+
}
18+
19+
pub fn optimize(m: &mut Module, config: OptimizerConfig) {
20+
prepare(m);
21+
22+
let mutations = {
23+
let mut cfg = ControlFlowGraph::anaylze(m);
24+
25+
if config.dce {
26+
remove_dead_code(&mut cfg);
27+
}
28+
29+
cfg.mutations
30+
};
31+
32+
mutations.apply(m);
33+
34+
clean_up(m);
35+
}

0 commit comments

Comments
 (0)