Browse Source

Add `Instruction` and `InstructionIterator` (#3201)

pull/3264/head
Haled Odat 1 year ago committed by GitHub
parent
commit
3ea0a77606
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      boa_engine/src/bytecompiler/mod.rs
  2. 5
      boa_engine/src/vm/call_frame/mod.rs
  3. 648
      boa_engine/src/vm/code_block.rs
  4. 651
      boa_engine/src/vm/flowgraph/mod.rs
  5. 7
      boa_engine/src/vm/mod.rs
  6. 2
      boa_engine/src/vm/opcode/control_flow/jump.rs
  7. 582
      boa_engine/src/vm/opcode/mod.rs

4
boa_engine/src/bytecompiler/mod.rs

@ -596,9 +596,9 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
let index = self.next_opcode_location();
self.emit(
Opcode::JumpTable,
&[Operand::U32(count), Operand::U32(Self::DUMMY_ADDRESS)],
&[Operand::U32(Self::DUMMY_ADDRESS), Operand::U32(count)],
);
let default = Label { index: index + 4 };
let default = Label { index };
let mut labels = Vec::with_capacity(count as usize);
for i in 0..count {
labels.push(Label {

5
boa_engine/src/vm/call_frame/mod.rs

@ -87,9 +87,10 @@ impl CallFrame {
}
/// Indicates how a generator function that has been called/resumed should return.
#[derive(Copy, Clone, Debug, PartialEq, Default)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub(crate) enum GeneratorResumeKind {
#[allow(missing_docs)]
pub enum GeneratorResumeKind {
#[default]
Normal = 0,
Throw,

648
boa_engine/src/vm/code_block.rs

@ -301,387 +301,335 @@ impl CodeBlock {
/// Returns an empty `String` if no operands are present.
#[cfg(any(feature = "trace", feature = "flowgraph"))]
pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String {
let opcode: Opcode = self.bytecode[*pc].into();
*pc += size_of::<Opcode>();
match opcode {
Opcode::SetFunctionName => {
let operand = self.read::<u8>(*pc);
*pc += size_of::<u8>();
match operand {
use super::Instruction;
let instruction = Instruction::from_bytecode(&self.bytecode, pc);
match instruction {
Instruction::SetFunctionName { prefix } => match prefix {
0 => "prefix: none",
1 => "prefix: get",
2 => "prefix: set",
_ => unreachable!(),
}
.to_owned()
}
Opcode::RotateLeft | Opcode::RotateRight => {
let result = self.read::<u8>(*pc).to_string();
*pc += size_of::<u8>();
result
}
Opcode::Generator => {
let result = self.read::<u8>(*pc);
*pc += size_of::<u8>();
format!("async: {}", result != 0)
}
Opcode::PushInt8 => {
let result = self.read::<i8>(*pc).to_string();
*pc += size_of::<i8>();
result
}
Opcode::PushInt16 => {
let result = self.read::<i16>(*pc).to_string();
*pc += size_of::<i16>();
result
}
Opcode::PushInt32 => {
let result = self.read::<i32>(*pc).to_string();
*pc += size_of::<i32>();
result
.to_owned(),
Instruction::RotateLeft { n } | Instruction::RotateRight { n } => n.to_string(),
Instruction::Generator { r#async } => {
format!("async: {async}")
}
Instruction::PushInt8 { value } => value.to_string(),
Instruction::PushInt16 { value } => value.to_string(),
Instruction::PushInt32 { value } => value.to_string(),
Instruction::PushFloat { value } => ryu_js::Buffer::new().format(value).to_string(),
Instruction::PushDouble { value } => ryu_js::Buffer::new().format(value).to_string(),
Instruction::PushLiteral { index: value }
| Instruction::ThrowNewTypeError { message: value }
| Instruction::Jump { address: value }
| Instruction::JumpIfTrue { address: value }
| Instruction::JumpIfFalse { address: value }
| Instruction::JumpIfNotUndefined { address: value }
| Instruction::JumpIfNullOrUndefined { address: value }
| Instruction::Case { address: value }
| Instruction::Default { address: value }
| Instruction::LogicalAnd { exit: value }
| Instruction::LogicalOr { exit: value }
| Instruction::Coalesce { exit: value }
| Instruction::CallEval {
argument_count: value,
}
| Instruction::Call {
argument_count: value,
}
| Instruction::New {
argument_count: value,
}
| Instruction::SuperCall {
argument_count: value,
}
| Instruction::ConcatToString { value_count: value } => value.to_string(),
Instruction::PushDeclarativeEnvironment {
compile_environments_index,
}
| Instruction::PushFunctionEnvironment {
compile_environments_index,
} => compile_environments_index.to_string(),
Instruction::CopyDataProperties {
excluded_key_count: value1,
excluded_key_count_computed: value2,
}
| Instruction::GeneratorDelegateNext {
return_method_undefined: value1,
throw_method_undefined: value2,
}
| Instruction::GeneratorDelegateResume {
exit: value1,
r#return: value2,
} => {
format!("{value1}, {value2}")
}
Opcode::PushFloat => {
let operand = self.read::<f32>(*pc);
*pc += size_of::<f32>();
ryu_js::Buffer::new().format(operand).to_string()
}
Opcode::PushDouble => {
let operand = self.read::<f64>(*pc);
*pc += size_of::<f64>();
ryu_js::Buffer::new().format(operand).to_string()
}
Opcode::PushLiteral
| Opcode::ThrowNewTypeError
| Opcode::Jump
| Opcode::JumpIfTrue
| Opcode::JumpIfFalse
| Opcode::JumpIfNotUndefined
| Opcode::JumpIfNullOrUndefined
| Opcode::Case
| Opcode::Default
| Opcode::LogicalAnd
| Opcode::LogicalOr
| Opcode::Coalesce
| Opcode::CallEval
| Opcode::Call
| Opcode::New
| Opcode::SuperCall
| Opcode::ConcatToString => {
let result = self.read::<u32>(*pc).to_string();
*pc += size_of::<u32>();
result
Instruction::TemplateLookup { exit: value, site }
| Instruction::TemplateCreate { count: value, site } => {
format!("{value}, {site}")
}
Opcode::PushDeclarativeEnvironment | Opcode::PushFunctionEnvironment => {
let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>();
format!("{operand}")
}
Opcode::CopyDataProperties
| Opcode::GeneratorDelegateNext
| Opcode::GeneratorDelegateResume => {
let operand1 = self.read::<u32>(*pc);
*pc += size_of::<u32>();
let operand2 = self.read::<u32>(*pc);
*pc += size_of::<u32>();
format!("{operand1}, {operand2}")
}
Opcode::TemplateLookup | Opcode::TemplateCreate => {
let operand1 = self.read::<u32>(*pc);
*pc += size_of::<u32>();
let operand2 = self.read::<u64>(*pc);
*pc += size_of::<u64>();
format!("{operand1}, {operand2}")
}
Opcode::GetArrowFunction
| Opcode::GetAsyncArrowFunction
| Opcode::GetFunction
| Opcode::GetFunctionAsync => {
let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>() + size_of::<u8>();
Instruction::GetArrowFunction { index, method }
| Instruction::GetAsyncArrowFunction { index, method }
| Instruction::GetFunction { index, method }
| Instruction::GetFunctionAsync { index, method } => {
format!(
"{operand:04}: '{}' (length: {})",
self.functions[operand as usize]
"{index:04}: '{}' (length: {}), method: {method}",
self.functions[index as usize]
.name()
.to_std_string_escaped(),
self.functions[operand as usize].length
self.functions[index as usize].length
)
}
Opcode::GetGenerator | Opcode::GetGeneratorAsync => {
let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>();
Instruction::GetGenerator { index } | Instruction::GetGeneratorAsync { index } => {
format!(
"{operand:04}: '{}' (length: {})",
self.functions[operand as usize]
"{index:04}: '{}' (length: {})",
self.functions[index as usize]
.name()
.to_std_string_escaped(),
self.functions[operand as usize].length
self.functions[index as usize].length
)
}
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>();
Instruction::DefVar { index }
| Instruction::DefInitVar { index }
| Instruction::PutLexicalValue { index }
| Instruction::GetName { index }
| Instruction::GetLocator { index }
| Instruction::GetNameAndLocator { index }
| Instruction::GetNameOrUndefined { index }
| Instruction::SetName { index }
| Instruction::DeleteName { index } => {
format!(
"{:04}: '{}'",
operand,
interner.resolve_expect(self.bindings[operand as usize].name().sym()),
"{index:04}: '{}'",
interner.resolve_expect(self.bindings[index as usize].name().sym()),
)
}
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::DeletePropertyByName
| Opcode::SetPrivateField
| Opcode::DefinePrivateField
| Opcode::SetPrivateMethod
| Opcode::SetPrivateSetter
| Opcode::SetPrivateGetter
| Opcode::GetPrivateField
| Opcode::PushClassFieldPrivate
| Opcode::PushClassPrivateGetter
| Opcode::PushClassPrivateSetter
| Opcode::PushClassPrivateMethod
| Opcode::InPrivate
| Opcode::ThrowMutateImmutable => {
let operand = self.read::<u32>(*pc);
*pc += size_of::<u32>();
Instruction::GetPropertyByName { index }
| Instruction::GetMethod { index }
| Instruction::SetPropertyByName { index }
| Instruction::DefineOwnPropertyByName { index }
| Instruction::DefineClassStaticMethodByName { index }
| Instruction::DefineClassMethodByName { index }
| Instruction::SetPropertyGetterByName { index }
| Instruction::DefineClassStaticGetterByName { index }
| Instruction::DefineClassGetterByName { index }
| Instruction::SetPropertySetterByName { index }
| Instruction::DefineClassStaticSetterByName { index }
| Instruction::DefineClassSetterByName { index }
| Instruction::DeletePropertyByName { index }
| Instruction::SetPrivateField { index }
| Instruction::DefinePrivateField { index }
| Instruction::SetPrivateMethod { index }
| Instruction::SetPrivateSetter { index }
| Instruction::SetPrivateGetter { index }
| Instruction::GetPrivateField { index }
| Instruction::PushClassFieldPrivate { index }
| Instruction::PushClassPrivateGetter { index }
| Instruction::PushClassPrivateSetter { index }
| Instruction::PushClassPrivateMethod { index }
| Instruction::InPrivate { index }
| Instruction::ThrowMutateImmutable { index } => {
format!(
"{operand:04}: '{}'",
self.names[operand as usize].to_std_string_escaped(),
"{index:04}: '{}'",
self.names[index as usize].to_std_string_escaped(),
)
}
Opcode::PushPrivateEnvironment => {
let count = self.read::<u32>(*pc);
*pc += size_of::<u32>() * (count as usize + 1);
String::new()
Instruction::PushPrivateEnvironment { name_indices } => {
format!("{name_indices:?}")
}
Opcode::JumpTable => {
let count = self.read::<u32>(*pc);
*pc += size_of::<u32>();
let default = self.read::<u32>(*pc);
*pc += size_of::<u32>();
let mut operands = format!("#{count}: Default: {default:4}");
for i in 1..=count {
let address = self.read::<u32>(*pc);
*pc += size_of::<u32>();
Instruction::JumpTable { default, addresses } => {
let mut operands = format!("#{}: Default: {default:4}", addresses.len());
for (i, address) in addresses.iter().enumerate() {
operands += &format!(", {i}: {address}");
}
operands
}
Opcode::JumpIfNotResumeKind => {
let exit = self.read::<u32>(*pc);
*pc += size_of::<u32>();
let resume_kind = self.read::<u8>(*pc);
*pc += size_of::<u8>();
format!(
"ResumeKind: {:?}, exit: {exit}",
JsValue::new(resume_kind).to_generator_resume_kind()
)
Instruction::JumpIfNotResumeKind { exit, resume_kind } => {
format!("ResumeKind: {resume_kind:?}, exit: {exit}")
}
Opcode::CreateIteratorResult => {
let done = self.read::<u8>(*pc) != 0;
*pc += size_of::<u8>();
Instruction::CreateIteratorResult { done } => {
format!("done: {done}")
}
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::Throw
| Opcode::ReThrow
| Opcode::Exception
| Opcode::MaybeException
| Opcode::This
| Opcode::Super
| Opcode::Return
| Opcode::AsyncGeneratorClose
| Opcode::CreatePromiseCapability
| Opcode::CompletePromiseCapability
| Opcode::PopEnvironment
| 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::GeneratorNext
| Opcode::PushClassField
| Opcode::SuperCallDerived
| Opcode::Await
| Opcode::NewTarget
| Opcode::ImportMeta
| Opcode::SuperCallPrepare
| Opcode::CallEvalSpread
| Opcode::CallSpread
| Opcode::NewSpread
| Opcode::SuperCallSpread
| Opcode::SetPrototype
| Opcode::PushObjectEnvironment
| Opcode::IsObject
| Opcode::SetNameByLocator
| Opcode::PopPrivateEnvironment
| Opcode::ImportCall
| Opcode::GetReturnValue
| Opcode::SetReturnValue
| Opcode::Nop => String::new(),
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::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::Throw
| Instruction::ReThrow
| Instruction::Exception
| Instruction::MaybeException
| Instruction::This
| Instruction::Super
| Instruction::Return
| Instruction::AsyncGeneratorClose
| Instruction::CreatePromiseCapability
| Instruction::CompletePromiseCapability
| Instruction::PopEnvironment
| 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::GeneratorNext
| Instruction::PushClassField
| Instruction::SuperCallDerived
| Instruction::Await
| Instruction::NewTarget
| Instruction::ImportMeta
| Instruction::SuperCallPrepare
| Instruction::CallEvalSpread
| Instruction::CallSpread
| Instruction::NewSpread
| Instruction::SuperCallSpread
| Instruction::SetPrototype
| Instruction::PushObjectEnvironment
| Instruction::IsObject
| Instruction::SetNameByLocator
| Instruction::PopPrivateEnvironment
| Instruction::ImportCall
| Instruction::GetReturnValue
| Instruction::SetReturnValue
| Instruction::Nop => String::new(),
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"),
}
}
}

651
boa_engine/src/vm/flowgraph/mod.rs

@ -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"),
}
}

7
boa_engine/src/vm/mod.rs

@ -33,10 +33,13 @@ mod runtime_limits;
pub mod flowgraph;
pub use runtime_limits::RuntimeLimits;
pub use {call_frame::CallFrame, code_block::CodeBlock, opcode::Opcode};
pub use {
call_frame::{CallFrame, GeneratorResumeKind},
code_block::CodeBlock,
opcode::{Instruction, InstructionIterator, Opcode},
};
pub(crate) use {
call_frame::GeneratorResumeKind,
code_block::{
create_function_object, create_function_object_fast, create_generator_function_object,
CodeBlockFlags, Handler,

2
boa_engine/src/vm/opcode/control_flow/jump.rs

@ -118,8 +118,8 @@ impl Operation for JumpTable {
const INSTRUCTION: &'static str = "INST - JumpTable";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let count = context.vm.read::<u32>();
let default = context.vm.read::<u32>();
let count = context.vm.read::<u32>();
let value = context.vm.pop();
if let JsValue::Integer(value) = &value {

582
boa_engine/src/vm/opcode/mod.rs

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save