@@ -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,9 @@ pub(crate) mod opcode;
5356pub ( crate ) mod shadow_stack;
5457pub ( crate ) mod source_info;
5558
59+ #[ cfg( feature = "trace" ) ]
60+ mod trace;
61+
5662#[ cfg( feature = "flowgraph" ) ]
5763pub mod flowgraph;
5864
@@ -98,6 +104,10 @@ pub struct Vm {
98104
99105 #[ cfg( feature = "trace" ) ]
100106 pub ( crate ) trace : bool ,
107+
108+ /// A tracer registered to emit VM events
109+ #[ cfg( feature = "trace" ) ]
110+ pub ( crate ) tracer : Box < dyn VirtualMachineTracer > ,
101111}
102112
103113/// The stack holds the [`JsValue`]s for the calling convention and registers.
@@ -334,6 +344,10 @@ impl Vm {
334344 shadow_stack : ShadowStack :: default ( ) ,
335345 #[ cfg( feature = "trace" ) ]
336346 trace : false ,
347+ #[ cfg( all( feature = "trace" , not( feature = "trace-stdout" ) ) ) ]
348+ tracer : Box :: new ( EmptyTracer ) ,
349+ #[ cfg( feature = "trace-stdout" ) ]
350+ tracer : Box :: new ( StdoutTracer ) ,
337351 }
338352 }
339353
@@ -581,40 +595,35 @@ impl Vm {
581595 }
582596}
583597
584- #[ allow( clippy:: print_stdout) ]
585598#[ cfg( feature = "trace" ) ]
586599impl 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 ;
600+ /// Sets the `Vm` tracer to the provided `VirtualMachineTracer` implementation
601+ pub fn set_virtual_machine_tracer ( & mut self , tracer : Box < dyn VirtualMachineTracer > ) {
602+ self . vm . tracer = tracer;
603+ }
592604
593605 pub ( crate ) fn trace_call_frame ( & self ) {
606+ use crate :: vm:: trace:: {
607+ CallFrameMessage , CallFrameName , ExecutionStartMessage , VirtualMachineEvent ,
608+ } ;
594609 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- )
610+ let call_frame_message = CallFrameMessage {
611+ bytecode : frame. code_block . to_string ( ) ,
602612 } ;
613+ self . vm
614+ . tracer
615+ . emit_event ( VirtualMachineEvent :: CallFrameTrace ( call_frame_message) ) ;
603616
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- ) ;
617+ let call_frame_name = if self . vm . frames . is_empty ( ) {
618+ CallFrameName :: Global
619+ } else {
620+ CallFrameName :: Name ( frame. code_block ( ) . name ( ) . to_std_string_escaped ( ) )
621+ } ;
622+ self . vm
623+ . tracer
624+ . emit_event ( VirtualMachineEvent :: ExecutionStart ( ExecutionStartMessage {
625+ call_frame_name,
626+ } ) ) ;
618627 }
619628
620629 fn trace_execute_instruction < F > (
@@ -625,6 +634,8 @@ impl Context {
625634 where
626635 F : FnOnce ( & mut Context , Opcode ) -> ControlFlow < CompletionRecord > ,
627636 {
637+ use crate :: vm:: trace:: { OpcodeExecutionMessage , VirtualMachineEvent } ;
638+
628639 let frame = self . vm . frame ( ) ;
629640 let ( instruction, _) = frame
630641 . code_block
@@ -647,7 +658,9 @@ impl Context {
647658 | Opcode :: SuperCall
648659 | Opcode :: SuperCallSpread
649660 | Opcode :: SuperCallDerived => {
650- println ! ( ) ;
661+ self . vm
662+ . tracer
663+ . emit_event ( VirtualMachineEvent :: ExecutionCallEvent ) ;
651664 }
652665 _ => { }
653666 }
@@ -661,14 +674,16 @@ impl Context {
661674 . stack
662675 . display_trace ( self . vm . frame ( ) , self . vm . frames . len ( ) - 1 ) ;
663676
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- ) ;
677+ self . vm
678+ . tracer
679+ . emit_event ( VirtualMachineEvent :: ExecutionTrace (
680+ OpcodeExecutionMessage {
681+ opcode : opcode. as_str ( ) ,
682+ duration,
683+ operands,
684+ stack,
685+ } ,
686+ ) ) ;
672687
673688 result
674689 }
0 commit comments