Browse Source

Make tracing an opt-in feature (#2709)

This PR adds the `"trace"` feature flag that enables vm opcode tracing (off by default), most users aren't interested in tracing/debugging that's why I think it should be made out-in.
pull/2716/head
Haled Odat 2 years ago
parent
commit
3b5122635f
  1. 2
      boa_cli/Cargo.toml
  2. 3
      boa_engine/Cargo.toml
  3. 1
      boa_engine/src/context/mod.rs
  4. 13
      boa_engine/src/vm/code_block.rs
  5. 21
      boa_engine/src/vm/mod.rs

2
boa_cli/Cargo.toml

@ -12,7 +12,7 @@ repository.workspace = true
rust-version.workspace = true
[dependencies]
boa_engine = { workspace = true, features = ["deser", "console", "flowgraph"] }
boa_engine = { workspace = true, features = ["deser", "console", "flowgraph", "trace"] }
boa_ast = { workspace = true, features = ["serde"]}
boa_parser.workspace = true
rustyline = { version = "11.0.0", features = ["derive"]}

3
boa_engine/Cargo.toml

@ -33,6 +33,9 @@ fuzz = ["boa_ast/arbitrary", "boa_interner/arbitrary"]
# Enable Boa's VM instruction flowgraph generator.
flowgraph = []
# Enable Boa's VM instruction tracing.
trace = []
# Enable Boa's WHATWG console object implementation.
console = []

1
boa_engine/src/context/mod.rs

@ -422,6 +422,7 @@ impl Context<'_> {
}
/// Set the value of trace on the context
#[cfg(feature = "trace")]
pub fn set_trace(&mut self, trace: bool) {
self.vm.trace = trace;
}

13
boa_engine/src/vm/code_block.rs

@ -18,7 +18,7 @@ use crate::{
},
property::PropertyDescriptor,
string::utf16,
vm::{CallFrame, Opcode},
vm::CallFrame,
Context, JsResult, JsString, JsValue,
};
use boa_ast::{
@ -26,9 +26,14 @@ use boa_ast::{
function::{FormalParameterList, PrivateName},
};
use boa_gc::{Finalize, Gc, GcRefCell, Trace};
use boa_interner::{Interner, Sym, ToInternedString};
use boa_interner::Sym;
use boa_profiler::Profiler;
use std::{collections::VecDeque, convert::TryInto, mem::size_of};
use std::{collections::VecDeque, mem::size_of};
#[cfg(any(feature = "trace", feature = "flowgraph"))]
use crate::vm::Opcode;
#[cfg(any(feature = "trace", feature = "flowgraph"))]
use boa_interner::{Interner, ToInternedString};
/// This represents whether a value can be read from [`CodeBlock`] code.
///
@ -190,6 +195,7 @@ impl CodeBlock {
/// Modifies the `pc` to point to the next instruction.
///
/// 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].try_into().expect("invalid opcode");
*pc += size_of::<Opcode>();
@ -450,6 +456,7 @@ impl CodeBlock {
}
}
#[cfg(any(feature = "trace", feature = "flowgraph"))]
impl ToInternedString for CodeBlock {
fn to_interned_string(&self, interner: &Interner) -> String {
let name = interner.resolve_expect(self.name);

21
boa_engine/src/vm/mod.rs

@ -11,9 +11,13 @@ use crate::{
};
#[cfg(feature = "fuzz")]
use crate::{JsNativeError, JsNativeErrorKind};
use boa_interner::ToInternedString;
use boa_profiler::Profiler;
use std::{convert::TryInto, mem::size_of, time::Instant};
use std::{convert::TryInto, mem::size_of};
#[cfg(feature = "trace")]
use boa_interner::ToInternedString;
#[cfg(feature = "trace")]
use std::time::Instant;
mod call_frame;
mod code_block;
@ -40,6 +44,7 @@ pub struct Vm {
pub(crate) frames: Vec<CallFrame>,
pub(crate) stack: Vec<JsValue>,
pub(crate) err: Option<JsError>,
#[cfg(feature = "trace")]
pub(crate) trace: bool,
pub(crate) stack_size_limit: usize,
}
@ -50,6 +55,7 @@ impl Default for Vm {
frames: Vec::with_capacity(16),
stack: Vec::with_capacity(1024),
err: None,
#[cfg(feature = "trace")]
trace: false,
stack_size_limit: 1024,
}
@ -133,14 +139,20 @@ impl Context<'_> {
}
pub(crate) fn run(&mut self) -> CompletionRecord {
#[cfg(feature = "trace")]
const COLUMN_WIDTH: usize = 26;
#[cfg(feature = "trace")]
const TIME_COLUMN_WIDTH: usize = COLUMN_WIDTH / 2;
#[cfg(feature = "trace")]
const OPCODE_COLUMN_WIDTH: usize = COLUMN_WIDTH;
#[cfg(feature = "trace")]
const OPERAND_COLUMN_WIDTH: usize = COLUMN_WIDTH;
#[cfg(feature = "trace")]
const NUMBER_OF_COLUMNS: usize = 4;
let _timer = Profiler::global().start_event("run", "vm");
#[cfg(feature = "trace")]
if self.vm.trace {
let msg = if self.vm.frames.last().is_some() {
" Call Frame "
@ -203,6 +215,7 @@ impl Context<'_> {
}
// 1. Run the next instruction.
#[cfg(feature = "trace")]
let result = if self.vm.trace {
let mut pc = self.vm.frame().pc;
let opcode: Opcode = self
@ -239,6 +252,9 @@ impl Context<'_> {
self.execute_instruction()
};
#[cfg(not(feature = "trace"))]
let result = self.execute_instruction();
// 2. Evaluate the result of executing the instruction.
match result {
Ok(CompletionType::Normal) => {}
@ -295,6 +311,7 @@ impl Context<'_> {
}
}
#[cfg(feature = "trace")]
if self.vm.trace {
println!("\nStack:");
if self.vm.stack.is_empty() {

Loading…
Cancel
Save