Skip to content

Commit 0348668

Browse files
committed
Implement unrachable BasicBlock elimination
1 parent 34d61b1 commit 0348668

File tree

4 files changed

+809
-667
lines changed

4 files changed

+809
-667
lines changed

boa_cli/src/debug/optimizer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use boa_engine::{
22
object::{FunctionObjectBuilder, ObjectInitializer},
33
optimizer::{
4-
control_flow_graph::{ControlFlowGraph, GraphSimplification},
4+
control_flow_graph::{
5+
ControlFlowGraph, GraphEliminateUnreachableBasicBlocks, GraphSimplification,
6+
},
57
OptimizerOptions,
68
},
79
property::Attribute,
@@ -80,6 +82,9 @@ fn graph(_: &JsValue, args: &[JsValue], _context: &mut Context<'_>) -> JsResult<
8082
let changed = GraphSimplification::perform(&mut cfg);
8183
println!("Simplified({changed}) \n{:#?}", cfg);
8284

85+
let changed = GraphEliminateUnreachableBasicBlocks::perform(&mut cfg);
86+
println!("Eliminate Unreachble({changed}) \n{:#?}", cfg);
87+
8388
Ok(JsValue::undefined())
8489
}
8590

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
use std::{
2+
cell::RefCell,
3+
hash::{Hash, Hasher},
4+
ops::Deref,
5+
rc::{Rc, Weak},
6+
};
7+
8+
use bitflags::bitflags;
9+
10+
use super::{
11+
instruction_iterator::{InstructionIterator, InstructionIteratorResult},
12+
Terminator,
13+
};
14+
15+
bitflags! {
16+
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
17+
pub(crate) struct BasicBlockFlags: u8 {
18+
const REACHABLE = 0b0000_0001;
19+
}
20+
}
21+
22+
/// TODO: doc
23+
#[derive(Default, Clone)]
24+
pub struct BasicBlock {
25+
pub(crate) predecessors: Vec<WeakBasicBlock>,
26+
pub(crate) bytecode: Vec<u8>,
27+
pub(crate) terminator: Terminator,
28+
29+
pub(crate) flags: BasicBlockFlags,
30+
}
31+
32+
impl BasicBlock {
33+
/// Get nth instruction in the [`BasicBlock`].
34+
pub(crate) fn get(&mut self, nth: usize) -> Option<InstructionIteratorResult<'_>> {
35+
InstructionIterator::new(&self.bytecode).nth(nth)
36+
}
37+
38+
/// Insert nth instruction in the [`BasicBlock`].
39+
pub(crate) fn insert(&mut self, nth: usize, instruction: &[u8]) -> bool {
40+
let start = if let Some(value) = self.get(nth) {
41+
value.next_opcode_pc
42+
} else {
43+
0
44+
};
45+
46+
for i in 0..instruction.len() {
47+
self.bytecode.insert(start + i, instruction[i]);
48+
}
49+
50+
true
51+
}
52+
53+
/// Insert instruction in the last position in the [`BasicBlock`].
54+
pub(crate) fn insert_last(&mut self, instruction: &[u8]) -> bool {
55+
let start = if let Some(value) = InstructionIterator::new(&self.bytecode).last() {
56+
value.next_opcode_pc
57+
} else {
58+
0
59+
};
60+
61+
for i in 0..instruction.len() {
62+
self.bytecode.insert(start + i, instruction[i]);
63+
}
64+
65+
true
66+
}
67+
68+
/// Remove nth instruction in the [`BasicBlock`].
69+
pub(crate) fn remove(&mut self, nth: usize) -> bool {
70+
let Some(value) = self.get(nth) else {
71+
return false;
72+
};
73+
74+
let start = value.current_opcode_pc;
75+
let length = value.next_opcode_pc - value.current_opcode_pc;
76+
77+
for i in 0..length {
78+
self.bytecode.remove(start + i);
79+
}
80+
81+
true
82+
}
83+
84+
/// Remove last instruction in the [`BasicBlock`].
85+
pub(crate) fn remove_last(&mut self) -> bool {
86+
let Some(value) = InstructionIterator::new(&self.bytecode).last() else {
87+
return false;
88+
};
89+
90+
let start = value.current_opcode_pc;
91+
let length = value.next_opcode_pc - value.current_opcode_pc;
92+
93+
for i in 0..length {
94+
self.bytecode.remove(start + i);
95+
}
96+
97+
true
98+
}
99+
100+
pub(crate) fn reachable(&self) -> bool {
101+
self.flags.contains(BasicBlockFlags::REACHABLE)
102+
}
103+
104+
pub(crate) fn successors(&self) -> Vec<RcBasicBlock> {
105+
match &self.terminator {
106+
Terminator::None => vec![],
107+
Terminator::JumpUnconditional { target, .. } => {
108+
vec![target.clone()]
109+
}
110+
Terminator::JumpConditional { no, yes, .. } => {
111+
vec![no.clone(), yes.clone()]
112+
}
113+
Terminator::Return { finally } => {
114+
let mut successors = Vec::new();
115+
if let Some(finally) = finally {
116+
successors.push(finally.clone());
117+
}
118+
successors
119+
}
120+
}
121+
}
122+
123+
pub(crate) fn next(&self, nexts: &mut Vec<RcBasicBlock>) {
124+
match &self.terminator {
125+
Terminator::None => {}
126+
Terminator::JumpUnconditional { target, .. } => {
127+
nexts.push(target.clone());
128+
}
129+
Terminator::JumpConditional { no, yes, .. } => {
130+
nexts.push(no.clone());
131+
nexts.push(yes.clone());
132+
}
133+
Terminator::Return { finally } => {
134+
if let Some(_finally) = finally {
135+
// FIXME: should we include this??
136+
// nexts.push(finally.clone());
137+
}
138+
}
139+
}
140+
}
141+
}
142+
143+
/// Reference counted [`BasicBlock`] with interor mutability.
144+
#[derive(Default, Clone)]
145+
pub struct RcBasicBlock {
146+
inner: Rc<RefCell<BasicBlock>>,
147+
}
148+
149+
impl From<Rc<RefCell<BasicBlock>>> for RcBasicBlock {
150+
fn from(inner: Rc<RefCell<BasicBlock>>) -> Self {
151+
Self { inner }
152+
}
153+
}
154+
155+
impl Deref for RcBasicBlock {
156+
type Target = Rc<RefCell<BasicBlock>>;
157+
fn deref(&self) -> &Self::Target {
158+
&self.inner
159+
}
160+
}
161+
162+
impl PartialEq<RcBasicBlock> for RcBasicBlock {
163+
fn eq(&self, other: &RcBasicBlock) -> bool {
164+
Rc::ptr_eq(&self.inner, &other.inner)
165+
}
166+
}
167+
168+
impl Eq for RcBasicBlock {}
169+
170+
impl Hash for RcBasicBlock {
171+
fn hash<H: Hasher>(&self, state: &mut H) {
172+
(self.as_ptr() as usize).hash(state);
173+
}
174+
}
175+
176+
impl RcBasicBlock {
177+
/// TODO: doc
178+
pub fn downgrade(&self) -> WeakBasicBlock {
179+
WeakBasicBlock::from(Rc::downgrade(&self.inner))
180+
}
181+
}
182+
183+
/// Reference counted [`BasicBlock`] with interor mutability.
184+
#[derive(Default, Clone)]
185+
pub struct WeakBasicBlock {
186+
inner: Weak<RefCell<BasicBlock>>,
187+
}
188+
189+
impl From<Weak<RefCell<BasicBlock>>> for WeakBasicBlock {
190+
fn from(inner: Weak<RefCell<BasicBlock>>) -> Self {
191+
Self { inner }
192+
}
193+
}
194+
195+
impl Deref for WeakBasicBlock {
196+
type Target = Weak<RefCell<BasicBlock>>;
197+
fn deref(&self) -> &Self::Target {
198+
&self.inner
199+
}
200+
}
201+
202+
impl PartialEq<WeakBasicBlock> for WeakBasicBlock {
203+
fn eq(&self, other: &WeakBasicBlock) -> bool {
204+
Weak::ptr_eq(&self.inner, &other.inner)
205+
}
206+
}
207+
208+
impl WeakBasicBlock {
209+
/// TODO: doc
210+
pub fn upgrade(&self) -> Option<RcBasicBlock> {
211+
Some(RcBasicBlock::from(self.inner.upgrade()?))
212+
}
213+
}

0 commit comments

Comments
 (0)