1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/JSONSpewer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,480 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/JSONSpewer.h" 1.11 + 1.12 +#include <stdarg.h> 1.13 + 1.14 +#include "jit/LinearScan.h" 1.15 +#include "jit/LIR.h" 1.16 +#include "jit/MIR.h" 1.17 +#include "jit/MIRGraph.h" 1.18 +#include "jit/RangeAnalysis.h" 1.19 + 1.20 +using namespace js; 1.21 +using namespace js::jit; 1.22 + 1.23 +JSONSpewer::~JSONSpewer() 1.24 +{ 1.25 + if (fp_) 1.26 + fclose(fp_); 1.27 +} 1.28 + 1.29 +void 1.30 +JSONSpewer::indent() 1.31 +{ 1.32 + if (!fp_) 1.33 + return; 1.34 + JS_ASSERT(indentLevel_ >= 0); 1.35 + fprintf(fp_, "\n"); 1.36 + for (int i = 0; i < indentLevel_; i++) 1.37 + fprintf(fp_, " "); 1.38 +} 1.39 + 1.40 +void 1.41 +JSONSpewer::property(const char *name) 1.42 +{ 1.43 + if (!fp_) 1.44 + return; 1.45 + 1.46 + if (!first_) 1.47 + fprintf(fp_, ","); 1.48 + indent(); 1.49 + fprintf(fp_, "\"%s\":", name); 1.50 + first_ = false; 1.51 +} 1.52 + 1.53 +void 1.54 +JSONSpewer::beginObject() 1.55 +{ 1.56 + if (!fp_) 1.57 + return; 1.58 + 1.59 + if (!first_) { 1.60 + fprintf(fp_, ","); 1.61 + indent(); 1.62 + } 1.63 + fprintf(fp_, "{"); 1.64 + indentLevel_++; 1.65 + first_ = true; 1.66 +} 1.67 + 1.68 +void 1.69 +JSONSpewer::beginObjectProperty(const char *name) 1.70 +{ 1.71 + if (!fp_) 1.72 + return; 1.73 + 1.74 + property(name); 1.75 + fprintf(fp_, "{"); 1.76 + indentLevel_++; 1.77 + first_ = true; 1.78 +} 1.79 + 1.80 +void 1.81 +JSONSpewer::beginListProperty(const char *name) 1.82 +{ 1.83 + if (!fp_) 1.84 + return; 1.85 + 1.86 + property(name); 1.87 + fprintf(fp_, "["); 1.88 + first_ = true; 1.89 +} 1.90 + 1.91 +void 1.92 +JSONSpewer::stringProperty(const char *name, const char *format, ...) 1.93 +{ 1.94 + if (!fp_) 1.95 + return; 1.96 + 1.97 + va_list ap; 1.98 + va_start(ap, format); 1.99 + 1.100 + property(name); 1.101 + fprintf(fp_, "\""); 1.102 + vfprintf(fp_, format, ap); 1.103 + fprintf(fp_, "\""); 1.104 + 1.105 + va_end(ap); 1.106 +} 1.107 + 1.108 +void 1.109 +JSONSpewer::stringValue(const char *format, ...) 1.110 +{ 1.111 + if (!fp_) 1.112 + return; 1.113 + 1.114 + va_list ap; 1.115 + va_start(ap, format); 1.116 + 1.117 + if (!first_) 1.118 + fprintf(fp_, ","); 1.119 + fprintf(fp_, "\""); 1.120 + vfprintf(fp_, format, ap); 1.121 + fprintf(fp_, "\""); 1.122 + 1.123 + va_end(ap); 1.124 + first_ = false; 1.125 +} 1.126 + 1.127 +void 1.128 +JSONSpewer::integerProperty(const char *name, int value) 1.129 +{ 1.130 + if (!fp_) 1.131 + return; 1.132 + 1.133 + property(name); 1.134 + fprintf(fp_, "%d", value); 1.135 +} 1.136 + 1.137 +void 1.138 +JSONSpewer::integerValue(int value) 1.139 +{ 1.140 + if (!fp_) 1.141 + return; 1.142 + 1.143 + if (!first_) 1.144 + fprintf(fp_, ","); 1.145 + fprintf(fp_, "%d", value); 1.146 + first_ = false; 1.147 +} 1.148 + 1.149 +void 1.150 +JSONSpewer::endObject() 1.151 +{ 1.152 + if (!fp_) 1.153 + return; 1.154 + 1.155 + indentLevel_--; 1.156 + indent(); 1.157 + fprintf(fp_, "}"); 1.158 + first_ = false; 1.159 +} 1.160 + 1.161 +void 1.162 +JSONSpewer::endList() 1.163 +{ 1.164 + if (!fp_) 1.165 + return; 1.166 + 1.167 + fprintf(fp_, "]"); 1.168 + first_ = false; 1.169 +} 1.170 + 1.171 +bool 1.172 +JSONSpewer::init(const char *path) 1.173 +{ 1.174 + fp_ = fopen(path, "w"); 1.175 + if (!fp_) 1.176 + return false; 1.177 + 1.178 + beginObject(); 1.179 + beginListProperty("functions"); 1.180 + return true; 1.181 +} 1.182 + 1.183 +void 1.184 +JSONSpewer::beginFunction(JSScript *script) 1.185 +{ 1.186 + if (inFunction_) 1.187 + endFunction(); 1.188 + 1.189 + beginObject(); 1.190 + if (script) 1.191 + stringProperty("name", "%s:%d", script->filename(), script->lineno()); 1.192 + else 1.193 + stringProperty("name", "asm.js compilation"); 1.194 + beginListProperty("passes"); 1.195 + 1.196 + inFunction_ = true; 1.197 +} 1.198 + 1.199 +void 1.200 +JSONSpewer::beginPass(const char *pass) 1.201 +{ 1.202 + beginObject(); 1.203 + stringProperty("name", pass); 1.204 +} 1.205 + 1.206 +void 1.207 +JSONSpewer::spewMResumePoint(MResumePoint *rp) 1.208 +{ 1.209 + if (!rp) 1.210 + return; 1.211 + 1.212 + beginObjectProperty("resumePoint"); 1.213 + 1.214 + if (rp->caller()) 1.215 + integerProperty("caller", rp->caller()->block()->id()); 1.216 + 1.217 + property("mode"); 1.218 + switch (rp->mode()) { 1.219 + case MResumePoint::ResumeAt: 1.220 + fprintf(fp_, "\"At\""); 1.221 + break; 1.222 + case MResumePoint::ResumeAfter: 1.223 + fprintf(fp_, "\"After\""); 1.224 + break; 1.225 + case MResumePoint::Outer: 1.226 + fprintf(fp_, "\"Outer\""); 1.227 + break; 1.228 + } 1.229 + 1.230 + beginListProperty("operands"); 1.231 + for (MResumePoint *iter = rp; iter; iter = iter->caller()) { 1.232 + for (int i = iter->numOperands() - 1; i >= 0; i--) 1.233 + integerValue(iter->getOperand(i)->id()); 1.234 + } 1.235 + endList(); 1.236 + 1.237 + endObject(); 1.238 +} 1.239 + 1.240 +void 1.241 +JSONSpewer::spewMDef(MDefinition *def) 1.242 +{ 1.243 + beginObject(); 1.244 + 1.245 + integerProperty("id", def->id()); 1.246 + 1.247 + property("opcode"); 1.248 + fprintf(fp_, "\""); 1.249 + def->printOpcode(fp_); 1.250 + fprintf(fp_, "\""); 1.251 + 1.252 + beginListProperty("attributes"); 1.253 +#define OUTPUT_ATTRIBUTE(X) do{ if(def->is##X()) stringValue(#X); } while(0); 1.254 + MIR_FLAG_LIST(OUTPUT_ATTRIBUTE); 1.255 +#undef OUTPUT_ATTRIBUTE 1.256 + endList(); 1.257 + 1.258 + beginListProperty("inputs"); 1.259 + for (size_t i = 0, e = def->numOperands(); i < e; i++) 1.260 + integerValue(def->getOperand(i)->id()); 1.261 + endList(); 1.262 + 1.263 + beginListProperty("uses"); 1.264 + for (MUseDefIterator use(def); use; use++) 1.265 + integerValue(use.def()->id()); 1.266 + endList(); 1.267 + 1.268 + bool isTruncated = false; 1.269 + if (def->isAdd() || def->isSub() || def->isMod() || def->isMul() || def->isDiv()) 1.270 + isTruncated = static_cast<MBinaryArithInstruction*>(def)->isTruncated(); 1.271 + 1.272 + if (def->type() != MIRType_None && def->range()) { 1.273 + Sprinter sp(GetIonContext()->cx); 1.274 + sp.init(); 1.275 + def->range()->print(sp); 1.276 + stringProperty("type", "%s : %s%s", sp.string(), StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); 1.277 + } else { 1.278 + stringProperty("type", "%s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); 1.279 + } 1.280 + 1.281 + if (def->isInstruction()) { 1.282 + if (MResumePoint *rp = def->toInstruction()->resumePoint()) 1.283 + spewMResumePoint(rp); 1.284 + } 1.285 + 1.286 + endObject(); 1.287 +} 1.288 + 1.289 +void 1.290 +JSONSpewer::spewMIR(MIRGraph *mir) 1.291 +{ 1.292 + if (!fp_) 1.293 + return; 1.294 + 1.295 + beginObjectProperty("mir"); 1.296 + beginListProperty("blocks"); 1.297 + 1.298 + for (MBasicBlockIterator block(mir->begin()); block != mir->end(); block++) { 1.299 + beginObject(); 1.300 + 1.301 + integerProperty("number", block->id()); 1.302 + 1.303 + beginListProperty("attributes"); 1.304 + if (block->isLoopBackedge()) 1.305 + stringValue("backedge"); 1.306 + if (block->isLoopHeader()) 1.307 + stringValue("loopheader"); 1.308 + if (block->isSplitEdge()) 1.309 + stringValue("splitedge"); 1.310 + endList(); 1.311 + 1.312 + beginListProperty("predecessors"); 1.313 + for (size_t i = 0; i < block->numPredecessors(); i++) 1.314 + integerValue(block->getPredecessor(i)->id()); 1.315 + endList(); 1.316 + 1.317 + beginListProperty("successors"); 1.318 + for (size_t i = 0; i < block->numSuccessors(); i++) 1.319 + integerValue(block->getSuccessor(i)->id()); 1.320 + endList(); 1.321 + 1.322 + beginListProperty("instructions"); 1.323 + for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) 1.324 + spewMDef(*phi); 1.325 + for (MInstructionIterator i(block->begin()); i != block->end(); i++) 1.326 + spewMDef(*i); 1.327 + endList(); 1.328 + 1.329 + spewMResumePoint(block->entryResumePoint()); 1.330 + 1.331 + endObject(); 1.332 + } 1.333 + 1.334 + endList(); 1.335 + endObject(); 1.336 +} 1.337 + 1.338 +void 1.339 +JSONSpewer::spewLIns(LInstruction *ins) 1.340 +{ 1.341 + if (!fp_) 1.342 + return; 1.343 + 1.344 + beginObject(); 1.345 + 1.346 + integerProperty("id", ins->id()); 1.347 + 1.348 + property("opcode"); 1.349 + fprintf(fp_, "\""); 1.350 + ins->dump(fp_); 1.351 + fprintf(fp_, "\""); 1.352 + 1.353 + beginListProperty("defs"); 1.354 + for (size_t i = 0; i < ins->numDefs(); i++) 1.355 + integerValue(ins->getDef(i)->virtualRegister()); 1.356 + endList(); 1.357 + 1.358 + endObject(); 1.359 +} 1.360 + 1.361 +void 1.362 +JSONSpewer::spewLIR(MIRGraph *mir) 1.363 +{ 1.364 + if (!fp_) 1.365 + return; 1.366 + 1.367 + beginObjectProperty("lir"); 1.368 + beginListProperty("blocks"); 1.369 + 1.370 + for (MBasicBlockIterator i(mir->begin()); i != mir->end(); i++) { 1.371 + LBlock *block = i->lir(); 1.372 + if (!block) 1.373 + continue; 1.374 + 1.375 + beginObject(); 1.376 + integerProperty("number", i->id()); 1.377 + 1.378 + beginListProperty("instructions"); 1.379 + for (size_t p = 0; p < block->numPhis(); p++) 1.380 + spewLIns(block->getPhi(p)); 1.381 + for (LInstructionIterator ins(block->begin()); ins != block->end(); ins++) 1.382 + spewLIns(*ins); 1.383 + endList(); 1.384 + 1.385 + endObject(); 1.386 + } 1.387 + 1.388 + endList(); 1.389 + endObject(); 1.390 +} 1.391 + 1.392 +void 1.393 +JSONSpewer::spewIntervals(LinearScanAllocator *regalloc) 1.394 +{ 1.395 + if (!fp_) 1.396 + return; 1.397 + 1.398 + beginObjectProperty("intervals"); 1.399 + beginListProperty("blocks"); 1.400 + 1.401 + for (size_t bno = 0; bno < regalloc->graph.numBlocks(); bno++) { 1.402 + beginObject(); 1.403 + integerProperty("number", bno); 1.404 + beginListProperty("vregs"); 1.405 + 1.406 + LBlock *lir = regalloc->graph.getBlock(bno); 1.407 + for (LInstructionIterator ins = lir->begin(); ins != lir->end(); ins++) { 1.408 + for (size_t k = 0; k < ins->numDefs(); k++) { 1.409 + uint32_t id = ins->getDef(k)->virtualRegister(); 1.410 + VirtualRegister *vreg = ®alloc->vregs[id]; 1.411 + 1.412 + beginObject(); 1.413 + integerProperty("vreg", id); 1.414 + beginListProperty("intervals"); 1.415 + 1.416 + for (size_t i = 0; i < vreg->numIntervals(); i++) { 1.417 + LiveInterval *live = vreg->getInterval(i); 1.418 + 1.419 + if (live->numRanges()) { 1.420 + beginObject(); 1.421 + property("allocation"); 1.422 + fprintf(fp_, "\"%s\"", live->getAllocation()->toString()); 1.423 + beginListProperty("ranges"); 1.424 + 1.425 + for (size_t j = 0; j < live->numRanges(); j++) { 1.426 + beginObject(); 1.427 + integerProperty("start", live->getRange(j)->from.pos()); 1.428 + integerProperty("end", live->getRange(j)->to.pos()); 1.429 + endObject(); 1.430 + } 1.431 + 1.432 + endList(); 1.433 + endObject(); 1.434 + } 1.435 + } 1.436 + 1.437 + endList(); 1.438 + endObject(); 1.439 + } 1.440 + } 1.441 + 1.442 + endList(); 1.443 + endObject(); 1.444 + } 1.445 + 1.446 + endList(); 1.447 + endObject(); 1.448 +} 1.449 + 1.450 +void 1.451 +JSONSpewer::endPass() 1.452 +{ 1.453 + endObject(); 1.454 + fflush(fp_); 1.455 +} 1.456 + 1.457 +void 1.458 +JSONSpewer::endFunction() 1.459 +{ 1.460 + JS_ASSERT(inFunction_); 1.461 + endList(); 1.462 + endObject(); 1.463 + fflush(fp_); 1.464 + inFunction_ = false; 1.465 +} 1.466 + 1.467 +void 1.468 +JSONSpewer::finish() 1.469 +{ 1.470 + if (!fp_) 1.471 + return; 1.472 + 1.473 + if (inFunction_) 1.474 + endFunction(); 1.475 + 1.476 + endList(); 1.477 + endObject(); 1.478 + fprintf(fp_, "\n"); 1.479 + 1.480 + fclose(fp_); 1.481 + fp_ = nullptr; 1.482 +} 1.483 +