|
|
|
@ -1,9 +1,8 @@
|
|
|
|
|
//! This module is responsible for generating the vm instruction flowgraph.
|
|
|
|
|
|
|
|
|
|
use crate::vm::{CodeBlock, Opcode}; |
|
|
|
|
use crate::vm::CodeBlock; |
|
|
|
|
use boa_interner::Interner; |
|
|
|
|
use boa_macros::utf16; |
|
|
|
|
use std::mem::size_of; |
|
|
|
|
|
|
|
|
|
mod color; |
|
|
|
|
mod edge; |
|
|
|
@ -15,6 +14,8 @@ pub use edge::*;
|
|
|
|
|
pub use graph::*; |
|
|
|
|
pub use node::*; |
|
|
|
|
|
|
|
|
|
use super::Instruction; |
|
|
|
|
|
|
|
|
|
impl CodeBlock { |
|
|
|
|
/// Output the [`CodeBlock`] VM instructions into a [`Graph`].
|
|
|
|
|
#[allow(clippy::match_same_arms)] |
|
|
|
@ -30,104 +31,78 @@ impl CodeBlock {
|
|
|
|
|
|
|
|
|
|
let mut pc = 0; |
|
|
|
|
while pc < self.bytecode.len() { |
|
|
|
|
let opcode: Opcode = self.bytecode[pc].into(); |
|
|
|
|
let opcode_str = opcode.as_str(); |
|
|
|
|
let previous_pc = pc; |
|
|
|
|
let instruction = Instruction::from_bytecode(&self.bytecode, &mut pc); |
|
|
|
|
let opcode = instruction.opcode(); |
|
|
|
|
let opcode_str = opcode.as_str(); |
|
|
|
|
|
|
|
|
|
let mut tmp = pc; |
|
|
|
|
let mut tmp = previous_pc; |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} {}", |
|
|
|
|
self.instruction_operands(&mut tmp, interner) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
pc += size_of::<Opcode>(); |
|
|
|
|
match opcode { |
|
|
|
|
Opcode::SetFunctionName => { |
|
|
|
|
let operand = self.read::<u8>(pc); |
|
|
|
|
pc += size_of::<u8>(); |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} {}", |
|
|
|
|
match operand { |
|
|
|
|
0 => "prefix: none", |
|
|
|
|
1 => "prefix: get", |
|
|
|
|
2 => "prefix: set", |
|
|
|
|
_ => unreachable!(), |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
match instruction { |
|
|
|
|
Instruction::SetFunctionName { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::RotateLeft | Opcode::RotateRight | Opcode::CreateIteratorResult => { |
|
|
|
|
pc += size_of::<u8>(); |
|
|
|
|
Instruction::RotateLeft { .. } |
|
|
|
|
| Instruction::RotateRight { .. } |
|
|
|
|
| Instruction::CreateIteratorResult { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::Generator => { |
|
|
|
|
pc += size_of::<u8>(); |
|
|
|
|
|
|
|
|
|
Instruction::Generator { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushInt8 => { |
|
|
|
|
pc += size_of::<i8>(); |
|
|
|
|
|
|
|
|
|
Instruction::PushInt8 { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushInt16 => { |
|
|
|
|
pc += size_of::<i16>(); |
|
|
|
|
Instruction::PushInt16 { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushInt32 => { |
|
|
|
|
pc += size_of::<i32>(); |
|
|
|
|
Instruction::PushInt32 { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushFloat => { |
|
|
|
|
pc += size_of::<f32>(); |
|
|
|
|
|
|
|
|
|
Instruction::PushFloat { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushDouble => { |
|
|
|
|
pc += size_of::<f64>(); |
|
|
|
|
|
|
|
|
|
Instruction::PushDouble { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushLiteral => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let operand_str = self.literals[operand as usize].display().to_string(); |
|
|
|
|
Instruction::PushLiteral { index } => { |
|
|
|
|
let operand_str = self.literals[index as usize].display().to_string(); |
|
|
|
|
let operand_str = operand_str.escape_debug(); |
|
|
|
|
let label = format!("{opcode_str} {operand_str}"); |
|
|
|
|
|
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::Jump => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::Jump { address } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
operand as usize, |
|
|
|
|
address as usize, |
|
|
|
|
None, |
|
|
|
|
Color::None, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::JumpIfFalse |
|
|
|
|
| Opcode::JumpIfTrue |
|
|
|
|
| Opcode::JumpIfNotUndefined |
|
|
|
|
| Opcode::JumpIfNullOrUndefined => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::JumpIfFalse { address } |
|
|
|
|
| Instruction::JumpIfTrue { address } |
|
|
|
|
| Instruction::JumpIfNotUndefined { address } |
|
|
|
|
| Instruction::JumpIfNullOrUndefined { address } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
operand as usize, |
|
|
|
|
address as usize, |
|
|
|
|
Some("YES".into()), |
|
|
|
|
Color::Green, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
@ -140,19 +115,13 @@ impl CodeBlock {
|
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::TemplateLookup | Opcode::TemplateCreate => { |
|
|
|
|
let start_address = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let end_address = self.read::<u64>(pc); |
|
|
|
|
pc += size_of::<u64>(); |
|
|
|
|
|
|
|
|
|
let label = format!("{opcode_str} {start_address}, {end_address}"); |
|
|
|
|
Instruction::TemplateLookup { .. } | Instruction::TemplateCreate { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::Red); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::LogicalAnd | Opcode::LogicalOr | Opcode::Coalesce => { |
|
|
|
|
let exit = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::LogicalAnd { exit } |
|
|
|
|
| Instruction::LogicalOr { exit } |
|
|
|
|
| Instruction::Coalesce { exit } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
graph.add_edge( |
|
|
|
@ -163,9 +132,7 @@ impl CodeBlock {
|
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::Case => { |
|
|
|
|
let address = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::Case { address } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
@ -176,23 +143,26 @@ impl CodeBlock {
|
|
|
|
|
); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
address, |
|
|
|
|
address as usize, |
|
|
|
|
Some("YES".into()), |
|
|
|
|
Color::Green, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::Default => { |
|
|
|
|
let address = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::Default { address } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, address, None, Color::None, EdgeStyle::Line); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
address as usize, |
|
|
|
|
None, |
|
|
|
|
Color::None, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::GeneratorDelegateNext => { |
|
|
|
|
let throw_method_undefined = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let return_method_undefined = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::GeneratorDelegateNext { |
|
|
|
|
return_method_undefined, |
|
|
|
|
throw_method_undefined, |
|
|
|
|
} => { |
|
|
|
|
graph.add_node( |
|
|
|
|
previous_pc, |
|
|
|
|
NodeShape::Diamond, |
|
|
|
@ -202,24 +172,20 @@ impl CodeBlock {
|
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
throw_method_undefined, |
|
|
|
|
throw_method_undefined as usize, |
|
|
|
|
Some("`throw` undefined".into()), |
|
|
|
|
Color::Red, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
return_method_undefined, |
|
|
|
|
return_method_undefined as usize, |
|
|
|
|
Some("`return` undefined".into()), |
|
|
|
|
Color::Blue, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::GeneratorDelegateResume => { |
|
|
|
|
let return_gen = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let exit = self.read::<u32>(pc) as usize; |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::GeneratorDelegateResume { r#return, exit } => { |
|
|
|
|
graph.add_node( |
|
|
|
|
previous_pc, |
|
|
|
|
NodeShape::Diamond, |
|
|
|
@ -229,35 +195,28 @@ impl CodeBlock {
|
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
return_gen, |
|
|
|
|
r#return as usize, |
|
|
|
|
Some("return".into()), |
|
|
|
|
Color::Yellow, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
exit, |
|
|
|
|
exit as usize, |
|
|
|
|
Some("done".into()), |
|
|
|
|
Color::Blue, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
Opcode::CallEval |
|
|
|
|
| Opcode::Call |
|
|
|
|
| Opcode::New |
|
|
|
|
| Opcode::SuperCall |
|
|
|
|
| Opcode::ConcatToString => { |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
Instruction::CallEval { .. } |
|
|
|
|
| Instruction::Call { .. } |
|
|
|
|
| Instruction::New { .. } |
|
|
|
|
| Instruction::SuperCall { .. } |
|
|
|
|
| Instruction::ConcatToString { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::JumpIfNotResumeKind => { |
|
|
|
|
let exit = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
let _resume_kind = self.read::<u8>(pc); |
|
|
|
|
pc += size_of::<u8>(); |
|
|
|
|
|
|
|
|
|
Instruction::JumpIfNotResumeKind { exit, .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
@ -268,21 +227,14 @@ impl CodeBlock {
|
|
|
|
|
); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::Green, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::CopyDataProperties => { |
|
|
|
|
let operand1 = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let operand2 = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
let label = format!("{opcode_str} {operand1}, {operand2}"); |
|
|
|
|
Instruction::CopyDataProperties { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PushDeclarativeEnvironment | Opcode::PushFunctionEnvironment => { |
|
|
|
|
Instruction::PushDeclarativeEnvironment { .. } |
|
|
|
|
| Instruction::PushFunctionEnvironment { .. } => { |
|
|
|
|
let random = rand::random(); |
|
|
|
|
|
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
graph.add_node( |
|
|
|
|
previous_pc, |
|
|
|
|
NodeShape::None, |
|
|
|
@ -291,93 +243,62 @@ impl CodeBlock {
|
|
|
|
|
); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::PopEnvironment => { |
|
|
|
|
Instruction::PopEnvironment => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::GetArrowFunction |
|
|
|
|
| Opcode::GetAsyncArrowFunction |
|
|
|
|
| Opcode::GetFunction |
|
|
|
|
| Opcode::GetFunctionAsync => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
let fn_name = self.functions[operand as usize] |
|
|
|
|
.name() |
|
|
|
|
.to_std_string_escaped(); |
|
|
|
|
pc += size_of::<u32>() + size_of::<u8>(); |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} '{fn_name}' (length: {})", |
|
|
|
|
self.functions[operand as usize].length |
|
|
|
|
); |
|
|
|
|
Instruction::GetArrowFunction { .. } |
|
|
|
|
| Instruction::GetAsyncArrowFunction { .. } |
|
|
|
|
| Instruction::GetFunction { .. } |
|
|
|
|
| Instruction::GetFunctionAsync { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::GetGenerator | Opcode::GetGeneratorAsync => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
let fn_name = self.functions[operand as usize] |
|
|
|
|
.name() |
|
|
|
|
.to_std_string_escaped(); |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} '{fn_name}' (length: {})", |
|
|
|
|
self.functions[operand as usize].length |
|
|
|
|
); |
|
|
|
|
Instruction::GetGenerator { .. } | Instruction::GetGeneratorAsync { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::DefVar |
|
|
|
|
| Opcode::DefInitVar |
|
|
|
|
| Opcode::PutLexicalValue |
|
|
|
|
| Opcode::GetName |
|
|
|
|
| Opcode::GetLocator |
|
|
|
|
| Opcode::GetNameAndLocator |
|
|
|
|
| Opcode::GetNameOrUndefined |
|
|
|
|
| Opcode::SetName |
|
|
|
|
| Opcode::DeleteName => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} '{}'", |
|
|
|
|
interner.resolve_expect(self.bindings[operand as usize].name().sym()), |
|
|
|
|
); |
|
|
|
|
Instruction::DefVar { .. } |
|
|
|
|
| Instruction::DefInitVar { .. } |
|
|
|
|
| Instruction::PutLexicalValue { .. } |
|
|
|
|
| Instruction::GetName { .. } |
|
|
|
|
| Instruction::GetLocator { .. } |
|
|
|
|
| Instruction::GetNameAndLocator { .. } |
|
|
|
|
| Instruction::GetNameOrUndefined { .. } |
|
|
|
|
| Instruction::SetName { .. } |
|
|
|
|
| Instruction::DeleteName { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::GetPropertyByName |
|
|
|
|
| Opcode::GetMethod |
|
|
|
|
| Opcode::SetPropertyByName |
|
|
|
|
| Opcode::DefineOwnPropertyByName |
|
|
|
|
| Opcode::DefineClassStaticMethodByName |
|
|
|
|
| Opcode::DefineClassMethodByName |
|
|
|
|
| Opcode::SetPropertyGetterByName |
|
|
|
|
| Opcode::DefineClassStaticGetterByName |
|
|
|
|
| Opcode::DefineClassGetterByName |
|
|
|
|
| Opcode::SetPropertySetterByName |
|
|
|
|
| Opcode::DefineClassStaticSetterByName |
|
|
|
|
| Opcode::DefineClassSetterByName |
|
|
|
|
| Opcode::SetPrivateField |
|
|
|
|
| Opcode::DefinePrivateField |
|
|
|
|
| Opcode::SetPrivateMethod |
|
|
|
|
| Opcode::SetPrivateSetter |
|
|
|
|
| Opcode::SetPrivateGetter |
|
|
|
|
| Opcode::GetPrivateField |
|
|
|
|
| Opcode::DeletePropertyByName |
|
|
|
|
| Opcode::PushClassFieldPrivate |
|
|
|
|
| Opcode::PushClassPrivateGetter |
|
|
|
|
| Opcode::PushClassPrivateSetter |
|
|
|
|
| Opcode::PushClassPrivateMethod |
|
|
|
|
| Opcode::InPrivate |
|
|
|
|
| Opcode::ThrowMutateImmutable => { |
|
|
|
|
let operand = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let label = format!( |
|
|
|
|
"{opcode_str} '{}'", |
|
|
|
|
self.names[operand as usize].to_std_string_escaped(), |
|
|
|
|
); |
|
|
|
|
Instruction::GetPropertyByName { .. } |
|
|
|
|
| Instruction::GetMethod { .. } |
|
|
|
|
| Instruction::SetPropertyByName { .. } |
|
|
|
|
| Instruction::DefineOwnPropertyByName { .. } |
|
|
|
|
| Instruction::DefineClassStaticMethodByName { .. } |
|
|
|
|
| Instruction::DefineClassMethodByName { .. } |
|
|
|
|
| Instruction::SetPropertyGetterByName { .. } |
|
|
|
|
| Instruction::DefineClassStaticGetterByName { .. } |
|
|
|
|
| Instruction::DefineClassGetterByName { .. } |
|
|
|
|
| Instruction::SetPropertySetterByName { .. } |
|
|
|
|
| Instruction::DefineClassStaticSetterByName { .. } |
|
|
|
|
| Instruction::DefineClassSetterByName { .. } |
|
|
|
|
| Instruction::SetPrivateField { .. } |
|
|
|
|
| Instruction::DefinePrivateField { .. } |
|
|
|
|
| Instruction::SetPrivateMethod { .. } |
|
|
|
|
| Instruction::SetPrivateSetter { .. } |
|
|
|
|
| Instruction::SetPrivateGetter { .. } |
|
|
|
|
| Instruction::GetPrivateField { .. } |
|
|
|
|
| Instruction::DeletePropertyByName { .. } |
|
|
|
|
| Instruction::PushClassFieldPrivate { .. } |
|
|
|
|
| Instruction::PushClassPrivateGetter { .. } |
|
|
|
|
| Instruction::PushClassPrivateSetter { .. } |
|
|
|
|
| Instruction::PushClassPrivateMethod { .. } |
|
|
|
|
| Instruction::InPrivate { .. } |
|
|
|
|
| Instruction::ThrowMutateImmutable { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::ThrowNewTypeError => { |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
Instruction::ThrowNewTypeError { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
if let Some((i, handler)) = self.find_handler(previous_pc as u32) { |
|
|
|
|
graph.add_edge( |
|
|
|
@ -389,7 +310,7 @@ impl CodeBlock {
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Opcode::Throw | Opcode::ReThrow => { |
|
|
|
|
Instruction::Throw | Instruction::ReThrow => { |
|
|
|
|
if let Some((i, handler)) = self.find_handler(previous_pc as u32) { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::Record, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
@ -403,18 +324,11 @@ impl CodeBlock {
|
|
|
|
|
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::None); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Opcode::PushPrivateEnvironment => { |
|
|
|
|
let count = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>() * (count as usize + 1); |
|
|
|
|
Instruction::PushPrivateEnvironment { .. } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::JumpTable => { |
|
|
|
|
let count = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
let default = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
Instruction::JumpTable { default, addresses } => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
@ -424,200 +338,197 @@ impl CodeBlock {
|
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
for i in 0..count { |
|
|
|
|
let address = self.read::<u32>(pc); |
|
|
|
|
pc += size_of::<u32>(); |
|
|
|
|
|
|
|
|
|
for (i, address) in addresses.iter().enumerate() { |
|
|
|
|
graph.add_edge( |
|
|
|
|
previous_pc, |
|
|
|
|
address as usize, |
|
|
|
|
*address as usize, |
|
|
|
|
Some(format!("Index: {i}").into()), |
|
|
|
|
Color::None, |
|
|
|
|
EdgeStyle::Line, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Opcode::Pop |
|
|
|
|
| Opcode::Dup |
|
|
|
|
| Opcode::Swap |
|
|
|
|
| Opcode::PushZero |
|
|
|
|
| Opcode::PushOne |
|
|
|
|
| Opcode::PushNaN |
|
|
|
|
| Opcode::PushPositiveInfinity |
|
|
|
|
| Opcode::PushNegativeInfinity |
|
|
|
|
| Opcode::PushNull |
|
|
|
|
| Opcode::PushTrue |
|
|
|
|
| Opcode::PushFalse |
|
|
|
|
| Opcode::PushUndefined |
|
|
|
|
| Opcode::PushEmptyObject |
|
|
|
|
| Opcode::PushClassPrototype |
|
|
|
|
| Opcode::SetClassPrototype |
|
|
|
|
| Opcode::SetHomeObject |
|
|
|
|
| Opcode::SetHomeObjectClass |
|
|
|
|
| Opcode::Add |
|
|
|
|
| Opcode::Sub |
|
|
|
|
| Opcode::Div |
|
|
|
|
| Opcode::Mul |
|
|
|
|
| Opcode::Mod |
|
|
|
|
| Opcode::Pow |
|
|
|
|
| Opcode::ShiftRight |
|
|
|
|
| Opcode::ShiftLeft |
|
|
|
|
| Opcode::UnsignedShiftRight |
|
|
|
|
| Opcode::BitOr |
|
|
|
|
| Opcode::BitAnd |
|
|
|
|
| Opcode::BitXor |
|
|
|
|
| Opcode::BitNot |
|
|
|
|
| Opcode::In |
|
|
|
|
| Opcode::Eq |
|
|
|
|
| Opcode::StrictEq |
|
|
|
|
| Opcode::NotEq |
|
|
|
|
| Opcode::StrictNotEq |
|
|
|
|
| Opcode::GreaterThan |
|
|
|
|
| Opcode::GreaterThanOrEq |
|
|
|
|
| Opcode::LessThan |
|
|
|
|
| Opcode::LessThanOrEq |
|
|
|
|
| Opcode::InstanceOf |
|
|
|
|
| Opcode::TypeOf |
|
|
|
|
| Opcode::Void |
|
|
|
|
| Opcode::LogicalNot |
|
|
|
|
| Opcode::Pos |
|
|
|
|
| Opcode::Neg |
|
|
|
|
| Opcode::Inc |
|
|
|
|
| Opcode::IncPost |
|
|
|
|
| Opcode::Dec |
|
|
|
|
| Opcode::DecPost |
|
|
|
|
| Opcode::GetPropertyByValue |
|
|
|
|
| Opcode::GetPropertyByValuePush |
|
|
|
|
| Opcode::SetPropertyByValue |
|
|
|
|
| Opcode::DefineOwnPropertyByValue |
|
|
|
|
| Opcode::DefineClassStaticMethodByValue |
|
|
|
|
| Opcode::DefineClassMethodByValue |
|
|
|
|
| Opcode::SetPropertyGetterByValue |
|
|
|
|
| Opcode::DefineClassStaticGetterByValue |
|
|
|
|
| Opcode::DefineClassGetterByValue |
|
|
|
|
| Opcode::SetPropertySetterByValue |
|
|
|
|
| Opcode::DefineClassStaticSetterByValue |
|
|
|
|
| Opcode::DefineClassSetterByValue |
|
|
|
|
| Opcode::DeletePropertyByValue |
|
|
|
|
| Opcode::DeleteSuperThrow |
|
|
|
|
| Opcode::ToPropertyKey |
|
|
|
|
| Opcode::ToBoolean |
|
|
|
|
| Opcode::This |
|
|
|
|
| Opcode::Super |
|
|
|
|
| Opcode::IncrementLoopIteration |
|
|
|
|
| Opcode::CreateForInIterator |
|
|
|
|
| Opcode::GetIterator |
|
|
|
|
| Opcode::GetAsyncIterator |
|
|
|
|
| Opcode::IteratorNext |
|
|
|
|
| Opcode::IteratorNextWithoutPop |
|
|
|
|
| Opcode::IteratorFinishAsyncNext |
|
|
|
|
| Opcode::IteratorValue |
|
|
|
|
| Opcode::IteratorValueWithoutPop |
|
|
|
|
| Opcode::IteratorResult |
|
|
|
|
| Opcode::IteratorDone |
|
|
|
|
| Opcode::IteratorToArray |
|
|
|
|
| Opcode::IteratorPop |
|
|
|
|
| Opcode::IteratorReturn |
|
|
|
|
| Opcode::IteratorStackEmpty |
|
|
|
|
| Opcode::RequireObjectCoercible |
|
|
|
|
| Opcode::ValueNotNullOrUndefined |
|
|
|
|
| Opcode::RestParameterInit |
|
|
|
|
| Opcode::RestParameterPop |
|
|
|
|
| Opcode::PushValueToArray |
|
|
|
|
| Opcode::PushElisionToArray |
|
|
|
|
| Opcode::PushIteratorToArray |
|
|
|
|
| Opcode::PushNewArray |
|
|
|
|
| Opcode::GeneratorYield |
|
|
|
|
| Opcode::AsyncGeneratorYield |
|
|
|
|
| Opcode::AsyncGeneratorClose |
|
|
|
|
| Opcode::CreatePromiseCapability |
|
|
|
|
| Opcode::CompletePromiseCapability |
|
|
|
|
| Opcode::GeneratorNext |
|
|
|
|
| Opcode::PushClassField |
|
|
|
|
| Opcode::SuperCallDerived |
|
|
|
|
| Opcode::Await |
|
|
|
|
| Opcode::NewTarget |
|
|
|
|
| Opcode::ImportMeta |
|
|
|
|
| Opcode::CallEvalSpread |
|
|
|
|
| Opcode::CallSpread |
|
|
|
|
| Opcode::NewSpread |
|
|
|
|
| Opcode::SuperCallSpread |
|
|
|
|
| Opcode::SuperCallPrepare |
|
|
|
|
| Opcode::SetPrototype |
|
|
|
|
| Opcode::IsObject |
|
|
|
|
| Opcode::SetNameByLocator |
|
|
|
|
| Opcode::PushObjectEnvironment |
|
|
|
|
| Opcode::PopPrivateEnvironment |
|
|
|
|
| Opcode::ImportCall |
|
|
|
|
| Opcode::GetReturnValue |
|
|
|
|
| Opcode::SetReturnValue |
|
|
|
|
| Opcode::Exception |
|
|
|
|
| Opcode::MaybeException |
|
|
|
|
| Opcode::Nop => { |
|
|
|
|
Instruction::Pop |
|
|
|
|
| Instruction::Dup |
|
|
|
|
| Instruction::Swap |
|
|
|
|
| Instruction::PushZero |
|
|
|
|
| Instruction::PushOne |
|
|
|
|
| Instruction::PushNaN |
|
|
|
|
| Instruction::PushPositiveInfinity |
|
|
|
|
| Instruction::PushNegativeInfinity |
|
|
|
|
| Instruction::PushNull |
|
|
|
|
| Instruction::PushTrue |
|
|
|
|
| Instruction::PushFalse |
|
|
|
|
| Instruction::PushUndefined |
|
|
|
|
| Instruction::PushEmptyObject |
|
|
|
|
| Instruction::PushClassPrototype |
|
|
|
|
| Instruction::SetClassPrototype |
|
|
|
|
| Instruction::SetHomeObject |
|
|
|
|
| Instruction::SetHomeObjectClass |
|
|
|
|
| Instruction::Add |
|
|
|
|
| Instruction::Sub |
|
|
|
|
| Instruction::Div |
|
|
|
|
| Instruction::Mul |
|
|
|
|
| Instruction::Mod |
|
|
|
|
| Instruction::Pow |
|
|
|
|
| Instruction::ShiftRight |
|
|
|
|
| Instruction::ShiftLeft |
|
|
|
|
| Instruction::UnsignedShiftRight |
|
|
|
|
| Instruction::BitOr |
|
|
|
|
| Instruction::BitAnd |
|
|
|
|
| Instruction::BitXor |
|
|
|
|
| Instruction::BitNot |
|
|
|
|
| Instruction::In |
|
|
|
|
| Instruction::Eq |
|
|
|
|
| Instruction::StrictEq |
|
|
|
|
| Instruction::NotEq |
|
|
|
|
| Instruction::StrictNotEq |
|
|
|
|
| Instruction::GreaterThan |
|
|
|
|
| Instruction::GreaterThanOrEq |
|
|
|
|
| Instruction::LessThan |
|
|
|
|
| Instruction::LessThanOrEq |
|
|
|
|
| Instruction::InstanceOf |
|
|
|
|
| Instruction::TypeOf |
|
|
|
|
| Instruction::Void |
|
|
|
|
| Instruction::LogicalNot |
|
|
|
|
| Instruction::Pos |
|
|
|
|
| Instruction::Neg |
|
|
|
|
| Instruction::Inc |
|
|
|
|
| Instruction::IncPost |
|
|
|
|
| Instruction::Dec |
|
|
|
|
| Instruction::DecPost |
|
|
|
|
| Instruction::GetPropertyByValue |
|
|
|
|
| Instruction::GetPropertyByValuePush |
|
|
|
|
| Instruction::SetPropertyByValue |
|
|
|
|
| Instruction::DefineOwnPropertyByValue |
|
|
|
|
| Instruction::DefineClassStaticMethodByValue |
|
|
|
|
| Instruction::DefineClassMethodByValue |
|
|
|
|
| Instruction::SetPropertyGetterByValue |
|
|
|
|
| Instruction::DefineClassStaticGetterByValue |
|
|
|
|
| Instruction::DefineClassGetterByValue |
|
|
|
|
| Instruction::SetPropertySetterByValue |
|
|
|
|
| Instruction::DefineClassStaticSetterByValue |
|
|
|
|
| Instruction::DefineClassSetterByValue |
|
|
|
|
| Instruction::DeletePropertyByValue |
|
|
|
|
| Instruction::DeleteSuperThrow |
|
|
|
|
| Instruction::ToPropertyKey |
|
|
|
|
| Instruction::ToBoolean |
|
|
|
|
| Instruction::This |
|
|
|
|
| Instruction::Super |
|
|
|
|
| Instruction::IncrementLoopIteration |
|
|
|
|
| Instruction::CreateForInIterator |
|
|
|
|
| Instruction::GetIterator |
|
|
|
|
| Instruction::GetAsyncIterator |
|
|
|
|
| Instruction::IteratorNext |
|
|
|
|
| Instruction::IteratorNextWithoutPop |
|
|
|
|
| Instruction::IteratorFinishAsyncNext |
|
|
|
|
| Instruction::IteratorValue |
|
|
|
|
| Instruction::IteratorValueWithoutPop |
|
|
|
|
| Instruction::IteratorResult |
|
|
|
|
| Instruction::IteratorDone |
|
|
|
|
| Instruction::IteratorToArray |
|
|
|
|
| Instruction::IteratorPop |
|
|
|
|
| Instruction::IteratorReturn |
|
|
|
|
| Instruction::IteratorStackEmpty |
|
|
|
|
| Instruction::RequireObjectCoercible |
|
|
|
|
| Instruction::ValueNotNullOrUndefined |
|
|
|
|
| Instruction::RestParameterInit |
|
|
|
|
| Instruction::RestParameterPop |
|
|
|
|
| Instruction::PushValueToArray |
|
|
|
|
| Instruction::PushElisionToArray |
|
|
|
|
| Instruction::PushIteratorToArray |
|
|
|
|
| Instruction::PushNewArray |
|
|
|
|
| Instruction::GeneratorYield |
|
|
|
|
| Instruction::AsyncGeneratorYield |
|
|
|
|
| Instruction::AsyncGeneratorClose |
|
|
|
|
| Instruction::CreatePromiseCapability |
|
|
|
|
| Instruction::CompletePromiseCapability |
|
|
|
|
| Instruction::GeneratorNext |
|
|
|
|
| Instruction::PushClassField |
|
|
|
|
| Instruction::SuperCallDerived |
|
|
|
|
| Instruction::Await |
|
|
|
|
| Instruction::NewTarget |
|
|
|
|
| Instruction::ImportMeta |
|
|
|
|
| Instruction::CallEvalSpread |
|
|
|
|
| Instruction::CallSpread |
|
|
|
|
| Instruction::NewSpread |
|
|
|
|
| Instruction::SuperCallSpread |
|
|
|
|
| Instruction::SuperCallPrepare |
|
|
|
|
| Instruction::SetPrototype |
|
|
|
|
| Instruction::IsObject |
|
|
|
|
| Instruction::SetNameByLocator |
|
|
|
|
| Instruction::PushObjectEnvironment |
|
|
|
|
| Instruction::PopPrivateEnvironment |
|
|
|
|
| Instruction::ImportCall |
|
|
|
|
| Instruction::GetReturnValue |
|
|
|
|
| Instruction::SetReturnValue |
|
|
|
|
| Instruction::Exception |
|
|
|
|
| Instruction::MaybeException |
|
|
|
|
| Instruction::Nop => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::None, label.into(), Color::None); |
|
|
|
|
graph.add_edge(previous_pc, pc, None, Color::None, EdgeStyle::Line); |
|
|
|
|
} |
|
|
|
|
Opcode::Return => { |
|
|
|
|
Instruction::Return => { |
|
|
|
|
graph.add_node(previous_pc, NodeShape::Diamond, label.into(), Color::Red); |
|
|
|
|
} |
|
|
|
|
Opcode::Reserved1 |
|
|
|
|
| Opcode::Reserved2 |
|
|
|
|
| Opcode::Reserved3 |
|
|
|
|
| Opcode::Reserved4 |
|
|
|
|
| Opcode::Reserved5 |
|
|
|
|
| Opcode::Reserved6 |
|
|
|
|
| Opcode::Reserved7 |
|
|
|
|
| Opcode::Reserved8 |
|
|
|
|
| Opcode::Reserved9 |
|
|
|
|
| Opcode::Reserved10 |
|
|
|
|
| Opcode::Reserved11 |
|
|
|
|
| Opcode::Reserved12 |
|
|
|
|
| Opcode::Reserved13 |
|
|
|
|
| Opcode::Reserved14 |
|
|
|
|
| Opcode::Reserved15 |
|
|
|
|
| Opcode::Reserved16 |
|
|
|
|
| Opcode::Reserved17 |
|
|
|
|
| Opcode::Reserved18 |
|
|
|
|
| Opcode::Reserved19 |
|
|
|
|
| Opcode::Reserved20 |
|
|
|
|
| Opcode::Reserved21 |
|
|
|
|
| Opcode::Reserved22 |
|
|
|
|
| Opcode::Reserved23 |
|
|
|
|
| Opcode::Reserved24 |
|
|
|
|
| Opcode::Reserved25 |
|
|
|
|
| Opcode::Reserved26 |
|
|
|
|
| Opcode::Reserved27 |
|
|
|
|
| Opcode::Reserved28 |
|
|
|
|
| Opcode::Reserved29 |
|
|
|
|
| Opcode::Reserved30 |
|
|
|
|
| Opcode::Reserved31 |
|
|
|
|
| Opcode::Reserved32 |
|
|
|
|
| Opcode::Reserved33 |
|
|
|
|
| Opcode::Reserved34 |
|
|
|
|
| Opcode::Reserved35 |
|
|
|
|
| Opcode::Reserved36 |
|
|
|
|
| Opcode::Reserved37 |
|
|
|
|
| Opcode::Reserved38 |
|
|
|
|
| Opcode::Reserved39 |
|
|
|
|
| Opcode::Reserved40 |
|
|
|
|
| Opcode::Reserved41 |
|
|
|
|
| Opcode::Reserved42 |
|
|
|
|
| Opcode::Reserved43 |
|
|
|
|
| Opcode::Reserved44 |
|
|
|
|
| Opcode::Reserved45 |
|
|
|
|
| Opcode::Reserved46 |
|
|
|
|
| Opcode::Reserved47 |
|
|
|
|
| Opcode::Reserved48 |
|
|
|
|
| Opcode::Reserved49 |
|
|
|
|
| Opcode::Reserved50 |
|
|
|
|
| Opcode::Reserved51 |
|
|
|
|
| Opcode::Reserved52 |
|
|
|
|
| Opcode::Reserved53 |
|
|
|
|
| Opcode::Reserved54 |
|
|
|
|
| Opcode::Reserved55 |
|
|
|
|
| Opcode::Reserved56 |
|
|
|
|
| Opcode::Reserved57 |
|
|
|
|
| Opcode::Reserved58 => unreachable!("Reserved opcodes are unrechable"), |
|
|
|
|
Instruction::Reserved1 |
|
|
|
|
| Instruction::Reserved2 |
|
|
|
|
| Instruction::Reserved3 |
|
|
|
|
| Instruction::Reserved4 |
|
|
|
|
| Instruction::Reserved5 |
|
|
|
|
| Instruction::Reserved6 |
|
|
|
|
| Instruction::Reserved7 |
|
|
|
|
| Instruction::Reserved8 |
|
|
|
|
| Instruction::Reserved9 |
|
|
|
|
| Instruction::Reserved10 |
|
|
|
|
| Instruction::Reserved11 |
|
|
|
|
| Instruction::Reserved12 |
|
|
|
|
| Instruction::Reserved13 |
|
|
|
|
| Instruction::Reserved14 |
|
|
|
|
| Instruction::Reserved15 |
|
|
|
|
| Instruction::Reserved16 |
|
|
|
|
| Instruction::Reserved17 |
|
|
|
|
| Instruction::Reserved18 |
|
|
|
|
| Instruction::Reserved19 |
|
|
|
|
| Instruction::Reserved20 |
|
|
|
|
| Instruction::Reserved21 |
|
|
|
|
| Instruction::Reserved22 |
|
|
|
|
| Instruction::Reserved23 |
|
|
|
|
| Instruction::Reserved24 |
|
|
|
|
| Instruction::Reserved25 |
|
|
|
|
| Instruction::Reserved26 |
|
|
|
|
| Instruction::Reserved27 |
|
|
|
|
| Instruction::Reserved28 |
|
|
|
|
| Instruction::Reserved29 |
|
|
|
|
| Instruction::Reserved30 |
|
|
|
|
| Instruction::Reserved31 |
|
|
|
|
| Instruction::Reserved32 |
|
|
|
|
| Instruction::Reserved33 |
|
|
|
|
| Instruction::Reserved34 |
|
|
|
|
| Instruction::Reserved35 |
|
|
|
|
| Instruction::Reserved36 |
|
|
|
|
| Instruction::Reserved37 |
|
|
|
|
| Instruction::Reserved38 |
|
|
|
|
| Instruction::Reserved39 |
|
|
|
|
| Instruction::Reserved40 |
|
|
|
|
| Instruction::Reserved41 |
|
|
|
|
| Instruction::Reserved42 |
|
|
|
|
| Instruction::Reserved43 |
|
|
|
|
| Instruction::Reserved44 |
|
|
|
|
| Instruction::Reserved45 |
|
|
|
|
| Instruction::Reserved46 |
|
|
|
|
| Instruction::Reserved47 |
|
|
|
|
| Instruction::Reserved48 |
|
|
|
|
| Instruction::Reserved49 |
|
|
|
|
| Instruction::Reserved50 |
|
|
|
|
| Instruction::Reserved51 |
|
|
|
|
| Instruction::Reserved52 |
|
|
|
|
| Instruction::Reserved53 |
|
|
|
|
| Instruction::Reserved54 |
|
|
|
|
| Instruction::Reserved55 |
|
|
|
|
| Instruction::Reserved56 |
|
|
|
|
| Instruction::Reserved57 |
|
|
|
|
| Instruction::Reserved58 => unreachable!("Reserved opcodes are unrechable"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|