michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/JSONSpewer.h" michael@0: michael@0: #include michael@0: michael@0: #include "jit/LinearScan.h" michael@0: #include "jit/LIR.h" michael@0: #include "jit/MIR.h" michael@0: #include "jit/MIRGraph.h" michael@0: #include "jit/RangeAnalysis.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: JSONSpewer::~JSONSpewer() michael@0: { michael@0: if (fp_) michael@0: fclose(fp_); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::indent() michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: JS_ASSERT(indentLevel_ >= 0); michael@0: fprintf(fp_, "\n"); michael@0: for (int i = 0; i < indentLevel_; i++) michael@0: fprintf(fp_, " "); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::property(const char *name) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: if (!first_) michael@0: fprintf(fp_, ","); michael@0: indent(); michael@0: fprintf(fp_, "\"%s\":", name); michael@0: first_ = false; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::beginObject() michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: if (!first_) { michael@0: fprintf(fp_, ","); michael@0: indent(); michael@0: } michael@0: fprintf(fp_, "{"); michael@0: indentLevel_++; michael@0: first_ = true; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::beginObjectProperty(const char *name) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: property(name); michael@0: fprintf(fp_, "{"); michael@0: indentLevel_++; michael@0: first_ = true; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::beginListProperty(const char *name) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: property(name); michael@0: fprintf(fp_, "["); michael@0: first_ = true; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::stringProperty(const char *name, const char *format, ...) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: va_list ap; michael@0: va_start(ap, format); michael@0: michael@0: property(name); michael@0: fprintf(fp_, "\""); michael@0: vfprintf(fp_, format, ap); michael@0: fprintf(fp_, "\""); michael@0: michael@0: va_end(ap); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::stringValue(const char *format, ...) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: va_list ap; michael@0: va_start(ap, format); michael@0: michael@0: if (!first_) michael@0: fprintf(fp_, ","); michael@0: fprintf(fp_, "\""); michael@0: vfprintf(fp_, format, ap); michael@0: fprintf(fp_, "\""); michael@0: michael@0: va_end(ap); michael@0: first_ = false; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::integerProperty(const char *name, int value) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: property(name); michael@0: fprintf(fp_, "%d", value); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::integerValue(int value) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: if (!first_) michael@0: fprintf(fp_, ","); michael@0: fprintf(fp_, "%d", value); michael@0: first_ = false; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::endObject() michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: indentLevel_--; michael@0: indent(); michael@0: fprintf(fp_, "}"); michael@0: first_ = false; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::endList() michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: fprintf(fp_, "]"); michael@0: first_ = false; michael@0: } michael@0: michael@0: bool michael@0: JSONSpewer::init(const char *path) michael@0: { michael@0: fp_ = fopen(path, "w"); michael@0: if (!fp_) michael@0: return false; michael@0: michael@0: beginObject(); michael@0: beginListProperty("functions"); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::beginFunction(JSScript *script) michael@0: { michael@0: if (inFunction_) michael@0: endFunction(); michael@0: michael@0: beginObject(); michael@0: if (script) michael@0: stringProperty("name", "%s:%d", script->filename(), script->lineno()); michael@0: else michael@0: stringProperty("name", "asm.js compilation"); michael@0: beginListProperty("passes"); michael@0: michael@0: inFunction_ = true; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::beginPass(const char *pass) michael@0: { michael@0: beginObject(); michael@0: stringProperty("name", pass); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewMResumePoint(MResumePoint *rp) michael@0: { michael@0: if (!rp) michael@0: return; michael@0: michael@0: beginObjectProperty("resumePoint"); michael@0: michael@0: if (rp->caller()) michael@0: integerProperty("caller", rp->caller()->block()->id()); michael@0: michael@0: property("mode"); michael@0: switch (rp->mode()) { michael@0: case MResumePoint::ResumeAt: michael@0: fprintf(fp_, "\"At\""); michael@0: break; michael@0: case MResumePoint::ResumeAfter: michael@0: fprintf(fp_, "\"After\""); michael@0: break; michael@0: case MResumePoint::Outer: michael@0: fprintf(fp_, "\"Outer\""); michael@0: break; michael@0: } michael@0: michael@0: beginListProperty("operands"); michael@0: for (MResumePoint *iter = rp; iter; iter = iter->caller()) { michael@0: for (int i = iter->numOperands() - 1; i >= 0; i--) michael@0: integerValue(iter->getOperand(i)->id()); michael@0: } michael@0: endList(); michael@0: michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewMDef(MDefinition *def) michael@0: { michael@0: beginObject(); michael@0: michael@0: integerProperty("id", def->id()); michael@0: michael@0: property("opcode"); michael@0: fprintf(fp_, "\""); michael@0: def->printOpcode(fp_); michael@0: fprintf(fp_, "\""); michael@0: michael@0: beginListProperty("attributes"); michael@0: #define OUTPUT_ATTRIBUTE(X) do{ if(def->is##X()) stringValue(#X); } while(0); michael@0: MIR_FLAG_LIST(OUTPUT_ATTRIBUTE); michael@0: #undef OUTPUT_ATTRIBUTE michael@0: endList(); michael@0: michael@0: beginListProperty("inputs"); michael@0: for (size_t i = 0, e = def->numOperands(); i < e; i++) michael@0: integerValue(def->getOperand(i)->id()); michael@0: endList(); michael@0: michael@0: beginListProperty("uses"); michael@0: for (MUseDefIterator use(def); use; use++) michael@0: integerValue(use.def()->id()); michael@0: endList(); michael@0: michael@0: bool isTruncated = false; michael@0: if (def->isAdd() || def->isSub() || def->isMod() || def->isMul() || def->isDiv()) michael@0: isTruncated = static_cast(def)->isTruncated(); michael@0: michael@0: if (def->type() != MIRType_None && def->range()) { michael@0: Sprinter sp(GetIonContext()->cx); michael@0: sp.init(); michael@0: def->range()->print(sp); michael@0: stringProperty("type", "%s : %s%s", sp.string(), StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); michael@0: } else { michael@0: stringProperty("type", "%s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); michael@0: } michael@0: michael@0: if (def->isInstruction()) { michael@0: if (MResumePoint *rp = def->toInstruction()->resumePoint()) michael@0: spewMResumePoint(rp); michael@0: } michael@0: michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewMIR(MIRGraph *mir) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: beginObjectProperty("mir"); michael@0: beginListProperty("blocks"); michael@0: michael@0: for (MBasicBlockIterator block(mir->begin()); block != mir->end(); block++) { michael@0: beginObject(); michael@0: michael@0: integerProperty("number", block->id()); michael@0: michael@0: beginListProperty("attributes"); michael@0: if (block->isLoopBackedge()) michael@0: stringValue("backedge"); michael@0: if (block->isLoopHeader()) michael@0: stringValue("loopheader"); michael@0: if (block->isSplitEdge()) michael@0: stringValue("splitedge"); michael@0: endList(); michael@0: michael@0: beginListProperty("predecessors"); michael@0: for (size_t i = 0; i < block->numPredecessors(); i++) michael@0: integerValue(block->getPredecessor(i)->id()); michael@0: endList(); michael@0: michael@0: beginListProperty("successors"); michael@0: for (size_t i = 0; i < block->numSuccessors(); i++) michael@0: integerValue(block->getSuccessor(i)->id()); michael@0: endList(); michael@0: michael@0: beginListProperty("instructions"); michael@0: for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) michael@0: spewMDef(*phi); michael@0: for (MInstructionIterator i(block->begin()); i != block->end(); i++) michael@0: spewMDef(*i); michael@0: endList(); michael@0: michael@0: spewMResumePoint(block->entryResumePoint()); michael@0: michael@0: endObject(); michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewLIns(LInstruction *ins) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: beginObject(); michael@0: michael@0: integerProperty("id", ins->id()); michael@0: michael@0: property("opcode"); michael@0: fprintf(fp_, "\""); michael@0: ins->dump(fp_); michael@0: fprintf(fp_, "\""); michael@0: michael@0: beginListProperty("defs"); michael@0: for (size_t i = 0; i < ins->numDefs(); i++) michael@0: integerValue(ins->getDef(i)->virtualRegister()); michael@0: endList(); michael@0: michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewLIR(MIRGraph *mir) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: beginObjectProperty("lir"); michael@0: beginListProperty("blocks"); michael@0: michael@0: for (MBasicBlockIterator i(mir->begin()); i != mir->end(); i++) { michael@0: LBlock *block = i->lir(); michael@0: if (!block) michael@0: continue; michael@0: michael@0: beginObject(); michael@0: integerProperty("number", i->id()); michael@0: michael@0: beginListProperty("instructions"); michael@0: for (size_t p = 0; p < block->numPhis(); p++) michael@0: spewLIns(block->getPhi(p)); michael@0: for (LInstructionIterator ins(block->begin()); ins != block->end(); ins++) michael@0: spewLIns(*ins); michael@0: endList(); michael@0: michael@0: endObject(); michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::spewIntervals(LinearScanAllocator *regalloc) michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: beginObjectProperty("intervals"); michael@0: beginListProperty("blocks"); michael@0: michael@0: for (size_t bno = 0; bno < regalloc->graph.numBlocks(); bno++) { michael@0: beginObject(); michael@0: integerProperty("number", bno); michael@0: beginListProperty("vregs"); michael@0: michael@0: LBlock *lir = regalloc->graph.getBlock(bno); michael@0: for (LInstructionIterator ins = lir->begin(); ins != lir->end(); ins++) { michael@0: for (size_t k = 0; k < ins->numDefs(); k++) { michael@0: uint32_t id = ins->getDef(k)->virtualRegister(); michael@0: VirtualRegister *vreg = ®alloc->vregs[id]; michael@0: michael@0: beginObject(); michael@0: integerProperty("vreg", id); michael@0: beginListProperty("intervals"); michael@0: michael@0: for (size_t i = 0; i < vreg->numIntervals(); i++) { michael@0: LiveInterval *live = vreg->getInterval(i); michael@0: michael@0: if (live->numRanges()) { michael@0: beginObject(); michael@0: property("allocation"); michael@0: fprintf(fp_, "\"%s\"", live->getAllocation()->toString()); michael@0: beginListProperty("ranges"); michael@0: michael@0: for (size_t j = 0; j < live->numRanges(); j++) { michael@0: beginObject(); michael@0: integerProperty("start", live->getRange(j)->from.pos()); michael@0: integerProperty("end", live->getRange(j)->to.pos()); michael@0: endObject(); michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: michael@0: endList(); michael@0: endObject(); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::endPass() michael@0: { michael@0: endObject(); michael@0: fflush(fp_); michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::endFunction() michael@0: { michael@0: JS_ASSERT(inFunction_); michael@0: endList(); michael@0: endObject(); michael@0: fflush(fp_); michael@0: inFunction_ = false; michael@0: } michael@0: michael@0: void michael@0: JSONSpewer::finish() michael@0: { michael@0: if (!fp_) michael@0: return; michael@0: michael@0: if (inFunction_) michael@0: endFunction(); michael@0: michael@0: endList(); michael@0: endObject(); michael@0: fprintf(fp_, "\n"); michael@0: michael@0: fclose(fp_); michael@0: fp_ = nullptr; michael@0: } michael@0: