Bug 1147403 part 3 - Make IonSpewer work during off-thread compilation. r=h4writer

This commit is contained in:
Nicolas B. Pierron 2015-05-28 19:26:55 +02:00
parent a9838faded
commit c3ac0db387
11 changed files with 337 additions and 275 deletions

View File

@ -7692,6 +7692,8 @@ CheckFunction(ModuleCompiler& m, LifoAlloc& lifo, MIRGenerator** mir, ModuleComp
*mir = f.extractMIR();
(*mir)->initMinAsmJSHeapLength(m.minHeapLength());
jit::SpewBeginFunction(*mir, nullptr);
*funcOut = func;
return true;
}
@ -7768,8 +7770,7 @@ CheckFunctionsSequential(ModuleCompiler& m)
int64_t before = PRMJ_Now();
JitContext jcx(m.cx(), &mir->alloc());
IonSpewNewFunction(&mir->graph(), nullptr);
jit::AutoSpewEndFunction spewEndFunction(mir);
if (!OptimizeMIR(mir))
return m.failOffset(func->srcBegin(), "internal compiler failure (probably out of memory)");
@ -7782,8 +7783,6 @@ CheckFunctionsSequential(ModuleCompiler& m)
if (!GenerateCode(m, *func, *mir, *lir))
return false;
IonSpewEndFunction();
}
if (!CheckAllFunctionsDefined(m))
@ -8022,7 +8021,7 @@ CheckFunctions(ModuleCompiler& m)
if (!ParallelCompilationEnabled(m.cx()) || !g.claim())
return CheckFunctionsSequential(m);
JitSpew(JitSpew_IonLogs, "Can't log asm.js script. (Compiled on background thread.)");
JitSpew(JitSpew_IonSyncLogs, "Can't log asm.js script. (Compiled on background thread.)");
// Saturate all helper threads.
size_t numParallelJobs = HelperThreadState().maxAsmJSCompilationThreads();

View File

@ -21,18 +21,9 @@
using namespace js;
using namespace js::jit;
bool
C1Spewer::init(const char* path)
{
return out_.init(path);
}
void
C1Spewer::beginFunction(MIRGraph* graph, HandleScript script)
C1Spewer::beginFunction(MIRGraph* graph, JSScript* script)
{
if (!out_.isInitialized())
return;
this->graph = graph;
out_.printf("begin_compilation\n");
@ -50,9 +41,6 @@ C1Spewer::beginFunction(MIRGraph* graph, HandleScript script)
void
C1Spewer::spewPass(const char* pass)
{
if (!out_.isInitialized())
return;
out_.printf("begin_cfg\n");
out_.printf(" name \"%s\"\n", pass);
@ -60,15 +48,11 @@ C1Spewer::spewPass(const char* pass)
spewPass(out_, *block);
out_.printf("end_cfg\n");
out_.flush();
}
void
C1Spewer::spewRanges(const char* pass, BacktrackingAllocator* regalloc)
{
if (!out_.isInitialized())
return;
out_.printf("begin_ranges\n");
out_.printf(" name \"%s\"\n", pass);
@ -76,7 +60,6 @@ C1Spewer::spewRanges(const char* pass, BacktrackingAllocator* regalloc)
spewRanges(out_, *block, regalloc);
out_.printf("end_ranges\n");
out_.flush();
}
void
@ -85,10 +68,11 @@ C1Spewer::endFunction()
}
void
C1Spewer::finish()
C1Spewer::dump(Fprinter& file)
{
if (out_.isInitialized())
out_.finish();
if (!out_.hadOutOfMemory())
out_.exportInto(file);
out_.clear();
}
static void

View File

