From 4decbb024c854ddc3dadc8c41b024b50bc1dbce0 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 15 May 2015 15:28:48 -0400 Subject: [PATCH] Backed out 8 changesets (bug 1147403) for debug asserts on a CLOSED TREE. Backed out changeset a1018d31e591 (bug 1147403) Backed out changeset fdb1dcf35e04 (bug 1147403) Backed out changeset 66ab1f789052 (bug 1147403) Backed out changeset 8ee01e148887 (bug 1147403) Backed out changeset 615c601284e3 (bug 1147403) Backed out changeset d7a4b4c31c94 (bug 1147403) Backed out changeset b1abceaf0f6e (bug 1147403) Backed out changeset 443b1a2a084f (bug 1147403) --- js/src/asmjs/AsmJSValidate.cpp | 9 +- js/src/builtin/TestingFunctions.cpp | 27 +- js/src/doc/Debugger/Debugger.md | 39 -- js/src/doc/Debugger/config.sh | 1 - .../tests/debug/Debugger-onIonCompilation.js | 121 ---- js/src/jit/AliasAnalysis.cpp | 27 +- js/src/jit/C1Spewer.cpp | 179 ++--- js/src/jit/C1Spewer.h | 17 +- js/src/jit/Ion.cpp | 196 ++---- js/src/jit/IonAnalysis.cpp | 29 +- js/src/jit/IonAnalysis.h | 3 +- js/src/jit/IonBuilder.h | 1 + js/src/jit/JSONSpewer.cpp | 170 +++-- js/src/jit/JSONSpewer.h | 21 +- js/src/jit/JitSpewer.cpp | 312 +++------ js/src/jit/JitSpewer.h | 96 +-- js/src/jit/LIR-Common.h | 2 +- js/src/jit/LIR.cpp | 97 ++- js/src/jit/LIR.h | 12 +- js/src/jit/Lowering.cpp | 21 +- js/src/jit/MCallOptimize.cpp | 11 + js/src/jit/MIR.cpp | 242 +++---- js/src/jit/MIR.h | 50 +- js/src/jit/MIRGenerator.h | 8 - js/src/jit/MIRGraph.cpp | 76 +-- js/src/jit/MIRGraph.h | 7 +- js/src/jit/RangeAnalysis.cpp | 96 +-- js/src/jit/RangeAnalysis.h | 5 +- js/src/jit/Safepoints.cpp | 14 +- js/src/jit/Snapshots.cpp | 48 +- js/src/jit/Snapshots.h | 6 +- js/src/jsopcode.cpp | 334 ++++++++++ js/src/jsopcode.h | 93 ++- js/src/jsscript.h | 1 + js/src/jsstr.cpp | 21 +- js/src/jsstr.h | 28 +- js/src/moz.build | 1 - js/src/vm/Debugger-inl.h | 23 - js/src/vm/Debugger.cpp | 243 +++---- js/src/vm/Debugger.h | 22 +- js/src/vm/HelperThreads.cpp | 1 - js/src/vm/Printer.cpp | 609 ------------------ js/src/vm/Printer.h | 223 ------- 43 files changed, 1324 insertions(+), 2218 deletions(-) delete mode 100644 js/src/jit-test/tests/debug/Debugger-onIonCompilation.js delete mode 100644 js/src/vm/Printer.cpp delete mode 100644 js/src/vm/Printer.h diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 6c73bc0c7424..8e75a73bee44 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -7692,8 +7692,6 @@ CheckFunction(ModuleCompiler& m, LifoAlloc& lifo, MIRGenerator** mir, ModuleComp *mir = f.extractMIR(); (*mir)->initMinAsmJSHeapLength(m.minHeapLength()); - jit::SpewBeginFunction(*mir, nullptr); - *funcOut = func; return true; } @@ -7770,7 +7768,8 @@ CheckFunctionsSequential(ModuleCompiler& m) int64_t before = PRMJ_Now(); JitContext jcx(m.cx(), &mir->alloc()); - jit::AutoSpewEndFunction spewEndFunction(mir); + + IonSpewNewFunction(&mir->graph(), NullPtr()); if (!OptimizeMIR(mir)) return m.failOffset(func->srcBegin(), "internal compiler failure (probably out of memory)"); @@ -7783,6 +7782,8 @@ CheckFunctionsSequential(ModuleCompiler& m) if (!GenerateCode(m, *func, *mir, *lir)) return false; + + IonSpewEndFunction(); } if (!CheckAllFunctionsDefined(m)) @@ -8021,7 +8022,7 @@ CheckFunctions(ModuleCompiler& m) if (!ParallelCompilationEnabled(m.cx()) || !g.claim()) return CheckFunctionsSequential(m); - JitSpew(JitSpew_IonSyncLogs, "Can't log asm.js script. (Compiled on background thread.)"); + JitSpew(JitSpew_IonLogs, "Can't log asm.js script. (Compiled on background thread.)"); // Saturate all helper threads. size_t numParallelJobs = HelperThreadState().maxAsmJSCompilationThreads(); diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 1dd28b3b1eb9..63358a9a4e65 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -30,7 +30,6 @@ #include "vm/Interpreter.h" #include "vm/ProxyObject.h" #include "vm/SavedStacks.h" -#include "vm/Stack.h" #include "vm/TraceLogging.h" #include "jscntxtinlines.h" @@ -1546,26 +1545,18 @@ js::testingFunc_inIon(JSContext* cx, unsigned argc, jsval* vp) return true; } - ScriptFrameIter iter(cx); - if (iter.isIon()) { - // Reset the counter of the IonScript's script. - JitFrameIterator jitIter(cx); - ++jitIter; - jitIter.script()->resetWarmUpResetCounter(); - } else { - // Check if we missed multiple attempts at compiling the innermost script. - JSScript* script = cx->currentScript(); - if (script && script->getWarmUpResetCount() >= 20) { - JSString* error = JS_NewStringCopyZ(cx, "Compilation is being repeatedly prevented. Giving up."); - if (!error) - return false; + JSScript* script = cx->currentScript(); + if (script && script->getWarmUpResetCount() >= 20) { + JSString* error = JS_NewStringCopyZ(cx, "Compilation is being repeatedly prevented. Giving up."); + if (!error) + return false; - args.rval().setString(error); - return true; - } + args.rval().setString(error); + return true; } - args.rval().setBoolean(iter.isIon()); + // false when not in ionMonkey + args.rval().setBoolean(false); return true; } diff --git a/js/src/doc/Debugger/Debugger.md b/js/src/doc/Debugger/Debugger.md index 42bc4746ad72..bcac1a395043 100644 --- a/js/src/doc/Debugger/Debugger.md +++ b/js/src/doc/Debugger/Debugger.md @@ -225,45 +225,6 @@ compartment. thereby escaping the capability-based limits. For this reason, `onNewGlobalObject` is only available to privileged code. -onIonCompilation(graph) -: A new IonMonkey compilation result is attached to a script instance of - the Debuggee, the graph contains the internal intermediate - representations of the compiler. - - The value graph is an object composed of the following properties: - - `json` - : String containing a JSON of the intermediate representation used by - the compiler. This JSON string content is composed of 2 intermediate - representation of the graph, a `mir` (Middle-level IR), and a - `lir` (Low-level IR). - - Both have a property `blocks`, which is an array of basic - blocks in [SSA form][ssa-form] which are used to construct the - control flow graph. All elements of these arrays are objects which - have a `number`, and an `instructions` properties. - - The MIR blocks have additional properties such as the - `predecessors` and `successors` of each block, which can - be used to reconstruct the control flow graph, with the - `number` properties of the blocks. - - The `instructions` properties are array of objects which have - an `id` and an `opcode`. The `id` corresponds to the - [SSA form][ssa-form] identifier (number) of each instruction, and the - `opcode` is a string which represents the instruction. - - This JSON string contains even more detailed internal information - which remains undocummented, as it is potentially subject to - frequent modifications. - - `scripts` - : Array of [`Debugger.Script`][script] instances. For a block at - `mir.blocks[i]` or `lir.blocks[i]` in the JSON, `scripts[i]` is the - [`Debugger.Script`][script] containing that block's code. - - This method's return value is ignored. - ## Function Properties of the Debugger Prototype Object diff --git a/js/src/doc/Debugger/config.sh b/js/src/doc/Debugger/config.sh index 077f69cc535d..a15fa87e0bcf 100644 --- a/js/src/doc/Debugger/config.sh +++ b/js/src/doc/Debugger/config.sh @@ -64,4 +64,3 @@ resource 'img-alloc-plot' alloc-plot-console.png $RBASE/8461 absolute-label 'protocol' https://wiki.mozilla.org/Remote_Debugging_Protocol "Remote Debugging Protocol" absolute-label 'saved-frame' https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/SavedFrame "SavedFrame" absolute-label 'bernoulli-trial' https://en.wikipedia.org/wiki/Bernoulli_trial "Bernoulli Trial" -absolute-label 'ssa-form' https://en.wikipedia.org/wiki/Static_single_assignment_form "SSA form" diff --git a/js/src/jit-test/tests/debug/Debugger-onIonCompilation.js b/js/src/jit-test/tests/debug/Debugger-onIonCompilation.js deleted file mode 100644 index 5d91481e58a2..000000000000 --- a/js/src/jit-test/tests/debug/Debugger-onIonCompilation.js +++ /dev/null @@ -1,121 +0,0 @@ - -function test() { - // Force Ion compilation with OSR. - for (var res = false; !res; res = inIon()) {}; - if (typeof res == "string") - throw "Skipping test: Ion compilation is disabled/prevented."; -}; - - -// Functions used to assert the representation of the graph which is exported in -// the JSON string argument. -function assertInstruction(ins) { - assertEq(typeof ins.id, "number"); - assertEq(ins.id | 0, ins.id); - assertEq(typeof ins.opcode, "string"); -} - -function assertBlock(block) { - assertEq(typeof block, "object"); - assertEq(typeof block.number, "number"); - assertEq(block.number | 0, block.number); - assertEq(typeof block.instructions, "object"); - for (var ins of block.instructions) - assertInstruction(ins); -} - -function assertGraph(graph, scripts) { - assertEq(typeof graph, "object"); - assertEq(typeof graph.blocks, "object"); - assertEq(graph.blocks.length, scripts.length); - for (var block of graph.blocks) - assertBlock(block); -} - -function assertJSON(str, scripts) { - assertEq(typeof str, "string"); - - var json = JSON.parse(str); - assertGraph(json.mir, scripts); - assertGraph(json.lir, scripts); -} - -function assertOnIonCompilationArgument(obj) { - assertEq(typeof obj, "object"); - assertEq(typeof obj.scripts, "object"); - assertJSON(obj.json, obj.scripts); -} - -// Attach the current global to a debugger. -var hits = 0; -var g = newGlobal(); -g.parent = this; -g.eval(` - var dbg = new Debugger(); - var parentw = dbg.addDebuggee(parent); - var testw = parentw.makeDebuggeeValue(parent.test); - var scriptw = testw.script; -`); - -// Wrap the testing function. -function check(assert) { - // print('reset compilation counter.'); - with ({}) { // Prevent Ion compilation. - gc(); // Flush previous compilation. - hits = 0; // Synchronized hit counts. - - try { // Skip this test if we cannot reliably compile with Ion. - test(); // Wait until the next Ion compilation. - } catch (msg) { - if (typeof msg == "string") { - // print(msg); - return; - } - } - - assert(); // Run the assertions given as arguments. - } -} - -// With the compilation graph inhibited, we should have no output. -g.eval(` - dbg.onIonCompilation = function (graph) { - // print('Compiled ' + graph.scripts[0].displayName + ':' + graph.scripts[0].startLine); - if (graph.scripts[0] !== scriptw) - return; - parent.assertOnIonCompilationArgument(graph); - parent.hits++; - }; -`); - -check(function () { - // '>= 1' is needed because --ion-eager is too eager. - assertEq(hits >= 1, true); -}); - - -// Try re-entering the same compartment as the compiled script. -g.dbg.onIonCompilation = function (graph) { - // print('Compiled ' + graph.scripts[0].displayName + ':' + graph.scripts[0].startLine); - if (graph.scripts[0] !== g.scriptw) - return; - assertOnIonCompilationArgument(graph); - hits++; -}; -check(function () { assertEq(hits >= 1, true); }); - -// Disable the debugger, and redo the last 2 tests. -g.eval(` - dbg.enabled = false; - dbg.onIonCompilation = function (graph) { - parent.hits++; - }; -`); -check(function () { assertEq(hits, 0); }); - - -g.dbg.enabled = false; -g.dbg.onIonCompilation = function (graph) { - hits++; -}; -check(function () { assertEq(hits, 0); }); diff --git a/js/src/jit/AliasAnalysis.cpp b/js/src/jit/AliasAnalysis.cpp index 1484ac5ada78..72cb99da03fe 100644 --- a/js/src/jit/AliasAnalysis.cpp +++ b/js/src/jit/AliasAnalysis.cpp @@ -14,8 +14,6 @@ #include "jit/MIR.h" #include "jit/MIRGraph.h" -#include "vm/Printer.h" - using namespace js; using namespace js::jit; @@ -130,12 +128,11 @@ IonSpewDependency(MInstruction* load, MInstruction* store, const char* verb, con if (!JitSpewEnabled(JitSpew_Alias)) return; - Fprinter& out = JitSpewPrinter(); - out.printf("Load "); - load->printName(out); - out.printf(" %s on store ", verb); - store->printName(out); - out.printf(" (%s)\n", reason); + fprintf(JitSpewFile, "Load "); + load->printName(JitSpewFile); + fprintf(JitSpewFile, " %s on store ", verb); + store->printName(JitSpewFile); + fprintf(JitSpewFile, " (%s)\n", reason); } static void @@ -144,10 +141,9 @@ IonSpewAliasInfo(const char* pre, MInstruction* ins, const char* post) if (!JitSpewEnabled(JitSpew_Alias)) return; - Fprinter& out = JitSpewPrinter(); - out.printf("%s ", pre); - ins->printName(out); - out.printf(" %s\n", post); + fprintf(JitSpewFile, "%s ", pre); + ins->printName(JitSpewFile); + fprintf(JitSpewFile, " %s\n", post); } // This pass annotates every load instruction with the last store instruction @@ -212,10 +208,9 @@ AliasAnalysis::analyze() } if (JitSpewEnabled(JitSpew_Alias)) { - Fprinter& out = JitSpewPrinter(); - out.printf("Processing store "); - def->printName(out); - out.printf(" (flags %x)\n", set.flags()); + fprintf(JitSpewFile, "Processing store "); + def->printName(JitSpewFile); + fprintf(JitSpewFile, " (flags %x)\n", set.flags()); } } else { // Find the most recent store on which this instruction depends. diff --git a/js/src/jit/C1Spewer.cpp b/js/src/jit/C1Spewer.cpp index c8b4a769dbef..8a6d9807c6e9 100644 --- a/js/src/jit/C1Spewer.cpp +++ b/js/src/jit/C1Spewer.cpp @@ -16,51 +16,67 @@ #include "jit/LIR.h" #include "jit/MIRGraph.h" -#include "vm/Printer.h" - using namespace js; using namespace js::jit; -void -C1Spewer::beginFunction(MIRGraph* graph, JSScript* script) +bool +C1Spewer::init(const char* path) { + spewout_ = fopen(path, "w"); + return spewout_ != nullptr; +} + +void +C1Spewer::beginFunction(MIRGraph* graph, HandleScript script) +{ + if (!spewout_) + return; + this->graph = graph; - out_.printf("begin_compilation\n"); + fprintf(spewout_, "begin_compilation\n"); if (script) { - out_.printf(" name \"%s:%" PRIuSIZE "\"\n", script->filename(), script->lineno()); - out_.printf(" method \"%s:%" PRIuSIZE "\"\n", script->filename(), script->lineno()); + fprintf(spewout_, " name \"%s:%" PRIuSIZE "\"\n", script->filename(), script->lineno()); + fprintf(spewout_, " method \"%s:%" PRIuSIZE "\"\n", script->filename(), script->lineno()); } else { - out_.printf(" name \"asm.js compilation\"\n"); - out_.printf(" method \"asm.js compilation\"\n"); + fprintf(spewout_, " name \"asm.js compilation\"\n"); + fprintf(spewout_, " method \"asm.js compilation\"\n"); } - out_.printf(" date %d\n", (int)time(nullptr)); - out_.printf("end_compilation\n"); + fprintf(spewout_, " date %d\n", (int)time(nullptr)); + fprintf(spewout_, "end_compilation\n"); } void C1Spewer::spewPass(const char* pass) { - out_.printf("begin_cfg\n"); - out_.printf(" name \"%s\"\n", pass); + if (!spewout_) + return; + + fprintf(spewout_, "begin_cfg\n"); + fprintf(spewout_, " name \"%s\"\n", pass); for (MBasicBlockIterator block(graph->begin()); block != graph->end(); block++) - spewPass(out_, *block); + spewPass(spewout_, *block); - out_.printf("end_cfg\n"); + fprintf(spewout_, "end_cfg\n"); + fflush(spewout_); } void C1Spewer::spewIntervals(const char* pass, BacktrackingAllocator* regalloc) { - out_.printf("begin_intervals\n"); - out_.printf(" name \"%s\"\n", pass); + if (!spewout_) + return; + + fprintf(spewout_, "begin_intervals\n"); + fprintf(spewout_, " name \"%s\"\n", pass); size_t nextId = 0x4000; for (MBasicBlockIterator block(graph->begin()); block != graph->end(); block++) - spewIntervals(out_, *block, regalloc, nextId); + spewIntervals(spewout_, *block, regalloc, nextId); - out_.printf("end_intervals\n"); + fprintf(spewout_, "end_intervals\n"); + fflush(spewout_); } void @@ -68,28 +84,35 @@ C1Spewer::endFunction() { } -static void -DumpDefinition(GenericPrinter& out, MDefinition* def) +void +C1Spewer::finish() { - out.printf(" "); - out.printf("%u %u ", def->id(), unsigned(def->useCount())); - def->printName(out); - out.printf(" "); - def->printOpcode(out); - out.printf(" <|@\n"); + if (spewout_) + fclose(spewout_); } static void -DumpLIR(GenericPrinter& out, LNode* ins) +DumpDefinition(FILE* fp, MDefinition* def) { - out.printf(" "); - out.printf("%d ", ins->id()); - ins->dump(out); - out.printf(" <|@\n"); + fprintf(fp, " "); + fprintf(fp, "%u %u ", def->id(), unsigned(def->useCount())); + def->printName(fp); + fprintf(fp, " "); + def->printOpcode(fp); + fprintf(fp, " <|@\n"); +} + +static void +DumpLIR(FILE* fp, LNode* ins) +{ + fprintf(fp, " "); + fprintf(fp, "%d ", ins->id()); + ins->dump(fp); + fprintf(fp, " <|@\n"); } void -C1Spewer::spewIntervals(GenericPrinter& out, BacktrackingAllocator* regalloc, LNode* ins, size_t& nextId) +C1Spewer::spewIntervals(FILE* fp, BacktrackingAllocator* regalloc, LNode* ins, size_t& nextId) { for (size_t k = 0; k < ins->numDefs(); k++) { uint32_t id = ins->getDef(k)->virtualRegister(); @@ -98,102 +121,102 @@ C1Spewer::spewIntervals(GenericPrinter& out, BacktrackingAllocator* regalloc, LN for (size_t i = 0; i < vreg->numIntervals(); i++) { LiveInterval* live = vreg->getInterval(i); if (live->numRanges()) { - out.printf("%d object \"", (i == 0) ? id : int32_t(nextId++)); - out.printf("%s", live->getAllocation()->toString()); - out.printf("\" %d -1", id); + fprintf(fp, "%d object \"", (i == 0) ? id : int32_t(nextId++)); + fprintf(fp, "%s", live->getAllocation()->toString()); + fprintf(fp, "\" %d -1", id); for (size_t j = 0; j < live->numRanges(); j++) { - out.printf(" [%u, %u[", live->getRange(j)->from.bits(), - live->getRange(j)->to.bits()); + fprintf(fp, " [%u, %u[", live->getRange(j)->from.bits(), + live->getRange(j)->to.bits()); } for (UsePositionIterator usePos(live->usesBegin()); usePos != live->usesEnd(); usePos++) - out.printf(" %u M", usePos->pos.bits()); - out.printf(" \"\"\n"); + fprintf(fp, " %u M", usePos->pos.bits()); + fprintf(fp, " \"\"\n"); } } } } void -C1Spewer::spewIntervals(GenericPrinter& out, MBasicBlock* block, BacktrackingAllocator* regalloc, size_t& nextId) +C1Spewer::spewIntervals(FILE* fp, MBasicBlock* block, BacktrackingAllocator* regalloc, size_t& nextId) { LBlock* lir = block->lir(); if (!lir) return; for (size_t i = 0; i < lir->numPhis(); i++) - spewIntervals(out, regalloc, lir->getPhi(i), nextId); + spewIntervals(fp, regalloc, lir->getPhi(i), nextId); for (LInstructionIterator ins = lir->begin(); ins != lir->end(); ins++) - spewIntervals(out, regalloc, *ins, nextId); + spewIntervals(fp, regalloc, *ins, nextId); } void -C1Spewer::spewPass(GenericPrinter& out, MBasicBlock* block) +C1Spewer::spewPass(FILE* fp, MBasicBlock* block) { - out.printf(" begin_block\n"); - out.printf(" name \"B%d\"\n", block->id()); - out.printf(" from_bci -1\n"); - out.printf(" to_bci -1\n"); + fprintf(fp, " begin_block\n"); + fprintf(fp, " name \"B%d\"\n", block->id()); + fprintf(fp, " from_bci -1\n"); + fprintf(fp, " to_bci -1\n"); - out.printf(" predecessors"); + fprintf(fp, " predecessors"); for (uint32_t i = 0; i < block->numPredecessors(); i++) { MBasicBlock* pred = block->getPredecessor(i); - out.printf(" \"B%d\"", pred->id()); + fprintf(fp, " \"B%d\"", pred->id()); } - out.printf("\n"); + fprintf(fp, "\n"); - out.printf(" successors"); + fprintf(fp, " successors"); for (uint32_t i = 0; i < block->numSuccessors(); i++) { MBasicBlock* successor = block->getSuccessor(i); - out.printf(" \"B%d\"", successor->id()); + fprintf(fp, " \"B%d\"", successor->id()); } - out.printf("\n"); + fprintf(fp, "\n"); - out.printf(" xhandlers\n"); - out.printf(" flags\n"); + fprintf(fp, " xhandlers\n"); + fprintf(fp, " flags\n"); if (block->lir() && block->lir()->begin() != block->lir()->end()) { - out.printf(" first_lir_id %d\n", block->lir()->firstId()); - out.printf(" last_lir_id %d\n", block->lir()->lastId()); + fprintf(fp, " first_lir_id %d\n", block->lir()->firstId()); + fprintf(fp, " last_lir_id %d\n", block->lir()->lastId()); } - out.printf(" begin_states\n"); + fprintf(fp, " begin_states\n"); if (block->entryResumePoint()) { - out.printf(" begin_locals\n"); - out.printf(" size %d\n", (int)block->numEntrySlots()); - out.printf(" method \"None\"\n"); + fprintf(fp, " begin_locals\n"); + fprintf(fp, " size %d\n", (int)block->numEntrySlots()); + fprintf(fp, " method \"None\"\n"); for (uint32_t i = 0; i < block->numEntrySlots(); i++) { MDefinition* ins = block->getEntrySlot(i); - out.printf(" "); - out.printf("%d ", i); + fprintf(fp, " "); + fprintf(fp, "%d ", i); if (ins->isUnused()) - out.printf("unused"); + fprintf(fp, "unused"); else - ins->printName(out); - out.printf("\n"); + ins->printName(fp); + fprintf(fp, "\n"); } - out.printf(" end_locals\n"); + fprintf(fp, " end_locals\n"); } - out.printf(" end_states\n"); + fprintf(fp, " end_states\n"); - out.printf(" begin_HIR\n"); + fprintf(fp, " begin_HIR\n"); for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) - DumpDefinition(out, *phi); + DumpDefinition(fp, *phi); for (MInstructionIterator i(block->begin()); i != block->end(); i++) - DumpDefinition(out, *i); - out.printf(" end_HIR\n"); + DumpDefinition(fp, *i); + fprintf(fp, " end_HIR\n"); if (block->lir()) { - out.printf(" begin_LIR\n"); + fprintf(fp, " begin_LIR\n"); for (size_t i = 0; i < block->lir()->numPhis(); i++) - DumpLIR(out, block->lir()->getPhi(i)); + DumpLIR(fp, block->lir()->getPhi(i)); for (LInstructionIterator i(block->lir()->begin()); i != block->lir()->end(); i++) - DumpLIR(out, *i); - out.printf(" end_LIR\n"); + DumpLIR(fp, *i); + fprintf(fp, " end_LIR\n"); } - out.printf(" end_block\n"); + fprintf(fp, " end_block\n"); } #endif /* DEBUG */ diff --git a/js/src/jit/C1Spewer.h b/js/src/jit/C1Spewer.h index 1f93827e3450..9caa6f11b62a 100644 --- a/js/src/jit/C1Spewer.h +++ b/js/src/jit/C1Spewer.h @@ -12,7 +12,6 @@ #include "NamespaceImports.h" #include "js/RootingAPI.h" -#include "vm/Printer.h" namespace js { namespace jit { @@ -25,22 +24,24 @@ class LNode; class C1Spewer { MIRGraph* graph; - GenericPrinter& out_; + FILE* spewout_; public: - explicit C1Spewer(GenericPrinter& out) - : graph(nullptr), out_(out) + C1Spewer() + : graph(nullptr), spewout_(nullptr) { } - void beginFunction(MIRGraph* graph, JSScript* script); + bool init(const char* path); + void beginFunction(MIRGraph* graph, HandleScript script); void spewPass(const char* pass); void spewIntervals(const char* pass, BacktrackingAllocator* regalloc); void endFunction(); + void finish(); private: - void spewPass(GenericPrinter& out, MBasicBlock* block); - void spewIntervals(GenericPrinter& out, BacktrackingAllocator* regalloc, LNode* ins, size_t& nextId); - void spewIntervals(GenericPrinter& out, MBasicBlock* block, BacktrackingAllocator* regalloc, size_t& nextId); + void spewPass(FILE* fp, MBasicBlock* block); + void spewIntervals(FILE* fp, BacktrackingAllocator* regalloc, LNode* ins, size_t& nextId); + void spewIntervals(FILE* fp, MBasicBlock* block, BacktrackingAllocator* regalloc, size_t& nextId); }; } // namespace jit diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 35ecd6376435..9007343e1f73 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -41,13 +41,11 @@ #include "jit/Sink.h" #include "jit/StupidAllocator.h" #include "jit/ValueNumbering.h" -#include "vm/Debugger.h" #include "vm/HelperThreads.h" #include "vm/TraceLogging.h" #include "jscompartmentinlines.h" #include "jsobjinlines.h" -#include "vm/Debugger-inl.h" using namespace js; using namespace js::jit; @@ -394,49 +392,6 @@ JitCompartment::ensureIonStubsExist(JSContext* cx) return true; } -// This function initializes the values which are given to the Debugger -// onIonCompilation hook, if the compilation was successful, and if Ion -// compilations of this compartment are watched by any debugger. -// -// This function must be called in the same AutoEnterAnalysis section as the -// CodeGenerator::link. Failing to do so might leave room to interleave other -// allocations which can invalidate any JSObject / JSFunction referenced by the -// MIRGraph. -// -// This function ignores any allocation failure and returns whether the -// Debugger::onIonCompilation should be called. -static inline bool -PrepareForDebuggerOnIonCompilationHook(JSContext* cx, bool success, jit::MIRGraph& graph, - AutoScriptVector* scripts, LSprinter* spew) -{ - if (!success) - return false; - - if (!Debugger::observesIonCompilation(cx)) - return false; - - // fireOnIonCompilation failures are ignored, do the same here. - if (!scripts->reserve(graph.numBlocks())) { - cx->clearPendingException(); - return false; - } - - // Collect the list of scripts which are inlined in the MIRGraph. - for (jit::MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) - scripts->infallibleAppend(block->info().script()); - - // Spew the JSON graph made for the Debugger at the end of the LifoAlloc - // used by the compiler. This would not prevent unexpected GC from the - // compartment of the Debuggee, but do them as part of the compartment of - // the Debugger when the content is copied over to a JSString. - jit::JSONSpewer spewer(*spew); - spewer.spewDebuggerGraph(&graph); - if (spew->hadOutOfMemory()) - return false; - - return true; -} - void jit::FinishOffThreadBuilder(JSContext* cx, IonBuilder* builder) { @@ -517,47 +472,33 @@ jit::LazyLinkTopActivation(JSContext* cx) IonBuilder* builder = calleeScript->ionScript()->pendingBuilder(); calleeScript->setPendingIonBuilder(cx, nullptr); + AutoEnterAnalysis enterTypes(cx); RootedScript script(cx, builder->script()); - // See PrepareForDebuggerOnIonCompilationHook - bool callOnIonCompilation = false; - AutoScriptVector debugScripts(cx); - LSprinter debugPrinter(builder->alloc().lifoAlloc()); - // Remove from pending. builder->remove(); - CodeGenerator* codegen = builder->backgroundCodegen(); - bool success = false; - if (codegen) { - JitContext jctx(cx, &builder->alloc()); - AutoEnterAnalysis enterTypes(cx); + if (CodeGenerator* codegen = builder->backgroundCodegen()) { js::TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script); AutoTraceLog logScript(logger, event); AutoTraceLog logLink(logger, TraceLogger_IonLinking); + JitContext jctx(cx, &builder->alloc()); + // Root the assembler until the builder is finished below. As it // was constructed off thread, the assembler has not been rooted // previously, though any GC activity would discard the builder. codegen->masm.constructRoot(cx); - success = codegen->link(cx, builder->constraints()); - if (!success) { + if (!codegen->link(cx, builder->constraints())) { // Silently ignore OOM during code generation. The assembly code // doesn't has code to handle it after linking happened. So it's // not OK to throw a catchable exception from there. cx->clearPendingException(); } - - callOnIonCompilation = PrepareForDebuggerOnIonCompilationHook( - cx, success, builder->graph(), &debugScripts, &debugPrinter); } - // Without AutoEnterAnalysis scope. - if (callOnIonCompilation) - Debugger::onIonCompilation(cx, debugScripts, debugPrinter); - FinishOffThreadBuilder(cx, builder); MOZ_ASSERT(script->hasBaselineScript()); @@ -1232,7 +1173,6 @@ bool OptimizeMIR(MIRGenerator* mir) { MIRGraph& graph = mir->graph(); - GraphSpewer& gs = mir->graphSpewer(); TraceLoggerThread* logger; if (GetJitContext()->runtime->onMainThread()) logger = TraceLoggerForMainThread(GetJitContext()->runtime); @@ -1244,7 +1184,7 @@ OptimizeMIR(MIRGenerator* mir) return false; } - gs.spewPass("BuildSSA"); + IonSpewPass("BuildSSA"); AssertBasicGraphCoherency(graph); if (mir->shouldCancel("Start")) @@ -1253,7 +1193,7 @@ OptimizeMIR(MIRGenerator* mir) if (!mir->compilingAsmJS()) { AutoTraceLog log(logger, TraceLogger_FoldTests); FoldTests(graph); - gs.spewPass("Fold Tests"); + IonSpewPass("Fold Tests"); AssertBasicGraphCoherency(graph); if (mir->shouldCancel("Fold Tests")) @@ -1264,7 +1204,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_SplitCriticalEdges); if (!SplitCriticalEdges(graph)) return false; - gs.spewPass("Split Critical Edges"); + IonSpewPass("Split Critical Edges"); AssertGraphCoherency(graph); if (mir->shouldCancel("Split Critical Edges")) @@ -1275,7 +1215,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_RenumberBlocks); if (!RenumberBlocks(graph)) return false; - gs.spewPass("Renumber Blocks"); + IonSpewPass("Renumber Blocks"); AssertGraphCoherency(graph); if (mir->shouldCancel("Renumber Blocks")) @@ -1303,7 +1243,7 @@ OptimizeMIR(MIRGenerator* mir) : AggressiveObservability; if (!EliminatePhis(mir, graph, observability)) return false; - gs.spewPass("Eliminate phis"); + IonSpewPass("Eliminate phis"); AssertGraphCoherency(graph); if (mir->shouldCancel("Eliminate phis")) @@ -1322,7 +1262,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_ScalarReplacement); if (!ScalarReplacement(mir, graph)) return false; - gs.spewPass("Scalar Replacement"); + IonSpewPass("Scalar Replacement"); AssertGraphCoherency(graph); if (mir->shouldCancel("Scalar Replacement")) @@ -1333,7 +1273,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_ApplyTypes); if (!ApplyTypeInformation(mir, graph)) return false; - gs.spewPass("Apply types"); + IonSpewPass("Apply types"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Apply types")) @@ -1344,7 +1284,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_EagerSimdUnbox); if (!EagerSimdUnbox(mir, graph)) return false; - gs.spewPass("Eager Simd Unbox"); + IonSpewPass("Eager Simd Unbox"); AssertGraphCoherency(graph); if (mir->shouldCancel("Eager Simd Unbox")) @@ -1356,7 +1296,7 @@ OptimizeMIR(MIRGenerator* mir) AlignmentMaskAnalysis ama(graph); if (!ama.analyze()) return false; - gs.spewPass("Alignment Mask Analysis"); + IonSpewPass("Alignment Mask Analysis"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Alignment Mask Analysis")) @@ -1376,7 +1316,7 @@ OptimizeMIR(MIRGenerator* mir) AliasAnalysis analysis(mir, graph); if (!analysis.analyze()) return false; - gs.spewPass("Alias analysis"); + IonSpewPass("Alias analysis"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Alias analysis")) @@ -1398,7 +1338,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_GVN); if (!gvn.run(ValueNumberer::UpdateAliasAnalysis)) return false; - gs.spewPass("GVN"); + IonSpewPass("GVN"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("GVN")) @@ -1414,7 +1354,7 @@ OptimizeMIR(MIRGenerator* mir) if (!script || !script->hadFrequentBailouts()) { if (!LICM(mir, graph)) return false; - gs.spewPass("LICM"); + IonSpewPass("LICM"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("LICM")) @@ -1427,7 +1367,7 @@ OptimizeMIR(MIRGenerator* mir) RangeAnalysis r(mir, graph); if (!r.addBetaNodes()) return false; - gs.spewPass("Beta"); + IonSpewPass("Beta"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("RA Beta")) @@ -1435,7 +1375,7 @@ OptimizeMIR(MIRGenerator* mir) if (!r.analyze() || !r.addRangeAssertions()) return false; - gs.spewPass("Range Analysis"); + IonSpewPass("Range Analysis"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Range Analysis")) @@ -1443,7 +1383,7 @@ OptimizeMIR(MIRGenerator* mir) if (!r.removeBetaNodes()) return false; - gs.spewPass("De-Beta"); + IonSpewPass("De-Beta"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("RA De-Beta")) @@ -1453,7 +1393,7 @@ OptimizeMIR(MIRGenerator* mir) bool shouldRunUCE = false; if (!r.prepareForUCE(&shouldRunUCE)) return false; - gs.spewPass("RA check UCE"); + IonSpewPass("RA check UCE"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("RA check UCE")) @@ -1462,7 +1402,7 @@ OptimizeMIR(MIRGenerator* mir) if (shouldRunUCE) { if (!gvn.run(ValueNumberer::DontUpdateAliasAnalysis)) return false; - gs.spewPass("UCE After RA"); + IonSpewPass("UCE After RA"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("UCE After RA")) @@ -1473,7 +1413,7 @@ OptimizeMIR(MIRGenerator* mir) if (mir->optimizationInfo().autoTruncateEnabled()) { if (!r.truncate()) return false; - gs.spewPass("Truncate Doubles"); + IonSpewPass("Truncate Doubles"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Truncate Doubles")) @@ -1486,7 +1426,7 @@ OptimizeMIR(MIRGenerator* mir) if (!UnrollLoops(graph, r.loopIterationBounds)) return false; - gs.spewPass("Unroll Loops"); + IonSpewPass("Unroll Loops"); AssertExtendedGraphCoherency(graph); } } @@ -1496,7 +1436,7 @@ OptimizeMIR(MIRGenerator* mir) EffectiveAddressAnalysis eaa(mir, graph); if (!eaa.analyze()) return false; - gs.spewPass("Effective Address Analysis"); + IonSpewPass("Effective Address Analysis"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Effective Address Analysis")) @@ -1507,7 +1447,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_EliminateDeadCode); if (!EliminateDeadCode(mir, graph)) return false; - gs.spewPass("DCE"); + IonSpewPass("DCE"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("DCE")) @@ -1518,7 +1458,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_EliminateDeadCode); if (!Sink(mir, graph)) return false; - gs.spewPass("Sink"); + IonSpewPass("Sink"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Sink")) @@ -1531,7 +1471,7 @@ OptimizeMIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_MakeLoopsContiguous); if (!MakeLoopsContiguous(graph)) return false; - gs.spewPass("Make loops contiguous"); + IonSpewPass("Make loops contiguous"); AssertExtendedGraphCoherency(graph); if (mir->shouldCancel("Make loops contiguous")) @@ -1546,7 +1486,7 @@ OptimizeMIR(MIRGenerator* mir) EdgeCaseAnalysis edgeCaseAnalysis(mir, graph); if (!edgeCaseAnalysis.analyzeLate()) return false; - gs.spewPass("Edge Case Analysis (Late)"); + IonSpewPass("Edge Case Analysis (Late)"); AssertGraphCoherency(graph); if (mir->shouldCancel("Edge Case Analysis (Late)")) @@ -1561,7 +1501,7 @@ OptimizeMIR(MIRGenerator* mir) // before its bounds check. if (!EliminateRedundantChecks(graph)) return false; - gs.spewPass("Bounds Check Elimination"); + IonSpewPass("Bounds Check Elimination"); AssertGraphCoherency(graph); } @@ -1572,7 +1512,6 @@ LIRGraph* GenerateLIR(MIRGenerator* mir) { MIRGraph& graph = mir->graph(); - GraphSpewer& gs = mir->graphSpewer(); TraceLoggerThread* logger; if (GetJitContext()->runtime->onMainThread()) @@ -1589,7 +1528,7 @@ GenerateLIR(MIRGenerator* mir) AutoTraceLog log(logger, TraceLogger_GenerateLIR); if (!lirgen.generate()) return nullptr; - gs.spewPass("Generate LIR"); + IonSpewPass("Generate LIR"); if (mir->shouldCancel("Generate LIR")) return nullptr; @@ -1616,7 +1555,7 @@ GenerateLIR(MIRGenerator* mir) return nullptr; #endif - gs.spewPass("Allocate Registers [Backtracking]"); + IonSpewPass("Allocate Registers [Backtracking]"); break; } @@ -1631,7 +1570,7 @@ GenerateLIR(MIRGenerator* mir) return nullptr; if (!integrity.check(true)) return nullptr; - gs.spewPass("Allocate Registers [Stupid]"); + IonSpewPass("Allocate Registers [Stupid]"); break; } @@ -1673,7 +1612,6 @@ CompileBackEnd(MIRGenerator* mir) { // Everything in CompileBackEnd can potentially run on a helper thread. AutoEnterIonCompilation enter; - AutoSpewEndFunction spewEndFunction(mir); if (!OptimizeMIR(mir)) return nullptr; @@ -1692,6 +1630,7 @@ AttachFinishedCompilations(JSContext* cx) if (!ion) return; + AutoEnterAnalysis enterTypes(cx); AutoLockHelperThreadState lock; GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(); @@ -1743,17 +1682,9 @@ AttachFinishedCompilations(JSContext* cx) } } - // See PrepareForDebuggerOnIonCompilationHook - bool callOnIonCompilation = false; - AutoScriptVector debugScripts(cx); - LSprinter debugPrinter(builder->alloc().lifoAlloc()); - - RootedScript script(cx, builder->script()); - CodeGenerator* codegen = builder->backgroundCodegen(); - bool success = false; - if (codegen) { + if (CodeGenerator* codegen = builder->backgroundCodegen()) { + RootedScript script(cx, builder->script()); JitContext jctx(cx, &builder->alloc()); - AutoEnterAnalysis enterTypes(cx); TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script); AutoTraceLog logScript(logger, event); AutoTraceLog logLink(logger, TraceLogger_IonLinking); @@ -1763,6 +1694,7 @@ AttachFinishedCompilations(JSContext* cx) // previously, though any GC activity would discard the builder. codegen->masm.constructRoot(cx); + bool success; { AutoUnlockHelperThreadState unlock; success = codegen->link(cx, builder->constraints()); @@ -1775,15 +1707,6 @@ AttachFinishedCompilations(JSContext* cx) // exception from there. cx->clearPendingException(); } - - callOnIonCompilation = PrepareForDebuggerOnIonCompilationHook( - cx, success, builder->graph(), &debugScripts, &debugPrinter); - } - - if (callOnIonCompilation) { - // Without AutoEnterAnalysis scope. - AutoUnlockHelperThreadState unlock; - Debugger::onIonCompilation(cx, debugScripts, debugPrinter); } FinishOffThreadBuilder(cx, builder); @@ -1936,6 +1859,8 @@ IonCompile(JSContext* cx, JSScript* script, JitContext jctx(cx, temp); + AutoEnterAnalysis enter(cx); + if (!cx->compartment()->ensureJitCompartmentExists(cx)) return AbortReason_Alloc; @@ -1990,18 +1915,15 @@ IonCompile(JSContext* cx, JSScript* script, if (recompile) builderScript->ionScript()->setRecompiling(); - SpewBeginFunction(builder, builderScript); +#ifdef DEBUG + IonSpewFunction ionSpewFunction(graph, builderScript); +#endif - bool succeeded; - { - AutoEnterAnalysis enter(cx); - succeeded = builder->build(); - builder->clearForBackEnd(); - } + bool succeeded = builder->build(); + builder->clearForBackEnd(); if (!succeeded) { AbortReason reason = builder->abortReason(); - builder->graphSpewer().endFunction(); if (reason == AbortReason_PreliminaryObjects) { // Some group was accessed which has associated preliminary objects // to analyze. Do this now and we will try to build again shortly. @@ -2035,8 +1957,7 @@ IonCompile(JSContext* cx, JSScript* script, if (!recompile) builderScript->setIonScript(cx, ION_COMPILING_SCRIPT); - JitSpew(JitSpew_IonSyncLogs, "Can't log script %s:%" PRIuSIZE - ". (Compiled on background thread.)", + JitSpew(JitSpew_IonLogs, "Can't log script %s:%" PRIuSIZE ". (Compiled on background thread.)", builderScript->filename(), builderScript->lineno()); JSRuntime* rt = cx->runtime(); @@ -2050,7 +1971,6 @@ IonCompile(JSContext* cx, JSScript* script, if (!StartOffThreadIonCompile(cx, builder)) { JitSpew(JitSpew_IonAbort, "Unable to start off-thread ion compilation."); - builder->graphSpewer().endFunction(); return AbortReason_Alloc; } @@ -2061,29 +1981,15 @@ IonCompile(JSContext* cx, JSScript* script, return AbortReason_NoAbort; } - // See PrepareForDebuggerOnIonCompilationHook - bool callOnIonCompilation = false; - AutoScriptVector debugScripts(cx); - LSprinter debugPrinter(builder->alloc().lifoAlloc()); - - ScopedJSDeletePtr codegen; - { - AutoEnterAnalysis enter(cx); - codegen = CompileBackEnd(builder); - if (!codegen) { - JitSpew(JitSpew_IonAbort, "Failed during back-end compilation."); - return AbortReason_Disable; - } - - succeeded = codegen->link(cx, builder->constraints()); - callOnIonCompilation = PrepareForDebuggerOnIonCompilationHook( - cx, succeeded, builder->graph(), &debugScripts, &debugPrinter); + ScopedJSDeletePtr codegen(CompileBackEnd(builder)); + if (!codegen) { + JitSpew(JitSpew_IonAbort, "Failed during back-end compilation."); + return AbortReason_Disable; } - if (callOnIonCompilation) - Debugger::onIonCompilation(cx, debugScripts, debugPrinter); + bool success = codegen->link(cx, builder->constraints()); - if (succeeded) + if (success) return AbortReason_NoAbort; if (cx->isExceptionPending()) return AbortReason_Error; diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index e1e6ada033a7..870455ae8ecf 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2827,7 +2827,7 @@ LinearSum::add(int32_t constant) } void -LinearSum::dump(GenericPrinter& out) const +LinearSum::print(Sprinter& sp) const { for (size_t i = 0; i < terms_.length(); i++) { int32_t scale = terms_[i].scale; @@ -2835,29 +2835,36 @@ LinearSum::dump(GenericPrinter& out) const MOZ_ASSERT(scale); if (scale > 0) { if (i) - out.printf("+"); + sp.printf("+"); if (scale == 1) - out.printf("#%d", id); + sp.printf("#%d", id); else - out.printf("%d*#%d", scale, id); + sp.printf("%d*#%d", scale, id); } else if (scale == -1) { - out.printf("-#%d", id); + sp.printf("-#%d", id); } else { - out.printf("%d*#%d", scale, id); + sp.printf("%d*#%d", scale, id); } } if (constant_ > 0) - out.printf("+%d", constant_); + sp.printf("+%d", constant_); else if (constant_ < 0) - out.printf("%d", constant_); + sp.printf("%d", constant_); +} + +void +LinearSum::dump(FILE* fp) const +{ + Sprinter sp(GetJitContext()->cx); + sp.init(); + print(sp); + fprintf(fp, "%s\n", sp.string()); } void LinearSum::dump() const { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } MDefinition* diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 0e95edf28b5d..5201db37e32a 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -148,7 +148,8 @@ class LinearSum LinearTerm term(size_t i) const { return terms_[i]; } void replaceTerm(size_t i, MDefinition* def) { terms_[i].term = def; } - void dump(GenericPrinter& out) const; + void print(Sprinter& sp) const; + void dump(FILE*) const; void dump() const; private: diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 589a3b785bc9..76b9d67fc145 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -871,6 +871,7 @@ class IonBuilder InliningStatus inlineBailout(CallInfo& callInfo); InliningStatus inlineAssertFloat32(CallInfo& callInfo); InliningStatus inlineAssertRecoveredOnBailout(CallInfo& callInfo); + InliningStatus inlineTrue(CallInfo& callInfo); // Bind function. InliningStatus inlineBoundFunction(CallInfo& callInfo, JSFunction* target); diff --git a/js/src/jit/JSONSpewer.cpp b/js/src/jit/JSONSpewer.cpp index 87fc769cf590..91d462f03b93 100644 --- a/js/src/jit/JSONSpewer.cpp +++ b/js/src/jit/JSONSpewer.cpp @@ -17,33 +17,47 @@ using namespace js; using namespace js::jit; +JSONSpewer::~JSONSpewer() +{ + if (fp_) + fclose(fp_); +} + void JSONSpewer::indent() { + if (!fp_) + return; MOZ_ASSERT(indentLevel_ >= 0); - out_.printf("\n"); + fprintf(fp_, "\n"); for (int i = 0; i < indentLevel_; i++) - out_.printf(" "); + fprintf(fp_, " "); } void JSONSpewer::property(const char* name) { + if (!fp_) + return; + if (!first_) - out_.printf(","); + fprintf(fp_, ","); indent(); - out_.printf("\"%s\":", name); + fprintf(fp_, "\"%s\":", name); first_ = false; } void JSONSpewer::beginObject() { + if (!fp_) + return; + if (!first_) { - out_.printf(","); + fprintf(fp_, ","); indent(); } - out_.printf("{"); + fprintf(fp_, "{"); indentLevel_++; first_ = true; } @@ -51,8 +65,11 @@ JSONSpewer::beginObject() void JSONSpewer::beginObjectProperty(const char* name) { + if (!fp_) + return; + property(name); - out_.printf("{"); + fprintf(fp_, "{"); indentLevel_++; first_ = true; } @@ -60,33 +77,27 @@ JSONSpewer::beginObjectProperty(const char* name) void JSONSpewer::beginListProperty(const char* name) { + if (!fp_) + return; + property(name); - out_.printf("["); + fprintf(fp_, "["); first_ = true; } -void -JSONSpewer::beginStringProperty(const char* name) -{ - property(name); - out_.printf("\""); -} - -void -JSONSpewer::endStringProperty() -{ - out_.printf("\""); -} - void JSONSpewer::stringProperty(const char* name, const char* format, ...) { + if (!fp_) + return; + va_list ap; va_start(ap, format); - beginStringProperty(name); - out_.vprintf(format, ap); - endStringProperty(); + property(name); + fprintf(fp_, "\""); + vfprintf(fp_, format, ap); + fprintf(fp_, "\""); va_end(ap); } @@ -94,14 +105,17 @@ JSONSpewer::stringProperty(const char* name, const char* format, ...) void JSONSpewer::stringValue(const char* format, ...) { + if (!fp_) + return; + va_list ap; va_start(ap, format); if (!first_) - out_.printf(","); - out_.printf("\""); - out_.vprintf(format, ap); - out_.printf("\""); + fprintf(fp_, ","); + fprintf(fp_, "\""); + vfprintf(fp_, format, ap); + fprintf(fp_, "\""); va_end(ap); first_ = false; @@ -110,44 +124,73 @@ JSONSpewer::stringValue(const char* format, ...) void JSONSpewer::integerProperty(const char* name, int value) { + if (!fp_) + return; + property(name); - out_.printf("%d", value); + fprintf(fp_, "%d", value); } void JSONSpewer::integerValue(int value) { + if (!fp_) + return; + if (!first_) - out_.printf(","); - out_.printf("%d", value); + fprintf(fp_, ","); + fprintf(fp_, "%d", value); first_ = false; } void JSONSpewer::endObject() { + if (!fp_) + return; + indentLevel_--; indent(); - out_.printf("}"); + fprintf(fp_, "}"); first_ = false; } void JSONSpewer::endList() { - out_.printf("]"); + if (!fp_) + return; + + fprintf(fp_, "]"); first_ = false; } +bool +JSONSpewer::init(const char* path) +{ + fp_ = fopen(path, "w"); + if (!fp_) + return false; + + beginObject(); + beginListProperty("functions"); + return true; +} + void JSONSpewer::beginFunction(JSScript* script) { + if (inFunction_) + endFunction(); + beginObject(); if (script) stringProperty("name", "%s:%d", script->filename(), script->lineno()); else stringProperty("name", "asm.js compilation"); beginListProperty("passes"); + + inFunction_ = true; } void @@ -171,13 +214,13 @@ JSONSpewer::spewMResumePoint(MResumePoint* rp) property("mode"); switch (rp->mode()) { case MResumePoint::ResumeAt: - out_.printf("\"At\""); + fprintf(fp_, "\"At\""); break; case MResumePoint::ResumeAfter: - out_.printf("\"After\""); + fprintf(fp_, "\"After\""); break; case MResumePoint::Outer: - out_.printf("\"Outer\""); + fprintf(fp_, "\"Outer\""); break; } @@ -201,9 +244,9 @@ JSONSpewer::spewMDef(MDefinition* def) integerProperty("id", def->id()); property("opcode"); - out_.printf("\""); - def->printOpcode(out_); - out_.printf("\""); + fprintf(fp_, "\""); + def->printOpcode(fp_); + fprintf(fp_, "\""); beginListProperty("attributes"); #define OUTPUT_ATTRIBUTE(X) do{ if(def->is##X()) stringValue(#X); } while(0); @@ -233,10 +276,10 @@ JSONSpewer::spewMDef(MDefinition* def) isTruncated = static_cast(def)->isTruncated(); if (def->type() != MIRType_None && def->range()) { - beginStringProperty("type"); - def->range()->dump(out_); - out_.printf(" : %s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); - endStringProperty(); + Sprinter sp(GetJitContext()->cx); + sp.init(); + def->range()->print(sp); + stringProperty("type", "%s : %s%s", sp.string(), StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); } else { stringProperty("type", "%s%s", StringFromMIRType(def->type()), (isTruncated ? " (t)" : "")); } @@ -252,6 +295,9 @@ JSONSpewer::spewMDef(MDefinition* def) void JSONSpewer::spewMIR(MIRGraph* mir) { + if (!fp_) + return; + beginObjectProperty("mir"); beginListProperty("blocks"); @@ -298,14 +344,17 @@ JSONSpewer::spewMIR(MIRGraph* mir) void JSONSpewer::spewLIns(LNode* ins) { + if (!fp_) + return; + beginObject(); integerProperty("id", ins->id()); property("opcode"); - out_.printf("\""); - ins->dump(out_); - out_.printf("\""); + fprintf(fp_, "\""); + ins->dump(fp_); + fprintf(fp_, "\""); beginListProperty("defs"); for (size_t i = 0; i < ins->numDefs(); i++) @@ -318,6 +367,9 @@ JSONSpewer::spewLIns(LNode* ins) void JSONSpewer::spewLIR(MIRGraph* mir) { + if (!fp_) + return; + beginObjectProperty("lir"); beginListProperty("blocks"); @@ -346,6 +398,9 @@ JSONSpewer::spewLIR(MIRGraph* mir) void JSONSpewer::spewIntervals(BacktrackingAllocator* regalloc) { + if (!fp_) + return; + beginObjectProperty("intervals"); beginListProperty("blocks"); @@ -370,7 +425,7 @@ JSONSpewer::spewIntervals(BacktrackingAllocator* regalloc) if (live->numRanges()) { beginObject(); property("allocation"); - out_.printf("\"%s\"", live->getAllocation()->toString()); + fprintf(fp_, "\"%s\"", live->getAllocation()->toString()); beginListProperty("ranges"); for (size_t j = 0; j < live->numRanges(); j++) { @@ -402,20 +457,33 @@ void JSONSpewer::endPass() { endObject(); + fflush(fp_); } void JSONSpewer::endFunction() { + MOZ_ASSERT(inFunction_); endList(); endObject(); + fflush(fp_); + inFunction_ = false; } void -JSONSpewer::spewDebuggerGraph(MIRGraph* graph) +JSONSpewer::finish() { - beginObject(); - spewMIR(graph); - spewLIR(graph); + if (!fp_) + return; + + if (inFunction_) + endFunction(); + + endList(); endObject(); + fprintf(fp_, "\n"); + + fclose(fp_); + fp_ = nullptr; } + diff --git a/js/src/jit/JSONSpewer.h b/js/src/jit/JSONSpewer.h index 43e34a6cb326..db121a8dfab8 100644 --- a/js/src/jit/JSONSpewer.h +++ b/js/src/jit/JSONSpewer.h @@ -10,7 +10,6 @@ #include #include "js/TypeDecls.h" -#include "vm/Printer.h" namespace js { namespace jit { @@ -24,9 +23,13 @@ class LNode; class JSONSpewer { private: + // Set by beginFunction(); unset by endFunction(). + // Used to correctly format output in case of abort during compilation. + bool inFunction_; + int indentLevel_; bool first_; - GenericPrinter& out_; + FILE* fp_; void indent(); @@ -36,20 +39,21 @@ class JSONSpewer void beginListProperty(const char* name); void stringValue(const char* format, ...); void stringProperty(const char* name, const char* format, ...); - void beginStringProperty(const char* name); - void endStringProperty(); void integerValue(int value); void integerProperty(const char* name, int value); void endObject(); void endList(); public: - explicit JSONSpewer(GenericPrinter& out) - : indentLevel_(0), + JSONSpewer() + : inFunction_(false), + indentLevel_(0), first_(true), - out_(out) + fp_(nullptr) { } + ~JSONSpewer(); + bool init(const char* path); void beginFunction(JSScript* script); void beginPass(const char * pass); void spewMDef(MDefinition* def); @@ -60,8 +64,7 @@ class JSONSpewer void spewIntervals(BacktrackingAllocator* regalloc); void endPass(); void endFunction(); - - void spewDebuggerGraph(MIRGraph* mir); + void finish(); }; } // namespace jit diff --git a/js/src/jit/JitSpewer.cpp b/js/src/jit/JitSpewer.cpp index 2ad82ed2c978..d00c995dc4ac 100644 --- a/js/src/jit/JitSpewer.cpp +++ b/js/src/jit/JitSpewer.cpp @@ -8,8 +8,6 @@ #include "jit/JitSpewer.h" -#include "mozilla/Atomics.h" - #include "jit/Ion.h" #include "jit/MIR.h" @@ -28,67 +26,12 @@ using namespace js; using namespace js::jit; -class IonSpewer -{ - private: - PRLock* outputLock_; - Fprinter c1Output_; - Fprinter jsonOutput_; - bool firstFunction_; - bool asyncLogging_; - bool inited_; - - void release(); - - public: - IonSpewer() - : firstFunction_(false), - asyncLogging_(false), - inited_(false) - { } - - // File output is terminated safely upon destruction. - ~IonSpewer(); - - bool init(); - bool isEnabled() { - return inited_; - } - void setAsyncLogging(bool incremental) { - asyncLogging_ = incremental; - } - bool getAsyncLogging() { - return asyncLogging_; - } - - void beginFunction(); - void spewPass(GraphSpewer* gs); - void endFunction(GraphSpewer* gs); - - // Lock used to sequentialized asynchronous compilation output. - void lockOutput() { - PR_Lock(outputLock_); - } - void unlockOutput() { - PR_Unlock(outputLock_); - } -}; - -class AutoLockIonSpewerOutput -{ - private: - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - public: - explicit AutoLockIonSpewerOutput(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); - ~AutoLockIonSpewerOutput(); -}; - // IonSpewer singleton. static IonSpewer ionspewer; static bool LoggingChecked = false; static uint32_t LoggingBits = 0; -static mozilla::Atomic filteredOutCompilations(0); +static uint32_t filteredOutCompilations = 0; static const char * const ChannelNames[] = { @@ -98,7 +41,7 @@ static const char * const ChannelNames[] = }; static bool -FilterContainsLocation(JSScript* function) +FilterContainsLocation(HandleScript function) { static const char* filter = getenv("IONFILTER"); @@ -130,31 +73,48 @@ FilterContainsLocation(JSScript* function) } void -jit::EnableIonDebugSyncLogging() +jit::EnableIonDebugLogging() { + EnableChannel(JitSpew_IonLogs); ionspewer.init(); - ionspewer.setAsyncLogging(false); - EnableChannel(JitSpew_IonSyncLogs); } void -jit::EnableIonDebugAsyncLogging() +jit::IonSpewNewFunction(MIRGraph* graph, HandleScript func) { - ionspewer.init(); - ionspewer.setAsyncLogging(true); + if (GetJitContext()->runtime->onMainThread()) + ionspewer.beginFunction(graph, func); } void -IonSpewer::release() +jit::IonSpewPass(const char* pass) { - if (c1Output_.isInitialized()) - c1Output_.finish(); - if (jsonOutput_.isInitialized()) - jsonOutput_.finish(); - if (outputLock_) - PR_DestroyLock(outputLock_); - outputLock_ = nullptr; - inited_ = false; + if (GetJitContext()->runtime->onMainThread()) + ionspewer.spewPass(pass); +} + +void +jit::IonSpewPass(const char* pass, BacktrackingAllocator* ra) +{ + if (GetJitContext()->runtime->onMainThread()) + ionspewer.spewPass(pass, ra); +} + +void +jit::IonSpewEndFunction() +{ + if (GetJitContext()->runtime->onMainThread()) + ionspewer.endFunction(); +} + + +IonSpewer::~IonSpewer() +{ + if (!inited_) + return; + + c1Spewer.finish(); + jsonSpewer.finish(); } bool @@ -163,191 +123,87 @@ IonSpewer::init() if (inited_) return true; - outputLock_ = PR_NewLock(); - if (!outputLock_ || - !c1Output_.init(JIT_SPEW_DIR "ion.cfg") || - !jsonOutput_.init(JIT_SPEW_DIR "ion.json")) - { - release(); + if (!c1Spewer.init(JIT_SPEW_DIR "ion.cfg")) + return false; + if (!jsonSpewer.init(JIT_SPEW_DIR "ion.json")) return false; - } - - jsonOutput_.printf("{\n \"functions\": [\n"); - firstFunction_ = true; inited_ = true; return true; } -AutoLockIonSpewerOutput::AutoLockIonSpewerOutput(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) +bool +IonSpewer::isSpewingFunction() const { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - ionspewer.lockOutput(); -} - -AutoLockIonSpewerOutput::~AutoLockIonSpewerOutput() -{ - ionspewer.unlockOutput(); + return inited_ && graph; } void -IonSpewer::beginFunction() -{ - // If we are doing a synchronous logging then we spew everything as we go, - // as this is useful in case of failure during the compilation. On the other - // hand, it is recommended to disabled off main thread compilation. - if (!getAsyncLogging() && !firstFunction_) { - AutoLockIonSpewerOutput outputLock; - jsonOutput_.put(","); // separate functions - } -} - -void -IonSpewer::spewPass(GraphSpewer* gs) -{ - if (!getAsyncLogging()) { - AutoLockIonSpewerOutput outputLock; - gs->dump(c1Output_, jsonOutput_); - } -} - -void -IonSpewer::endFunction(GraphSpewer* gs) -{ - AutoLockIonSpewerOutput outputLock; - if (getAsyncLogging() && !firstFunction_) - jsonOutput_.put(","); // separate functions - - gs->dump(c1Output_, jsonOutput_); - firstFunction_ = false; -} - -IonSpewer::~IonSpewer() +IonSpewer::beginFunction(MIRGraph* graph, HandleScript function) { if (!inited_) return; - jsonOutput_.printf("\n]}\n"); - release(); -} - -void -GraphSpewer::init(MIRGraph* graph, JSScript* function) -{ - MOZ_ASSERT(!isSpewing()); - if (!ionspewer.isEnabled()) - return; - if (!FilterContainsLocation(function)) { + MOZ_ASSERT(!this->graph); // filter out logs during the compilation. filteredOutCompilations++; - MOZ_ASSERT(!isSpewing()); return; } - graph_ = graph; - MOZ_ASSERT(isSpewing()); + this->graph = graph; + + c1Spewer.beginFunction(graph, function); + jsonSpewer.beginFunction(function); } void -GraphSpewer::beginFunction(JSScript* function) +IonSpewer::spewPass(const char* pass) { - if (!isSpewing()) + if (!isSpewingFunction()) return; - c1Spewer_.beginFunction(graph_, function); - jsonSpewer_.beginFunction(function); - - ionspewer.beginFunction(); + c1Spewer.spewPass(pass); + jsonSpewer.beginPass(pass); + jsonSpewer.spewMIR(graph); + jsonSpewer.spewLIR(graph); + jsonSpewer.endPass(); } void -GraphSpewer::spewPass(const char* pass) +IonSpewer::spewPass(const char* pass, BacktrackingAllocator* ra) { - if (!isSpewing()) + if (!isSpewingFunction()) return; - c1Spewer_.spewPass(pass); - - jsonSpewer_.beginPass(pass); - jsonSpewer_.spewMIR(graph_); - jsonSpewer_.spewLIR(graph_); - jsonSpewer_.endPass(); - - ionspewer.spewPass(this); + c1Spewer.spewPass(pass); + c1Spewer.spewIntervals(pass, ra); + jsonSpewer.beginPass(pass); + jsonSpewer.spewMIR(graph); + jsonSpewer.spewLIR(graph); + jsonSpewer.spewIntervals(ra); + jsonSpewer.endPass(); } void -GraphSpewer::spewPass(const char* pass, BacktrackingAllocator* ra) +IonSpewer::endFunction() { - if (!isSpewing()) - return; - - c1Spewer_.spewPass(pass); - c1Spewer_.spewIntervals(pass, ra); - - jsonSpewer_.beginPass(pass); - jsonSpewer_.spewMIR(graph_); - jsonSpewer_.spewLIR(graph_); - jsonSpewer_.spewIntervals(ra); - jsonSpewer_.endPass(); - - ionspewer.spewPass(this); -} - -void -GraphSpewer::endFunction() -{ - if (!ionspewer.isEnabled()) - return; - - if (!isSpewing()) { - MOZ_ASSERT(filteredOutCompilations != 0); - filteredOutCompilations--; + if (!isSpewingFunction()) { + if (inited_) { + MOZ_ASSERT(filteredOutCompilations != 0); + filteredOutCompilations--; + } return; } - c1Spewer_.endFunction(); - jsonSpewer_.endFunction(); + c1Spewer.endFunction(); + jsonSpewer.endFunction(); - ionspewer.endFunction(this); - graph_ = nullptr; + this->graph = nullptr; } -void -GraphSpewer::dump(Fprinter& c1Out, Fprinter& jsonOut) -{ - if (!c1Printer_.hadOutOfMemory()) - c1Printer_.exportInto(c1Out); - c1Printer_.clear(); - - if (!jsonPrinter_.hadOutOfMemory()) - jsonPrinter_.exportInto(jsonOut); - else - jsonOut.put("{}"); - jsonPrinter_.clear(); -} - -void -jit::SpewBeginFunction(MIRGenerator* mir, JSScript* function) -{ - MIRGraph* graph = &mir->graph(); - mir->graphSpewer().init(graph, function); - mir->graphSpewer().beginFunction(function); -} - -AutoSpewEndFunction::~AutoSpewEndFunction() -{ - mir_->graphSpewer().endFunction(); -} - -Fprinter& -jit::JitSpewPrinter() -{ - static Fprinter out; - return out; -} +FILE* jit::JitSpewFile = nullptr; static bool ContainsFlag(const char* str, const char* flag) @@ -398,7 +254,6 @@ jit::CheckLogging() " range Range Analysis\n" " unroll Loop unrolling\n" " logs C1 and JSON visualization logging\n" - " logs-sync Same as logs, but flushes between each pass (sync. compiled functions only).\n" " profiling Profiling-related information\n" " trackopts Optimization tracking information\n" " all Everything\n" @@ -458,9 +313,7 @@ jit::CheckLogging() if (ContainsFlag(env, "cacheflush")) EnableChannel(JitSpew_CacheFlush); if (ContainsFlag(env, "logs")) - EnableIonDebugAsyncLogging(); - if (ContainsFlag(env, "logs-sync")) - EnableIonDebugSyncLogging(); + EnableIonDebugLogging(); if (ContainsFlag(env, "profiling")) EnableChannel(JitSpew_Profiling); if (ContainsFlag(env, "trackopts")) @@ -495,7 +348,7 @@ jit::CheckLogging() EnableChannel(JitSpew_BaselineDebugModeOSR); } - JitSpewPrinter().init(stderr); + JitSpewFile = stderr; } void @@ -549,10 +402,9 @@ jit::JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def) return; JitSpewHeader(channel); - Fprinter& out = JitSpewPrinter(); - out.put(str); - def->dump(out); - def->dumpLocation(out); + fprintf(JitSpewFile, "%s", str); + def->dump(JitSpewFile); + def->dumpLocation(JitSpewFile); } void @@ -602,5 +454,15 @@ jit::DisableChannel(JitSpewChannel channel) LoggingBits &= ~(1 << uint32_t(channel)); } +IonSpewFunction::IonSpewFunction(MIRGraph* graph, JS::HandleScript function) +{ + IonSpewNewFunction(graph, function); +} + +IonSpewFunction::~IonSpewFunction() +{ + IonSpewEndFunction(); +} + #endif /* DEBUG */ diff --git a/js/src/jit/JitSpewer.h b/js/src/jit/JitSpewer.h index 2076e7cf3a3e..8915a50e381d 100644 --- a/js/src/jit/JitSpewer.h +++ b/js/src/jit/JitSpewer.h @@ -77,7 +77,7 @@ namespace jit { /* Information about compiled scripts */\ _(IonScripts) \ /* Info about failing to log script */ \ - _(IonSyncLogs) \ + _(IonLogs) \ /* Information during MIR building */ \ _(IonMIR) \ /* Information during bailouts */ \ @@ -103,52 +103,44 @@ static const int NULL_ID = -1; #ifdef DEBUG -// Class made to hold the MIR and LIR graphs of an AsmJS / Ion compilation. -class GraphSpewer +class IonSpewer { private: - MIRGraph* graph_; - LSprinter c1Printer_; - LSprinter jsonPrinter_; - C1Spewer c1Spewer_; - JSONSpewer jsonSpewer_; + MIRGraph* graph; + C1Spewer c1Spewer; + JSONSpewer jsonSpewer; + bool inited_; public: - explicit GraphSpewer(TempAllocator *alloc) - : graph_(nullptr), - c1Printer_(alloc->lifoAlloc()), - jsonPrinter_(alloc->lifoAlloc()), - c1Spewer_(c1Printer_), - jsonSpewer_(jsonPrinter_) + IonSpewer() + : graph(nullptr), inited_(false) { } - bool isSpewing() const { - return graph_; - } - void init(MIRGraph* graph, JSScript* function); - void beginFunction(JSScript* function); + // File output is terminated safely upon destruction. + ~IonSpewer(); + + bool init(); + void beginFunction(MIRGraph* graph, JS::HandleScript); + bool isSpewingFunction() const; void spewPass(const char* pass); void spewPass(const char* pass, BacktrackingAllocator* ra); void endFunction(); - - void dump(Fprinter& c1, Fprinter& json); }; -void SpewBeginFunction(MIRGenerator* mir, JSScript* function); -class AutoSpewEndFunction +class IonSpewFunction { - private: - MIRGenerator* mir_; - public: - explicit AutoSpewEndFunction(MIRGenerator* mir) - : mir_(mir) - { } - ~AutoSpewEndFunction(); + IonSpewFunction(MIRGraph* graph, JS::HandleScript function); + ~IonSpewFunction(); }; +void IonSpewNewFunction(MIRGraph* graph, JS::HandleScript function); +void IonSpewPass(const char* pass); +void IonSpewPass(const char* pass, BacktrackingAllocator* ra); +void IonSpewEndFunction(); + void CheckLogging(); -Fprinter& JitSpewPrinter(); +extern FILE* JitSpewFile; void JitSpew(JitSpewChannel channel, const char* fmt, ...); void JitSpewStart(JitSpewChannel channel, const char* fmt, ...); void JitSpewCont(JitSpewChannel channel, const char* fmt, ...); @@ -162,42 +154,22 @@ void JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def); void EnableChannel(JitSpewChannel channel); void DisableChannel(JitSpewChannel channel); -void EnableIonDebugSyncLogging(); -void EnableIonDebugAsyncLogging(); +void EnableIonDebugLogging(); #else -class GraphSpewer -{ - public: - GraphSpewer(TempAllocator *alloc) { } - - bool isSpewing() { return false; } - void init(MIRGraph* graph, JSScript* function) { } - void beginFunction(JSScript* function) { } - void spewPass(const char* pass) { } - void spewPass(const char* pass, BacktrackingAllocator* ra) { } - void endFunction() { } - - void dump(Fprinter& c1, Fprinter& json) { } -}; - -static inline void SpewBeginFunction(MIRGenerator* mir, JSScript* function) +static inline void IonSpewNewFunction(MIRGraph* graph, JS::HandleScript function) +{ } +static inline void IonSpewPass(const char* pass) +{ } +static inline void IonSpewPass(const char* pass, BacktrackingAllocator* ra) +{ } +static inline void IonSpewEndFunction() { } - -class AutoSpewEndFunction -{ - public: - explicit AutoSpewEndFunction(MIRGenerator* mir) { } - ~AutoSpewEndFunction() { } -}; static inline void CheckLogging() { } -static inline Fprinter& JitSpewPrinter() -{ - MOZ_CRASH("No empty backend for JitSpewPrinter"); -} +static FILE* const JitSpewFile = nullptr; static inline void JitSpew(JitSpewChannel, const char* fmt, ...) { } static inline void JitSpewStart(JitSpewChannel channel, const char* fmt, ...) @@ -220,9 +192,7 @@ static inline void EnableChannel(JitSpewChannel) { } static inline void DisableChannel(JitSpewChannel) { } -static inline void EnableIonDebugSyncLogging() -{ } -static inline void EnableIonDebugAsyncLogging() +static inline void EnableIonDebugLogging() { } #endif /* DEBUG */ diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index bbd0dbc1d3b0..34227c2db633 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -106,7 +106,7 @@ class LMoveGroup : public LInstructionHelper<0, 0, 0> return new(alloc) LMoveGroup(alloc); } - void printOperands(GenericPrinter& out); + void printOperands(FILE* fp); // Add a move which takes place simultaneously with all others in the group. bool add(LAllocation* from, LAllocation* to, LDefinition::Type type); diff --git a/js/src/jit/LIR.cpp b/js/src/jit/LIR.cpp index 9f1695c99daa..61b0441512ec 100644 --- a/js/src/jit/LIR.cpp +++ b/js/src/jit/LIR.cpp @@ -57,20 +57,18 @@ LIRGraph::noteNeedsSafepoint(LInstruction* ins) } void -LIRGraph::dump(GenericPrinter& out) +LIRGraph::dump(FILE* fp) { for (size_t i = 0; i < numBlocks(); i++) { - getBlock(i)->dump(out); - out.printf("\n"); + getBlock(i)->dump(fp); + fprintf(fp, "\n"); } } void LIRGraph::dump() { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } LBlock::LBlock(MBasicBlock* from) @@ -152,25 +150,23 @@ LBlock::getExitMoveGroup(TempAllocator& alloc) } void -LBlock::dump(GenericPrinter& out) +LBlock::dump(FILE* fp) { - out.printf("block%u:\n", mir()->id()); + fprintf(fp, "block%u:\n", mir()->id()); for (size_t i = 0; i < numPhis(); ++i) { - getPhi(i)->dump(out); - out.printf("\n"); + getPhi(i)->dump(fp); + fprintf(fp, "\n"); } for (LInstructionIterator iter = begin(); iter != end(); iter++) { - iter->dump(out); - out.printf("\n"); + iter->dump(fp); + fprintf(fp, "\n"); } } void LBlock::dump() { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } static size_t @@ -313,7 +309,7 @@ LSnapshot::rewriteRecoveredInput(LUse input) } void -LNode::printName(GenericPrinter& out, Opcode op) +LNode::printName(FILE* fp, Opcode op) { static const char * const names[] = { @@ -324,13 +320,13 @@ LNode::printName(GenericPrinter& out, Opcode op) const char* name = names[op]; size_t len = strlen(name); for (size_t i = 0; i < len; i++) - out.printf("%c", tolower(name[i])); + fprintf(fp, "%c", tolower(name[i])); } void -LNode::printName(GenericPrinter& out) +LNode::printName(FILE* fp) { - printName(out, op()); + printName(fp, op()); } bool @@ -460,12 +456,12 @@ LDefinition::dump() const } void -LNode::printOperands(GenericPrinter& out) +LNode::printOperands(FILE* fp) { for (size_t i = 0, e = numOperands(); i < e; i++) { - out.printf(" (%s)", getOperand(i)->toString()); + fprintf(fp, " (%s)", getOperand(i)->toString()); if (i != numOperands() - 1) - out.printf(","); + fprintf(fp, ","); } } @@ -478,59 +474,56 @@ LInstruction::assignSnapshot(LSnapshot* snapshot) #ifdef DEBUG if (JitSpewEnabled(JitSpew_IonSnapshots)) { JitSpewHeader(JitSpew_IonSnapshots); - Fprinter& out = JitSpewPrinter(); - out.printf("Assigning snapshot %p to instruction %p (", - (void*)snapshot, (void*)this); - printName(out); - out.printf(")\n"); + fprintf(JitSpewFile, "Assigning snapshot %p to instruction %p (", + (void*)snapshot, (void*)this); + printName(JitSpewFile); + fprintf(JitSpewFile, ")\n"); } #endif } void -LNode::dump(GenericPrinter& out) +LNode::dump(FILE* fp) { if (numDefs() != 0) { - out.printf("{"); + fprintf(fp, "{"); for (size_t i = 0; i < numDefs(); i++) { - out.printf("%s", getDef(i)->toString()); + fprintf(fp, "%s", getDef(i)->toString()); if (i != numDefs() - 1) - out.printf(", "); + fprintf(fp, ", "); } - out.printf("} <- "); + fprintf(fp, "} <- "); } - printName(out); - printOperands(out); + printName(fp); + printOperands(fp); if (numTemps()) { - out.printf(" t=("); + fprintf(fp, " t=("); for (size_t i = 0; i < numTemps(); i++) { - out.printf("%s", getTemp(i)->toString()); + fprintf(fp, "%s", getTemp(i)->toString()); if (i != numTemps() - 1) - out.printf(", "); + fprintf(fp, ", "); } - out.printf(")"); + fprintf(fp, ")"); } if (numSuccessors()) { - out.printf(" s=("); + fprintf(fp, " s=("); for (size_t i = 0; i < numSuccessors(); i++) { - out.printf("block%u", getSuccessor(i)->id()); + fprintf(fp, "block%u", getSuccessor(i)->id()); if (i != numSuccessors() - 1) - out.printf(", "); + fprintf(fp, ", "); } - out.printf(")"); + fprintf(fp, ")"); } } void LNode::dump() { - Fprinter out(stderr); - dump(out); - out.printf("\n"); - out.finish(); + dump(stderr); + fprintf(stderr, "\n"); } void @@ -598,18 +591,18 @@ LMoveGroup::addAfter(LAllocation* from, LAllocation* to, LDefinition::Type type) } void -LMoveGroup::printOperands(GenericPrinter& out) +LMoveGroup::printOperands(FILE* fp) { for (size_t i = 0; i < numMoves(); i++) { const LMove& move = getMove(i); // Use two printfs, as LAllocation::toString is not reentrant. - out.printf(" [%s", move.from()->toString()); - out.printf(" -> %s", move.to()->toString()); + fprintf(fp, " [%s", move.from()->toString()); + fprintf(fp, " -> %s", move.to()->toString()); #ifdef DEBUG - out.printf(", %s", TypeChars[move.type()]); + fprintf(fp, ", %s", TypeChars[move.type()]); #endif - out.printf("]"); + fprintf(fp, "]"); if (i != numMoves() - 1) - out.printf(","); + fprintf(fp, ","); } } diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h index 53a77cb7c4a9..085c2902ad41 100644 --- a/js/src/jit/LIR.h +++ b/js/src/jit/LIR.h @@ -702,11 +702,11 @@ class LNode return false; } - virtual void dump(GenericPrinter& out); + virtual void dump(FILE* fp); void dump(); - static void printName(GenericPrinter& out, Opcode op); - virtual void printName(GenericPrinter& out); - virtual void printOperands(GenericPrinter& out); + static void printName(FILE* fp, Opcode op); + virtual void printName(FILE* fp); + virtual void printOperands(FILE* fp); public: // Opcode testing and casts. @@ -986,7 +986,7 @@ class LBlock return begin()->isGoto() && !mir()->isLoopHeader(); } - void dump(GenericPrinter& out); + void dump(FILE* fp); void dump(); }; @@ -1799,7 +1799,7 @@ class LIRGraph return safepoints_[i]; } - void dump(GenericPrinter& out); + void dump(FILE* fp); void dump(); }; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index f22351d3f62d..290cc0d2fd17 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4172,28 +4172,27 @@ LIRGenerator::visitNurseryObject(MNurseryObject* ins) static void SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint) { - Fprinter& out = JitSpewPrinter(); - out.printf("Current resume point %p details:\n", (void*)resumePoint); - out.printf(" frame count: %u\n", resumePoint->frameCount()); + fprintf(JitSpewFile, "Current resume point %p details:\n", (void*)resumePoint); + fprintf(JitSpewFile, " frame count: %u\n", resumePoint->frameCount()); if (ins) { - out.printf(" taken after: "); - ins->printName(out); + fprintf(JitSpewFile, " taken after: "); + ins->printName(JitSpewFile); } else { - out.printf(" taken at block %d entry", block->id()); + fprintf(JitSpewFile, " taken at block %d entry", block->id()); } - out.printf("\n"); + fprintf(JitSpewFile, "\n"); - out.printf(" pc: %p (script: %p, offset: %d)\n", + fprintf(JitSpewFile, " pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(), (void*)resumePoint->block()->info().script(), int(resumePoint->block()->info().script()->pcToOffset(resumePoint->pc()))); for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) { MDefinition* in = resumePoint->getOperand(i); - out.printf(" slot%u: ", (unsigned)i); - in->printName(out); - out.printf("\n"); + fprintf(JitSpewFile, " slot%u: ", (unsigned)i); + in->printName(JitSpewFile); + fprintf(JitSpewFile, "\n"); } } diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 277d45c8f1b7..5237ad409137 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -263,6 +263,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineAssertFloat32(callInfo); if (native == testingFunc_assertRecoveredOnBailout) return inlineAssertRecoveredOnBailout(callInfo); + if (native == testingFunc_inIon || native == testingFunc_inJit) + return inlineTrue(callInfo); // Bound function if (native == js::CallOrConstructBoundFunction) @@ -2670,6 +2672,15 @@ IonBuilder::inlineBailout(CallInfo& callInfo) return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineTrue(CallInfo& callInfo) +{ + callInfo.setImplicitlyUsedUnchecked(); + + pushConstant(BooleanValue(true)); + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineAssertFloat32(CallInfo& callInfo) { diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 42c3c603cc19..7465e40bad8a 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -61,7 +61,7 @@ CheckUsesAreFloat32Consumers(MInstruction* ins) } void -MDefinition::PrintOpcodeName(GenericPrinter& out, MDefinition::Opcode op) +MDefinition::PrintOpcodeName(FILE* fp, MDefinition::Opcode op) { static const char * const names[] = { @@ -72,7 +72,7 @@ MDefinition::PrintOpcodeName(GenericPrinter& out, MDefinition::Opcode op) const char* name = names[op]; size_t len = strlen(name); for (size_t i = 0; i < len; i++) - out.printf("%c", tolower(name[i])); + fprintf(fp, "%c", tolower(name[i])); } const Value& @@ -209,10 +209,10 @@ EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) } void -MDefinition::printName(GenericPrinter& out) const +MDefinition::printName(FILE* fp) const { - PrintOpcodeName(out, op()); - out.printf("%u", id()); + PrintOpcodeName(fp, op()); + fprintf(fp, "%u", id()); } HashNumber @@ -439,42 +439,40 @@ MTest::filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filt } void -MDefinition::printOpcode(GenericPrinter& out) const +MDefinition::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); + PrintOpcodeName(fp, op()); for (size_t j = 0, e = numOperands(); j < e; j++) { - out.printf(" "); + fprintf(fp, " "); if (getUseFor(j)->hasProducer()) - getOperand(j)->printName(out); + getOperand(j)->printName(fp); else - out.printf("(null)"); + fprintf(fp, "(null)"); } } void -MDefinition::dump(GenericPrinter& out) const +MDefinition::dump(FILE* fp) const { - printName(out); - out.printf(" = "); - printOpcode(out); - out.printf("\n"); + printName(fp); + fprintf(fp, " = "); + printOpcode(fp); + fprintf(fp, "\n"); if (isInstruction()) { if (MResumePoint* resume = toInstruction()->resumePoint()) - resume->dump(out); + resume->dump(fp); } } void MDefinition::dump() const { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } void -MDefinition::dumpLocation(GenericPrinter& out) const +MDefinition::dumpLocation(FILE* fp) const { MResumePoint* rp = nullptr; const char* linkWord = nullptr; @@ -489,7 +487,7 @@ MDefinition::dumpLocation(GenericPrinter& out) const while (rp) { JSScript* script = rp->block()->info().script(); uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc()); - out.printf(" %s %s:%d\n", linkWord, script->filename(), lineno); + fprintf(fp, " %s %s:%d\n", linkWord, script->filename(), lineno); rp = rp->caller(); linkWord = "in"; } @@ -498,9 +496,7 @@ MDefinition::dumpLocation(GenericPrinter& out) const void MDefinition::dumpLocation() const { - Fprinter out(stderr); - dumpLocation(out); - out.finish(); + dumpLocation(stderr); } #ifdef DEBUG @@ -757,72 +753,72 @@ MConstant::congruentTo(const MDefinition* ins) const } void -MConstant::printOpcode(GenericPrinter& out) const +MConstant::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); - out.printf(" "); + PrintOpcodeName(fp, op()); + fprintf(fp, " "); switch (type()) { case MIRType_Undefined: - out.printf("undefined"); + fprintf(fp, "undefined"); break; case MIRType_Null: - out.printf("null"); + fprintf(fp, "null"); break; case MIRType_Boolean: - out.printf(value().toBoolean() ? "true" : "false"); + fprintf(fp, value().toBoolean() ? "true" : "false"); break; case MIRType_Int32: - out.printf("0x%x", value().toInt32()); + fprintf(fp, "0x%x", value().toInt32()); break; case MIRType_Double: - out.printf("%f", value().toDouble()); + fprintf(fp, "%f", value().toDouble()); break; case MIRType_Float32: { float val = value().toDouble(); - out.printf("%f", val); + fprintf(fp, "%f", val); break; } case MIRType_Object: if (value().toObject().is()) { JSFunction* fun = &value().toObject().as(); if (fun->displayAtom()) { - out.put("function "); - EscapedStringPrinter(out, fun->displayAtom(), 0); + fputs("function ", fp); + FileEscapedString(fp, fun->displayAtom(), 0); } else { - out.put("unnamed function"); + fputs("unnamed function", fp); } if (fun->hasScript()) { JSScript* script = fun->nonLazyScript(); - out.printf(" (%s:%" PRIuSIZE ")", + fprintf(fp, " (%s:%" PRIuSIZE ")", script->filename() ? script->filename() : "", script->lineno()); } - out.printf(" at %p", (void*) fun); + fprintf(fp, " at %p", (void*) fun); break; } - out.printf("object %p (%s)", (void*)&value().toObject(), + fprintf(fp, "object %p (%s)", (void*)&value().toObject(), value().toObject().getClass()->name); break; case MIRType_Symbol: - out.printf("symbol at %p", (void*)value().toSymbol()); + fprintf(fp, "symbol at %p", (void*)value().toSymbol()); break; case MIRType_String: - out.printf("string %p", (void*)value().toString()); + fprintf(fp, "string %p", (void*)value().toString()); break; case MIRType_MagicOptimizedArguments: - out.printf("magic lazyargs"); + fprintf(fp, "magic lazyargs"); break; case MIRType_MagicHole: - out.printf("magic hole"); + fprintf(fp, "magic hole"); break; case MIRType_MagicIsConstructing: - out.printf("magic is-constructing"); + fprintf(fp, "magic is-constructing"); break; case MIRType_MagicOptimizedOut: - out.printf("magic optimized-out"); + fprintf(fp, "magic optimized-out"); break; case MIRType_MagicUninitializedLexical: - out.printf("magic uninitialized-lexical"); + fprintf(fp, "magic uninitialized-lexical"); break; default: MOZ_CRASH("unexpected type"); @@ -1005,43 +1001,43 @@ MSimdGeneralShuffle::foldsTo(TempAllocator& alloc) template static void -PrintOpcodeOperation(T* mir, GenericPrinter& out) +PrintOpcodeOperation(T* mir, FILE* fp) { - mir->MDefinition::printOpcode(out); - out.printf(" (%s)", T::OperationName(mir->operation())); + mir->MDefinition::printOpcode(fp); + fprintf(fp, " (%s)", T::OperationName(mir->operation())); } void -MSimdBinaryArith::printOpcode(GenericPrinter& out) const +MSimdBinaryArith::printOpcode(FILE* fp) const { - PrintOpcodeOperation(this, out); + PrintOpcodeOperation(this, fp); } void -MSimdBinaryBitwise::printOpcode(GenericPrinter& out) const +MSimdBinaryBitwise::printOpcode(FILE* fp) const { - PrintOpcodeOperation(this, out); + PrintOpcodeOperation(this, fp); } void -MSimdUnaryArith::printOpcode(GenericPrinter& out) const +MSimdUnaryArith::printOpcode(FILE* fp) const { - PrintOpcodeOperation(this, out); + PrintOpcodeOperation(this, fp); } void -MSimdBinaryComp::printOpcode(GenericPrinter& out) const +MSimdBinaryComp::printOpcode(FILE* fp) const { - PrintOpcodeOperation(this, out); + PrintOpcodeOperation(this, fp); } void -MSimdShift::printOpcode(GenericPrinter& out) const +MSimdShift::printOpcode(FILE* fp) const { - PrintOpcodeOperation(this, out); + PrintOpcodeOperation(this, fp); } void -MSimdInsertElement::printOpcode(GenericPrinter& out) const +MSimdInsertElement::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); - out.printf(" (%s)", MSimdInsertElement::LaneName(lane())); + MDefinition::printOpcode(fp); + fprintf(fp, " (%s)", MSimdInsertElement::LaneName(lane())); } MCloneLiteral* @@ -1051,40 +1047,42 @@ MCloneLiteral::New(TempAllocator& alloc, MDefinition* obj) } void -MControlInstruction::printOpcode(GenericPrinter& out) const +MControlInstruction::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); + MDefinition::printOpcode(fp); for (size_t j = 0; j < numSuccessors(); j++) - out.printf(" block%u", getSuccessor(j)->id()); + fprintf(fp, " block%u", getSuccessor(j)->id()); } void -MCompare::printOpcode(GenericPrinter& out) const +MCompare::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); - out.printf(" %s", js_CodeName[jsop()]); + MDefinition::printOpcode(fp); + fprintf(fp, " %s", js_CodeName[jsop()]); } void -MConstantElements::printOpcode(GenericPrinter& out) const +MConstantElements::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); - out.printf(" %p", value()); + PrintOpcodeName(fp, op()); + fprintf(fp, " %p", value()); } void -MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const +MLoadUnboxedScalar::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); - out.printf(" %s", ScalarTypeDescr::typeName(indexType())); + MDefinition::printOpcode(fp); + fprintf(fp, " %s", ScalarTypeDescr::typeName(indexType())); } void -MAssertRange::printOpcode(GenericPrinter& out) const +MAssertRange::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); - out.put(" "); - assertedRange()->dump(out); + MDefinition::printOpcode(fp); + Sprinter sp(GetJitContext()->cx); + sp.init(); + assertedRange()->print(sp); + fprintf(fp, " %s", sp.string()); } const char* @@ -1121,10 +1119,10 @@ MMathFunction::FunctionName(Function function) } void -MMathFunction::printOpcode(GenericPrinter& out) const +MMathFunction::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); - out.printf(" %s", FunctionName(function())); + MDefinition::printOpcode(fp); + fprintf(fp, " %s", FunctionName(function())); } MDefinition* @@ -1229,13 +1227,13 @@ MParameter::New(TempAllocator& alloc, int32_t index, TemporaryTypeSet* types) } void -MParameter::printOpcode(GenericPrinter& out) const +MParameter::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); + PrintOpcodeName(fp, op()); if (index() == THIS_SLOT) - out.printf(" THIS_SLOT"); + fprintf(fp, " THIS_SLOT"); else - out.printf(" %d", index()); + fprintf(fp, " %d", index()); } HashNumber @@ -1487,37 +1485,37 @@ MGoto::New(TempAllocator& alloc, MBasicBlock* target) } void -MUnbox::printOpcode(GenericPrinter& out) const +MUnbox::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); - out.printf(" "); - getOperand(0)->printName(out); - out.printf(" "); + PrintOpcodeName(fp, op()); + fprintf(fp, " "); + getOperand(0)->printName(fp); + fprintf(fp, " "); switch (type()) { - case MIRType_Int32: out.printf("to Int32"); break; - case MIRType_Double: out.printf("to Double"); break; - case MIRType_Boolean: out.printf("to Boolean"); break; - case MIRType_String: out.printf("to String"); break; - case MIRType_Symbol: out.printf("to Symbol"); break; - case MIRType_Object: out.printf("to Object"); break; + case MIRType_Int32: fprintf(fp, "to Int32"); break; + case MIRType_Double: fprintf(fp, "to Double"); break; + case MIRType_Boolean: fprintf(fp, "to Boolean"); break; + case MIRType_String: fprintf(fp, "to String"); break; + case MIRType_Symbol: fprintf(fp, "to Symbol"); break; + case MIRType_Object: fprintf(fp, "to Object"); break; default: break; } switch (mode()) { - case Fallible: out.printf(" (fallible)"); break; - case Infallible: out.printf(" (infallible)"); break; - case TypeBarrier: out.printf(" (typebarrier)"); break; + case Fallible: fprintf(fp, " (fallible)"); break; + case Infallible: fprintf(fp, " (infallible)"); break; + case TypeBarrier: fprintf(fp, " (typebarrier)"); break; default: break; } } void -MTypeBarrier::printOpcode(GenericPrinter& out) const +MTypeBarrier::printOpcode(FILE* fp) const { - PrintOpcodeName(out, op()); - out.printf(" "); - getOperand(0)->printName(out); + PrintOpcodeName(fp, op()); + fprintf(fp, " "); + getOperand(0)->printName(fp); } bool @@ -3227,41 +3225,39 @@ MResumePoint::addStore(TempAllocator& alloc, MDefinition* store, const MResumePo } void -MResumePoint::dump(GenericPrinter& out) const +MResumePoint::dump(FILE* fp) const { - out.printf("resumepoint mode="); + fprintf(fp, "resumepoint mode="); switch (mode()) { case MResumePoint::ResumeAt: - out.printf("At"); + fprintf(fp, "At"); break; case MResumePoint::ResumeAfter: - out.printf("After"); + fprintf(fp, "After"); break; case MResumePoint::Outer: - out.printf("Outer"); + fprintf(fp, "Outer"); break; } if (MResumePoint* c = caller()) - out.printf(" (caller in block%u)", c->block()->id()); + fprintf(fp, " (caller in block%u)", c->block()->id()); for (size_t i = 0; i < numOperands(); i++) { - out.printf(" "); + fprintf(fp, " "); if (operands_[i].hasProducer()) - getOperand(i)->printName(out); + getOperand(i)->printName(fp); else - out.printf("(null)"); + fprintf(fp, "(null)"); } - out.printf("\n"); + fprintf(fp, "\n"); } void MResumePoint::dump() const { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } bool @@ -3904,12 +3900,18 @@ MNot::trySpecializeFloat32(TempAllocator& alloc) } void -MBeta::printOpcode(GenericPrinter& out) const +MBeta::printOpcode(FILE* fp) const { - MDefinition::printOpcode(out); + MDefinition::printOpcode(fp); - out.printf(" "); - comparison_->dump(out); + if (JitContext* context = MaybeGetJitContext()) { + Sprinter sp(context->cx); + sp.init(); + comparison_->print(sp); + fprintf(fp, " %s", sp.string()); + } else { + fprintf(fp, " ???"); + } } bool diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 89899c09b9ee..08bdf0438226 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -281,7 +281,7 @@ class MNode : public TempObject virtual bool writeRecoverData(CompactBufferWriter& writer) const; - virtual void dump(GenericPrinter& out) const = 0; + virtual void dump(FILE* fp) const = 0; virtual void dump() const = 0; protected: @@ -445,12 +445,12 @@ class MDefinition : public MNode virtual const char* opName() const = 0; virtual void accept(MDefinitionVisitor* visitor) = 0; - void printName(GenericPrinter& out) const; - static void PrintOpcodeName(GenericPrinter& out, Opcode op); - virtual void printOpcode(GenericPrinter& out) const; - void dump(GenericPrinter& out) const override; + void printName(FILE* fp) const; + static void PrintOpcodeName(FILE* fp, Opcode op); + virtual void printOpcode(FILE* fp) const; + void dump(FILE* fp) const override; void dump() const override; - void dumpLocation(GenericPrinter& out) const; + void dumpLocation(FILE* fp) const; void dumpLocation() const; // For LICM. @@ -753,7 +753,9 @@ class MDefinition : public MNode void setVirtualRegister(uint32_t vreg) { virtualRegister_ = vreg; +#ifdef DEBUG setLoweredUnchecked(); +#endif } uint32_t virtualRegister() const { MOZ_ASSERT(isLowered()); @@ -1329,7 +1331,7 @@ class MConstant : public MNullaryInstruction return ToBoolean(HandleValue::fromMarkedLocation(&value_)); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; HashNumber valueHash() const override; bool congruentTo(const MDefinition* ins) const override; @@ -1720,7 +1722,7 @@ class MSimdInsertElement return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; ALLOW_CLONE(MSimdInsertElement) }; @@ -2046,7 +2048,7 @@ class MSimdUnaryArith return congruentIfOperandsEqual(ins) && ins->toSimdUnaryArith()->operation() == operation(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; ALLOW_CLONE(MSimdUnaryArith); }; @@ -2133,7 +2135,7 @@ class MSimdBinaryComp operation_ == other->operation(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; ALLOW_CLONE(MSimdBinaryComp) }; @@ -2202,7 +2204,7 @@ class MSimdBinaryArith return operation_ == ins->toSimdBinaryArith()->operation(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; ALLOW_CLONE(MSimdBinaryArith) }; @@ -2267,7 +2269,7 @@ class MSimdBinaryBitwise return operation_ == ins->toSimdBinaryBitwise()->operation(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; ALLOW_CLONE(MSimdBinaryBitwise) }; @@ -2324,7 +2326,7 @@ class MSimdShift MOZ_CRASH("unexpected operation"); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; bool congruentTo(const MDefinition* ins) const override { if (!binaryCongruentTo(ins)) @@ -2427,7 +2429,7 @@ class MParameter : public MNullaryInstruction int32_t index() const { return index_; } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; HashNumber valueHash() const override; bool congruentTo(const MDefinition* ins) const override; @@ -2493,7 +2495,7 @@ class MControlInstruction : public MInstruction return true; } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; }; class MTableSwitch final @@ -4263,7 +4265,7 @@ class MCompare return AliasSet::None(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; void collectRangeInfoPreTrunc() override; void trySpecializeFloat32(TempAllocator& alloc) override; @@ -4442,7 +4444,7 @@ class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data AliasSet getAliasSet() const override { return AliasSet::None(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; void makeInfallible() { // Should only be called if we're already Infallible or TypeBarrier MOZ_ASSERT(mode() != Fallible); @@ -4554,7 +4556,7 @@ class MAssertRange return AliasSet::None(); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; }; // Caller-side allocation of |this| for |new|: @@ -6088,7 +6090,7 @@ class MMathFunction MDefinition* foldsTo(TempAllocator& alloc) override; - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; static const char* FunctionName(Function function); @@ -6908,7 +6910,7 @@ class MBeta public: INSTRUCTION_HEADER(Beta) - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; static MBeta* New(TempAllocator& alloc, MDefinition* val, const Range* comp) { return new(alloc) MBeta(val, comp); @@ -7659,7 +7661,7 @@ class MConstantElements : public MNullaryInstruction return value_; } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; HashNumber valueHash() const override { return (HashNumber)(size_t) value_; @@ -9240,7 +9242,7 @@ class MLoadUnboxedScalar return congruentIfOperandsEqual(other); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; void computeRange(TempAllocator& alloc) override; @@ -12055,7 +12057,7 @@ class MTypeBarrier return new(alloc) MTypeBarrier(def, types, kind); } - void printOpcode(GenericPrinter& out) const override; + void printOpcode(FILE* fp) const override; bool congruentTo(const MDefinition* def) const override; AliasSet getAliasSet() const override { @@ -12441,7 +12443,7 @@ class MResumePoint final : return stores_.end(); } - virtual void dump(GenericPrinter& out) const override; + virtual void dump(FILE* fp) const override; virtual void dump() const override; }; diff --git a/js/src/jit/MIRGenerator.h b/js/src/jit/MIRGenerator.h index 2e56b4d19d6e..30fcab97eb43 100644 --- a/js/src/jit/MIRGenerator.h +++ b/js/src/jit/MIRGenerator.h @@ -245,14 +245,6 @@ class MIRGenerator } bool needsAsmJSBoundsCheckBranch(const MAsmJSHeapAccess* access) const; size_t foldableOffsetRange(const MAsmJSHeapAccess* access) const; - - private: - GraphSpewer gs_; - - public: - GraphSpewer& graphSpewer() { - return gs_; - } }; } // namespace jit diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index a71c9a4a84de..6e6ae4b7d9eb 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -48,8 +48,7 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti #if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB) usesSignalHandlersForAsmJSOOB_(usesSignalHandlersForAsmJSOOB), #endif - options(options), - gs_(alloc) + options(options) { } bool @@ -1517,6 +1516,19 @@ MBasicBlock::specializePhis() return true; } +void +MBasicBlock::dumpStack(FILE* fp) +{ +#ifdef DEBUG + fprintf(fp, " %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next"); + fprintf(fp, "-------------------------------------------\n"); + for (uint32_t i = 0; i < stackPosition_; i++) { + fprintf(fp, " %-3d", i); + fprintf(fp, " %-16p\n", (void*)slots_[i]); + } +#endif +} + MTest* MBasicBlock::immediateDominatorBranch(BranchDirection* pdirection) { @@ -1546,33 +1558,12 @@ MBasicBlock::immediateDominatorBranch(BranchDirection* pdirection) } void -MBasicBlock::dumpStack(GenericPrinter& out) -{ -#ifdef DEBUG - out.printf(" %-3s %-16s %-6s %-10s\n", "#", "name", "copyOf", "first/next"); - out.printf("-------------------------------------------\n"); - for (uint32_t i = 0; i < stackPosition_; i++) { - out.printf(" %-3d", i); - out.printf(" %-16p\n", (void*)slots_[i]); - } -#endif -} - -void -MBasicBlock::dumpStack() -{ - Fprinter out(stderr); - dumpStack(out); - out.finish(); -} - -void -MIRGraph::dump(GenericPrinter& out) +MIRGraph::dump(FILE* fp) { #ifdef DEBUG for (MBasicBlockIterator iter(begin()); iter != end(); iter++) { - iter->dump(out); - out.printf("\n"); + iter->dump(fp); + fprintf(fp, "\n"); } #endif } @@ -1580,32 +1571,31 @@ MIRGraph::dump(GenericPrinter& out) void MIRGraph::dump() { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } void -MBasicBlock::dump(GenericPrinter& out) +MBasicBlock::dump(FILE* fp) { #ifdef DEBUG - out.printf("block%u:%s%s%s\n", id(), - isLoopHeader() ? " (loop header)" : "", - unreachable() ? " (unreachable)" : "", - isMarked() ? " (marked)" : ""); - if (MResumePoint* resume = entryResumePoint()) - resume->dump(out); - for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++) - iter->dump(out); - for (MInstructionIterator iter(begin()); iter != end(); iter++) - iter->dump(out); + fprintf(fp, "block%u:%s%s%s\n", id(), + isLoopHeader() ? " (loop header)" : "", + unreachable() ? " (unreachable)" : "", + isMarked() ? " (marked)" : ""); + if (MResumePoint* resume = entryResumePoint()) { + resume->dump(); + } + for (MPhiIterator iter(phisBegin()); iter != phisEnd(); iter++) { + iter->dump(fp); + } + for (MInstructionIterator iter(begin()); iter != end(); iter++) { + iter->dump(fp); + } #endif } void MBasicBlock::dump() { - Fprinter out(stderr); - dump(out); - out.finish(); + dump(stderr); } diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 7516161d40b7..11671bb4d713 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -599,10 +599,9 @@ class MBasicBlock : public TempObject, public InlineListNode return info_.script()->strict(); } - void dumpStack(GenericPrinter& out); - void dumpStack(); + void dumpStack(FILE* fp); - void dump(GenericPrinter& out); + void dump(FILE* fp); void dump(); // Track bailouts by storing the current pc in MIR instruction added at @@ -810,7 +809,7 @@ class MIRGraph hasTryBlock_ = true; } - void dump(GenericPrinter& out); + void dump(FILE* fp); void dump(); }; diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index e07e1395e9fb..122a8c9e1600 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -115,10 +115,9 @@ SpewRange(MDefinition* def) #ifdef DEBUG if (JitSpewEnabled(JitSpew_Range) && def->type() != MIRType_None && def->range()) { JitSpewHeader(JitSpew_Range); - Fprinter& out = JitSpewPrinter(); - def->printName(out); - out.printf(" has range "); - def->range()->dump(out); + def->printName(JitSpewFile); + fprintf(JitSpewFile, " has range "); + def->range()->dump(JitSpewFile); } #endif } @@ -282,9 +281,8 @@ RangeAnalysis::addBetaNodes() if (JitSpewEnabled(JitSpew_Range)) { JitSpewHeader(JitSpew_Range); - Fprinter& out = JitSpewPrinter(); - out.printf("Adding beta node for %d with range ", val->id()); - comp.dump(out); + fprintf(JitSpewFile, "Adding beta node for %d with range ", val->id()); + comp.dump(JitSpewFile); } MBeta* beta = MBeta::New(alloc(), val, new(alloc()) Range(comp)); @@ -322,20 +320,20 @@ RangeAnalysis::removeBetaNodes() } void -SymbolicBound::dump(GenericPrinter& out) const +SymbolicBound::print(Sprinter& sp) const { if (loop) - out.printf("[loop] "); - sum.dump(out); + sp.printf("[loop] "); + sum.print(sp); } void SymbolicBound::dump() const { - Fprinter out(stderr); - dump(out); - out.printf("\n"); - out.finish(); + Sprinter sp(GetJitContext()->cx); + sp.init(); + print(sp); + fprintf(stderr, "%s\n", sp.string()); } // Test whether the given range's exponent tells us anything that its lower @@ -358,41 +356,41 @@ IsExponentInteresting(const Range* r) } void -Range::dump(GenericPrinter& out) const +Range::print(Sprinter& sp) const { assertInvariants(); // Floating-point or Integer subset. if (canHaveFractionalPart_) - out.printf("F"); + sp.printf("F"); else - out.printf("I"); + sp.printf("I"); - out.printf("["); + sp.printf("["); if (!hasInt32LowerBound_) - out.printf("?"); + sp.printf("?"); else - out.printf("%d", lower_); + sp.printf("%d", lower_); if (symbolicLower_) { - out.printf(" {"); - symbolicLower_->dump(out); - out.printf("}"); + sp.printf(" {"); + symbolicLower_->print(sp); + sp.printf("}"); } - out.printf(", "); + sp.printf(", "); if (!hasInt32UpperBound_) - out.printf("?"); + sp.printf("?"); else - out.printf("%d", upper_); + sp.printf("%d", upper_); if (symbolicUpper_) { - out.printf(" {"); - symbolicUpper_->dump(out); - out.printf("}"); + sp.printf(" {"); + symbolicUpper_->print(sp); + sp.printf("}"); } - out.printf("]"); + sp.printf("]"); bool includesNaN = max_exponent_ == IncludesInfinityAndNaN; bool includesNegativeInfinity = max_exponent_ >= IncludesInfinity && !hasInt32LowerBound_; @@ -404,49 +402,55 @@ Range::dump(GenericPrinter& out) const includesPositiveInfinity || includesNegativeZero) { - out.printf(" ("); + sp.printf(" ("); bool first = true; if (includesNaN) { if (first) first = false; else - out.printf(" "); - out.printf("U NaN"); + sp.printf(" "); + sp.printf("U NaN"); } if (includesNegativeInfinity) { if (first) first = false; else - out.printf(" "); - out.printf("U -Infinity"); + sp.printf(" "); + sp.printf("U -Infinity"); } if (includesPositiveInfinity) { if (first) first = false; else - out.printf(" "); - out.printf("U Infinity"); + sp.printf(" "); + sp.printf("U Infinity"); } if (includesNegativeZero) { if (first) first = false; else - out.printf(" "); - out.printf("U -0"); + sp.printf(" "); + sp.printf("U -0"); } - out.printf(")"); + sp.printf(")"); } if (max_exponent_ < IncludesInfinity && IsExponentInteresting(this)) - out.printf(" (< pow(2, %d+1))", max_exponent_); + sp.printf(" (< pow(2, %d+1))", max_exponent_); +} + +void +Range::dump(FILE* fp) const +{ + Sprinter sp(GetJitContext()->cx); + sp.init(); + print(sp); + fprintf(fp, "%s\n", sp.string()); } void Range::dump() const { - Fprinter out(stderr); - dump(out); - out.printf("\n"); - out.finish(); + dump(stderr); } Range* @@ -1867,7 +1871,7 @@ RangeAnalysis::analyzeLoop(MBasicBlock* header) if (JitSpewEnabled(JitSpew_Range)) { Sprinter sp(GetJitContext()->cx); sp.init(); - iterationBound->boundSum.dump(sp); + iterationBound->boundSum.print(sp); JitSpew(JitSpew_Range, "computed symbolic bound on backedges: %s", sp.string()); } diff --git a/js/src/jit/RangeAnalysis.h b/js/src/jit/RangeAnalysis.h index 911549881872..df1df4d30d4e 100644 --- a/js/src/jit/RangeAnalysis.h +++ b/js/src/jit/RangeAnalysis.h @@ -81,7 +81,7 @@ struct SymbolicBound : public TempObject // Computed symbolic bound, see above. LinearSum sum; - void dump(GenericPrinter& out) const; + void print(Sprinter& sp) const; void dump() const; }; @@ -450,7 +450,8 @@ class Range : public TempObject { return r; } - void dump(GenericPrinter& out) const; + void print(Sprinter& sp) const; + void dump(FILE* fp) const; void dump() const; bool update(const Range* other); diff --git a/js/src/jit/Safepoints.cpp b/js/src/jit/Safepoints.cpp index f980c73cbc60..3aec50a2229a 100644 --- a/js/src/jit/Safepoints.cpp +++ b/js/src/jit/Safepoints.cpp @@ -205,13 +205,12 @@ SafepointWriter::writeValueSlots(LSafepoint* safepoint) static void DumpNunboxPart(const LAllocation& a) { - Fprinter& out = JitSpewPrinter(); if (a.isStackSlot()) { - out.printf("stack %d", a.toStackSlot()->slot()); + fprintf(JitSpewFile, "stack %d", a.toStackSlot()->slot()); } else if (a.isArgument()) { - out.printf("arg %d", a.toArgument()->index()); + fprintf(JitSpewFile, "arg %d", a.toArgument()->index()); } else { - out.printf("reg %s", a.toGeneralReg()->reg().name()); + fprintf(JitSpewFile, "reg %s", a.toGeneralReg()->reg().name()); } } #endif // DEBUG @@ -296,12 +295,11 @@ SafepointWriter::writeNunboxParts(LSafepoint* safepoint) if (entry.type.isUse() || entry.payload.isUse()) continue; JitSpewHeader(JitSpew_Safepoints); - Fprinter& out = JitSpewPrinter(); - out.printf(" nunbox (type in "); + fprintf(JitSpewFile, " nunbox (type in "); DumpNunboxPart(entry.type); - out.printf(", payload in "); + fprintf(JitSpewFile, ", payload in "); DumpNunboxPart(entry.payload); - out.printf(")\n"); + fprintf(JitSpewFile, ")\n"); } } # endif diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp index 5eeec897255f..fc7d0ff76ef2 100644 --- a/js/src/jit/Snapshots.cpp +++ b/js/src/jit/Snapshots.cpp @@ -16,8 +16,6 @@ #include "jit/MIR.h" #include "jit/Recover.h" -#include "vm/Printer.h" - using namespace js; using namespace js::jit; @@ -421,43 +419,43 @@ ValTypeToString(JSValueType type) } void -RValueAllocation::dumpPayload(GenericPrinter& out, PayloadType type, Payload p) +RValueAllocation::dumpPayload(FILE* fp, PayloadType type, Payload p) { switch (type) { case PAYLOAD_NONE: break; case PAYLOAD_INDEX: - out.printf("index %u", p.index); + fprintf(fp, "index %u", p.index); break; case PAYLOAD_STACK_OFFSET: - out.printf("stack %d", p.stackOffset); + fprintf(fp, "stack %d", p.stackOffset); break; case PAYLOAD_GPR: - out.printf("reg %s", p.gpr.name()); + fprintf(fp, "reg %s", p.gpr.name()); break; case PAYLOAD_FPU: - out.printf("reg %s", p.fpu.name()); + fprintf(fp, "reg %s", p.fpu.name()); break; case PAYLOAD_PACKED_TAG: - out.printf("%s", ValTypeToString(p.type)); + fprintf(fp, "%s", ValTypeToString(p.type)); break; } } void -RValueAllocation::dump(GenericPrinter& out) const +RValueAllocation::dump(FILE* fp) const { const Layout& layout = layoutFromMode(mode()); - out.printf("%s", layout.name); + fprintf(fp, "%s", layout.name); if (layout.type1 != PAYLOAD_NONE) - out.printf(" ("); - dumpPayload(out, layout.type1, arg1_); + fprintf(fp, " ("); + dumpPayload(fp, layout.type1, arg1_); if (layout.type2 != PAYLOAD_NONE) - out.printf(", "); - dumpPayload(out, layout.type2, arg2_); + fprintf(fp, ", "); + dumpPayload(fp, layout.type2, arg2_); if (layout.type1 != PAYLOAD_NONE) - out.printf(")"); + fprintf(fp, ")"); } bool @@ -550,13 +548,12 @@ SnapshotReader::spewBailingFrom() const { if (JitSpewEnabled(JitSpew_IonBailouts)) { JitSpewHeader(JitSpew_IonBailouts); - Fprinter& out = JitSpewPrinter(); - out.printf(" bailing from bytecode: %s, MIR: ", js_CodeName[pcOpcode_]); - MDefinition::PrintOpcodeName(out, MDefinition::Opcode(mirOpcode_)); - out.printf(" [%u], LIR: ", mirId_); - LInstruction::printName(out, LInstruction::Opcode(lirOpcode_)); - out.printf(" [%u]", lirId_); - out.printf("\n"); + fprintf(JitSpewFile, " bailing from bytecode: %s, MIR: ", js_CodeName[pcOpcode_]); + MDefinition::PrintOpcodeName(JitSpewFile, MDefinition::Opcode(mirOpcode_)); + fprintf(JitSpewFile, " [%u], LIR: ", mirId_); + LInstruction::printName(JitSpewFile, LInstruction::Opcode(lirOpcode_)); + fprintf(JitSpewFile, " [%u]", lirId_); + fprintf(JitSpewFile, "\n"); } } #endif @@ -669,10 +666,9 @@ SnapshotWriter::add(const RValueAllocation& alloc) if (JitSpewEnabled(JitSpew_IonSnapshots)) { JitSpewHeader(JitSpew_IonSnapshots); - Fprinter& out = JitSpewPrinter(); - out.printf(" slot %u (%d): ", allocWritten_, offset); - alloc.dump(out); - out.printf("\n"); + fprintf(JitSpewFile, " slot %u (%d): ", allocWritten_, offset); + alloc.dump(JitSpewFile); + fprintf(JitSpewFile, "\n"); } allocWritten_++; diff --git a/js/src/jit/Snapshots.h b/js/src/jit/Snapshots.h index ace4b565082a..66b9a81030dd 100644 --- a/js/src/jit/Snapshots.h +++ b/js/src/jit/Snapshots.h @@ -19,8 +19,6 @@ #include "js/HashTable.h" namespace js { -class GenericPrinter; - namespace jit { class RValueAllocation; @@ -167,7 +165,7 @@ class RValueAllocation static void writePayload(CompactBufferWriter& writer, PayloadType t, Payload p); static void writePadding(CompactBufferWriter& writer); - static void dumpPayload(GenericPrinter& out, PayloadType t, Payload p); + static void dumpPayload(FILE* fp, PayloadType t, Payload p); static bool equalPayloads(PayloadType t, Payload lhs, Payload rhs); RValueAllocation(Mode mode, Payload a1, Payload a2) @@ -336,7 +334,7 @@ class RValueAllocation } public: - void dump(GenericPrinter& out) const; + void dump(FILE* fp) const; public: bool operator==(const RValueAllocation& rhs) const { diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 32b9d0f5bd81..6adb4c895a5c 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -13,6 +13,7 @@ #include "mozilla/SizePrintfMacros.h" #include +#include #include #include @@ -824,6 +825,9 @@ js::DumpScript(JSContext* cx, JSScript* scriptArg) return ok; } +static char* +QuoteString(Sprinter* sp, JSString* str, char16_t quote); + static bool ToDisassemblySource(JSContext* cx, HandleValue v, JSAutoByteString* bytes) { @@ -1083,6 +1087,336 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc, #endif /* DEBUG */ +/************************************************************************/ + +const size_t Sprinter::DefaultSize = 64; + +bool +Sprinter::realloc_(size_t newSize) +{ + MOZ_ASSERT(newSize > (size_t) offset); + char* newBuf = (char*) js_realloc(base, newSize); + if (!newBuf) { + reportOutOfMemory(); + return false; + } + base = newBuf; + size = newSize; + base[size - 1] = 0; + return true; +} + +Sprinter::Sprinter(ExclusiveContext* cx) + : context(cx), +#ifdef DEBUG + initialized(false), +#endif + base(nullptr), size(0), offset(0), reportedOOM(false) +{ } + +Sprinter::~Sprinter() +{ +#ifdef DEBUG + if (initialized) + checkInvariants(); +#endif + js_free(base); +} + +bool +Sprinter::init() +{ + MOZ_ASSERT(!initialized); + base = (char*) js_malloc(DefaultSize); + if (!base) { + reportOutOfMemory(); + return false; + } +#ifdef DEBUG + initialized = true; +#endif + *base = 0; + size = DefaultSize; + base[size - 1] = 0; + return true; +} + +void +Sprinter::checkInvariants() const +{ + MOZ_ASSERT(initialized); + MOZ_ASSERT((size_t) offset < size); + MOZ_ASSERT(base[size - 1] == 0); +} + +const char* +Sprinter::string() const +{ + return base; +} + +const char* +Sprinter::stringEnd() const +{ + return base + offset; +} + +char* +Sprinter::stringAt(ptrdiff_t off) const +{ + MOZ_ASSERT(off >= 0 && (size_t) off < size); + return base + off; +} + +char& +Sprinter::operator[](size_t off) +{ + MOZ_ASSERT(off < size); + return *(base + off); +} + +char* +Sprinter::reserve(size_t len) +{ + InvariantChecker ic(this); + + while (len + 1 > size - offset) { /* Include trailing \0 */ + if (!realloc_(size * 2)) + return nullptr; + } + + char* sb = base + offset; + offset += len; + return sb; +} + +ptrdiff_t +Sprinter::put(const char* s, size_t len) +{ + InvariantChecker ic(this); + + const char* oldBase = base; + const char* oldEnd = base + size; + + ptrdiff_t oldOffset = offset; + char* bp = reserve(len); + if (!bp) + return -1; + + /* s is within the buffer already */ + if (s >= oldBase && s < oldEnd) { + /* buffer was realloc'ed */ + if (base != oldBase) + s = stringAt(s - oldBase); /* this is where it lives now */ + memmove(bp, s, len); + } else { + js_memcpy(bp, s, len); + } + + bp[len] = 0; + return oldOffset; +} + +ptrdiff_t +Sprinter::put(const char* s) +{ + return put(s, strlen(s)); +} + +ptrdiff_t +Sprinter::putString(JSString* s) +{ + InvariantChecker ic(this); + + size_t length = s->length(); + size_t size = length; + + ptrdiff_t oldOffset = offset; + char* buffer = reserve(size); + if (!buffer) + return -1; + + JSLinearString* linear = s->ensureLinear(context); + if (!linear) + return -1; + + AutoCheckCannotGC nogc; + if (linear->hasLatin1Chars()) + mozilla::PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc), length); + else + DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size); + + buffer[size] = 0; + return oldOffset; +} + +int +Sprinter::printf(const char* fmt, ...) +{ + InvariantChecker ic(this); + + do { + va_list va; + va_start(va, fmt); + int i = vsnprintf(base + offset, size - offset, fmt, va); + va_end(va); + + if (i > -1 && (size_t) i < size - offset) { + offset += i; + return i; + } + } while (realloc_(size * 2)); + + return -1; +} + +ptrdiff_t +Sprinter::getOffset() const +{ + return offset; +} + +void +Sprinter::reportOutOfMemory() +{ + if (reportedOOM) + return; + if (context) + ReportOutOfMemory(context); + reportedOOM = true; +} + +bool +Sprinter::hadOutOfMemory() const +{ + return reportedOOM; +} + +ptrdiff_t +js::Sprint(Sprinter* sp, const char* format, ...) +{ + va_list ap; + char* bp; + ptrdiff_t offset; + + va_start(ap, format); + bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ + va_end(ap); + if (!bp) { + sp->reportOutOfMemory(); + return -1; + } + offset = sp->put(bp); + js_free(bp); + return offset; +} + +const char js_EscapeMap[] = { + '\b', 'b', + '\f', 'f', + '\n', 'n', + '\r', 'r', + '\t', 't', + '\v', 'v', + '"', '"', + '\'', '\'', + '\\', '\\', + '\0' +}; + +template +static char* +QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote) +{ + /* Sample off first for later return value pointer computation. */ + ptrdiff_t offset = sp->getOffset(); + + if (quote && Sprint(sp, "%c", char(quote)) < 0) + return nullptr; + + const CharT* end = s + length; + + /* Loop control variables: end points at end of string sentinel. */ + for (const CharT* t = s; t < end; s = ++t) { + /* Move t forward from s past un-quote-worthy characters. */ + char16_t c = *t; + while (c < 127 && isprint(c) && c != quote && c != '\\' && c != '\t') { + c = *++t; + if (t == end) + break; + } + + { + ptrdiff_t len = t - s; + ptrdiff_t base = sp->getOffset(); + if (!sp->reserve(len)) + return nullptr; + + for (ptrdiff_t i = 0; i < len; ++i) + (*sp)[base + i] = char(*s++); + (*sp)[base + len] = 0; + } + + if (t == end) + break; + + /* Use js_EscapeMap, \u, or \x only if necessary. */ + const char* escape; + if (!(c >> 8) && c != 0 && (escape = strchr(js_EscapeMap, int(c))) != nullptr) { + if (Sprint(sp, "\\%c", escape[1]) < 0) + return nullptr; + } else { + /* + * Use \x only if the high byte is 0 and we're in a quoted string, + * because ECMA-262 allows only \u, not \x, in Unicode identifiers + * (see bug 621814). + */ + if (Sprint(sp, (quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c) < 0) + return nullptr; + } + } + + /* Sprint the closing quote and return the quoted string. */ + if (quote && Sprint(sp, "%c", char(quote)) < 0) + return nullptr; + + /* + * If we haven't Sprint'd anything yet, Sprint an empty string so that + * the return below gives a valid result. + */ + if (offset == sp->getOffset() && Sprint(sp, "") < 0) + return nullptr; + + return sp->stringAt(offset); +} + +static char* +QuoteString(Sprinter* sp, JSString* str, char16_t quote) +{ + JSLinearString* linear = str->ensureLinear(sp->context); + if (!linear) + return nullptr; + + AutoCheckCannotGC nogc; + return linear->hasLatin1Chars() + ? QuoteString(sp, linear->latin1Chars(nogc), linear->length(), quote) + : QuoteString(sp, linear->twoByteChars(nogc), linear->length(), quote); +} + +JSString* +js::QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote) +{ + Sprinter sprinter(cx); + if (!sprinter.init()) + return nullptr; + char* bytes = QuoteString(&sprinter, str, quote); + if (!bytes) + return nullptr; + return NewStringCopyZ(cx, bytes); +} + +/************************************************************************/ + namespace { /* * The expression decompiler is invoked by error handling code to produce a diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index 3e828b53a160..6d6794600f7a 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -19,7 +19,6 @@ #include "frontend/SourceNotes.h" #include "vm/Opcodes.h" -#include "vm/Printer.h" /* * JS operation bytecodes. @@ -383,6 +382,7 @@ struct JSCodeSpec { extern const JSCodeSpec js_CodeSpec[]; extern const unsigned js_NumCodeSpecs; extern const char * const js_CodeName[]; +extern const char js_EscapeMap[]; /* Shorthand for type from opcode. */ @@ -400,6 +400,14 @@ JOF_OPTYPE(JSOp op) namespace js { +/* + * Return a GC'ed string containing the chars in str, with any non-printing + * chars or quotes (' or " as specified by the quote argument) escaped, and + * with the quote character at the beginning and end of the result string. + */ +extern JSString* +QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote); + static inline bool IsJumpOpcode(JSOp op) { @@ -569,6 +577,89 @@ DecompileValueGenerator(JSContext* cx, int spindex, HandleValue v, char* DecompileArgument(JSContext* cx, int formalIndex, HandleValue v); +/* + * Sprintf, but with unlimited and automatically allocated buffering. + */ +class Sprinter +{ + public: + struct InvariantChecker + { + const Sprinter* parent; + + explicit InvariantChecker(const Sprinter* p) : parent(p) { + parent->checkInvariants(); + } + + ~InvariantChecker() { + parent->checkInvariants(); + } + }; + + ExclusiveContext* context; /* context executing the decompiler */ + + private: + static const size_t DefaultSize; +#ifdef DEBUG + bool initialized; /* true if this is initialized, use for debug builds */ +#endif + char* base; /* malloc'd buffer address */ + size_t size; /* size of buffer allocated at base */ + ptrdiff_t offset; /* offset of next free char in buffer */ + bool reportedOOM; /* this sprinter has reported OOM in string ops */ + + bool realloc_(size_t newSize); + + public: + explicit Sprinter(ExclusiveContext* cx); + ~Sprinter(); + + /* Initialize this sprinter, returns false on error */ + bool init(); + + void checkInvariants() const; + + const char* string() const; + const char* stringEnd() const; + /* Returns the string at offset |off| */ + char* stringAt(ptrdiff_t off) const; + /* Returns the char at offset |off| */ + char& operator[](size_t off); + + /* + * Attempt to reserve len + 1 space (for a trailing nullptr byte). If the + * attempt succeeds, return a pointer to the start of that space and adjust the + * internal content. The caller *must* completely fill this space on success. + */ + char* reserve(size_t len); + + /* + * Puts |len| characters from |s| at the current position and return an offset to + * the beginning of this new data + */ + ptrdiff_t put(const char* s, size_t len); + ptrdiff_t put(const char* s); + ptrdiff_t putString(JSString* str); + + /* Prints a formatted string into the buffer */ + int printf(const char* fmt, ...); + + ptrdiff_t getOffset() const; + + /* + * Report that a string operation failed to get the memory it requested. The + * first call to this function calls JS_ReportOutOfMemory, and sets this + * Sprinter's outOfMemory flag; subsequent calls do nothing. + */ + void reportOutOfMemory(); + + /* Return true if this Sprinter ran out of memory. */ + bool hadOutOfMemory() const; +}; + +extern ptrdiff_t +Sprint(Sprinter* sp, const char* format, ...); + extern bool CallResultEscapes(jsbytecode* pc); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index ba324ef00fef..5d90ab2dfa4f 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1373,6 +1373,7 @@ class JSScript : public js::gc::TenuredCell if (hasIonScript()) js::jit::IonScript::writeBarrierPre(zone(), ion); ion = ionScript; + resetWarmUpResetCounter(); MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript()); updateBaselineOrIonRaw(maybecx); } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 73e37e12d94a..eba322e566af 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -39,7 +39,6 @@ #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/Opcodes.h" -#include "vm/Printer.h" #include "vm/RegExpObject.h" #include "vm/RegExpStatics.h" #include "vm/ScopeObject.h" @@ -5040,19 +5039,19 @@ js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char) } size_t -js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str, +js::PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, JSLinearString* str, uint32_t quote) { size_t len = str->length(); AutoCheckCannotGC nogc; return str->hasLatin1Chars() - ? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote) - : PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote); + ? PutEscapedStringImpl(buffer, bufferSize, fp, str->latin1Chars(nogc), len, quote) + : PutEscapedStringImpl(buffer, bufferSize, fp, str->twoByteChars(nogc), len, quote); } template size_t -js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars, +js::PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, const CharT* chars, size_t length, uint32_t quote) { enum { @@ -5061,7 +5060,7 @@ js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, c MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"'); MOZ_ASSERT_IF(!buffer, bufferSize == 0); - MOZ_ASSERT_IF(out, !buffer); + MOZ_ASSERT_IF(fp, !buffer); if (bufferSize == 0) buffer = nullptr; @@ -5150,8 +5149,8 @@ js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, c buffer[n] = '\0'; buffer = nullptr; } - } else if (out) { - if (out->put(&c, 1) < 0) + } else if (fp) { + if (fputc(c, fp) < 0) return size_t(-1); } n++; @@ -5163,15 +5162,15 @@ js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, c } template size_t -js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars, +js::PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, const Latin1Char* chars, size_t length, uint32_t quote); template size_t -js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars, +js::PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, const char* chars, size_t length, uint32_t quote); template size_t -js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars, +js::PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, const char16_t* chars, size_t length, uint32_t quote); template size_t diff --git a/js/src/jsstr.h b/js/src/jsstr.h index ee8f1685c826..feec7846e1e4 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -16,7 +16,6 @@ #include "gc/Rooting.h" #include "js/RootingAPI.h" -#include "vm/Printer.h" #include "vm/Unicode.h" class JSAutoByteString; @@ -343,12 +342,11 @@ extern int OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char); extern size_t -PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str, - uint32_t quote); +PutEscapedStringImpl(char* buffer, size_t size, FILE* fp, JSLinearString* str, uint32_t quote); template extern size_t -PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars, +PutEscapedStringImpl(char* buffer, size_t bufferSize, FILE* fp, const CharT* chars, size_t length, uint32_t quote); /* @@ -381,18 +379,6 @@ PutEscapedString(char* buffer, size_t bufferSize, const CharT* chars, size_t len return n; } -inline bool -EscapedStringPrinter(GenericPrinter& out, JSLinearString* str, uint32_t quote) -{ - return PutEscapedStringImpl(nullptr, 0, &out, str, quote) != size_t(-1); -} - -inline bool -EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint32_t quote) -{ - return PutEscapedStringImpl(nullptr, 0, &out, chars, length, quote) != size_t(-1); -} - /* * Write str into file escaping any non-printable or non-ASCII character. * If quote is not 0, it must be a single or double quote character that @@ -401,19 +387,13 @@ EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint inline bool FileEscapedString(FILE* fp, JSLinearString* str, uint32_t quote) { - Fprinter out(fp); - bool res = EscapedStringPrinter(out, str, quote); - out.finish(); - return res; + return PutEscapedStringImpl(nullptr, 0, fp, str, quote) != size_t(-1); } inline bool FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote) { - Fprinter out(fp); - bool res = EscapedStringPrinter(out, chars, length, quote); - out.finish(); - return res; + return PutEscapedStringImpl(nullptr, 0, fp, chars, length, quote) != size_t(-1); } bool diff --git a/js/src/moz.build b/js/src/moz.build index 578e83f7c7f2..2ed1c73b86d6 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -295,7 +295,6 @@ UNIFIED_SOURCES += [ 'vm/NativeObject.cpp', 'vm/ObjectGroup.cpp', 'vm/PIC.cpp', - 'vm/Printer.cpp', 'vm/Probes.cpp', 'vm/ProxyObject.cpp', 'vm/ReceiverGuard.cpp', diff --git a/js/src/vm/Debugger-inl.h b/js/src/vm/Debugger-inl.h index f61f6bebb98a..007267b3be5d 100644 --- a/js/src/vm/Debugger-inl.h +++ b/js/src/vm/Debugger-inl.h @@ -58,27 +58,4 @@ js::Debugger::onExceptionUnwind(JSContext* cx, AbstractFramePtr frame) return slowPathOnExceptionUnwind(cx, frame); } -/* static */ bool -js::Debugger::observesIonCompilation(JSContext* cx) -{ - // If the current compartment is observed by any Debugger. - if (!cx->compartment()->isDebuggee()) - return false; - - // If any attached Debugger watch for Jit compilation results. - if (!Debugger::hasLiveHook(cx->global(), Debugger::OnIonCompilation)) - return false; - - return true; -} - -/* static */ void -js::Debugger::onIonCompilation(JSContext* cx, AutoScriptVector& scripts, LSprinter& graph) -{ - if (!observesIonCompilation(cx)) - return; - - slowPathOnIonCompilation(cx, scripts, graph); -} - #endif /* vm_Debugger_inl_h */ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 49641de1f36e..808a75892b1f 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -20,8 +20,6 @@ #include "gc/Marking.h" #include "jit/BaselineDebugModeOSR.h" #include "jit/BaselineJIT.h" -#include "jit/JSONSpewer.h" -#include "jit/MIRGraph.h" #include "js/GCAPI.h" #include "js/UbiNodeTraverse.h" #include "js/Vector.h" @@ -542,15 +540,33 @@ Debugger::hasAnyLiveHooks() const /* static */ JSTrapStatus Debugger::slowPathOnEnterFrame(JSContext* cx, AbstractFramePtr frame) { + // Build the list of recipients. + AutoValueVector triggered(cx); + Handle global = cx->global(); + + if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) { + for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) { + Debugger* dbg = *p; + if (dbg->observesFrame(frame) && dbg->observesEnterFrame() && + !triggered.append(ObjectValue(*dbg->toJSObject()))) + { + cx->clearPendingException(); + return JSTRAP_ERROR; + } + } + } + + JSTrapStatus status = JSTRAP_CONTINUE; RootedValue rval(cx); - JSTrapStatus status = dispatchHook( - cx, - [frame](Debugger* dbg) -> bool { - return dbg->observesFrame(frame) && dbg->observesEnterFrame(); - }, - [&](Debugger* dbg) -> JSTrapStatus { - return dbg->fireEnterFrame(cx, frame, &rval); - }); + // Deliver the event, checking again as in dispatchHook. + for (Value* p = triggered.begin(); p != triggered.end(); p++) { + Debugger* dbg = Debugger::fromJSObject(&p->toObject()); + if (dbg->debuggees.has(global) && dbg->observesEnterFrame()) { + status = dbg->fireEnterFrame(cx, frame, &rval); + if (status != JSTRAP_CONTINUE) + break; + } + } switch (status) { case JSTRAP_CONTINUE: @@ -689,12 +705,7 @@ Debugger::slowPathOnLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool frame Debugger::slowPathOnDebuggerStatement(JSContext* cx, AbstractFramePtr frame) { RootedValue rval(cx); - JSTrapStatus status = dispatchHook( - cx, - [](Debugger* dbg) -> bool { return dbg->getHook(OnDebuggerStatement); }, - [&](Debugger* dbg) -> JSTrapStatus { - return dbg->fireDebuggerStatement(cx, &rval); - }); + JSTrapStatus status = dispatchHook(cx, &rval, OnDebuggerStatement, NullPtr()); switch (status) { case JSTRAP_CONTINUE: @@ -725,12 +736,7 @@ Debugger::slowPathOnExceptionUnwind(JSContext* cx, AbstractFramePtr frame) return JSTRAP_CONTINUE; RootedValue rval(cx); - JSTrapStatus status = dispatchHook( - cx, - [](Debugger* dbg) -> bool { return dbg->getHook(OnExceptionUnwind); }, - [&](Debugger* dbg) -> JSTrapStatus { - return dbg->fireExceptionUnwind(cx, &rval); - }); + JSTrapStatus status = dispatchHook(cx, &rval, OnExceptionUnwind, NullPtr()); switch (status) { case JSTRAP_CONTINUE: @@ -1286,80 +1292,14 @@ Debugger::fireOnGarbageCollectionHook(JSContext* cx, handleUncaughtException(ac, true); } -JSTrapStatus -Debugger::fireOnIonCompilationHook(JSContext* cx, AutoScriptVector& scripts, LSprinter& graph) -{ - RootedObject hook(cx, getHook(OnIonCompilation)); - MOZ_ASSERT(hook); - MOZ_ASSERT(hook->isCallable()); - - Maybe ac; - ac.emplace(cx, object); - - // Copy the vector of scripts to a JS Array of Debugger.Script - RootedObject tmpObj(cx); - RootedValue tmpVal(cx); - AutoValueVector dbgScripts(cx); - for (size_t i = 0; i < scripts.length(); i++) { - tmpObj = wrapScript(cx, scripts[i]); - if (!tmpObj) - return handleUncaughtException(ac, false); - - tmpVal.setObject(*tmpObj); - if (!dbgScripts.append(tmpVal)) - return handleUncaughtException(ac, false); - } - - RootedObject dbgScriptsArray(cx, JS_NewArrayObject(cx, dbgScripts)); - if (!dbgScriptsArray) - return handleUncaughtException(ac, false); - - // Copy the JSON compilation graph to a JS String which is allocated as part - // of the Debugger compartment. - Sprinter jsonPrinter(cx); - if (!jsonPrinter.init()) - return handleUncaughtException(ac, false); - - graph.exportInto(jsonPrinter); - if (jsonPrinter.hadOutOfMemory()) - return handleUncaughtException(ac, false); - - RootedString json(cx, JS_NewStringCopyZ(cx, jsonPrinter.string())); - if (!json) - return handleUncaughtException(ac, false); - - // Create a JS Object which has the array of scripts, and the string of the - // JSON graph. - const char* names[] = { "scripts", "json" }; - JS::AutoValueArray<2> values(cx); - values[0].setObject(*dbgScriptsArray); - values[1].setString(json); - - RootedObject obj(cx, JS_NewObject(cx, nullptr)); - if (!obj) - return handleUncaughtException(ac, false); - - MOZ_ASSERT(mozilla::ArrayLength(names) == values.length()); - for (size_t i = 0; i < mozilla::ArrayLength(names); i++) { - if (!JS_DefineProperty(cx, obj, names[i], values[i], JSPROP_ENUMERATE, nullptr, nullptr)) - return handleUncaughtException(ac, false); - } - - // Call Debugger.onIonCompilation hook. - JS::AutoValueArray<1> argv(cx); - argv[0].setObject(*obj); - - RootedValue rv(cx); - if (!Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv.begin(), &rv)) - return handleUncaughtException(ac, true); - return JSTRAP_CONTINUE; -} - -template /* static */ JSTrapStatus -Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFun fireHook) +Debugger::dispatchHook(JSContext* cx, MutableHandleValue vp, Hook which, HandleObject payload) { + MOZ_ASSERT(which == OnDebuggerStatement || + which == OnExceptionUnwind || + which == OnNewPromise || + which == OnPromiseSettled); + /* * Determine which debuggers will receive this event, and in what order. * Make a copy of the list, since the original is mutable and we will be @@ -1373,7 +1313,7 @@ Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFu if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) { for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) { Debugger* dbg = *p; - if (dbg->enabled && hookIsEnabled(dbg)) { + if (dbg->enabled && dbg->getHook(which)) { if (!triggered.append(ObjectValue(*dbg->toJSObject()))) return JSTRAP_ERROR; } @@ -1386,8 +1326,23 @@ Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFu */ for (Value* p = triggered.begin(); p != triggered.end(); p++) { Debugger* dbg = Debugger::fromJSObject(&p->toObject()); - if (dbg->debuggees.has(global) && dbg->enabled && hookIsEnabled(dbg)) { - JSTrapStatus st = fireHook(dbg); + if (dbg->debuggees.has(global) && dbg->enabled && dbg->getHook(which)) { + JSTrapStatus st; + switch (which) { + case OnDebuggerStatement: + st = dbg->fireDebuggerStatement(cx, vp); + break; + case OnExceptionUnwind: + st = dbg->fireExceptionUnwind(cx, vp); + break; + case OnNewPromise: + case OnPromiseSettled: + st = dbg->firePromiseHook(cx, which, payload, vp); + break; + default: + MOZ_ASSERT_UNREACHABLE("Unexpected debugger hook"); + st = JSTRAP_CONTINUE; + } if (st != JSTRAP_CONTINUE) return st; } @@ -1398,22 +1353,39 @@ Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFu void Debugger::slowPathOnNewScript(JSContext* cx, HandleScript script) { - JSTrapStatus status = dispatchHook( - cx, - [script](Debugger* dbg) -> bool { - return dbg->observesNewScript() && dbg->observesScript(script); - }, - [&](Debugger* dbg) -> JSTrapStatus { - dbg->fireNewScript(cx, script); - return JSTRAP_CONTINUE; - }); + Rooted global(cx, &script->global()); - if (status == JSTRAP_ERROR) { - ReportOutOfMemory(cx); - return; + /* + * Build the list of recipients based on the debuggers observing the + * script's compartment. + */ + AutoValueVector triggered(cx); + GlobalObject::DebuggerVector* debuggers = global->getDebuggers(); + if (debuggers) { + for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) { + Debugger* dbg = *p; + if (dbg->observesNewScript() && dbg->observesScript(script)) { + if (!triggered.append(ObjectValue(*dbg->toJSObject()))) { + ReportOutOfMemory(cx); + return; + } + } + } } - MOZ_ASSERT(status == JSTRAP_CONTINUE); + /* + * Deliver the event to each debugger, checking again as in + * Debugger::dispatchHook. + */ + for (Value* p = triggered.begin(); p != triggered.end(); p++) { + Debugger* dbg = Debugger::fromJSObject(&p->toObject()); + if (dbg->debuggees.has(global) && + dbg->enabled && + dbg->getHook(OnNewScript)) + { + dbg->fireNewScript(cx, script); + } + } } /* static */ JSTrapStatus @@ -1673,25 +1645,6 @@ Debugger::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSav return true; } -/* static */ void -Debugger::slowPathOnIonCompilation(JSContext* cx, AutoScriptVector& scripts, LSprinter& graph) -{ - JSTrapStatus status = dispatchHook( - cx, - [](Debugger* dbg) -> bool { return dbg->getHook(OnIonCompilation); }, - [&](Debugger* dbg) -> JSTrapStatus { - (void) dbg->fireOnIonCompilationHook(cx, scripts, graph); - return JSTRAP_CONTINUE; - }); - - if (status == JSTRAP_ERROR) { - cx->clearPendingException(); - return; - } - - MOZ_ASSERT(status == JSTRAP_CONTINUE); -} - bool Debugger::isDebuggee(const JSCompartment* compartment) const { @@ -1795,24 +1748,9 @@ Debugger::slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise) MOZ_ASSERT(hook == OnNewPromise || hook == OnPromiseSettled); RootedValue rval(cx); - JSTrapStatus status = dispatchHook( - cx, - [hook](Debugger* dbg) -> bool { return dbg->getHook(hook); }, - [&](Debugger* dbg) -> JSTrapStatus { - (void) dbg->firePromiseHook(cx, hook, promise, &rval); - return JSTRAP_CONTINUE; - }); - - if (status == JSTRAP_ERROR) { - // The dispatch hook function might fail to append into the list of - // Debuggers which are watching for the hook. - cx->clearPendingException(); - return; - } - // Promise hooks are infallible and we ignore errors from uncaught // exceptions by design. - MOZ_ASSERT(status == JSTRAP_CONTINUE); + (void) dispatchHook(cx, &rval, hook, promise); } @@ -2905,20 +2843,6 @@ Debugger::getMemory(JSContext* cx, unsigned argc, Value* vp) return true; } -/* static */ bool -Debugger::getOnIonCompilation(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER(cx, argc, vp, "(get onIonCompilation)", args, dbg); - return getHookImpl(cx, args, *dbg, OnIonCompilation); -} - -/* static */ bool -Debugger::setOnIonCompilation(JSContext* cx, unsigned argc, Value* vp) -{ - THIS_DEBUGGER(cx, argc, vp, "(set onIonCompilation)", args, dbg); - return setHookImpl(cx, args, *dbg, OnIonCompilation); -} - /* * Given a value used to designate a global (there's quite a variety; see the * docs), return the actual designee. @@ -4334,7 +4258,6 @@ const JSPropertySpec Debugger::properties[] = { JS_PSGS("allowUnobservedAsmJS", Debugger::getAllowUnobservedAsmJS, Debugger::setAllowUnobservedAsmJS, 0), JS_PSG("memory", Debugger::getMemory, 0), - JS_PSGS("onIonCompilation", Debugger::getOnIonCompilation, Debugger::setOnIonCompilation, 0), JS_PS_END }; const JSFunctionSpec Debugger::methods[] = { diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 472b3c25cc10..a4bb68a89f55 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -35,8 +35,6 @@ enum JSTrapStatus { namespace js { -class LSprinter; - class Breakpoint; class DebuggerMemory; @@ -206,7 +204,6 @@ class Debugger : private mozilla::LinkedListElement OnNewPromise, OnPromiseSettled, OnGarbageCollection, - OnIonCompilation, HookCount }; enum { @@ -482,8 +479,6 @@ class Debugger : private mozilla::LinkedListElement static bool getAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp); static bool setAllowUnobservedAsmJS(JSContext* cx, unsigned argc, Value* vp); static bool getMemory(JSContext* cx, unsigned argc, Value* vp); - static bool getOnIonCompilation(JSContext* cx, unsigned argc, Value* vp); - static bool setOnIonCompilation(JSContext* cx, unsigned argc, Value* vp); static bool addDebuggee(JSContext* cx, unsigned argc, Value* vp); static bool addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp); static bool removeDebuggee(JSContext* cx, unsigned argc, Value* vp); @@ -551,12 +546,8 @@ class Debugger : private mozilla::LinkedListElement static bool slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame, int64_t when, GlobalObject::DebuggerVector& dbgs); static void slowPathPromiseHook(JSContext* cx, Hook hook, HandleObject promise); - static void slowPathOnIonCompilation(JSContext* cx, AutoScriptVector& scripts, LSprinter& graph); - - template - static JSTrapStatus dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, - FireHookFun fireHook); + static JSTrapStatus dispatchHook(JSContext* cx, MutableHandleValue vp, Hook which, + HandleObject payload); JSTrapStatus fireDebuggerStatement(JSContext* cx, MutableHandleValue vp); JSTrapStatus fireExceptionUnwind(JSContext* cx, MutableHandleValue vp); @@ -589,13 +580,6 @@ class Debugger : private mozilla::LinkedListElement void fireOnGarbageCollectionHook(JSContext* cx, const JS::dbg::GarbageCollectionEvent::Ptr& gcData); - /* - * Receive a "Ion compilation" event from the engine. An Ion compilation with - * the given summary just got linked. - */ - JSTrapStatus fireOnIonCompilationHook(JSContext* cx, AutoScriptVector& scripts, - LSprinter& graph); - /* * Gets a Debugger.Frame object. If maybeIter is non-null, we eagerly copy * its data if we need to make a new Debugger.Frame. @@ -713,8 +697,6 @@ class Debugger : private mozilla::LinkedListElement static inline void onNewGlobalObject(JSContext* cx, Handle global); static inline bool onLogAllocationSite(JSContext* cx, JSObject* obj, HandleSavedFrame frame, int64_t when); - static inline bool observesIonCompilation(JSContext* cx); - static inline void onIonCompilation(JSContext* cx, AutoScriptVector& scripts, LSprinter& graph); static JSTrapStatus onTrap(JSContext* cx, MutableHandleValue vp); static JSTrapStatus onSingleStep(JSContext* cx, MutableHandleValue vp); static bool handleBaselineOsr(JSContext* cx, InterpreterFrame* from, jit::BaselineFrame* to); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 0e528e2b605b..536fd45b668a 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1054,7 +1054,6 @@ HelperThread::handleAsmJSWorkload() &asmData->mir->alloc()); int64_t before = PRMJ_Now(); - jit::AutoSpewEndFunction spewEndFunction(asmData->mir); if (!OptimizeMIR(asmData->mir)) break; diff --git a/js/src/vm/Printer.cpp b/js/src/vm/Printer.cpp deleted file mode 100644 index bff27d7e96be..000000000000 --- a/js/src/vm/Printer.cpp +++ /dev/null @@ -1,609 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "vm/Printer.h" - -#include -#include -#include - -#include "jscntxt.h" -#include "jsprf.h" -#include "jsutil.h" - -#include "ds/LifoAlloc.h" - -namespace js { - -GenericPrinter::GenericPrinter() - : reportedOOM_(false) -{ -} - -void -GenericPrinter::reportOutOfMemory() -{ - if (reportedOOM_) - return; - reportedOOM_ = true; -} - -bool -GenericPrinter::hadOutOfMemory() const -{ - return reportedOOM_; -} - -int -GenericPrinter::put(const char* s) -{ - return put(s, strlen(s)); -} - -int -GenericPrinter::printf(const char* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int i = vprintf(fmt, va); - va_end(va); - return i; -} - -int -GenericPrinter::vprintf(const char* fmt, va_list ap) -{ - // Simple shortcut to avoid allocating strings. - if (strchr(fmt, '%') == nullptr) - return put(fmt); - - char* bp; - bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */ - if (!bp) { - reportOutOfMemory(); - return -1; - } - int i = put(bp); - js_free(bp); - return i; -} - -const size_t Sprinter::DefaultSize = 64; - -bool -Sprinter::realloc_(size_t newSize) -{ - MOZ_ASSERT(newSize > (size_t) offset); - char* newBuf = (char*) js_realloc(base, newSize); - if (!newBuf) { - reportOutOfMemory(); - return false; - } - base = newBuf; - size = newSize; - base[size - 1] = 0; - return true; -} - -Sprinter::Sprinter(ExclusiveContext* cx) - : context(cx), -#ifdef DEBUG - initialized(false), -#endif - base(nullptr), size(0), offset(0) -{ } - -Sprinter::~Sprinter() -{ -#ifdef DEBUG - if (initialized) - checkInvariants(); -#endif - js_free(base); -} - -bool -Sprinter::init() -{ - MOZ_ASSERT(!initialized); - base = (char*) js_malloc(DefaultSize); - if (!base) { - reportOutOfMemory(); - return false; - } -#ifdef DEBUG - initialized = true; -#endif - *base = 0; - size = DefaultSize; - base[size - 1] = 0; - return true; -} - -void -Sprinter::checkInvariants() const -{ - MOZ_ASSERT(initialized); - MOZ_ASSERT((size_t) offset < size); - MOZ_ASSERT(base[size - 1] == 0); -} - -const char* -Sprinter::string() const -{ - return base; -} - -const char* -Sprinter::stringEnd() const -{ - return base + offset; -} - -char* -Sprinter::stringAt(ptrdiff_t off) const -{ - MOZ_ASSERT(off >= 0 && (size_t) off < size); - return base + off; -} - -char& -Sprinter::operator[](size_t off) -{ - MOZ_ASSERT(off < size); - return *(base + off); -} - -char* -Sprinter::reserve(size_t len) -{ - InvariantChecker ic(this); - - while (len + 1 > size - offset) { /* Include trailing \0 */ - if (!realloc_(size * 2)) - return nullptr; - } - - char* sb = base + offset; - offset += len; - return sb; -} - -int -Sprinter::put(const char* s, size_t len) -{ - InvariantChecker ic(this); - - const char* oldBase = base; - const char* oldEnd = base + size; - - ptrdiff_t oldOffset = offset; - char* bp = reserve(len); - if (!bp) - return -1; - - /* s is within the buffer already */ - if (s >= oldBase && s < oldEnd) { - /* buffer was realloc'ed */ - if (base != oldBase) - s = stringAt(s - oldBase); /* this is where it lives now */ - memmove(bp, s, len); - } else { - js_memcpy(bp, s, len); - } - - bp[len] = 0; - return oldOffset; -} - -int -Sprinter::vprintf(const char* fmt, va_list ap) -{ - InvariantChecker ic(this); - - do { - va_list aq; - va_copy(aq, ap); - int i = vsnprintf(base + offset, size - offset, fmt, aq); - va_end(aq); - if (i > -1 && (size_t) i < size - offset) { - offset += i; - return i; - } - } while (realloc_(size * 2)); - - return -1; -} - -int -Sprinter::putString(JSString* s) -{ - InvariantChecker ic(this); - - size_t length = s->length(); - size_t size = length; - - ptrdiff_t oldOffset = offset; - char* buffer = reserve(size); - if (!buffer) - return -1; - - JSLinearString* linear = s->ensureLinear(context); - if (!linear) - return -1; - - JS::AutoCheckCannotGC nogc; - if (linear->hasLatin1Chars()) - mozilla::PodCopy(reinterpret_cast(buffer), linear->latin1Chars(nogc), length); - else - DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size); - - buffer[size] = 0; - return oldOffset; -} - -ptrdiff_t -Sprinter::getOffset() const -{ - return offset; -} - -void -Sprinter::reportOutOfMemory() -{ - if (reportedOOM_) - return; - if (context) - ReportOutOfMemory(context); - reportedOOM_ = true; -} - -ptrdiff_t -Sprint(Sprinter* sp, const char* format, ...) -{ - va_list ap; - char* bp; - ptrdiff_t offset; - - va_start(ap, format); - bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ - va_end(ap); - if (!bp) { - sp->reportOutOfMemory(); - return -1; - } - offset = sp->put(bp); - js_free(bp); - return offset; -} - -const char js_EscapeMap[] = { - '\b', 'b', - '\f', 'f', - '\n', 'n', - '\r', 'r', - '\t', 't', - '\v', 'v', - '"', '"', - '\'', '\'', - '\\', '\\', - '\0' -}; - -template -static char* -QuoteString(Sprinter* sp, const CharT* s, size_t length, char16_t quote) -{ - /* Sample off first for later return value pointer computation. */ - ptrdiff_t offset = sp->getOffset(); - - if (quote && Sprint(sp, "%c", char(quote)) < 0) - return nullptr; - - const CharT* end = s + length; - - /* Loop control variables: end points at end of string sentinel. */ - for (const CharT* t = s; t < end; s = ++t) { - /* Move t forward from s past un-quote-worthy characters. */ - char16_t c = *t; - while (c < 127 && isprint(c) && c != quote && c != '\\' && c != '\t') { - c = *++t; - if (t == end) - break; - } - - { - ptrdiff_t len = t - s; - ptrdiff_t base = sp->getOffset(); - if (!sp->reserve(len)) - return nullptr; - - for (ptrdiff_t i = 0; i < len; ++i) - (*sp)[base + i] = char(*s++); - (*sp)[base + len] = 0; - } - - if (t == end) - break; - - /* Use js_EscapeMap, \u, or \x only if necessary. */ - const char* escape; - if (!(c >> 8) && c != 0 && (escape = strchr(js_EscapeMap, int(c))) != nullptr) { - if (Sprint(sp, "\\%c", escape[1]) < 0) - return nullptr; - } else { - /* - * Use \x only if the high byte is 0 and we're in a quoted string, - * because ECMA-262 allows only \u, not \x, in Unicode identifiers - * (see bug 621814). - */ - if (Sprint(sp, (quote && !(c >> 8)) ? "\\x%02X" : "\\u%04X", c) < 0) - return nullptr; - } - } - - /* Sprint the closing quote and return the quoted string. */ - if (quote && Sprint(sp, "%c", char(quote)) < 0) - return nullptr; - - /* - * If we haven't Sprint'd anything yet, Sprint an empty string so that - * the return below gives a valid result. - */ - if (offset == sp->getOffset() && Sprint(sp, "") < 0) - return nullptr; - - return sp->stringAt(offset); -} - -char* -QuoteString(Sprinter* sp, JSString* str, char16_t quote) -{ - JSLinearString* linear = str->ensureLinear(sp->context); - if (!linear) - return nullptr; - - JS::AutoCheckCannotGC nogc; - return linear->hasLatin1Chars() - ? QuoteString(sp, linear->latin1Chars(nogc), linear->length(), quote) - : QuoteString(sp, linear->twoByteChars(nogc), linear->length(), quote); -} - -JSString* -QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote) -{ - Sprinter sprinter(cx); - if (!sprinter.init()) - return nullptr; - char* bytes = QuoteString(&sprinter, str, quote); - if (!bytes) - return nullptr; - return NewStringCopyZ(cx, bytes); -} - -Fprinter::Fprinter(FILE* fp) - : file_(nullptr) -{ - init(fp); -} - -Fprinter::Fprinter() - : file_(nullptr) -{ } - -Fprinter::~Fprinter() -{ - MOZ_ASSERT_IF(init_, !file_); -} - -bool -Fprinter::init(const char* path) -{ - MOZ_ASSERT(!file_); - file_ = fopen(path, "w"); - if (!file_) - return false; - init_ = true; - return true; -} - -void -Fprinter::init(FILE *fp) -{ - MOZ_ASSERT(!file_); - file_ = fp; - init_ = false; -} - -void -Fprinter::flush() -{ - MOZ_ASSERT(file_); - fflush(file_); -} - -void -Fprinter::finish() -{ - MOZ_ASSERT(file_); - if (init_) - fclose(file_); - file_ = nullptr; -} - -int -Fprinter::put(const char* s, size_t len) -{ - MOZ_ASSERT(file_); - int i = fwrite(s, len, 1, file_); - if (i == -1 || i != int(len)) - reportOutOfMemory(); - return i; -} - -int -Fprinter::put(const char* s) -{ - MOZ_ASSERT(file_); - int i = fputs(s, file_); - if (i == -1) - reportOutOfMemory(); - return i; -} - -int -Fprinter::printf(const char* fmt, ...) -{ - MOZ_ASSERT(file_); - va_list ap; - va_start(ap, fmt); - int i = vfprintf(file_, fmt, ap); - if (i == -1) - reportOutOfMemory(); - va_end(ap); - return i; -} - -int -Fprinter::vprintf(const char* fmt, va_list ap) -{ - MOZ_ASSERT(file_); - int i = vfprintf(file_, fmt, ap); - if (i == -1) - reportOutOfMemory(); - return i; -} - -LSprinter::LSprinter(LifoAlloc* lifoAlloc) - : alloc_(lifoAlloc), - head_(nullptr), - tail_(nullptr), - unused_(0) -{ } - -LSprinter::~LSprinter() -{ - // This LSprinter might be allocated as part of the same LifoAlloc, so we - // should not expect the destructor to be called. -} - -void -LSprinter::exportInto(GenericPrinter& out) const -{ - if (!head_) - return; - - for (Chunk* it = head_; it != tail_; it = it->next) - out.put(it->chars(), it->length); - out.put(tail_->chars(), tail_->length - unused_); -} - -void -LSprinter::clear() -{ - head_ = nullptr; - tail_ = nullptr; - unused_ = 0; - reportedOOM_ = false; -} - -int -LSprinter::put(const char* s, size_t len) -{ - size_t origLen = len; - if (unused_ > 0 && tail_) { - size_t minLen = unused_ < len ? unused_ : len; - js_memcpy(tail_->end() - unused_, s, minLen); - unused_ -= minLen; - len -= minLen; - s += minLen; - } - - if (len == 0) - return origLen; - - size_t allocLength = AlignBytes(sizeof(Chunk) + len, js::detail::LIFO_ALLOC_ALIGN); - Chunk* last = reinterpret_cast(alloc_->alloc(allocLength)); - if (!last) { - reportOutOfMemory(); - return origLen - len; - } - - if (tail_ && reinterpret_cast(last) == tail_->end()) { - // tail_ and last are next to each others in memory, knowing that the - // TempAlloctator has no meta data and is just a bump allocator, we - // append the new allocated space to the tail_. - unused_ = allocLength; - tail_->length += allocLength; - } else { - // Remove the size of the header from the allocated length. - allocLength -= sizeof(Chunk); - last->next = nullptr; - last->length = allocLength; - unused_ = allocLength; - if (!head_) - head_ = last; - else - tail_->next = last; - - tail_ = last; - } - - MOZ_ASSERT(tail_->length >= unused_); - js_memcpy(tail_->end() - unused_, s, len); - unused_ -= len; - return origLen; -} - -int -LSprinter::put(const char* s) -{ - return put(s, strlen(s)); -} - -int -LSprinter::printf(const char* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int i = vprintf(fmt, va); - va_end(va); - return i; -} - -int -LSprinter::vprintf(const char* fmt, va_list ap) -{ - // Simple shortcut to avoid allocating strings. - if (strchr(fmt, '%') == nullptr) - return put(fmt); - - char* bp; - bp = JS_vsmprintf(fmt, ap); /* XXX vsaprintf */ - if (!bp) { - reportOutOfMemory(); - return -1; - } - int i = put(bp); - js_free(bp); - return i; -} - -void -LSprinter::reportOutOfMemory() -{ - if (reportedOOM_) - return; - reportedOOM_ = true; -} - -bool -LSprinter::hadOutOfMemory() const -{ - return reportedOOM_; -} - -} // namespace js diff --git a/js/src/vm/Printer.h b/js/src/vm/Printer.h deleted file mode 100644 index ef759d283cff..000000000000 --- a/js/src/vm/Printer.h +++ /dev/null @@ -1,223 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef vm_Printer_h -#define vm_Printer_h - -#include -#include - -class JSString; - -namespace js { - -class ExclusiveContext; -class LifoAlloc; - -// Generic printf interface, similar to an ostream in the standard library. -// -// This class is useful to make generic printers which can work either with a -// file backend, with a buffer allocated with an ExclusiveContext or a link-list -// of chunks allocated with a LifoAlloc. -class GenericPrinter -{ - protected: - bool reportedOOM_; // record reported OOM. - - GenericPrinter(); - - public: - // Puts |len| characters from |s| at the current position and return an offset to - // the beginning of this new data. - virtual int put(const char* s, size_t len) = 0; - virtual int put(const char* s); - - // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...); - virtual int vprintf(const char* fmt, va_list ap); - - // Report that a string operation failed to get the memory it requested. The - // first call to this function calls JS_ReportOutOfMemory, and sets this - // Sprinter's outOfMemory flag; subsequent calls do nothing. - virtual void reportOutOfMemory(); - - // Return true if this Sprinter ran out of memory. - virtual bool hadOutOfMemory() const; -}; - -// Sprintf, but with unlimited and automatically allocated buffering. -class Sprinter final : public GenericPrinter -{ - public: - struct InvariantChecker - { - const Sprinter* parent; - - explicit InvariantChecker(const Sprinter* p) : parent(p) { - parent->checkInvariants(); - } - - ~InvariantChecker() { - parent->checkInvariants(); - } - }; - - ExclusiveContext* context; // context executing the decompiler - - private: - static const size_t DefaultSize; -#ifdef DEBUG - bool initialized; // true if this is initialized, use for debug builds -#endif - char* base; // malloc'd buffer address - size_t size; // size of buffer allocated at base - ptrdiff_t offset; // offset of next free char in buffer - - bool realloc_(size_t newSize); - - public: - explicit Sprinter(ExclusiveContext* cx); - ~Sprinter(); - - // Initialize this sprinter, returns false on error. - bool init(); - - void checkInvariants() const; - - const char* string() const; - const char* stringEnd() const; - // Returns the string at offset |off|. - char* stringAt(ptrdiff_t off) const; - // Returns the char at offset |off|. - char& operator[](size_t off); - - // Attempt to reserve len + 1 space (for a trailing nullptr byte). If the - // attempt succeeds, return a pointer to the start of that space and adjust the - // internal content. The caller *must* completely fill this space on success. - char* reserve(size_t len); - - // Puts |len| characters from |s| at the current position and return an offset to - // the beginning of this new data. - using GenericPrinter::put; - virtual int put(const char* s, size_t len) override; - - // Prints a formatted string into the buffer. - virtual int vprintf(const char* fmt, va_list ap) override; - - int putString(JSString* str); - - ptrdiff_t getOffset() const; - - // Report that a string operation failed to get the memory it requested. The - // first call to this function calls JS_ReportOutOfMemory, and sets this - // Sprinter's outOfMemory flag; subsequent calls do nothing. - virtual void reportOutOfMemory() override; -}; - -// Fprinter, print a string directly into a file. -class Fprinter final : public GenericPrinter -{ - private: - FILE* file_; - bool init_; - - public: - explicit Fprinter(FILE* fp); - Fprinter(); - ~Fprinter(); - - // Initialize this printer, returns false on error. - bool init(const char* path); - void init(FILE* fp); - bool isInitialized() { - return file_ != nullptr; - } - void flush(); - void finish(); - - // Puts |len| characters from |s| at the current position and return an - // offset to the beginning of this new data. - virtual int put(const char* s, size_t len) override; - virtual int put(const char* s) override; - - // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...) override; - virtual int vprintf(const char* fmt, va_list ap) override; -}; - -// LSprinter, is similar to Sprinter except that instead of using an -// ExclusiveContext to allocate strings, it use a LifoAlloc as a backend for the -// allocation of the chunk of the string. -class LSprinter final : public GenericPrinter -{ - private: - struct Chunk - { - Chunk* next; - size_t length; - - char* chars() { - return reinterpret_cast(this + 1); - } - char* end() { - return chars() + length; - } - }; - - private: - LifoAlloc* alloc_; // LifoAlloc used as a backend of chunk allocations. - Chunk* head_; - Chunk* tail_; - size_t unused_; - - public: - explicit LSprinter(LifoAlloc* lifoAlloc); - ~LSprinter(); - - // Copy the content of the chunks into another printer, such that we can - // flush the content of this printer to a file. - void exportInto(GenericPrinter& out) const; - - // Drop the current string, and let them be free with the LifoAlloc. - void clear(); - - // Puts |len| characters from |s| at the current position and return an - // offset to the beginning of this new data. - virtual int put(const char* s, size_t len) override; - virtual int put(const char* s) override; - - // Prints a formatted string into the buffer. - virtual int printf(const char* fmt, ...) override; - virtual int vprintf(const char* fmt, va_list ap) override; - - // Report that a string operation failed to get the memory it requested. The - // first call to this function calls JS_ReportOutOfMemory, and sets this - // Sprinter's outOfMemory flag; subsequent calls do nothing. - virtual void reportOutOfMemory() override; - - // Return true if this Sprinter ran out of memory. - virtual bool hadOutOfMemory() const override; -}; - -extern ptrdiff_t -Sprint(Sprinter* sp, const char* format, ...); - -// Map escaped code to the letter/symbol escaped with a backslash. -extern const char js_EscapeMap[]; - -// Return a GC'ed string containing the chars in str, with any non-printing -// chars or quotes (' or " as specified by the quote argument) escaped, and -// with the quote character at the beginning and end of the result string. -extern JSString* -QuoteString(ExclusiveContext* cx, JSString* str, char16_t quote); - -extern char* -QuoteString(Sprinter* sp, JSString* str, char16_t quote); - - -} // namespace js - -#endif // vm_Printer_h