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)
This commit is contained in:
Ryan VanderMeulen 2015-05-15 15:28:48 -04:00
Родитель beb52571e8
Коммит 4decbb024c
43 изменённых файлов: 1324 добавлений и 2218 удалений

Просмотреть файл

@ -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();

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -225,45 +225,6 @@ compartment.
thereby escaping the capability-based limits. For this reason,
`onNewGlobalObject` is only available to privileged code.
<code>onIonCompilation(<i>graph</i>)</code>
: A new IonMonkey compilation result is attached to a script instance of
the Debuggee, the <i>graph</i> contains the internal intermediate
representations of the compiler.
The value <i>graph</i> 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

Просмотреть файл

@ -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"

Просмотреть файл

@ -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); });

Просмотреть файл

@ -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.

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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

Просмотреть файл

@ -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<CodeGenerator> 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<CodeGenerator> 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;

Просмотреть файл

@ -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*

Просмотреть файл

@ -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:

Просмотреть файл

@ -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);

Просмотреть файл

@ -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<MBinaryArithInstruction*>(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;
}

Просмотреть файл

@ -10,7 +10,6 @@
#include <stdio.h>
#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

Просмотреть файл

@ -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<uint32_t, mozilla::Relaxed> 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 */

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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);

Просмотреть файл

@ -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, ",");
}
}

Просмотреть файл

@ -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();
};

Просмотреть файл

@ -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");
}
}

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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>()) {
JSFunction* fun = &value().toObject().as<JSFunction>();
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 <typename T>
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

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -599,10 +599,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
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();
};

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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

Просмотреть файл

@ -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_++;

Просмотреть файл

@ -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 {

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/SizePrintfMacros.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@ -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<Latin1Char*>(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 <typename CharT>
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<CanGC>(cx, bytes);
}
/************************************************************************/
namespace {
/*
* The expression decompiler is invoked by error handling code to produce a

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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 <typename CharT>
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

Просмотреть файл

@ -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 <typename CharT>
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

Просмотреть файл

@ -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',

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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<GlobalObject*> 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<AutoCompartment> 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 <typename HookIsEnabledFun /* bool (Debugger*) */,
typename FireHookFun /* JSTrapStatus (Debugger*) */>
/* 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<GlobalObject*> 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[] = {

Просмотреть файл

@ -35,8 +35,6 @@ enum JSTrapStatus {
namespace js {
class LSprinter;
class Breakpoint;
class DebuggerMemory;
@ -206,7 +204,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
OnNewPromise,
OnPromiseSettled,
OnGarbageCollection,
OnIonCompilation,
HookCount
};
enum {
@ -482,8 +479,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
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<Debugger>
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 <typename HookIsEnabledFun /* bool (Debugger*) */,
typename FireHookFun /* JSTrapStatus (Debugger*) */>
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<Debugger>
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<Debugger>
static inline void onNewGlobalObject(JSContext* cx, Handle<GlobalObject*> 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);

Просмотреть файл

@ -1054,7 +1054,6 @@ HelperThread::handleAsmJSWorkload()
&asmData->mir->alloc());
int64_t before = PRMJ_Now();
jit::AutoSpewEndFunction spewEndFunction(asmData->mir);
if (!OptimizeMIR(asmData->mir))
break;

Просмотреть файл

@ -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 <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#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<Latin1Char*>(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 <typename CharT>
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<CanGC>(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<Chunk*>(alloc_->alloc(allocLength));
if (!last) {
reportOutOfMemory();
return origLen - len;
}
if (tail_ && reinterpret_cast<char*>(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

Просмотреть файл

@ -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 <stdarg.h>
#include <stdio.h>
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<char*>(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