@@ -9,6 +9,41 @@ use boa_interner::{Interner, ToInternedString};
9
9
10
10
use super :: Vm ;
11
11
12
+ // TODO: Build out further, maybe provide more element visiblity and events/outputs
13
+ /// The `Tracer` trait is a customizable trait that can be provided to `Boa`
14
+ /// for customizing output.
15
+ pub trait Tracer {
16
+ /// The output from tracing a `CodeBlock`'s bytecode.
17
+ fn emit_bytecode_trace ( & self , msg : & str ) ;
18
+ /// The output from entering a `CallFrame`.
19
+ fn emit_call_frame_entrance_trace ( & self , msg : & str ) ;
20
+ /// The trace output from an execution.
21
+ fn emit_instruction_trace ( & self , msg : & str ) ;
22
+ /// Trace output from exiting a `CallFrame`.
23
+ fn emit_call_frame_exit_trace ( & self , msg : & str ) ;
24
+ }
25
+
26
+ #[ derive( Debug ) ]
27
+ pub ( crate ) struct DefaultTracer ;
28
+
29
+ impl Tracer for DefaultTracer {
30
+ fn emit_bytecode_trace ( & self , msg : & str ) {
31
+ println ! ( "{msg}" ) ;
32
+ }
33
+
34
+ fn emit_call_frame_entrance_trace ( & self , msg : & str ) {
35
+ println ! ( "{msg}" ) ;
36
+ }
37
+
38
+ fn emit_instruction_trace ( & self , msg : & str ) {
39
+ println ! ( "{msg}" ) ;
40
+ }
41
+
42
+ fn emit_call_frame_exit_trace ( & self , msg : & str ) {
43
+ println ! ( "{msg}" ) ;
44
+ }
45
+ }
46
+
12
47
bitflags ! {
13
48
#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
14
49
pub ( crate ) struct TraceOptions : u8 {
@@ -28,16 +63,12 @@ impl Vm {
28
63
impl Default for VmTrace {
29
64
fn default ( ) -> Self {
30
65
Self {
31
- compiled_action : None ,
32
- trace_action : None ,
33
66
options : Cell :: new ( TraceOptions :: FULL_TRACE ) ,
67
+ tracer : Box :: new ( DefaultTracer ) ,
34
68
}
35
69
}
36
70
}
37
71
38
- // Action function provided by the user.
39
- type ActionFunction = Box < dyn Fn ( & str ) > ;
40
-
41
72
/// `VmTrace` is a boa spcific structure for running Boa's Virtual Machine trace.
42
73
///
43
74
/// The struct provides options for a user to set customized actions for handling
@@ -52,9 +83,8 @@ type ActionFunction = Box<dyn Fn(&str)>;
52
83
/// After the Global callframe is initially provided. It searches
53
84
/// for all possible compiled output
54
85
pub struct VmTrace {
55
- compiled_action : Option < ActionFunction > ,
56
- trace_action : Option < ActionFunction > ,
57
86
options : Cell < TraceOptions > ,
87
+ tracer : Box < dyn Tracer > ,
58
88
}
59
89
60
90
// ==== Public API ====
@@ -64,34 +94,21 @@ impl VmTrace {
64
94
/// Create a partial `VmTrace`.
65
95
pub fn partial ( ) -> Self {
66
96
Self {
67
- compiled_action : None ,
68
- trace_action : None ,
69
97
options : Cell :: new ( TraceOptions :: empty ( ) ) ,
98
+ tracer : Box :: new ( DefaultTracer ) ,
70
99
}
71
100
}
72
101
73
102
#[ must_use]
74
103
/// Method for adding a compiled action on initialization.
75
- pub fn with_compiled_action ( mut self , f : ActionFunction ) -> Self {
76
- self . set_compiled_action ( f ) ;
104
+ pub fn with_tracer ( mut self , tracer : Box < dyn Tracer > ) -> Self {
105
+ self . set_tracer ( tracer ) ;
77
106
self
78
107
}
79
108
80
- #[ must_use]
81
- /// Method for adding a trace action on initialization.
82
- pub fn with_trace_action ( mut self , f : ActionFunction ) -> Self {
83
- self . set_trace_action ( f) ;
84
- self
85
- }
86
-
87
- /// Sets the `compiled_action` of `VmTrace` to a custom user-defined action.
88
- pub fn set_compiled_action ( & mut self , f : ActionFunction ) {
89
- self . compiled_action = Some ( f) ;
90
- }
91
-
92
- /// Sets the `trace_action` of `VmTrace` to a custom user-defined action.
93
- pub fn set_trace_action ( & mut self , f : ActionFunction ) {
94
- self . trace_action = Some ( f) ;
109
+ /// Sets the current `Tracer` of `VmTrace`.
110
+ pub fn set_tracer ( & mut self , tracer : Box < dyn Tracer > ) {
111
+ self . tracer = tracer;
95
112
}
96
113
}
97
114
@@ -133,32 +150,15 @@ impl VmTrace {
133
150
}
134
151
}
135
152
136
- // ---- Trace Event/Action Methods ----
153
+ // ==== Trace Event/Action Methods ====
154
+
137
155
impl VmTrace {
138
156
const COLUMN_WIDTH : usize = 26 ;
139
157
const TIME_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH / 2 ;
140
158
const OPCODE_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH ;
141
159
const OPERAND_COLUMN_WIDTH : usize = Self :: COLUMN_WIDTH ;
142
160
const NUMBER_OF_COLUMNS : usize = 4 ;
143
161
144
- pub ( crate ) fn trigger_compiled_output_action ( & self , msg : & str ) {
145
- if let Some ( action) = & self . compiled_action {
146
- action ( & format ! ( "{msg}\n " ) ) ;
147
- } else {
148
- println ! ( "{msg}" ) ;
149
- }
150
- }
151
-
152
- pub ( crate ) fn trigger_trace_action ( & self , msg : & str ) {
153
- if let Some ( action) = & self . trace_action {
154
- action ( & format ! ( "{msg}\n " ) ) ;
155
- } else {
156
- println ! ( "{msg}" ) ;
157
- }
158
- }
159
- }
160
-
161
- impl VmTrace {
162
162
/// Trace the current `CallFrame` according to current state
163
163
pub ( crate ) fn trace_call_frame ( & self , vm : & Vm , interner : & Interner ) {
164
164
if self . is_full_trace ( ) {
@@ -187,7 +187,7 @@ impl VmTrace {
187
187
"{msg:-^width$}" ,
188
188
width = Self :: COLUMN_WIDTH * Self :: NUMBER_OF_COLUMNS - 10
189
189
) ;
190
- self . trigger_trace_action ( & frame_header) ;
190
+ self . tracer . emit_call_frame_entrance_trace ( & frame_header) ;
191
191
192
192
if vm. frames . len ( ) == 1 {
193
193
let column_headers = format ! (
@@ -200,7 +200,7 @@ impl VmTrace {
200
200
OPERAND_COLUMN_WIDTH = Self :: OPERAND_COLUMN_WIDTH ,
201
201
) ;
202
202
203
- self . trigger_trace_action ( & column_headers) ;
203
+ self . tracer . emit_call_frame_entrance_trace ( & column_headers) ;
204
204
}
205
205
}
206
206
@@ -216,26 +216,31 @@ impl VmTrace {
216
216
217
217
queue. extend ( block. functions . iter ( ) . cloned ( ) ) ;
218
218
219
- self . trigger_compiled_output_action ( & block. to_interned_string ( interner) ) ;
219
+ self . tracer
220
+ . emit_bytecode_trace ( & block. to_interned_string ( interner) ) ;
220
221
}
221
222
}
222
223
}
223
224
224
225
/// Searches and traces for only current frame's `CodeBlock`.
225
226
pub ( crate ) fn trace_current_bytecode ( & self , vm : & Vm , interner : & Interner ) {
226
- self . trigger_compiled_output_action ( & vm. frame ( ) . code_block ( ) . to_interned_string ( interner) ) ;
227
+ self . tracer
228
+ . emit_bytecode_trace ( & vm. frame ( ) . code_block ( ) . to_interned_string ( interner) ) ;
227
229
}
228
230
229
231
/// Emits an exit message for the current `CallFrame`.
230
232
pub ( crate ) fn trace_frame_end ( & self , vm : & Vm , return_msg : & str ) {
231
233
if self . should_trace ( ) {
232
- let msg = format ! ( " Call Frame -- <Exiting {} via {return_msg}> " , vm. frame( ) . code_block( ) . name. to_std_string_escaped( ) ) ;
234
+ let msg = format ! (
235
+ " Call Frame -- <Exiting {} via {return_msg}> " ,
236
+ vm. frame( ) . code_block( ) . name. to_std_string_escaped( )
237
+ ) ;
233
238
let frame_footer = format ! (
234
239
"{msg:-^width$}" ,
235
240
width = Self :: COLUMN_WIDTH * Self :: NUMBER_OF_COLUMNS - 10
236
241
) ;
237
242
238
- self . trigger_trace_action ( & frame_footer) ;
243
+ self . tracer . emit_call_frame_exit_trace ( & frame_footer) ;
239
244
}
240
245
241
246
self . inactivate ( ) ;
@@ -253,7 +258,7 @@ impl VmTrace {
253
258
OPERAND_COLUMN_WIDTH = Self :: OPERAND_COLUMN_WIDTH ,
254
259
) ;
255
260
256
- self . trigger_trace_action ( & instruction_trace) ;
261
+ self . tracer . emit_instruction_trace ( & instruction_trace) ;
257
262
}
258
263
259
264
#[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -273,27 +278,12 @@ impl VmTrace {
273
278
OPERAND_COLUMN_WIDTH = Self :: OPERAND_COLUMN_WIDTH ,
274
279
) ;
275
280
276
- self . trigger_trace_action ( & instruction_trace) ;
281
+ self . tracer . emit_instruction_trace ( & instruction_trace) ;
277
282
}
278
283
}
279
284
280
285
impl fmt:: Debug for VmTrace {
281
286
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
282
- let compiled_action_val = if self . compiled_action . is_none ( ) {
283
- "None"
284
- } else {
285
- "User Defined Fn"
286
- } ;
287
-
288
- let trace_action_val = if self . trace_action . is_none ( ) {
289
- "None"
290
- } else {
291
- "User Defined Fn"
292
- } ;
293
-
294
- f. debug_struct ( "VmTrace" )
295
- . field ( "Compiled Action" , & compiled_action_val)
296
- . field ( "Runtime Trace Action" , & trace_action_val)
297
- . finish ( )
287
+ write ! ( f, "Current Active Tracer" )
298
288
}
299
289
}
0 commit comments