Skip to content

Commit 14f4cca

Browse files
committed
refactor(semantic/cfg): cleanup control flow and it's builder.
1 parent 5faf0e9 commit 14f4cca

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 */
@@ -1370,8 +1359,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
13701359
func.scope_id.set(Some(self.current_scope_id));
13711360

13721361
/* cfg */
1373-
let preserved = self.cfg.preserve_expression_state();
1374-
13751362
let before_function_graph_ix = self.cfg.current_node_ix;
13761363
let error_harness = self.cfg.attach_error_harness(ErrorEdgeKind::Implicit);
13771364
let function_graph_ix = self.cfg.new_basic_block_function();
@@ -1395,7 +1382,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
13951382
}
13961383

13971384
/* cfg */
1398-
self.cfg.restore_expression_state(preserved);
13991385
self.cfg.ctx(None).resolve_expect(CtxFlags::FUNCTION);
14001386
self.cfg.release_error_harness(error_harness);
14011387
let after_function_graph_ix = self.cfg.new_basic_block_normal();
@@ -1432,11 +1418,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14321418

14331419
self.enter_node(kind);
14341420

1435-
/* cfg */
1436-
let preserved = self.cfg.preserve_expression_state();
1437-
self.cfg.store_final_assignments_into_this_array.push(vec![]);
1438-
/* cfg */
1439-
14401421
if let Some(id) = &class.id {
14411422
self.visit_binding_identifier(id);
14421423
}
@@ -1452,14 +1433,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14521433
}
14531434
self.visit_class_body(&class.body);
14541435

1455-
/* cfg */
1456-
let _elements = self.cfg.store_final_assignments_into_this_array.pop().expect(
1457-
"expected there to be atleast one vec in the store_final_assignments_into_this_arrays",
1458-
);
1459-
self.cfg.restore_expression_state(preserved);
1460-
self.cfg.spread_indices.push(vec![]);
1461-
/* cfg */
1462-
14631436
self.leave_node(kind);
14641437
if is_class_expr {
14651438
self.leave_scope();
@@ -1482,7 +1455,6 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14821455
expr.scope_id.set(Some(self.current_scope_id));
14831456

14841457
/* cfg */
1485-
let preserved = self.cfg.preserve_expression_state();
14861458
let current_node_ix = self.cfg.current_node_ix;
14871459
let error_harness = self.cfg.attach_error_harness(ErrorEdgeKind::Implicit);
14881460
let function_graph_ix = self.cfg.new_basic_block_function();
@@ -1497,15 +1469,11 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
14971469

14981470
/* cfg */
14991471
self.cfg.add_edge(current_node_ix, function_graph_ix, EdgeType::NewFunction);
1500-
if expr.expression {
1501-
self.cfg.store_assignments_into_this_array.push(vec![]);
1502-
self.cfg.use_this_register = Some(Register::Return);
1503-
}
15041472
/* cfg */
1473+
15051474
self.visit_function_body(&expr.body);
15061475

15071476
/* cfg */
1508-
self.cfg.restore_expression_state(preserved);
15091477
self.cfg.ctx(None).resolve_expect(CtxFlags::FUNCTION);
15101478
self.cfg.release_error_harness(error_harness);
15111479
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)