Skip to content

Commit 5c87d1f

Browse files
committed
refactor(semantic/cfg): cleanup control flow and it's builder.
1 parent 2efdc8b commit 5c87d1f

File tree

4 files changed

+9
-101
lines changed

4 files changed

+9
-101
lines changed

crates/oxc_linter/src/rules/react/rules_of_hooks.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ impl Rule for RulesOfHooks {
225225
return;
226226
}
227227

228-
if !ctx.semantic().cfg().is_reachabale(func_cfg_id, node_cfg_id) {
228+
if !ctx.semantic().cfg().is_reachable(func_cfg_id, node_cfg_id) {
229229
// There should always be a control flow path between a parent and child node.
230230
// If there is none it means we always do an early exit before reaching our hook call.
231231
// In some cases it might mean that we are operating on an invalid `cfg` but in either
@@ -302,7 +302,7 @@ fn has_conditional_path_accept_throw(
302302
.into_iter()
303303
.filter(|(_, val)| *val == 0)
304304
.any(|(f, _)| {
305-
!cfg.is_reachabale_filtered(f, to_graph_id, |it| {
305+
!cfg.is_reachable_filtered(f, to_graph_id, |it| {
306306
if cfg
307307
.basic_block(it)
308308
.instructions()

crates/oxc_semantic/src/builder.rs

+2-34
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
class::ClassTableBuilder,
1919
control_flow::{
2020
ControlFlowGraphBuilder, CtxCursor, CtxFlags, EdgeType, ErrorEdgeKind,
21-
IterationInstructionKind, Register, ReturnInstructionKind,
21+
IterationInstructionKind, ReturnInstructionKind,
2222
},
2323
diagnostics::redeclaration,
2424
jsdoc::JSDocBuilder,
@@ -541,13 +541,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
541541
fn visit_debugger_statement(&mut self, stmt: &DebuggerStatement) {
542542
let kind = AstKind::DebuggerStatement(self.alloc(stmt));
543543
self.enter_node(kind);
544-
545-
/* cfg */
546-
// just take the next_label since it should be taken by the next
547-
// statement regardless of whether the statement can use it or not
548-
self.cfg.next_label.take();
549-
/* cfg */
550-
551544
self.leave_node(kind);
552545
}
553546

@@ -1006,10 +999,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
1006999

10071000
self.visit_label_identifier(&stmt.label);
10081001

1009-
/* cfg */
1010-
self.cfg.next_label = Some(stmt.label.name.to_compact_str());
1011-
/* cfg */
1012-
10131002
self.visit_statement(&stmt.body);
10141003

10151004
/* cfg */
@@ -1373,8 +1362,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
13731362
func.scope_id.set(Some(self.current_scope_id));
13741363

13751364
/* cfg */
1376-
let preserved = self.cfg.preserve_expression_state();
1377-
13781365
let before_function_graph_ix = self.cfg.current_node_ix;
13791366
let error_harness = self.cfg.attach_error_harness(ErrorEdgeKind::Implicit);
13801367
let function_graph_ix = self.cfg.new_basic_block_function();
@@ -1398,7 +1385,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
13981385
}
13991386

14001387
/* cfg */
1401-
self.cfg.restore_expression_state(preserved);
14021388
self.cfg.ctx(None).resolve_expect(CtxFlags::FUNCTION);
14031389
self.cfg.release_error_harness(error_harness);
14041390
let after_function_graph_ix = self.cfg.new_basic_block_normal();
@@ -1435,11 +1421,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14351421

14361422
self.enter_node(kind);
14371423

1438-
/* cfg */
1439-
let preserved = self.cfg.preserve_expression_state();
1440-
self.cfg.store_final_assignments_into_this_array.push(vec![]);
1441-
/* cfg */
1442-
14431424
if let Some(id) = &class.id {
14441425
self.visit_binding_identifier(id);
14451426
}
@@ -1455,14 +1436,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14551436
}
14561437
self.visit_class_body(&class.body);
14571438

1458-
/* cfg */
1459-
let _elements = self.cfg.store_final_assignments_into_this_array.pop().expect(
1460-
"expected there to be atleast one vec in the store_final_assignments_into_this_arrays",
1461-
);
1462-
self.cfg.restore_expression_state(preserved);
1463-
self.cfg.spread_indices.push(vec![]);
1464-
/* cfg */
1465-
14661439
self.leave_node(kind);
14671440
if is_class_expr {
14681441
self.leave_scope();
@@ -1485,7 +1458,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14851458
expr.scope_id.set(Some(self.current_scope_id));
14861459

14871460
/* cfg */
1488-
let preserved = self.cfg.preserve_expression_state();
14891461
let current_node_ix = self.cfg.current_node_ix;
14901462
let error_harness = self.cfg.attach_error_harness(ErrorEdgeKind::Implicit);
14911463
let function_graph_ix = self.cfg.new_basic_block_function();
@@ -1500,15 +1472,11 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
15001472

15011473
/* cfg */
15021474
self.cfg.add_edge(current_node_ix, function_graph_ix, EdgeType::NewFunction);
1503-
if expr.expression {
1504-
self.cfg.store_assignments_into_this_array.push(vec![]);
1505-
self.cfg.use_this_register = Some(Register::Return);
1506-
}
15071475
/* cfg */
1476+
15081477
self.visit_function_body(&expr.body);
15091478

15101479
/* cfg */
1511-
self.cfg.restore_expression_state(preserved);
15121480
self.cfg.ctx(None).resolve_expect(CtxFlags::FUNCTION);
15131481
self.cfg.release_error_harness(error_harness);
15141482
self.cfg.current_node_ix = current_node_ix;

crates/oxc_semantic/src/control_flow/builder/mod.rs

+2-45
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ pub use context::{CtxCursor, CtxFlags};
77
use petgraph::Direction;
88

99
use super::{
10-
AstNodeId, BasicBlock, BasicBlockId, CompactStr, ControlFlowGraph, EdgeType, ErrorEdgeKind,
11-
Graph, Instruction, InstructionKind, IterationInstructionKind, LabeledInstruction,
12-
PreservedExpressionState, Register,
10+
AstNodeId, BasicBlock, BasicBlockId, ControlFlowGraph, EdgeType, ErrorEdgeKind, Graph,
11+
Instruction, InstructionKind, IterationInstructionKind, LabeledInstruction,
1312
};
1413

1514
#[derive(Debug, Default)]
@@ -25,27 +24,6 @@ pub struct ControlFlowGraphBuilder<'a> {
2524
error_path: Vec<ErrorHarness>,
2625
/// Stack of finalizers, the top most element is always the appropriate one for current node.
2726
finalizers: Vec<BasicBlockId>,
28-
// note: this should only land in the big box for all things that take arguments
29-
// ie: callexpression, arrayexpression, etc
30-
// todo: add assert that it is used every time?
31-
pub use_this_register: Option<Register>,
32-
pub next_free_register: u32,
33-
pub store_assignments_into_this_array: Vec<Vec<Register>>,
34-
pub store_final_assignments_into_this_array: Vec<Vec<Register>>,
35-
// indexes of spreads in the store_assignments_into_this_array
36-
pub spread_indices: Vec<Vec<usize>>,
37-
// computed member expressions are only executed when we reach
38-
// that part of the chain, so we keep this vec to patch them in later
39-
pub should_save_stores_for_patching: bool,
40-
pub saved_store: Option<usize>,
41-
pub basic_blocks_with_breaks: Vec<Vec<BasicBlockId>>,
42-
pub basic_blocks_with_continues: Vec<Vec<BasicBlockId>>,
43-
// node indexes of the basic blocks of switch case conditions
44-
pub switch_case_conditions: Vec<Vec<BasicBlockId>>,
45-
pub next_label: Option<CompactStr>,
46-
pub label_to_ast_node_ix: Vec<(CompactStr, AstNodeId)>,
47-
pub ast_node_to_break_continue: Vec<(AstNodeId, usize, Option<usize>)>,
48-
pub after_throw_block: Option<BasicBlockId>,
4927
}
5028

5129
impl<'a> ControlFlowGraphBuilder<'a> {
@@ -243,27 +221,6 @@ impl<'a> ControlFlowGraphBuilder<'a> {
243221
self.basic_block_mut(block).instructions.push(Instruction { kind, node_id });
244222
}
245223

246-
#[must_use]
247-
pub fn preserve_expression_state(&mut self) -> PreservedExpressionState {
248-
let use_this_register = self.use_this_register.take();
249-
let mut store_final_assignments_into_this_array = vec![];
250-
std::mem::swap(
251-
&mut store_final_assignments_into_this_array,
252-
&mut self.store_final_assignments_into_this_array,
253-
);
254-
255-
// DO NOT preserve: saved_stores, should_save_stores_for_patching
256-
// should_save_stores_for_patching must always be active to catch
257-
// all stores, preserving will mess it up.
258-
PreservedExpressionState { use_this_register, store_final_assignments_into_this_array }
259-
}
260-
261-
pub fn restore_expression_state(&mut self, mut preserved_state: PreservedExpressionState) {
262-
self.use_this_register = preserved_state.use_this_register.take();
263-
self.store_final_assignments_into_this_array =
264-
preserved_state.store_final_assignments_into_this_array;
265-
}
266-
267224
pub fn enter_statement(&mut self, stmt: AstNodeId) {
268225
self.push_statement(stmt);
269226
}

crates/oxc_semantic/src/control_flow/mod.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,11 @@ impl ControlFlowGraph {
222222
self.basic_blocks.get_mut(ix).expect("expected a valid node id in self.basic_blocks")
223223
}
224224

225-
pub fn is_reachabale(&self, from: BasicBlockId, to: BasicBlockId) -> bool {
226-
self.is_reachabale_filtered(from, to, |_| Control::Continue)
225+
pub fn is_reachable(&self, from: BasicBlockId, to: BasicBlockId) -> bool {
226+
self.is_reachable_filtered(from, to, |_| Control::Continue)
227227
}
228228

229-
pub fn is_reachabale_filtered<F: Fn(BasicBlockId) -> Control<bool>>(
229+
pub fn is_reachable_filtered<F: Fn(BasicBlockId) -> Control<bool>>(
230230
&self,
231231
from: BasicBlockId,
232232
to: BasicBlockId,
@@ -352,21 +352,4 @@ impl ControlFlowGraph {
352352
})
353353
.is_err()
354354
}
355-
356-
pub fn has_conditional_path(&self, from: BasicBlockId, to: BasicBlockId) -> bool {
357-
let graph = &self.graph;
358-
// All nodes should be able to reach the `to` node, Otherwise we have a conditional/branching flow.
359-
petgraph::algo::dijkstra(graph, from, Some(to), |e| match e.weight() {
360-
EdgeType::NewFunction | EdgeType::Error(_) | EdgeType::Finalize | EdgeType::Join => 1,
361-
EdgeType::Jump | EdgeType::Unreachable | EdgeType::Backedge | EdgeType::Normal => 0,
362-
})
363-
.into_iter()
364-
.filter(|(_, val)| *val == 0)
365-
.any(|(f, _)| !self.is_reachabale(f, to))
366-
}
367-
}
368-
369-
pub struct PreservedExpressionState {
370-
pub use_this_register: Option<Register>,
371-
pub store_final_assignments_into_this_array: Vec<Vec<Register>>,
372355
}

0 commit comments

Comments
 (0)