@@ -18,6 +18,9 @@ use boa_gc::{Finalize, Gc, Trace, custom_trace};
1818use shadow_stack:: ShadowStack ;
1919use std:: { future:: Future , ops:: ControlFlow , pin:: Pin , task} ;
2020
21+ #[ cfg( feature = "trace" ) ]
22+ pub use trace:: { EmptyTracer , StdoutTracer , VirtualMachineTracer } ;
23+
2124#[ cfg( feature = "trace" ) ]
2225use crate :: sys:: time:: Instant ;
2326
@@ -53,6 +56,8 @@ pub(crate) mod opcode;
5356pub ( crate ) mod shadow_stack;
5457pub ( crate ) mod source_info;
5558
59+ mod trace;
60+
5661#[ cfg( feature = "flowgraph" ) ]
5762pub mod flowgraph;
5863
@@ -98,6 +103,10 @@ pub struct Vm {
98103
99104 #[ cfg( feature = "trace" ) ]
100105 pub ( crate ) trace : bool ,
106+
107+ /// A tracer registered to emit VM events
108+ #[ cfg( feature = "trace" ) ]
109+ pub ( crate ) tracer : Box < dyn VirtualMachineTracer > ,
101110}
102111
103112/// The stack holds the [`JsValue`]s for the calling convention and registers.
@@ -334,6 +343,7 @@ impl Vm {
334343 shadow_stack : ShadowStack :: default ( ) ,
335344 #[ cfg( feature = "trace" ) ]
336345 trace : false ,
346+ tracer : Box :: new ( EmptyTracer ) ,
337347 }
338348 }
339349
@@ -581,40 +591,35 @@ impl Vm {
581591 }
582592}
583593
584- #[ allow( clippy:: print_stdout) ]
585594#[ cfg( feature = "trace" ) ]
586595impl Context {
587- const COLUMN_WIDTH : usize = 26 ;
588- const TIME_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH / 2 ;
589- const OPCODE_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH ;
590- const OPERAND_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH ;
591- const NUMBER_OF_COLUMNS : usize = 4 ;
596+ /// Sets the `Vm` tracer to the provided `VirtualMachineTracer` implementation
597+ pub fn set_virtual_machine_tracer ( & mut self , tracer : Box < dyn VirtualMachineTracer > ) {
598+ self . vm . tracer = tracer;
599+ }
592600
593601 pub ( crate ) fn trace_call_frame ( & self ) {
602+ use crate :: vm:: trace:: {
603+ CallFrameMessage , CallFrameName , ExecutionStartMessage , VirtualMachineEvent ,
604+ } ;
594605 let frame = self . vm . frame ( ) ;
595- let msg = if self . vm . frames . is_empty ( ) {
596- " VM Start " . to_string ( )
597- } else {
598- format ! (
599- " Call Frame -- {} " ,
600- frame. code_block( ) . name( ) . to_std_string_escaped( )
601- )
606+ let call_frame_message = CallFrameMessage {
607+ bytecode : frame. code_block . to_string ( ) ,
602608 } ;
609+ self . vm
610+ . tracer
611+ . emit_event ( VirtualMachineEvent :: CallFrameTrace ( call_frame_message) ) ;
603612
604- println ! ( "{}" , frame. code_block) ;
605- println ! (
606- "{msg:-^width$}" ,
607- width = Self :: COLUMN_WIDTH * Self :: NUMBER_OF_COLUMNS - 10
608- ) ;
609- println ! (
610- "{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {:<OPERAND_COLUMN_WIDTH$} Stack\n " ,
611- "Time" ,
612- "Opcode" ,
613- "Operands" ,
614- TIME_COLUMN_WIDTH = Self :: TIME_COLUMN_WIDTH ,
615- OPCODE_COLUMN_WIDTH = Self :: OPCODE_COLUMN_WIDTH ,
616- OPERAND_COLUMN_WIDTH = Self :: OPERAND_COLUMN_WIDTH ,
617- ) ;
613+ let call_frame_name = if self . vm . frames . is_empty ( ) {
614+ CallFrameName :: Global
615+ } else {
616+ CallFrameName :: Name ( frame. code_block ( ) . name ( ) . to_std_string_escaped ( ) )
617+ } ;
618+ self . vm
619+ . tracer
620+ . emit_event ( VirtualMachineEvent :: ExecutionStart ( ExecutionStartMessage {
621+ call_frame_name,
622+ } ) ) ;
618623 }
619624
620625 fn trace_execute_instruction < F > (
@@ -625,6 +630,8 @@ impl Context {
625630 where
626631 F : FnOnce ( & mut Context , Opcode ) -> ControlFlow < CompletionRecord > ,
627632 {
633+ use crate :: vm:: trace:: { OpcodeExecutionMessage , VirtualMachineEvent } ;
634+
628635 let frame = self . vm . frame ( ) ;
629636 let ( instruction, _) = frame
630637 . code_block
@@ -647,7 +654,9 @@ impl Context {
647654 | Opcode :: SuperCall
648655 | Opcode :: SuperCallSpread
649656 | Opcode :: SuperCallDerived => {
650- println ! ( ) ;
657+ self . vm
658+ . tracer
659+ . emit_event ( VirtualMachineEvent :: ExecutionCallEvent ) ;
651660 }
652661 _ => { }
653662 }
@@ -661,14 +670,16 @@ impl Context {
661670 . stack
662671 . display_trace ( self . vm . frame ( ) , self . vm . frames . len ( ) - 1 ) ;
663672
664- println ! (
665- "{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {operands:<OPERAND_COLUMN_WIDTH$} {stack}" ,
666- format!( "{}μs" , duration. as_micros( ) ) ,
667- format!( "{}" , opcode. as_str( ) ) ,
668- TIME_COLUMN_WIDTH = Self :: TIME_COLUMN_WIDTH ,
669- OPCODE_COLUMN_WIDTH = Self :: OPCODE_COLUMN_WIDTH ,
670- OPERAND_COLUMN_WIDTH = Self :: OPERAND_COLUMN_WIDTH ,
671- ) ;
673+ self . vm
674+ . tracer
675+ . emit_event ( VirtualMachineEvent :: ExecutionTrace (
676+ OpcodeExecutionMessage {
677+ opcode : opcode. as_str ( ) ,
678+ duration,
679+ operands,
680+ stack,
681+ } ,
682+ ) ) ;
672683
673684 result
674685 }
0 commit comments