|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifdef DEBUG |
|
8 |
|
9 #include "jit/IonSpewer.h" |
|
10 |
|
11 #include "jsworkers.h" |
|
12 |
|
13 #include "jit/Ion.h" |
|
14 |
|
15 #ifndef ION_SPEW_DIR |
|
16 # if defined(_WIN32) |
|
17 # define ION_SPEW_DIR "" |
|
18 # elif defined(__ANDROID__) |
|
19 # define ION_SPEW_DIR "/data/local/tmp/" |
|
20 # else |
|
21 # define ION_SPEW_DIR "/tmp/" |
|
22 # endif |
|
23 #endif |
|
24 |
|
25 using namespace js; |
|
26 using namespace js::jit; |
|
27 |
|
28 // IonSpewer singleton. |
|
29 static IonSpewer ionspewer; |
|
30 |
|
31 static bool LoggingChecked = false; |
|
32 static uint32_t LoggingBits = 0; |
|
33 static uint32_t filteredOutCompilations = 0; |
|
34 |
|
35 static const char * const ChannelNames[] = |
|
36 { |
|
37 #define IONSPEW_CHANNEL(name) #name, |
|
38 IONSPEW_CHANNEL_LIST(IONSPEW_CHANNEL) |
|
39 #undef IONSPEW_CHANNEL |
|
40 }; |
|
41 |
|
42 static bool |
|
43 FilterContainsLocation(HandleScript function) |
|
44 { |
|
45 static const char *filter = getenv("IONFILTER"); |
|
46 |
|
47 // If there is no filter we accept all outputs. |
|
48 if (!filter || !filter[0]) |
|
49 return true; |
|
50 |
|
51 // Disable asm.js output when filter is set. |
|
52 if (!function) |
|
53 return false; |
|
54 |
|
55 const char *filename = function->filename(); |
|
56 const size_t line = function->lineno(); |
|
57 const size_t filelen = strlen(filename); |
|
58 const char *index = strstr(filter, filename); |
|
59 while (index) { |
|
60 if (index == filter || index[-1] == ',') { |
|
61 if (index[filelen] == 0 || index[filelen] == ',') |
|
62 return true; |
|
63 if (index[filelen] == ':' && line != size_t(-1)) { |
|
64 size_t read_line = strtoul(&index[filelen + 1], nullptr, 10); |
|
65 if (read_line == line) |
|
66 return true; |
|
67 } |
|
68 } |
|
69 index = strstr(index + filelen, filename); |
|
70 } |
|
71 return false; |
|
72 } |
|
73 |
|
74 void |
|
75 jit::EnableIonDebugLogging() |
|
76 { |
|
77 EnableChannel(IonSpew_Logs); |
|
78 ionspewer.init(); |
|
79 } |
|
80 |
|
81 void |
|
82 jit::IonSpewNewFunction(MIRGraph *graph, HandleScript func) |
|
83 { |
|
84 if (GetIonContext()->runtime->onMainThread()) |
|
85 ionspewer.beginFunction(graph, func); |
|
86 } |
|
87 |
|
88 void |
|
89 jit::IonSpewPass(const char *pass) |
|
90 { |
|
91 if (GetIonContext()->runtime->onMainThread()) |
|
92 ionspewer.spewPass(pass); |
|
93 } |
|
94 |
|
95 void |
|
96 jit::IonSpewPass(const char *pass, LinearScanAllocator *ra) |
|
97 { |
|
98 if (GetIonContext()->runtime->onMainThread()) |
|
99 ionspewer.spewPass(pass, ra); |
|
100 } |
|
101 |
|
102 void |
|
103 jit::IonSpewEndFunction() |
|
104 { |
|
105 if (GetIonContext()->runtime->onMainThread()) |
|
106 ionspewer.endFunction(); |
|
107 } |
|
108 |
|
109 |
|
110 IonSpewer::~IonSpewer() |
|
111 { |
|
112 if (!inited_) |
|
113 return; |
|
114 |
|
115 c1Spewer.finish(); |
|
116 jsonSpewer.finish(); |
|
117 } |
|
118 |
|
119 bool |
|
120 IonSpewer::init() |
|
121 { |
|
122 if (inited_) |
|
123 return true; |
|
124 |
|
125 if (!c1Spewer.init(ION_SPEW_DIR "ion.cfg")) |
|
126 return false; |
|
127 if (!jsonSpewer.init(ION_SPEW_DIR "ion.json")) |
|
128 return false; |
|
129 |
|
130 inited_ = true; |
|
131 return true; |
|
132 } |
|
133 |
|
134 bool |
|
135 IonSpewer::isSpewingFunction() const |
|
136 { |
|
137 return inited_ && graph; |
|
138 } |
|
139 |
|
140 void |
|
141 IonSpewer::beginFunction(MIRGraph *graph, HandleScript function) |
|
142 { |
|
143 if (!inited_) |
|
144 return; |
|
145 |
|
146 if (!FilterContainsLocation(function)) { |
|
147 JS_ASSERT(!this->graph); |
|
148 // filter out logs during the compilation. |
|
149 filteredOutCompilations++; |
|
150 return; |
|
151 } |
|
152 |
|
153 this->graph = graph; |
|
154 this->function.repoint(function); |
|
155 |
|
156 c1Spewer.beginFunction(graph, function); |
|
157 jsonSpewer.beginFunction(function); |
|
158 } |
|
159 |
|
160 void |
|
161 IonSpewer::spewPass(const char *pass) |
|
162 { |
|
163 if (!isSpewingFunction()) |
|
164 return; |
|
165 |
|
166 c1Spewer.spewPass(pass); |
|
167 jsonSpewer.beginPass(pass); |
|
168 jsonSpewer.spewMIR(graph); |
|
169 jsonSpewer.spewLIR(graph); |
|
170 jsonSpewer.endPass(); |
|
171 } |
|
172 |
|
173 void |
|
174 IonSpewer::spewPass(const char *pass, LinearScanAllocator *ra) |
|
175 { |
|
176 if (!isSpewingFunction()) |
|
177 return; |
|
178 |
|
179 c1Spewer.spewPass(pass); |
|
180 c1Spewer.spewIntervals(pass, ra); |
|
181 jsonSpewer.beginPass(pass); |
|
182 jsonSpewer.spewMIR(graph); |
|
183 jsonSpewer.spewLIR(graph); |
|
184 jsonSpewer.spewIntervals(ra); |
|
185 jsonSpewer.endPass(); |
|
186 } |
|
187 |
|
188 void |
|
189 IonSpewer::endFunction() |
|
190 { |
|
191 if (!isSpewingFunction()) { |
|
192 if (inited_) { |
|
193 JS_ASSERT(filteredOutCompilations != 0); |
|
194 filteredOutCompilations--; |
|
195 } |
|
196 return; |
|
197 } |
|
198 |
|
199 c1Spewer.endFunction(); |
|
200 jsonSpewer.endFunction(); |
|
201 |
|
202 this->graph = nullptr; |
|
203 } |
|
204 |
|
205 |
|
206 FILE *jit::IonSpewFile = nullptr; |
|
207 |
|
208 static bool |
|
209 ContainsFlag(const char *str, const char *flag) |
|
210 { |
|
211 size_t flaglen = strlen(flag); |
|
212 const char *index = strstr(str, flag); |
|
213 while (index) { |
|
214 if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ',')) |
|
215 return true; |
|
216 index = strstr(index + flaglen, flag); |
|
217 } |
|
218 return false; |
|
219 } |
|
220 |
|
221 void |
|
222 jit::CheckLogging() |
|
223 { |
|
224 if (LoggingChecked) |
|
225 return; |
|
226 LoggingChecked = true; |
|
227 const char *env = getenv("IONFLAGS"); |
|
228 if (!env) |
|
229 return; |
|
230 if (strstr(env, "help")) { |
|
231 fflush(nullptr); |
|
232 printf( |
|
233 "\n" |
|
234 "usage: IONFLAGS=option,option,option,... where options can be:\n" |
|
235 "\n" |
|
236 " aborts Compilation abort messages\n" |
|
237 " scripts Compiled scripts\n" |
|
238 " mir MIR information\n" |
|
239 " alias Alias analysis\n" |
|
240 " gvn Global Value Numbering\n" |
|
241 " licm Loop invariant code motion\n" |
|
242 " regalloc Register allocation\n" |
|
243 " inline Inlining\n" |
|
244 " snapshots Snapshot information\n" |
|
245 " codegen Native code generation\n" |
|
246 " bailouts Bailouts\n" |
|
247 " caches Inline caches\n" |
|
248 " osi Invalidation\n" |
|
249 " safepoints Safepoints\n" |
|
250 " pools Literal Pools (ARM only for now)\n" |
|
251 " cacheflush Instruction Cache flushes (ARM only for now)\n" |
|
252 " range Range Analysis\n" |
|
253 " logs C1 and JSON visualization logging\n" |
|
254 " trace Generate calls to js::jit::Trace() for effectful instructions\n" |
|
255 " all Everything\n" |
|
256 "\n" |
|
257 " bl-aborts Baseline compiler abort messages\n" |
|
258 " bl-scripts Baseline script-compilation\n" |
|
259 " bl-op Baseline compiler detailed op-specific messages\n" |
|
260 " bl-ic Baseline inline-cache messages\n" |
|
261 " bl-ic-fb Baseline IC fallback stub messages\n" |
|
262 " bl-osr Baseline IC OSR messages\n" |
|
263 " bl-bails Baseline bailouts\n" |
|
264 " bl-dbg-osr Baseline debug mode on stack recompile messages\n" |
|
265 " bl-all All baseline spew\n" |
|
266 "\n" |
|
267 ); |
|
268 exit(0); |
|
269 /*NOTREACHED*/ |
|
270 } |
|
271 if (ContainsFlag(env, "aborts")) |
|
272 EnableChannel(IonSpew_Abort); |
|
273 if (ContainsFlag(env, "alias")) |
|
274 EnableChannel(IonSpew_Alias); |
|
275 if (ContainsFlag(env, "scripts")) |
|
276 EnableChannel(IonSpew_Scripts); |
|
277 if (ContainsFlag(env, "mir")) |
|
278 EnableChannel(IonSpew_MIR); |
|
279 if (ContainsFlag(env, "gvn")) |
|
280 EnableChannel(IonSpew_GVN); |
|
281 if (ContainsFlag(env, "range")) |
|
282 EnableChannel(IonSpew_Range); |
|
283 if (ContainsFlag(env, "licm")) |
|
284 EnableChannel(IonSpew_LICM); |
|
285 if (ContainsFlag(env, "regalloc")) |
|
286 EnableChannel(IonSpew_RegAlloc); |
|
287 if (ContainsFlag(env, "inline")) |
|
288 EnableChannel(IonSpew_Inlining); |
|
289 if (ContainsFlag(env, "snapshots")) |
|
290 EnableChannel(IonSpew_Snapshots); |
|
291 if (ContainsFlag(env, "codegen")) |
|
292 EnableChannel(IonSpew_Codegen); |
|
293 if (ContainsFlag(env, "bailouts")) |
|
294 EnableChannel(IonSpew_Bailouts); |
|
295 if (ContainsFlag(env, "osi")) |
|
296 EnableChannel(IonSpew_Invalidate); |
|
297 if (ContainsFlag(env, "caches")) |
|
298 EnableChannel(IonSpew_InlineCaches); |
|
299 if (ContainsFlag(env, "safepoints")) |
|
300 EnableChannel(IonSpew_Safepoints); |
|
301 if (ContainsFlag(env, "pools")) |
|
302 EnableChannel(IonSpew_Pools); |
|
303 if (ContainsFlag(env, "cacheflush")) |
|
304 EnableChannel(IonSpew_CacheFlush); |
|
305 if (ContainsFlag(env, "logs")) |
|
306 EnableIonDebugLogging(); |
|
307 if (ContainsFlag(env, "trace")) |
|
308 EnableChannel(IonSpew_Trace); |
|
309 if (ContainsFlag(env, "all")) |
|
310 LoggingBits = uint32_t(-1); |
|
311 |
|
312 if (ContainsFlag(env, "bl-aborts")) |
|
313 EnableChannel(IonSpew_BaselineAbort); |
|
314 if (ContainsFlag(env, "bl-scripts")) |
|
315 EnableChannel(IonSpew_BaselineScripts); |
|
316 if (ContainsFlag(env, "bl-op")) |
|
317 EnableChannel(IonSpew_BaselineOp); |
|
318 if (ContainsFlag(env, "bl-ic")) |
|
319 EnableChannel(IonSpew_BaselineIC); |
|
320 if (ContainsFlag(env, "bl-ic-fb")) |
|
321 EnableChannel(IonSpew_BaselineICFallback); |
|
322 if (ContainsFlag(env, "bl-osr")) |
|
323 EnableChannel(IonSpew_BaselineOSR); |
|
324 if (ContainsFlag(env, "bl-bails")) |
|
325 EnableChannel(IonSpew_BaselineBailouts); |
|
326 if (ContainsFlag(env, "bl-dbg-osr")) |
|
327 EnableChannel(IonSpew_BaselineDebugModeOSR); |
|
328 if (ContainsFlag(env, "bl-all")) { |
|
329 EnableChannel(IonSpew_BaselineAbort); |
|
330 EnableChannel(IonSpew_BaselineScripts); |
|
331 EnableChannel(IonSpew_BaselineOp); |
|
332 EnableChannel(IonSpew_BaselineIC); |
|
333 EnableChannel(IonSpew_BaselineICFallback); |
|
334 EnableChannel(IonSpew_BaselineOSR); |
|
335 EnableChannel(IonSpew_BaselineBailouts); |
|
336 EnableChannel(IonSpew_BaselineDebugModeOSR); |
|
337 } |
|
338 |
|
339 IonSpewFile = stderr; |
|
340 } |
|
341 |
|
342 void |
|
343 jit::IonSpewStartVA(IonSpewChannel channel, const char *fmt, va_list ap) |
|
344 { |
|
345 if (!IonSpewEnabled(channel)) |
|
346 return; |
|
347 |
|
348 IonSpewHeader(channel); |
|
349 vfprintf(stderr, fmt, ap); |
|
350 } |
|
351 |
|
352 void |
|
353 jit::IonSpewContVA(IonSpewChannel channel, const char *fmt, va_list ap) |
|
354 { |
|
355 if (!IonSpewEnabled(channel)) |
|
356 return; |
|
357 |
|
358 vfprintf(stderr, fmt, ap); |
|
359 } |
|
360 |
|
361 void |
|
362 jit::IonSpewFin(IonSpewChannel channel) |
|
363 { |
|
364 if (!IonSpewEnabled(channel)) |
|
365 return; |
|
366 |
|
367 fprintf(stderr, "\n"); |
|
368 } |
|
369 |
|
370 void |
|
371 jit::IonSpewVA(IonSpewChannel channel, const char *fmt, va_list ap) |
|
372 { |
|
373 IonSpewStartVA(channel, fmt, ap); |
|
374 IonSpewFin(channel); |
|
375 } |
|
376 |
|
377 void |
|
378 jit::IonSpew(IonSpewChannel channel, const char *fmt, ...) |
|
379 { |
|
380 va_list ap; |
|
381 va_start(ap, fmt); |
|
382 IonSpewVA(channel, fmt, ap); |
|
383 va_end(ap); |
|
384 } |
|
385 |
|
386 void |
|
387 jit::IonSpewStart(IonSpewChannel channel, const char *fmt, ...) |
|
388 { |
|
389 va_list ap; |
|
390 va_start(ap, fmt); |
|
391 IonSpewStartVA(channel, fmt, ap); |
|
392 va_end(ap); |
|
393 } |
|
394 void |
|
395 jit::IonSpewCont(IonSpewChannel channel, const char *fmt, ...) |
|
396 { |
|
397 va_list ap; |
|
398 va_start(ap, fmt); |
|
399 IonSpewContVA(channel, fmt, ap); |
|
400 va_end(ap); |
|
401 } |
|
402 |
|
403 void |
|
404 jit::IonSpewHeader(IonSpewChannel channel) |
|
405 { |
|
406 if (!IonSpewEnabled(channel)) |
|
407 return; |
|
408 |
|
409 fprintf(stderr, "[%s] ", ChannelNames[channel]); |
|
410 } |
|
411 |
|
412 bool |
|
413 jit::IonSpewEnabled(IonSpewChannel channel) |
|
414 { |
|
415 JS_ASSERT(LoggingChecked); |
|
416 return (LoggingBits & (1 << uint32_t(channel))) && !filteredOutCompilations; |
|
417 } |
|
418 |
|
419 void |
|
420 jit::EnableChannel(IonSpewChannel channel) |
|
421 { |
|
422 JS_ASSERT(LoggingChecked); |
|
423 LoggingBits |= (1 << uint32_t(channel)); |
|
424 } |
|
425 |
|
426 void |
|
427 jit::DisableChannel(IonSpewChannel channel) |
|
428 { |
|
429 JS_ASSERT(LoggingChecked); |
|
430 LoggingBits &= ~(1 << uint32_t(channel)); |
|
431 } |
|
432 |
|
433 #endif /* DEBUG */ |
|
434 |