@ -11,6 +11,7 @@
#include "NamespaceImports.h"
#include "jit/JitAllocPolicy.h"
#include "js/RootingAPI.h"
#include "vm/Printer.h"
@ -25,19 +26,19 @@ class LNode;
class C1Spewer
{
MIRGraph* graph;
Fprinter out_;
LSprinter out_;
public:
C1Spewer()
: graph(nullptr), out_()
explicit C1Spewer(TempAllocator *alloc)
: graph(nullptr), out_(alloc->lifoAlloc())
{ }
bool init(const char* path);
void beginFunction(MIRGraph* graph, HandleScript script);
void beginFunction(MIRGraph* graph, JSScript* script);
void spewPass(const char* pass);
void spewRanges(const char* pass, BacktrackingAllocator* regalloc);
void endFunction();
void finish();
void dump(Fprinter &file);
private:
void spewPass(GenericPrinter& out, MBasicBlock* block);

View File

@ -1169,6 +1169,7 @@ bool
OptimizeMIR(MIRGenerator* mir)
{
MIRGraph& graph = mir->graph();
GraphSpewer& gs = mir->graphSpewer();
TraceLoggerThread* logger;
if (GetJitContext()->runtime->onMainThread())
logger = TraceLoggerForMainThread(GetJitContext()->runtime);
@ -1180,7 +1181,7 @@ OptimizeMIR(MIRGenerator* mir)
return false;
}
IonSpewPass("BuildSSA");
gs.spewPass("BuildSSA");
AssertBasicGraphCoherency(graph);
if (mir->shouldCancel("Start"))
@ -1189,7 +1190,7 @@ OptimizeMIR(MIRGenerator* mir)
if (!mir->compilingAsmJS()) {
AutoTraceLog log(logger, TraceLogger_FoldTests);
FoldTests(graph);
IonSpewPass("Fold Tests");
gs.spewPass("Fold Tests");
AssertBasicGraphCoherency(graph);
if (mir->shouldCancel("Fold Tests"))
@ -1200,7 +1201,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_SplitCriticalEdges);
if (!SplitCriticalEdges(graph))
return false;
IonSpewPass("Split Critical Edges");
gs.spewPass("Split Critical Edges");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Split Critical Edges"))
@ -1211,7 +1212,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_RenumberBlocks);
if (!RenumberBlocks(graph))
return false;
IonSpewPass("Renumber Blocks");
gs.spewPass("Renumber Blocks");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Renumber Blocks"))
@ -1239,7 +1240,7 @@ OptimizeMIR(MIRGenerator* mir)
: AggressiveObservability;
if (!EliminatePhis(mir, graph, observability))
return false;
IonSpewPass("Eliminate phis");
gs.spewPass("Eliminate phis");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Eliminate phis"))
@ -1258,7 +1259,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
if (!ScalarReplacement(mir, graph))
return false;
IonSpewPass("Scalar Replacement");
gs.spewPass("Scalar Replacement");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Scalar Replacement"))
@ -1269,7 +1270,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_ApplyTypes);
if (!ApplyTypeInformation(mir, graph))
return false;
IonSpewPass("Apply types");
gs.spewPass("Apply types");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Apply types"))
@ -1280,7 +1281,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_EagerSimdUnbox);
if (!EagerSimdUnbox(mir, graph))
return false;
IonSpewPass("Eager Simd Unbox");
gs.spewPass("Eager Simd Unbox");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Eager Simd Unbox"))
@ -1292,7 +1293,7 @@ OptimizeMIR(MIRGenerator* mir)
AlignmentMaskAnalysis ama(graph);
if (!ama.analyze())
return false;
IonSpewPass("Alignment Mask Analysis");
gs.spewPass("Alignment Mask Analysis");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Alignment Mask Analysis"))
@ -1312,7 +1313,7 @@ OptimizeMIR(MIRGenerator* mir)
AliasAnalysis analysis(mir, graph);
if (!analysis.analyze())
return false;
IonSpewPass("Alias analysis");
gs.spewPass("Alias analysis");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Alias analysis"))
@ -1334,7 +1335,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_GVN);
if (!gvn.run(ValueNumberer::UpdateAliasAnalysis))
return false;
IonSpewPass("GVN");
gs.spewPass("GVN");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("GVN"))
@ -1350,7 +1351,7 @@ OptimizeMIR(MIRGenerator* mir)
if (!script || !script->hadFrequentBailouts()) {
if (!LICM(mir, graph))
return false;
IonSpewPass("LICM");
gs.spewPass("LICM");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("LICM"))
@ -1363,7 +1364,7 @@ OptimizeMIR(MIRGenerator* mir)
RangeAnalysis r(mir, graph);
if (!r.addBetaNodes())
return false;
IonSpewPass("Beta");
gs.spewPass("Beta");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("RA Beta"))
@ -1371,7 +1372,7 @@ OptimizeMIR(MIRGenerator* mir)
if (!r.analyze() || !r.addRangeAssertions())
return false;
IonSpewPass("Range Analysis");
gs.spewPass("Range Analysis");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Range Analysis"))
@ -1379,7 +1380,7 @@ OptimizeMIR(MIRGenerator* mir)
if (!r.removeBetaNodes())
return false;
IonSpewPass("De-Beta");
gs.spewPass("De-Beta");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("RA De-Beta"))
@ -1389,7 +1390,7 @@ OptimizeMIR(MIRGenerator* mir)
bool shouldRunUCE = false;
if (!r.prepareForUCE(&shouldRunUCE))
return false;
IonSpewPass("RA check UCE");
gs.spewPass("RA check UCE");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("RA check UCE"))
@ -1398,7 +1399,7 @@ OptimizeMIR(MIRGenerator* mir)
if (shouldRunUCE) {
if (!gvn.run(ValueNumberer::DontUpdateAliasAnalysis))
return false;
IonSpewPass("UCE After RA");
gs.spewPass("UCE After RA");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("UCE After RA"))
@ -1409,7 +1410,7 @@ OptimizeMIR(MIRGenerator* mir)
if (mir->optimizationInfo().autoTruncateEnabled()) {
if (!r.truncate())
return false;
IonSpewPass("Truncate Doubles");
gs.spewPass("Truncate Doubles");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Truncate Doubles"))
@ -1422,7 +1423,7 @@ OptimizeMIR(MIRGenerator* mir)
if (!UnrollLoops(graph, r.loopIterationBounds))
return false;
IonSpewPass("Unroll Loops");
gs.spewPass("Unroll Loops");
AssertExtendedGraphCoherency(graph);
}
}
@ -1432,7 +1433,7 @@ OptimizeMIR(MIRGenerator* mir)
EffectiveAddressAnalysis eaa(mir, graph);
if (!eaa.analyze())
return false;
IonSpewPass("Effective Address Analysis");
gs.spewPass("Effective Address Analysis");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Effective Address Analysis"))
@ -1443,7 +1444,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
if (!EliminateDeadCode(mir, graph))
return false;
IonSpewPass("DCE");
gs.spewPass("DCE");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("DCE"))
@ -1454,7 +1455,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
if (!Sink(mir, graph))
return false;
IonSpewPass("Sink");
gs.spewPass("Sink");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Sink"))
@ -1467,7 +1468,7 @@ OptimizeMIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_MakeLoopsContiguous);
if (!MakeLoopsContiguous(graph))
return false;
IonSpewPass("Make loops contiguous");
gs.spewPass("Make loops contiguous");
AssertExtendedGraphCoherency(graph);
if (mir->shouldCancel("Make loops contiguous"))
@ -1482,7 +1483,7 @@ OptimizeMIR(MIRGenerator* mir)
EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
if (!edgeCaseAnalysis.analyzeLate())
return false;
IonSpewPass("Edge Case Analysis (Late)");
gs.spewPass("Edge Case Analysis (Late)");
AssertGraphCoherency(graph);
if (mir->shouldCancel("Edge Case Analysis (Late)"))
@ -1497,7 +1498,7 @@ OptimizeMIR(MIRGenerator* mir)
// before its bounds check.
if (!EliminateRedundantChecks(graph))
return false;
IonSpewPass("Bounds Check Elimination");
gs.spewPass("Bounds Check Elimination");
AssertGraphCoherency(graph);
}
@ -1515,6 +1516,7 @@ LIRGraph*
GenerateLIR(MIRGenerator* mir)
{
MIRGraph& graph = mir->graph();
GraphSpewer& gs = mir->graphSpewer();
TraceLoggerThread* logger;
if (GetJitContext()->runtime->onMainThread())
@ -1531,7 +1533,7 @@ GenerateLIR(MIRGenerator* mir)
AutoTraceLog log(logger, TraceLogger_GenerateLIR);
if (!lirgen.generate())
return nullptr;
IonSpewPass("Generate LIR");
gs.spewPass("Generate LIR");
if (mir->shouldCancel("Generate LIR"))
return nullptr;
@ -1558,7 +1560,7 @@ GenerateLIR(MIRGenerator* mir)
return nullptr;
#endif
IonSpewPass("Allocate Registers [Backtracking]");
gs.spewPass("Allocate Registers [Backtracking]");
break;
}
@ -1573,7 +1575,7 @@ GenerateLIR(MIRGenerator* mir)
return nullptr;
if (!integrity.check(true))
return nullptr;
IonSpewPass("Allocate Registers [Stupid]");
gs.spewPass("Allocate Registers [Stupid]");
break;
}
@ -1615,6 +1617,7 @@ CompileBackEnd(MIRGenerator* mir)
{
// Everything in CompileBackEnd can potentially run on a helper thread.
AutoEnterIonCompilation enter;
AutoSpewEndFunction spewEndFunction(mir);
if (!OptimizeMIR(mir))
return nullptr;
@ -1918,15 +1921,14 @@ IonCompile(JSContext* cx, JSScript* script,
if (recompile)
builderScript->ionScript()->setRecompiling();
#ifdef DEBUG
IonSpewFunction ionSpewFunction(graph, builderScript);
#endif
SpewBeginFunction(builder, builderScript);
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.
@ -1960,7 +1962,8 @@ IonCompile(JSContext* cx, JSScript* script,
if (!recompile)
builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
JitSpew(JitSpew_IonLogs, "Can't log script %s:%" PRIuSIZE ". (Compiled on background thread.)",
JitSpew(JitSpew_IonSyncLogs, "Can't log script %s:%" PRIuSIZE
". (Compiled on background thread.)",
builderScript->filename(), builderScript->lineno());
JSRuntime* rt = cx->runtime();
@ -1974,6 +1977,7 @@ 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;
}

View File

@ -17,17 +17,9 @@
using namespace js;
using namespace js::jit;
JSONSpewer::~JSONSpewer()
{
if (out_.isInitialized())
out_.finish();
}
void
JSONSpewer::indent()
{
if (!out_.isInitialized())
return;
MOZ_ASSERT(indentLevel_ >= 0);
out_.printf("\n");
for (int i = 0; i < indentLevel_; i++)
@ -37,9 +29,6 @@ JSONSpewer::indent()
void
JSONSpewer::property(const char* name)
{
if (!out_.isInitialized())
return;
if (!first_)
out_.printf(",");
indent();
@ -50,9 +39,6 @@ JSONSpewer::property(const char* name)
void
JSONSpewer::beginObject()
{
if (!out_.isInitialized())
return;
if (!first_) {
out_.printf(",");
indent();
@ -65,9 +51,6 @@ JSONSpewer::beginObject()
void
JSONSpewer::beginObjectProperty(const char* name)
{
if (!out_.isInitialized())
return;
property(name);
out_.printf("{");
indentLevel_++;
@ -77,9 +60,6 @@ JSONSpewer::beginObjectProperty(const char* name)
void
JSONSpewer::beginListProperty(const char* name)
{
if (!out_.isInitialized())
return;
property(name);
out_.printf("[");
first_ = true;
@ -88,9 +68,6 @@ JSONSpewer::beginListProperty(const char* name)
void
JSONSpewer::stringProperty(const char* name, const char* format, ...)
{
if (!out_.isInitialized())
return;
va_list ap;
va_start(ap, format);
@ -105,9 +82,6 @@ JSONSpewer::stringProperty(const char* name, const char* format, ...)
void
JSONSpewer::stringValue(const char* format, ...)
{
if (!out_.isInitialized())
return;
va_list ap;
va_start(ap, format);
@ -124,9 +98,6 @@ JSONSpewer::stringValue(const char* format, ...)
void
JSONSpewer::integerProperty(const char* name, int value)
{
if (!out_.isInitialized())
return;
property(name);
out_.printf("%d", value);
}
@ -134,9 +105,6 @@ JSONSpewer::integerProperty(const char* name, int value)
void
JSONSpewer::integerValue(int value)
{
if (!out_.isInitialized())
return;
if (!first_)
out_.printf(",");
out_.printf("%d", value);
@ -146,9 +114,6 @@ JSONSpewer::integerValue(int value)
void
JSONSpewer::endObject()
{
if (!out_.isInitialized())
return;
indentLevel_--;
indent();
out_.printf("}");
@ -158,38 +123,19 @@ JSONSpewer::endObject()
void
JSONSpewer::endList()
{
if (!out_.isInitialized())
return;
out_.printf("]");
first_ = false;
}
bool
JSONSpewer::init(const char* path)
{
if (out_.init(path))
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
@ -294,9 +240,6 @@ JSONSpewer::spewMDef(MDefinition* def)
void
JSONSpewer::spewMIR(MIRGraph* mir)
{
if (!out_.isInitialized())
return;
beginObjectProperty("mir");
beginListProperty("blocks");
@ -343,9 +286,6 @@ JSONSpewer::spewMIR(MIRGraph* mir)
void
JSONSpewer::spewLIns(LNode* ins)
{
if (!out_.isInitialized())
return;
beginObject();
integerProperty("id", ins->id());
@ -366,9 +306,6 @@ JSONSpewer::spewLIns(LNode* ins)
void
JSONSpewer::spewLIR(MIRGraph* mir)
{
if (!out_.isInitialized())
return;
beginObjectProperty("lir");
beginListProperty("blocks");
@ -397,9 +334,6 @@ JSONSpewer::spewLIR(MIRGraph* mir)
void
JSONSpewer::spewRanges(BacktrackingAllocator* regalloc)
{
if (!out_.isInitialized())
return;
beginObjectProperty("ranges");
beginListProperty("blocks");
@ -446,32 +380,21 @@ void
JSONSpewer::endPass()
{
endObject();
out_.flush();
}
void
JSONSpewer::endFunction()
{
MOZ_ASSERT(inFunction_);
endList();
endObject();
out_.flush();
inFunction_ = false;
}
void
JSONSpewer::finish()
JSONSpewer::dump(Fprinter& file)
{
if (!out_.isInitialized())
return;
if (inFunction_)
endFunction();
endList();
endObject();
out_.printf("\n");
out_.finish();
if (!out_.hadOutOfMemory())
out_.exportInto(file);
else
file.put("{}");
out_.clear();
}

View File

@ -9,8 +9,8 @@
#include <stdio.h>
#include "jit/JitAllocPolicy.h"
#include "js/TypeDecls.h"
#include "vm/Printer.h"
namespace js {
@ -25,13 +25,9 @@ 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_;
Fprinter out_;
LSprinter out_;
void indent();
@ -47,15 +43,12 @@ class JSONSpewer
void endList();
public:
JSONSpewer()
: inFunction_(false),
indentLevel_(0),
explicit JSONSpewer(TempAllocator *alloc)
: indentLevel_(0),
first_(true),
out_()
out_(alloc->lifoAlloc())
{ }
~JSONSpewer();
bool init(const char* path);
void beginFunction(JSScript* script);
void beginPass(const char * pass);
void spewMDef(MDefinition* def);
@ -66,7 +59,8 @@ class JSONSpewer
void spewRanges(BacktrackingAllocator* regalloc);
void endPass();
void endFunction();
void finish();
void dump(Fprinter& file);
};
} // namespace jit

View File

@ -8,6 +8,8 @@
#include "jit/JitSpewer.h"
#include "mozilla/Atomics.h"
#include "jit/Ion.h"
#include "jit/MIR.h"
@ -26,12 +28,67 @@
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 uint32_t filteredOutCompilations = 0;
static mozilla::Atomic<uint32_t, mozilla::Relaxed> filteredOutCompilations(0);
static const char * const ChannelNames[] =
{
@ -41,7 +98,7 @@ static const char * const ChannelNames[] =
};
static bool
FilterContainsLocation(HandleScript function)
FilterContainsLocation(JSScript* function)
{
static const char* filter = getenv("IONFILTER");
@ -73,48 +130,31 @@ FilterContainsLocation(HandleScript function)
}
void
jit::EnableIonDebugLogging()
jit::EnableIonDebugSyncLogging()
{
EnableChannel(JitSpew_IonLogs);
ionspewer.init();
ionspewer.setAsyncLogging(false);
EnableChannel(JitSpew_IonSyncLogs);
}
void
jit::IonSpewNewFunction(MIRGraph* graph, HandleScript func)
jit::EnableIonDebugAsyncLogging()
{
if (GetJitContext()->runtime->onMainThread())
ionspewer.beginFunction(graph, func);
ionspewer.init();
ionspewer.setAsyncLogging(true);
}
void
jit::IonSpewPass(const char* pass)
IonSpewer::release()
{
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();
if (c1Output_.isInitialized())
c1Output_.finish();
if (jsonOutput_.isInitialized())
jsonOutput_.finish();
if (outputLock_)
PR_DestroyLock(outputLock_);
outputLock_ = nullptr;
inited_ = false;
}
bool
@ -123,85 +163,176 @@ IonSpewer::init()
if (inited_)
return true;
if (!c1Spewer.init(JIT_SPEW_DIR "ion.cfg"))
return false;
if (!jsonSpewer.init(JIT_SPEW_DIR "ion.json"))
outputLock_ = PR_NewLock();
if (!outputLock_ ||
!c1Output_.init(JIT_SPEW_DIR "ion.cfg") ||
!jsonOutput_.init(JIT_SPEW_DIR "ion.json"))
{
release();
return false;
}
jsonOutput_.printf("{\n \"functions\": [\n");
firstFunction_ = true;
inited_ = true;
return true;
}
bool
IonSpewer::isSpewingFunction() const
AutoLockIonSpewerOutput::AutoLockIonSpewerOutput(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
{
return inited_ && graph;
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
ionspewer.lockOutput();
}
AutoLockIonSpewerOutput::~AutoLockIonSpewerOutput()
{
ionspewer.unlockOutput();
}
void
IonSpewer::beginFunction(MIRGraph* graph, HandleScript function)
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()
{
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;
}
this->graph = graph;
c1Spewer.beginFunction(graph, function);
jsonSpewer.beginFunction(function);
graph_ = graph;
MOZ_ASSERT(isSpewing());
}
void
IonSpewer::spewPass(const char* pass)
GraphSpewer::beginFunction(JSScript* function)
{
if (!isSpewingFunction())
if (!isSpewing())
return;
c1Spewer.spewPass(pass);
jsonSpewer.beginPass(pass);
jsonSpewer.spewMIR(graph);
jsonSpewer.spewLIR(graph);
jsonSpewer.endPass();
c1Spewer_.beginFunction(graph_, function);
jsonSpewer_.beginFunction(function);
ionspewer.beginFunction();
}
void
IonSpewer::spewPass(const char* pass, BacktrackingAllocator* ra)
GraphSpewer::spewPass(const char* pass)
{
if (!isSpewingFunction())
if (!isSpewing())
return;
c1Spewer.spewPass(pass);
c1Spewer.spewRanges(pass, ra);
jsonSpewer.beginPass(pass);
jsonSpewer.spewMIR(graph);
jsonSpewer.spewLIR(graph);
jsonSpewer.spewRanges(ra);
jsonSpewer.endPass();
c1Spewer_.spewPass(pass);
jsonSpewer_.beginPass(pass);
jsonSpewer_.spewMIR(graph_);
jsonSpewer_.spewLIR(graph_);
jsonSpewer_.endPass();
ionspewer.spewPass(this);
}
void
IonSpewer::endFunction()
GraphSpewer::spewPass(const char* pass, BacktrackingAllocator* ra)
{
if (!isSpewingFunction()) {
if (inited_) {
MOZ_ASSERT(filteredOutCompilations != 0);
filteredOutCompilations--;
}
if (!isSpewing())
return;
c1Spewer_.spewPass(pass);
c1Spewer_.spewRanges(pass, ra);
jsonSpewer_.beginPass(pass);
jsonSpewer_.spewMIR(graph_);
jsonSpewer_.spewLIR(graph_);
jsonSpewer_.spewRanges(ra);
jsonSpewer_.endPass();
ionspewer.spewPass(this);
}
void
GraphSpewer::endFunction()
{
if (!ionspewer.isEnabled())
return;
if (!isSpewing()) {
MOZ_ASSERT(filteredOutCompilations != 0);
filteredOutCompilations--;
return;
}
c1Spewer.endFunction();
jsonSpewer.endFunction();
c1Spewer_.endFunction();
jsonSpewer_.endFunction();
this->graph = nullptr;
ionspewer.endFunction(this);
graph_ = nullptr;
}
void
GraphSpewer::dump(Fprinter& c1Out, Fprinter& jsonOut)
{
c1Spewer_.dump(c1Out);
jsonSpewer_.dump(jsonOut);
}
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()
@ -260,6 +391,7 @@ 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"
@ -319,7 +451,9 @@ jit::CheckLogging()
if (ContainsFlag(env, "cacheflush"))
EnableChannel(JitSpew_CacheFlush);
if (ContainsFlag(env, "logs"))
EnableIonDebugLogging();
EnableIonDebugAsyncLogging();
if (ContainsFlag(env, "logs-sync"))
EnableIonDebugSyncLogging();
if (ContainsFlag(env, "profiling"))
EnableChannel(JitSpew_Profiling);
if (ContainsFlag(env, "trackopts"))
@ -461,15 +595,5 @@ jit::DisableChannel(JitSpewChannel channel)
LoggingBits &= ~(1 << uint32_t(channel));
}
IonSpewFunction::IonSpewFunction(MIRGraph* graph, JS::HandleScript function)
{
IonSpewNewFunction(graph, function);
}
IonSpewFunction::~IonSpewFunction()
{
IonSpewEndFunction();
}
#endif /* DEBUG */

View File

@ -77,7 +77,7 @@ namespace jit {
/* Information about compiled scripts */\
_(IonScripts) \
/* Info about failing to log script */ \
_(IonLogs) \
_(IonSyncLogs) \
/* Information during MIR building */ \
_(IonMIR) \
/* Information during bailouts */ \
@ -103,41 +103,45 @@ static const int NULL_ID = -1;
#ifdef DEBUG
class IonSpewer
// Class made to hold the MIR and LIR graphs of an AsmJS / Ion compilation.
class GraphSpewer
{
private:
MIRGraph* graph;
C1Spewer c1Spewer;
JSONSpewer jsonSpewer;
bool inited_;
MIRGraph* graph_;
C1Spewer c1Spewer_;
JSONSpewer jsonSpewer_;
public:
IonSpewer()
: graph(nullptr), inited_(false)
explicit GraphSpewer(TempAllocator *alloc)
: graph_(nullptr),
c1Spewer_(alloc),
jsonSpewer_(alloc)
{ }
// File output is terminated safely upon destruction.
~IonSpewer();
bool init();
void beginFunction(MIRGraph* graph, JS::HandleScript);
bool isSpewingFunction() const;
bool isSpewing() const {
return graph_;
}
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);
};
class IonSpewFunction
void SpewBeginFunction(MIRGenerator* mir, JSScript* function);
class AutoSpewEndFunction
{
public:
IonSpewFunction(MIRGraph* graph, JS::HandleScript function);
~IonSpewFunction();
};
private:
MIRGenerator* mir_;
void IonSpewNewFunction(MIRGraph* graph, JS::HandleScript function);
void IonSpewPass(const char* pass);
void IonSpewPass(const char* pass, BacktrackingAllocator* ra);
void IonSpewEndFunction();
public:
explicit AutoSpewEndFunction(MIRGenerator* mir)
: mir_(mir)
{ }
~AutoSpewEndFunction();
};
void CheckLogging();
Fprinter& JitSpewPrinter();
@ -154,19 +158,36 @@ void JitSpewDef(JitSpewChannel channel, const char* str, MDefinition* def);
void EnableChannel(JitSpewChannel channel);
void DisableChannel(JitSpewChannel channel);
void EnableIonDebugLogging();
void EnableIonDebugSyncLogging();
void EnableIonDebugAsyncLogging();
#else
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 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)
{ }
class AutoSpewEndFunction
{
public:
explicit AutoSpewEndFunction(MIRGenerator* mir) { }
~AutoSpewEndFunction() { }
};
static inline void CheckLogging()
{ }
static inline Fprinter& JitSpewPrinter()
@ -195,7 +216,9 @@ static inline void EnableChannel(JitSpewChannel)
{ }
static inline void DisableChannel(JitSpewChannel)
{ }
static inline void EnableIonDebugLogging()
static inline void EnableIonDebugSyncLogging()
{ }
static inline void EnableIonDebugAsyncLogging()
{ }
#endif /* DEBUG */

View File

@ -245,6 +245,14 @@ 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

View File

@ -48,7 +48,8 @@ MIRGenerator::MIRGenerator(CompileCompartment* compartment, const JitCompileOpti
#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
usesSignalHandlersForAsmJSOOB_(usesSignalHandlersForAsmJSOOB),
#endif
options(options)
options(options),
gs_(alloc)
{ }
bool

View File

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