mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
feat(semantic/cfg): add iteration instructions. (#3566)
This commit is contained in:
parent
defef057e1
commit
f2dfd667df
11 changed files with 77 additions and 43 deletions
|
|
@ -275,6 +275,7 @@ impl GetterReturn {
|
||||||
// Ignore irrelevant elements.
|
// Ignore irrelevant elements.
|
||||||
| InstructionKind::Break(_)
|
| InstructionKind::Break(_)
|
||||||
| InstructionKind::Continue(_)
|
| InstructionKind::Continue(_)
|
||||||
|
| InstructionKind::Iteration(_)
|
||||||
| InstructionKind::Statement => {}
|
| InstructionKind::Statement => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ fn contains_return_statement<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> b
|
||||||
InstructionKind::Return(ReturnInstructionKind::ImplicitUndefined)
|
InstructionKind::Return(ReturnInstructionKind::ImplicitUndefined)
|
||||||
| InstructionKind::Break(_)
|
| InstructionKind::Break(_)
|
||||||
| InstructionKind::Continue(_)
|
| InstructionKind::Continue(_)
|
||||||
|
| InstructionKind::Iteration(_)
|
||||||
| InstructionKind::Statement => {}
|
| InstructionKind::Statement => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ use crate::{
|
||||||
checker::{EarlyErrorJavaScript, EarlyErrorTypeScript},
|
checker::{EarlyErrorJavaScript, EarlyErrorTypeScript},
|
||||||
class::ClassTableBuilder,
|
class::ClassTableBuilder,
|
||||||
control_flow::{
|
control_flow::{
|
||||||
ControlFlowGraphBuilder, CtxCursor, CtxFlags, EdgeType, ErrorEdgeKind, Register,
|
ControlFlowGraphBuilder, CtxCursor, CtxFlags, EdgeType, ErrorEdgeKind,
|
||||||
ReturnInstructionKind,
|
IterationInstructionKind, Register, ReturnInstructionKind,
|
||||||
},
|
},
|
||||||
diagnostics::redeclaration,
|
diagnostics::redeclaration,
|
||||||
jsdoc::JSDocBuilder,
|
jsdoc::JSDocBuilder,
|
||||||
|
|
@ -71,6 +71,8 @@ pub struct SemanticBuilder<'a> {
|
||||||
pub cfg: ControlFlowGraphBuilder<'a>,
|
pub cfg: ControlFlowGraphBuilder<'a>,
|
||||||
|
|
||||||
pub class_table_builder: ClassTableBuilder,
|
pub class_table_builder: ClassTableBuilder,
|
||||||
|
|
||||||
|
ast_nodes_records: Vec<Vec<AstNodeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SemanticBuilderReturn<'a> {
|
pub struct SemanticBuilderReturn<'a> {
|
||||||
|
|
@ -105,6 +107,7 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
check_syntax_error: false,
|
check_syntax_error: false,
|
||||||
cfg: ControlFlowGraphBuilder::default(),
|
cfg: ControlFlowGraphBuilder::default(),
|
||||||
class_table_builder: ClassTableBuilder::new(),
|
class_table_builder: ClassTableBuilder::new(),
|
||||||
|
ast_nodes_records: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,6 +210,7 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
} else {
|
} else {
|
||||||
self.nodes.add_node(ast_node, Some(self.current_node_id))
|
self.nodes.add_node(ast_node, Some(self.current_node_id))
|
||||||
};
|
};
|
||||||
|
self.record_ast_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_ast_node(&mut self) {
|
fn pop_ast_node(&mut self) {
|
||||||
|
|
@ -215,6 +219,20 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn record_ast_nodes(&mut self) {
|
||||||
|
self.ast_nodes_records.push(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn retrieve_recorded_ast_nodes(&mut self) -> Vec<AstNodeId> {
|
||||||
|
self.ast_nodes_records.pop().expect("there is no ast nodes record to stop.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record_ast_node(&mut self) {
|
||||||
|
if let Some(records) = self.ast_nodes_records.last_mut() {
|
||||||
|
records.push(self.current_node_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn current_scope_flags(&self) -> ScopeFlags {
|
pub fn current_scope_flags(&self) -> ScopeFlags {
|
||||||
self.scope.get_flags(self.current_scope_id)
|
self.scope.get_flags(self.current_scope_id)
|
||||||
}
|
}
|
||||||
|
|
@ -741,7 +759,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
let after_body_graph_ix = self.cfg.current_node_ix;
|
let after_body_graph_ix = self.cfg.current_node_ix;
|
||||||
let after_for_stmt = self.cfg.new_basic_block_normal();
|
let after_for_stmt = self.cfg.new_basic_block_normal();
|
||||||
self.cfg.add_edge(before_for_graph_ix, test_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(before_for_graph_ix, test_graph_ix, EdgeType::Normal);
|
||||||
self.cfg.add_edge(after_test_graph_ix, before_body_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(after_test_graph_ix, before_body_graph_ix, EdgeType::Jump);
|
||||||
self.cfg.add_edge(after_body_graph_ix, update_graph_ix, EdgeType::Backedge);
|
self.cfg.add_edge(after_body_graph_ix, update_graph_ix, EdgeType::Backedge);
|
||||||
self.cfg.add_edge(update_graph_ix, test_graph_ix, EdgeType::Backedge);
|
self.cfg.add_edge(update_graph_ix, test_graph_ix, EdgeType::Backedge);
|
||||||
self.cfg.add_edge(after_test_graph_ix, after_for_stmt, EdgeType::Normal);
|
self.cfg.add_edge(after_test_graph_ix, after_for_stmt, EdgeType::Normal);
|
||||||
|
|
@ -749,7 +767,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
self.cfg
|
self.cfg
|
||||||
.ctx(None)
|
.ctx(None)
|
||||||
.mark_break(after_for_stmt)
|
.mark_break(after_for_stmt)
|
||||||
.mark_continue(test_graph_ix)
|
.mark_continue(update_graph_ix)
|
||||||
.resolve_with_upper_label();
|
.resolve_with_upper_label();
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
|
|
@ -782,6 +800,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
stmt.scope_id.set(Some(self.current_scope_id));
|
stmt.scope_id.set(Some(self.current_scope_id));
|
||||||
}
|
}
|
||||||
self.enter_node(kind);
|
self.enter_node(kind);
|
||||||
|
|
||||||
self.visit_for_statement_left(&stmt.left);
|
self.visit_for_statement_left(&stmt.left);
|
||||||
|
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
@ -789,12 +808,14 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
let start_prepare_cond_graph_ix = self.cfg.new_basic_block_normal();
|
let start_prepare_cond_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
|
self.record_ast_nodes();
|
||||||
self.visit_expression(&stmt.right);
|
self.visit_expression(&stmt.right);
|
||||||
|
let right_node = self.retrieve_recorded_ast_nodes().into_iter().next();
|
||||||
|
|
||||||
/* cfg */
|
/* cfg */
|
||||||
let end_of_prepare_cond_graph_ix = self.cfg.current_node_ix;
|
let end_of_prepare_cond_graph_ix = self.cfg.current_node_ix;
|
||||||
// this basic block is always empty since there's no update condition in a for-in loop.
|
let iteration_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
let basic_block_with_backedge_graph_ix = self.cfg.new_basic_block_normal();
|
self.cfg.append_iteration(right_node, IterationInstructionKind::In);
|
||||||
let body_graph_ix = self.cfg.new_basic_block_normal();
|
let body_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
|
|
||||||
self.cfg.ctx(None).default().allow_break().allow_continue();
|
self.cfg.ctx(None).default().allow_break().allow_continue();
|
||||||
|
|
@ -808,28 +829,20 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
// connect before for statement to the iterable expression
|
// connect before for statement to the iterable expression
|
||||||
self.cfg.add_edge(before_for_stmt_graph_ix, start_prepare_cond_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(before_for_stmt_graph_ix, start_prepare_cond_graph_ix, EdgeType::Normal);
|
||||||
// connect the end of the iterable expression to the basic block with back edge
|
// connect the end of the iterable expression to the basic block with back edge
|
||||||
self.cfg.add_edge(
|
self.cfg.add_edge(end_of_prepare_cond_graph_ix, iteration_graph_ix, EdgeType::Normal);
|
||||||
end_of_prepare_cond_graph_ix,
|
|
||||||
basic_block_with_backedge_graph_ix,
|
|
||||||
EdgeType::Normal,
|
|
||||||
);
|
|
||||||
// connect the basic block with back edge to the start of the body
|
// connect the basic block with back edge to the start of the body
|
||||||
self.cfg.add_edge(basic_block_with_backedge_graph_ix, body_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(iteration_graph_ix, body_graph_ix, EdgeType::Jump);
|
||||||
// connect the end of the body back to the basic block
|
// connect the end of the body back to the basic block
|
||||||
// with back edge for the next iteration
|
// with back edge for the next iteration
|
||||||
self.cfg.add_edge(
|
self.cfg.add_edge(end_of_body_graph_ix, iteration_graph_ix, EdgeType::Backedge);
|
||||||
end_of_body_graph_ix,
|
|
||||||
basic_block_with_backedge_graph_ix,
|
|
||||||
EdgeType::Backedge,
|
|
||||||
);
|
|
||||||
// connect the basic block with back edge to the basic block after the for loop
|
// connect the basic block with back edge to the basic block after the for loop
|
||||||
// for when there are no more iterations left in the iterable
|
// for when there are no more iterations left in the iterable
|
||||||
self.cfg.add_edge(basic_block_with_backedge_graph_ix, after_for_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(iteration_graph_ix, after_for_graph_ix, EdgeType::Normal);
|
||||||
|
|
||||||
self.cfg
|
self.cfg
|
||||||
.ctx(None)
|
.ctx(None)
|
||||||
.mark_break(after_for_graph_ix)
|
.mark_break(after_for_graph_ix)
|
||||||
.mark_continue(basic_block_with_backedge_graph_ix)
|
.mark_continue(iteration_graph_ix)
|
||||||
.resolve_with_upper_label();
|
.resolve_with_upper_label();
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
|
|
@ -847,6 +860,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
stmt.scope_id.set(Some(self.current_scope_id));
|
stmt.scope_id.set(Some(self.current_scope_id));
|
||||||
}
|
}
|
||||||
self.enter_node(kind);
|
self.enter_node(kind);
|
||||||
|
|
||||||
self.visit_for_statement_left(&stmt.left);
|
self.visit_for_statement_left(&stmt.left);
|
||||||
|
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
@ -854,12 +868,14 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
let start_prepare_cond_graph_ix = self.cfg.new_basic_block_normal();
|
let start_prepare_cond_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
|
self.record_ast_nodes();
|
||||||
self.visit_expression(&stmt.right);
|
self.visit_expression(&stmt.right);
|
||||||
|
let right_node = self.retrieve_recorded_ast_nodes().into_iter().next();
|
||||||
|
|
||||||
/* cfg */
|
/* cfg */
|
||||||
let end_of_prepare_cond_graph_ix = self.cfg.current_node_ix;
|
let end_of_prepare_cond_graph_ix = self.cfg.current_node_ix;
|
||||||
// this basic block is always empty since there's no update condition in a for-of loop.
|
let iteration_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
let basic_block_with_backedge_graph_ix = self.cfg.new_basic_block_normal();
|
self.cfg.append_iteration(right_node, IterationInstructionKind::Of);
|
||||||
let body_graph_ix = self.cfg.new_basic_block_normal();
|
let body_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
|
|
||||||
self.cfg.ctx(None).default().allow_break().allow_continue();
|
self.cfg.ctx(None).default().allow_break().allow_continue();
|
||||||
|
|
@ -873,28 +889,20 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
// connect before for statement to the iterable expression
|
// connect before for statement to the iterable expression
|
||||||
self.cfg.add_edge(before_for_stmt_graph_ix, start_prepare_cond_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(before_for_stmt_graph_ix, start_prepare_cond_graph_ix, EdgeType::Normal);
|
||||||
// connect the end of the iterable expression to the basic block with back edge
|
// connect the end of the iterable expression to the basic block with back edge
|
||||||
self.cfg.add_edge(
|
self.cfg.add_edge(end_of_prepare_cond_graph_ix, iteration_graph_ix, EdgeType::Normal);
|
||||||
end_of_prepare_cond_graph_ix,
|
|
||||||
basic_block_with_backedge_graph_ix,
|
|
||||||
EdgeType::Normal,
|
|
||||||
);
|
|
||||||
// connect the basic block with back edge to the start of the body
|
// connect the basic block with back edge to the start of the body
|
||||||
self.cfg.add_edge(basic_block_with_backedge_graph_ix, body_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(iteration_graph_ix, body_graph_ix, EdgeType::Jump);
|
||||||
// connect the end of the body back to the basic block
|
// connect the end of the body back to the basic block
|
||||||
// with back edge for the next iteration
|
// with back edge for the next iteration
|
||||||
self.cfg.add_edge(
|
self.cfg.add_edge(end_of_body_graph_ix, iteration_graph_ix, EdgeType::Backedge);
|
||||||
end_of_body_graph_ix,
|
|
||||||
basic_block_with_backedge_graph_ix,
|
|
||||||
EdgeType::Backedge,
|
|
||||||
);
|
|
||||||
// connect the basic block with back edge to the basic block after the for loop
|
// connect the basic block with back edge to the basic block after the for loop
|
||||||
// for when there are no more iterations left in the iterable
|
// for when there are no more iterations left in the iterable
|
||||||
self.cfg.add_edge(basic_block_with_backedge_graph_ix, after_for_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(iteration_graph_ix, after_for_graph_ix, EdgeType::Normal);
|
||||||
|
|
||||||
self.cfg
|
self.cfg
|
||||||
.ctx(None)
|
.ctx(None)
|
||||||
.mark_break(after_for_graph_ix)
|
.mark_break(after_for_graph_ix)
|
||||||
.mark_continue(basic_block_with_backedge_graph_ix)
|
.mark_continue(iteration_graph_ix)
|
||||||
.resolve_with_upper_label();
|
.resolve_with_upper_label();
|
||||||
/* cfg */
|
/* cfg */
|
||||||
|
|
||||||
|
|
@ -1281,7 +1289,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||||
let after_while_graph_ix = self.cfg.new_basic_block_normal();
|
let after_while_graph_ix = self.cfg.new_basic_block_normal();
|
||||||
|
|
||||||
self.cfg.add_edge(before_while_stmt_graph_ix, condition_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(before_while_stmt_graph_ix, condition_graph_ix, EdgeType::Normal);
|
||||||
self.cfg.add_edge(condition_graph_ix, body_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(condition_graph_ix, body_graph_ix, EdgeType::Jump);
|
||||||
self.cfg.add_edge(after_body_graph_ix, condition_graph_ix, EdgeType::Backedge);
|
self.cfg.add_edge(after_body_graph_ix, condition_graph_ix, EdgeType::Backedge);
|
||||||
self.cfg.add_edge(condition_graph_ix, after_while_graph_ix, EdgeType::Normal);
|
self.cfg.add_edge(condition_graph_ix, after_while_graph_ix, EdgeType::Normal);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ pub use context::{CtxCursor, CtxFlags};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AstNodeId, BasicBlock, BasicBlockId, CompactStr, ControlFlowGraph, EdgeType, ErrorEdgeKind,
|
AstNodeId, BasicBlock, BasicBlockId, CompactStr, ControlFlowGraph, EdgeType, ErrorEdgeKind,
|
||||||
Graph, Instruction, InstructionKind, LabeledInstruction, PreservedExpressionState, Register,
|
Graph, Instruction, InstructionKind, IterationInstructionKind, LabeledInstruction,
|
||||||
|
PreservedExpressionState, Register,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|
@ -144,6 +145,10 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append_iteration(&mut self, node: Option<AstNodeId>, kind: IterationInstructionKind) {
|
||||||
|
self.push_instruction(InstructionKind::Iteration(kind), node);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn append_throw(&mut self, node: AstNodeId) {
|
pub fn append_throw(&mut self, node: AstNodeId) {
|
||||||
self.push_instruction(InstructionKind::Throw, Some(node));
|
self.push_instruction(InstructionKind::Throw, Some(node));
|
||||||
self.append_unreachable();
|
self.append_unreachable();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use crate::{
|
||||||
LabeledInstruction, ReturnInstructionKind,
|
LabeledInstruction, ReturnInstructionKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::IterationInstructionKind;
|
||||||
|
|
||||||
pub trait DisplayDot {
|
pub trait DisplayDot {
|
||||||
fn display_dot(&self) -> String;
|
fn display_dot(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
@ -78,6 +80,8 @@ impl DisplayDot for Instruction {
|
||||||
InstructionKind::Break(LabeledInstruction::Unlabeled) => "break",
|
InstructionKind::Break(LabeledInstruction::Unlabeled) => "break",
|
||||||
InstructionKind::Continue(LabeledInstruction::Labeled) => "continue <label>",
|
InstructionKind::Continue(LabeledInstruction::Labeled) => "continue <label>",
|
||||||
InstructionKind::Continue(LabeledInstruction::Unlabeled) => "continue",
|
InstructionKind::Continue(LabeledInstruction::Unlabeled) => "continue",
|
||||||
|
InstructionKind::Iteration(IterationInstructionKind::Of) => "iteration <of>",
|
||||||
|
InstructionKind::Iteration(IterationInstructionKind::In) => "iteration <in>",
|
||||||
InstructionKind::Return(ReturnInstructionKind::ImplicitUndefined) => {
|
InstructionKind::Return(ReturnInstructionKind::ImplicitUndefined) => {
|
||||||
"return <implicit undefined>"
|
"return <implicit undefined>"
|
||||||
}
|
}
|
||||||
|
|
@ -132,6 +136,15 @@ impl DebugDot for Instruction {
|
||||||
}
|
}
|
||||||
InstructionKind::Unreachable => "unreachable".to_string(),
|
InstructionKind::Unreachable => "unreachable".to_string(),
|
||||||
InstructionKind::Throw => "throw".to_string(),
|
InstructionKind::Throw => "throw".to_string(),
|
||||||
|
InstructionKind::Iteration(ref kind) => {
|
||||||
|
format!(
|
||||||
|
"Iteration({} {} {})",
|
||||||
|
self.node_id.map_or("None".to_string(), |id| ctx.debug_ast_kind(id)),
|
||||||
|
if matches!(kind, IterationInstructionKind::Of) { "of" } else { "in" },
|
||||||
|
// TODO: at this point we can't evaluate this note. needs access to the graph information.
|
||||||
|
"expr"
|
||||||
|
)
|
||||||
|
}
|
||||||
InstructionKind::Break(LabeledInstruction::Labeled) => {
|
InstructionKind::Break(LabeledInstruction::Labeled) => {
|
||||||
let Some(AstKind::BreakStatement(BreakStatement { label: Some(label), .. })) =
|
let Some(AstKind::BreakStatement(BreakStatement { label: Some(label), .. })) =
|
||||||
self.node_id.map(|id| ctx.0.get_node(id)).map(AstNode::kind)
|
self.node_id.map(|id| ctx.0.get_node(id)).map(AstNode::kind)
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ pub enum InstructionKind {
|
||||||
Break(LabeledInstruction),
|
Break(LabeledInstruction),
|
||||||
Continue(LabeledInstruction),
|
Continue(LabeledInstruction),
|
||||||
Throw,
|
Throw,
|
||||||
|
Iteration(IterationInstructionKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ReturnInstructionKind {
|
pub enum ReturnInstructionKind {
|
||||||
ImplicitUndefined,
|
ImplicitUndefined,
|
||||||
|
|
@ -162,6 +162,12 @@ pub enum LabeledInstruction {
|
||||||
Unlabeled,
|
Unlabeled,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum IterationInstructionKind {
|
||||||
|
Of,
|
||||||
|
In,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum EdgeType {
|
pub enum EdgeType {
|
||||||
/// Conditional jumps
|
/// Conditional jumps
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ digraph {
|
||||||
6 -> 2 [ label = "Error(Implicit)" ]
|
6 -> 2 [ label = "Error(Implicit)" ]
|
||||||
7 -> 2 [ label = "Error(Implicit)" ]
|
7 -> 2 [ label = "Error(Implicit)" ]
|
||||||
3 -> 4 [ label = "Normal" ]
|
3 -> 4 [ label = "Normal" ]
|
||||||
4 -> 6 [ label = "Normal" ]
|
4 -> 6 [ label = "Jump" ]
|
||||||
6 -> 5 [ label = "Backedge" ]
|
6 -> 5 [ label = "Backedge" ]
|
||||||
5 -> 4 [ label = "Backedge" ]
|
5 -> 4 [ label = "Backedge" ]
|
||||||
4 -> 7 [ label = "Normal" ]
|
4 -> 7 [ label = "Normal" ]
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ digraph {
|
||||||
2 [ label = "" ]
|
2 [ label = "" ]
|
||||||
3 [ label = "ForInStatement\nVariableDeclaration" ]
|
3 [ label = "ForInStatement\nVariableDeclaration" ]
|
||||||
4 [ label = "" ]
|
4 [ label = "" ]
|
||||||
5 [ label = "" ]
|
5 [ label = "Iteration(IdentifierReference(array) in expr)" ]
|
||||||
6 [ label = "BlockStatement\nIfStatement" ]
|
6 [ label = "BlockStatement\nIfStatement" ]
|
||||||
7 [ label = "BlockStatement\nExpressionStatement\nbreak" ]
|
7 [ label = "BlockStatement\nExpressionStatement\nbreak" ]
|
||||||
8 [ label = "unreachable" ]
|
8 [ label = "unreachable" ]
|
||||||
|
|
@ -45,7 +45,7 @@ digraph {
|
||||||
14 -> 2 [ label = "Error(Implicit)" ]
|
14 -> 2 [ label = "Error(Implicit)" ]
|
||||||
3 -> 4 [ label = "Normal" ]
|
3 -> 4 [ label = "Normal" ]
|
||||||
4 -> 5 [ label = "Normal" ]
|
4 -> 5 [ label = "Normal" ]
|
||||||
5 -> 6 [ label = "Normal" ]
|
5 -> 6 [ label = "Jump" ]
|
||||||
13 -> 5 [ label = "Backedge" ]
|
13 -> 5 [ label = "Backedge" ]
|
||||||
5 -> 14 [ label = "Normal" ]
|
5 -> 14 [ label = "Normal" ]
|
||||||
7 -> 14 [ label = "Jump" ]
|
7 -> 14 [ label = "Jump" ]
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ bb4: {
|
||||||
}
|
}
|
||||||
|
|
||||||
bb5: {
|
bb5: {
|
||||||
|
iteration <in>
|
||||||
}
|
}
|
||||||
|
|
||||||
bb6: {
|
bb6: {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ digraph {
|
||||||
3 -> 9 [ label = "Normal" ]
|
3 -> 9 [ label = "Normal" ]
|
||||||
10 -> 0 [ label = "Error(Implicit)" ]
|
10 -> 0 [ label = "Error(Implicit)" ]
|
||||||
1 -> 2 [ label = "Normal" ]
|
1 -> 2 [ label = "Normal" ]
|
||||||
2 -> 3 [ label = "Normal" ]
|
2 -> 3 [ label = "Jump" ]
|
||||||
9 -> 2 [ label = "Backedge" ]
|
9 -> 2 [ label = "Backedge" ]
|
||||||
2 -> 10 [ label = "Normal" ]
|
2 -> 10 [ label = "Normal" ]
|
||||||
5 -> 2 [ label = "Jump" ]
|
5 -> 2 [ label = "Jump" ]
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ digraph {
|
||||||
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
|
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
|
||||||
9 -> 2 [ label = "Error(Implicit)" ]
|
9 -> 2 [ label = "Error(Implicit)" ]
|
||||||
3 -> 4 [ label = "Normal" ]
|
3 -> 4 [ label = "Normal" ]
|
||||||
4 -> 7 [ label = "Normal" ]
|
4 -> 7 [ label = "Jump" ]
|
||||||
8 -> 4 [ label = "Backedge" ]
|
8 -> 4 [ label = "Backedge" ]
|
||||||
4 -> 9 [ label = "Normal" ]
|
4 -> 9 [ label = "Normal" ]
|
||||||
10 -> 2 [ label = "Error(Implicit)" ]
|
10 -> 2 [ label = "Error(Implicit)" ]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue