|
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 #include "jit/JSONSpewer.h" |
|
8 |
|
9 #include <stdarg.h> |
|
10 |
|
11 #include "jit/LinearScan.h" |
|
12 #include "jit/LIR.h" |
|
13 #include "jit/MIR.h" |
|
14 #include "jit/MIRGraph.h" |
|
15 #include "jit/RangeAnalysis.h" |
|
16 |
|
17 using namespace js; |
|
18 using namespace js::jit; |
|
19 |
|
20 JSONSpewer::~JSONSpewer() |
|
21 { |
|
22 if (fp_) |
|
23 fclose(fp_); |
|
24 } |
|
25 |
|
26 void |
|
27 JSONSpewer::indent() |
|
28 { |
|
29 if (!fp_) |
|
30 return; |
|
31 JS_ASSERT(indentLevel_ >= 0); |
|
32 fprintf(fp_, "\n"); |
|
33 for (int i = 0; i < indentLevel_; i++) |
|
34 fprintf(fp_, " "); |
|
35 } |
|
36 |
|
37 void |
|
38 JSONSpewer::property(const char *name) |
|
39 { |
|
40 if (!fp_) |
|
41 return; |
|
42 |
|
43 if (!first_) |
|
44 fprintf(fp_, ","); |
|
45 indent(); |
|
46 fprintf(fp_, "\"%s\":", name); |
|
47 first_ = false; |
|
48 } |
|
49 |
|
50 void |
|
51 JSONSpewer::beginObject() |
|
52 { |
|
53 if (!fp_) |
|
54 return; |
|
55 |
|
56 if (!first_) { |
|
57 fprintf(fp_, ","); |
|
58 indent(); |
|
59 } |
|
60 fprintf(fp_, "{"); |
|
61 indentLevel_++; |
|
62 first_ = true; |
|
63 } |
|
64 |
|
65 void |
|
66 JSONSpewer::beginObjectProperty(const char *name) |
|
67 { |
|
68 if (!fp_) |
|
69 return; |
|
70 |
|
71 property(name); |
|
72 fprintf(fp_, "{"); |
|
73 indentLevel_++; |
|
74 first_ = true; |
|
75 } |
|
76 |
|
77 void |
|
78 JSONSpewer::beginListProperty(const char *name) |
|
79 { |
|
80 if (!fp_) |
|
81 return; |
|
82 |
|
83 property(name); |
|
84 fprintf(fp_, "["); |
|
85 first_ = true; |
|
86 } |
|
87 |
|
88 void |
|
89 JSONSpewer::stringProperty(const char *name, const char *format, ...) |
|
90 { |
|
91 if (!fp_) |
|
92 return; |
|
93 |
|
94 va_list ap; |
|
95 va_start(ap, format); |
|
96 |
|
97 property(name); |
|
98 fprintf(fp_, "\""); |
|
99 vfprintf(fp_, format, ap); |
|
100 fprintf(fp_, "\""); |
|
101 |
|
102 va_end(ap); |
|
103 } |
|
104 |
|
105 void |
|
106 JSONSpewer::stringValue(const char *format, ...) |
|
107 { |
|
108 if (!fp_) |
|
109 return; |
|
110 |
|
111 va_list ap; |
|
112 va_start(ap, format); |
|
113 |
|
114 if (!first_) |
|
115 fprintf(fp_, ","); |
|
116 fprintf(fp_, "\""); |
|
117 vfprintf(fp_, format, ap); |
|
118 fprintf(fp_, "\""); |
|
119 |
|
120 va_end(ap); |
|
121 first_ = false; |
|
122 } |
|
123 |
|
124 void |
|
125 JSONSpewer::integerProperty(const char *name, int value) |
|
126 { |
|
127 if (!fp_) |
|
128 return; |
|
129 |
|
130 property(name); |
|
131 fprintf(fp_, "%d", value); |
|
132 } |
|
133 |
|
134 void |
|
135 JSONSpewer::integerValue(int value) |
|
136 { |
|
137 if (!fp_) |
|
138 return; |
|
139 |
|
140 if (!first_) |
|
141 fprintf(fp_, ","); |
|
142 fprintf(fp_, "%d", value); |
|
143 first_ = false; |
|
144 } |
|
145 |
|
146 void |
|
147 JSONSpewer::endObject() |
|
148 { |
|
149 if (!fp_) |
|
150 return; |
|
151 |
|
152 indentLevel_--; |
|
153 indent(); |
|
154 fprintf(fp_, "}"); |
|
155 first_ = false; |
|
156 } |
|
157 |
|
158 void |
|
159 JSONSpewer::endList() |
|
160 { |
|
161 if (!fp_) |
|
162 return; |
|
163 |
|
164 fprintf(fp_, "]"); |
|
165 first_ = false; |
|
166 } |
|
167 |
|
168 bool |
|
169 JSONSpewer::init(const char *path) |
|
170 { |
|
171 fp_ = fopen(path, "w"); |
|
172 if (!fp_) |
|
173 return false; |
|
174 |
|
175 beginObject(); |
|
176 beginListProperty("functions"); |
|
177 return true; |
|
178 } |
|
179 |
|
180 void |
|
181 JSONSpewer::beginFunction(JSScript *script) |
|
182 { |
|
183 if (inFunction_) |
|
184 endFunction(); |
|
185 |
|
186 beginObject(); |
|
187 if (script) |
|
188 stringProperty("name", "%s:%d", script->filename(), script->lineno()); |
|
189 else |
|
190 stringProperty("name", "asm.js compilation"); |
|
191 beginListProperty("passes"); |
|
192 |
|
193 inFunction_ = true; |
|
194 } |
|
195 |
|
196 void |
|
197 JSONSpewer::beginPass(const char *pass) |
|
198 { |
|
199 beginObject(); |
|
200 stringProperty("name", pass); |
|
201 } |
|
202 |
|
203 void |
|
204 JSONSpewer::spewMResumePoint(MResumePoint *rp) |
|
205 { |
|
206 if (!rp) |
|
207 return; |
|
208 |
|
209 beginObjectProperty("resumePoint"); |
|
210 |
|
211 if (rp->caller()) |
|
212 integerProperty("caller", rp->caller()->block()->id()); |
|
213 |
|
214 property("mode"); |
|
215 switch (rp->mode()) { |
|
216 case MResumePoint::ResumeAt: |
|
217 fprintf(fp_, "\"At\""); |
|
218 break; |
|
219 case MResumePoint::ResumeAfter: |
|
220 fprintf(fp_, "\"After\""); |
|
221 break; |
|
222 case MResumePoint::Outer: |
|
223 fprintf(fp_, "\"Outer\""); |
|
224 break; |
|
225 } |
|
226 |
|
227 beginListProperty("operands"); |
|
228 for (MResumePoint *iter = rp; iter; iter = iter->caller()) { |
|
229 for (int i = iter->numOperands() - 1; i >= 0; i--) |
|
230 integerValue(iter->getOperand(i)->id()); |
|
231 } |
|
232 endList(); |
|
233 |
|
234 endObject(); |
|
235 } |
|
236 |
|
237 void |
|
238 JSONSpewer::spewMDef(MDefinition *def) |
|
239 { |
|
240 beginObject(); |
|
241 |
|
242 integerProperty("id", def->id()); |
|
243 |
|
244 property("opcode"); |
|
245 fprintf(fp_, "\""); |
|
246 def->printOpcode(fp_); |
|
247 fprintf(fp_, "\""); |
|
248 |
|
249 beginListProperty("attributes"); |
|
250 #define OUTPUT_ATTRIBUTE(X) do{ if(def->is##X()) stringValue(#X); } while(0); |
|
251 MIR_FLAG_LIST(OUTPUT_ATTRIBUTE); |
|
252 #undef OUTPUT_ATTRIBUTE |
|
253 endList(); |
|
254 |
|
255 beginListProperty("inputs"); |
|
256 for (size_t i = 0, e = def->numOperands(); i < e; i++) |
|
257 integerValue(def->getOperand(i)->id()); |
|
258 endList(); |
|
259 |
|
260 beginListProperty("uses"); |
|
261 for (MUseDefIterator use(def); use; use++) |
|
262 integerValue(use.def()->id()); |
|
263 endList(); |
|
264 |
|
265 bool isTruncated = false; |
|
266 if (def->isAdd() || def->isSub() || def->isMod() || def->isMul() || def->isDiv()) |
|
267 isTruncated = static_cast<MBinaryArithInstruction*>(def)->isTruncated(); |
|
268 |
|
269 if (def->type() != MIRType_None && def->range()) { |
|
270 Sprinter sp(GetIonContext()->cx); |
|
271 sp.init(); |
|
272 def->range()->print(sp); |
|
273 stringProperty("type", "%s : %s%s", sp.string(), StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); |
|
274 } else { |
|
275 stringProperty("type", "%s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); |
|
276 } |
|
277 |
|
278 if (def->isInstruction()) { |
|
279 if (MResumePoint *rp = def->toInstruction()->resumePoint()) |
|
280 spewMResumePoint(rp); |
|
281 } |
|
282 |
|
283 endObject(); |
|
284 } |
|
285 |
|
286 void |
|
287 JSONSpewer::spewMIR(MIRGraph *mir) |
|
288 { |
|
289 if (!fp_) |
|
290 return; |
|
291 |
|
292 beginObjectProperty("mir"); |
|
293 beginListProperty("blocks"); |
|
294 |
|
295 for (MBasicBlockIterator block(mir->begin()); block != mir->end(); block++) { |
|
296 beginObject(); |
|
297 |
|
298 integerProperty("number", block->id()); |
|
299 |
|
300 beginListProperty("attributes"); |
|
301 if (block->isLoopBackedge()) |
|
302 stringValue("backedge"); |
|
303 if (block->isLoopHeader()) |
|
304 stringValue("loopheader"); |
|
305 if (block->isSplitEdge()) |
|
306 stringValue("splitedge"); |
|
307 endList(); |
|
308 |
|
309 beginListProperty("predecessors"); |
|
310 for (size_t i = 0; i < block->numPredecessors(); i++) |
|
311 integerValue(block->getPredecessor(i)->id()); |
|
312 endList(); |
|
313 |
|
314 beginListProperty("successors"); |
|
315 for (size_t i = 0; i < block->numSuccessors(); i++) |
|
316 integerValue(block->getSuccessor(i)->id()); |
|
317 endList(); |
|
318 |
|
319 beginListProperty("instructions"); |
|
320 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) |
|
321 spewMDef(*phi); |
|
322 for (MInstructionIterator i(block->begin()); i != block->end(); i++) |
|
323 spewMDef(*i); |
|
324 endList(); |
|
325 |
|
326 spewMResumePoint(block->entryResumePoint()); |
|
327 |
|
328 endObject(); |
|
329 } |
|
330 |
|
331 endList(); |
|
332 endObject(); |
|
333 } |
|
334 |
|
335 void |
|
336 JSONSpewer::spewLIns(LInstruction *ins) |
|
337 { |
|
338 if (!fp_) |
|
339 return; |
|
340 |
|
341 beginObject(); |
|
342 |
|
343 integerProperty("id", ins->id()); |
|
344 |
|
345 property("opcode"); |
|
346 fprintf(fp_, "\""); |
|
347 ins->dump(fp_); |
|
348 fprintf(fp_, "\""); |
|
349 |
|
350 beginListProperty("defs"); |
|
351 for (size_t i = 0; i < ins->numDefs(); i++) |
|
352 integerValue(ins->getDef(i)->virtualRegister()); |
|
353 endList(); |
|
354 |
|
355 endObject(); |
|
356 } |
|
357 |
|
358 void |
|
359 JSONSpewer::spewLIR(MIRGraph *mir) |
|
360 { |
|
361 if (!fp_) |
|
362 return; |
|
363 |
|
364 beginObjectProperty("lir"); |
|
365 beginListProperty("blocks"); |
|
366 |
|
367 for (MBasicBlockIterator i(mir->begin()); i != mir->end(); i++) { |
|
368 LBlock *block = i->lir(); |
|
369 if (!block) |
|
370 continue; |
|
371 |
|
372 beginObject(); |
|
373 integerProperty("number", i->id()); |
|
374 |
|
375 beginListProperty("instructions"); |
|
376 for (size_t p = 0; p < block->numPhis(); p++) |
|
377 spewLIns(block->getPhi(p)); |
|
378 for (LInstructionIterator ins(block->begin()); ins != block->end(); ins++) |
|
379 spewLIns(*ins); |
|
380 endList(); |
|
381 |
|
382 endObject(); |
|
383 } |
|
384 |
|
385 endList(); |
|
386 endObject(); |
|
387 } |
|
388 |
|
389 void |
|
390 JSONSpewer::spewIntervals(LinearScanAllocator *regalloc) |
|
391 { |
|
392 if (!fp_) |
|
393 return; |
|
394 |
|
395 beginObjectProperty("intervals"); |
|
396 beginListProperty("blocks"); |
|
397 |
|
398 for (size_t bno = 0; bno < regalloc->graph.numBlocks(); bno++) { |
|
399 beginObject(); |
|
400 integerProperty("number", bno); |
|
401 beginListProperty("vregs"); |
|
402 |
|
403 LBlock *lir = regalloc->graph.getBlock(bno); |
|
404 for (LInstructionIterator ins = lir->begin(); ins != lir->end(); ins++) { |
|
405 for (size_t k = 0; k < ins->numDefs(); k++) { |
|
406 uint32_t id = ins->getDef(k)->virtualRegister(); |
|
407 VirtualRegister *vreg = ®alloc->vregs[id]; |
|
408 |
|
409 beginObject(); |
|
410 integerProperty("vreg", id); |
|
411 beginListProperty("intervals"); |
|
412 |
|
413 for (size_t i = 0; i < vreg->numIntervals(); i++) { |
|
414 LiveInterval *live = vreg->getInterval(i); |
|
415 |
|
416 if (live->numRanges()) { |
|
417 beginObject(); |
|
418 property("allocation"); |
|
419 fprintf(fp_, "\"%s\"", live->getAllocation()->toString()); |
|
420 beginListProperty("ranges"); |
|
421 |
|
422 for (size_t j = 0; j < live->numRanges(); j++) { |
|
423 beginObject(); |
|
424 integerProperty("start", live->getRange(j)->from.pos()); |
|
425 integerProperty("end", live->getRange(j)->to.pos()); |
|
426 endObject(); |
|
427 } |
|
428 |
|
429 endList(); |
|
430 endObject(); |
|
431 } |
|
432 } |
|
433 |
|
434 endList(); |
|
435 endObject(); |
|
436 } |
|
437 } |
|
438 |
|
439 endList(); |
|
440 endObject(); |
|
441 } |
|
442 |
|
443 endList(); |
|
444 endObject(); |
|
445 } |
|
446 |
|
447 void |
|
448 JSONSpewer::endPass() |
|
449 { |
|
450 endObject(); |
|
451 fflush(fp_); |
|
452 } |
|
453 |
|
454 void |
|
455 JSONSpewer::endFunction() |
|
456 { |
|
457 JS_ASSERT(inFunction_); |
|
458 endList(); |
|
459 endObject(); |
|
460 fflush(fp_); |
|
461 inFunction_ = false; |
|
462 } |
|
463 |
|
464 void |
|
465 JSONSpewer::finish() |
|
466 { |
|
467 if (!fp_) |
|
468 return; |
|
469 |
|
470 if (inFunction_) |
|
471 endFunction(); |
|
472 |
|
473 endList(); |
|
474 endObject(); |
|
475 fprintf(fp_, "\n"); |
|
476 |
|
477 fclose(fp_); |
|
478 fp_ = nullptr; |
|
479 } |
|
480 |