зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound on a CLOSED TREE
This commit is contained in:
Коммит
d6a3510342
|
@ -1704,7 +1704,7 @@ static bool
|
|||
EnableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
args.rval().setBoolean(TraceLoggerEnable(logger, cx));
|
||||
|
||||
return true;
|
||||
|
@ -1714,7 +1714,7 @@ static bool
|
|||
DisableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
args.rval().setBoolean(TraceLoggerDisable(logger));
|
||||
|
||||
return true;
|
||||
|
|
|
@ -2985,16 +2985,16 @@ AC_SUBST(MOZ_OPTIMIZE_SIZE_TWEAK)
|
|||
AC_SUBST(MOZ_PGO_OPTIMIZE_FLAGS)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Disable trace logging
|
||||
dnl = Enable trace logging
|
||||
dnl ========================================================
|
||||
ENABLE_TRACE_LOGGING=1
|
||||
MOZ_ARG_DISABLE_BOOL(trace-logging,
|
||||
[ --disable-trace-logging Disable trace logging],
|
||||
MOZ_ARG_ENABLE_BOOL(trace-logging,
|
||||
[ --enable-trace-logging Enable trace logging],
|
||||
ENABLE_TRACE_LOGGING=1,
|
||||
ENABLE_TRACE_LOGGING= )
|
||||
|
||||
AC_SUBST(ENABLE_TRACE_LOGGING)
|
||||
|
||||
if test -n "$ENABLE_TRACE_LOGGING"; then
|
||||
if test "$ENABLE_TRACE_LOGGING"; then
|
||||
AC_DEFINE(JS_TRACE_LOGGING)
|
||||
fi
|
||||
|
||||
|
|
|
@ -220,14 +220,14 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
|
|||
|
||||
RootedString source(cx, source_);
|
||||
|
||||
js::TraceLoggerThread *logger = nullptr;
|
||||
js::TraceLogger *logger = nullptr;
|
||||
if (cx->isJSContext())
|
||||
logger = TraceLoggerForMainThread(cx->asJSContext()->runtime());
|
||||
else
|
||||
logger = TraceLoggerForCurrentThread();
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileScript);
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileScript);
|
||||
|
||||
/*
|
||||
* The scripted callerFrame can only be given for compile-and-go scripts
|
||||
|
@ -475,10 +475,10 @@ frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const cha
|
|||
.setNoScriptRval(false)
|
||||
.setSelfHostingMode(false);
|
||||
|
||||
js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileLazy);
|
||||
js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileLazy);
|
||||
|
||||
Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars, length,
|
||||
/* foldConstants = */ true, nullptr, lazy);
|
||||
|
@ -533,10 +533,10 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp
|
|||
const AutoNameVector &formals, SourceBufferHolder &srcBuf,
|
||||
HandleObject enclosingScope, GeneratorKind generatorKind)
|
||||
{
|
||||
js::TraceLoggerThread *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
js::TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, options);
|
||||
js::AutoTraceLog scriptLogger(logger, event);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger_ParserCompileFunction);
|
||||
js::TraceLogger *logger = js::TraceLoggerForMainThread(cx->runtime());
|
||||
uint32_t logId = js::TraceLogCreateTextId(logger, options);
|
||||
js::AutoTraceLog scriptLogger(logger, logId);
|
||||
js::AutoTraceLog typeLogger(logger, TraceLogger::ParserCompileFunction);
|
||||
|
||||
// FIXME: make Function pass in two strings and parse them as arguments and
|
||||
// ProgramElements respectively.
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
function TestDrainTraceLoggerInvariants(obj) {
|
||||
var scripts = 0;
|
||||
var stops = 0;
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
if (objs[i].logType == "Scripts") {
|
||||
scripts++;
|
||||
assertEq("fileName" in objs[i], true);
|
||||
assertEq("lineNumber" in objs[i], true);
|
||||
assertEq("columnNumber" in objs[i], true);
|
||||
} else if (objs[i].logType == "Stop") {
|
||||
stops++;
|
||||
} else {
|
||||
assertEq(true, false);
|
||||
}
|
||||
}
|
||||
assertEq(scripts, stops);
|
||||
}
|
||||
|
||||
function GetMaxScriptDepth(obj) {
|
||||
var max_depth = 0;
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
if (objs[i].logType == "Stop")
|
||||
depth--;
|
||||
else {
|
||||
depth++;
|
||||
if (depth > max_depth)
|
||||
max_depth = depth;
|
||||
}
|
||||
}
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
function foo1() {
|
||||
foo2();
|
||||
}
|
||||
function foo2() {
|
||||
|
||||
}
|
||||
|
||||
var du = new Debugger();
|
||||
if (typeof du.drainTraceLoggerTraces == "function") {
|
||||
print(1);
|
||||
// Test normal setup.
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerForTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
var empty_depth = GetMaxScriptDepth(objs);
|
||||
var empty_length = objs.length;
|
||||
|
||||
// Test basic script.
|
||||
for (var i=0; i<20; i++)
|
||||
foo1();
|
||||
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
foo1();
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
assertEq(empty_depth + 2 == GetMaxScriptDepth(objs));
|
||||
assertEq(empty_length + 4 == GetMaxScriptDepth(objs));
|
||||
|
||||
// Test basic script.
|
||||
for (var i=0; i<20; i++)
|
||||
foo1();
|
||||
|
||||
du = new Debugger();
|
||||
du.setupTraceLoggerForTraces();
|
||||
|
||||
du.startTraceLogger();
|
||||
for (var i=0; i<100; i++) {
|
||||
foo1();
|
||||
}
|
||||
du.endTraceLogger();
|
||||
|
||||
var objs = du.drainTraceLoggerTraces();
|
||||
TestDrainTraceLoggerInvariants(objs);
|
||||
assertEq(empty_depth + 2 == GetMaxScriptDepth(objs));
|
||||
assertEq(empty_length + 4*100 == GetMaxScriptDepth(objs));
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
|
||||
var du = new Debugger();
|
||||
if (typeof du.setupTraceLogger == "function") {
|
||||
|
||||
// Try enabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: true
|
||||
}), true);
|
||||
|
||||
// No fail on re-enabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: true
|
||||
}), true);
|
||||
|
||||
// Try disabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: false
|
||||
}), true);
|
||||
|
||||
// No fail on re-disabling.
|
||||
assertEq(du.setupTraceLogger({
|
||||
Scripts: false
|
||||
}), true);
|
||||
|
||||
// Throw exception if TraceLog item to report isn't found.
|
||||
var success = du.setupTraceLogger({
|
||||
Scripts: false,
|
||||
Test: true
|
||||
});
|
||||
assertEq(success, false);
|
||||
|
||||
// SetupTraceLogger only enables individual items,
|
||||
// when all items can be toggled.
|
||||
du.startTraceLogger();
|
||||
var obj = du.drainTraceLogger();
|
||||
du.setupTraceLogger({
|
||||
Scripts: true,
|
||||
Test: true,
|
||||
});
|
||||
assertEq(du.drainTraceLogger().length, 0);
|
||||
du.endTraceLogger();
|
||||
|
||||
// Expects an object as first argument.
|
||||
succes = du.setupTraceLogger("blaat");
|
||||
assertEq(succes, false);
|
||||
|
||||
// Expects an object as first argument.
|
||||
succes = du.setupTraceLogger("blaat");
|
||||
assertEq(succes, false);
|
||||
|
||||
// Expects an object as first argument.
|
||||
failed = false;
|
||||
try {
|
||||
du.setupTraceLogger();
|
||||
} catch (e) {
|
||||
failed = true;
|
||||
}
|
||||
assertEq(failed, true);
|
||||
|
||||
// No problem with added to many arguments.
|
||||
succes = du.setupTraceLogger({}, "test");
|
||||
assertEq(succes, true);
|
||||
}
|
||||
|
||||
var du2 = new Debugger();
|
||||
if (typeof du2.setupTraceLoggerForTraces == "function") {
|
||||
du2.setupTraceLoggerForTraces({});
|
||||
du2.setupTraceLoggerForTraces("test");
|
||||
du2.setupTraceLoggerForTraces({}, "test");
|
||||
}
|
|
@ -41,8 +41,8 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
|
|||
JitFrameIterator iter(jitActivations);
|
||||
MOZ_ASSERT(!iter.ionScript()->invalidated());
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Bailout);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger::Bailout);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
|
||||
|
@ -107,8 +107,8 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
|||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Invalidation);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger::Invalidation);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
|
||||
|
|
|
@ -1347,9 +1347,9 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
|||
MOZ_ASSERT(poppedLastSPSFrameOut);
|
||||
MOZ_ASSERT(!*poppedLastSPSFrameOut);
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
|
||||
// The caller of the top frame must be one of the following:
|
||||
// IonJS - Ion calling into Ion.
|
||||
|
@ -1460,12 +1460,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
|||
snapIter.settleOnFrame();
|
||||
|
||||
if (frameNo > 0) {
|
||||
// TraceLogger doesn't create entries for inlined frames. But we
|
||||
// see them in Baseline. Here we create the start events of those
|
||||
// entries. So they correspond to what we will see in Baseline.
|
||||
TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, scr);
|
||||
TraceLogStartEvent(logger, scriptEvent);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr));
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_BaselineBailouts, " FrameNo %d", frameNo);
|
||||
|
|
|
@ -81,10 +81,9 @@ BaselineCompiler::compile()
|
|||
JitSpew(JitSpew_Codegen, "# Emitting baseline code for script %s:%d",
|
||||
script->filename(), script->lineno());
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent scriptEvent(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, scriptEvent);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logCompile(logger, TraceLogger::BaselineCompilation);
|
||||
|
||||
if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
|
||||
return Method_Error;
|
||||
|
@ -178,10 +177,6 @@ BaselineCompiler::compile()
|
|||
prologueOffset_.fixup(&masm);
|
||||
epilogueOffset_.fixup(&masm);
|
||||
spsPushToggleOffset_.fixup(&masm);
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
traceLoggerEnterToggleOffset_.fixup(&masm);
|
||||
traceLoggerExitToggleOffset_.fixup(&masm);
|
||||
#endif
|
||||
postDebugPrologueOffset_.fixup(&masm);
|
||||
|
||||
// Note: There is an extra entry in the bytecode type map for the search hint, see below.
|
||||
|
@ -191,8 +186,6 @@ BaselineCompiler::compile()
|
|||
BaselineScript::New(script, prologueOffset_.offset(),
|
||||
epilogueOffset_.offset(),
|
||||
spsPushToggleOffset_.offset(),
|
||||
traceLoggerEnterToggleOffset_.offset(),
|
||||
traceLoggerExitToggleOffset_.offset(),
|
||||
postDebugPrologueOffset_.offset(),
|
||||
icEntries_.length(),
|
||||
pcMappingIndexEntries.length(),
|
||||
|
@ -248,11 +241,6 @@ BaselineCompiler::compile()
|
|||
if (cx->runtime()->spsProfiler.enabled())
|
||||
baselineScript->toggleSPS(true);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
// Initialize the tracelogger instrumentation.
|
||||
baselineScript->initTraceLogger(cx->runtime(), script);
|
||||
#endif
|
||||
|
||||
uint32_t *bytecodeMap = baselineScript->bytecodeTypeMap();
|
||||
types::FillBytecodeTypeMap(script, bytecodeMap);
|
||||
|
||||
|
@ -385,8 +373,13 @@ BaselineCompiler::emitPrologue()
|
|||
masm.bind(&earlyStackCheckFailed);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (!emitTraceLoggerEnter())
|
||||
return false;
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
masm.tracelogStart(loggerReg, TraceLogCreateTextId(logger, script));
|
||||
masm.tracelogStart(loggerReg, TraceLogger::Baseline);
|
||||
masm.Pop(loggerReg);
|
||||
#endif
|
||||
|
||||
// Record the offset of the prologue, because Ion can bailout before
|
||||
|
@ -426,8 +419,15 @@ BaselineCompiler::emitEpilogue()
|
|||
masm.bind(&return_);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (!emitTraceLoggerExit())
|
||||
return false;
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
masm.tracelogStop(loggerReg, TraceLogger::Baseline);
|
||||
// Stop the script. Using a stop without checking the textId, since we
|
||||
// we didn't save the textId for the script.
|
||||
masm.tracelogStop(loggerReg);
|
||||
masm.Pop(loggerReg);
|
||||
#endif
|
||||
|
||||
// Pop SPS frame if necessary
|
||||
|
@ -767,64 +767,6 @@ BaselineCompiler::emitDebugTrap()
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
bool
|
||||
BaselineCompiler::emitTraceLoggerEnter()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
Register loggerReg = regs.takeGeneral();
|
||||
Register scriptReg = regs.takeGeneral();
|
||||
|
||||
Label noTraceLogger;
|
||||
traceLoggerEnterToggleOffset_ = masm.toggledJump(&noTraceLogger);
|
||||
|
||||
masm.Push(loggerReg);
|
||||
masm.Push(scriptReg);
|
||||
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
|
||||
// Script start.
|
||||
masm.movePtr(ImmGCPtr(script), scriptReg);
|
||||
masm.loadPtr(Address(scriptReg, JSScript::offsetOfBaselineScript()), scriptReg);
|
||||
Address scriptEvent(scriptReg, BaselineScript::offsetOfTraceLoggerScriptEvent());
|
||||
masm.computeEffectiveAddress(scriptEvent, scriptReg);
|
||||
masm.tracelogStartEvent(loggerReg, scriptReg);
|
||||
|
||||
// Engine start.
|
||||
masm.tracelogStartId(loggerReg, TraceLogger_Baseline, /* force = */ true);
|
||||
|
||||
masm.Pop(scriptReg);
|
||||
masm.Pop(loggerReg);
|
||||
|
||||
masm.bind(&noTraceLogger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitTraceLoggerExit()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
Register loggerReg = RegisterSet::Volatile().takeGeneral();
|
||||
|
||||
Label noTraceLogger;
|
||||
traceLoggerExitToggleOffset_ = masm.toggledJump(&noTraceLogger);
|
||||
|
||||
masm.Push(loggerReg);
|
||||
masm.movePtr(ImmPtr(logger), loggerReg);
|
||||
|
||||
masm.tracelogStopId(loggerReg, TraceLogger_Baseline, /* force = */ true);
|
||||
masm.tracelogStopId(loggerReg, TraceLogger_Scripts, /* force = */ true);
|
||||
|
||||
masm.Pop(loggerReg);
|
||||
|
||||
masm.bind(&noTraceLogger);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitSPSPush()
|
||||
{
|
||||
|
|
|
@ -250,8 +250,6 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
bool emitArgumentTypeChecks();
|
||||
bool emitDebugPrologue();
|
||||
bool emitDebugTrap();
|
||||
bool emitTraceLoggerEnter();
|
||||
bool emitTraceLoggerExit();
|
||||
bool emitSPSPush();
|
||||
void emitSPSPop();
|
||||
|
||||
|
|
|
@ -41,9 +41,7 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal)
|
|||
}
|
||||
|
||||
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset)
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset)
|
||||
: method_(nullptr),
|
||||
templateScope_(nullptr),
|
||||
fallbackStubSpace_(),
|
||||
|
@ -53,15 +51,6 @@ BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
|||
spsOn_(false),
|
||||
#endif
|
||||
spsPushToggleOffset_(spsPushToggleOffset),
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_(false),
|
||||
traceLoggerEngineEnabled_(false),
|
||||
# endif
|
||||
traceLoggerEnterToggleOffset_(traceLoggerEnterToggleOffset),
|
||||
traceLoggerExitToggleOffset_(traceLoggerExitToggleOffset),
|
||||
traceLoggerScriptEvent_(),
|
||||
#endif
|
||||
postDebugPrologueOffset_(postDebugPrologueOffset),
|
||||
flags_(0)
|
||||
{ }
|
||||
|
@ -201,9 +190,9 @@ jit::EnterBaselineAtBranch(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc)
|
|||
data.calleeToken = CalleeToToken(fp->script());
|
||||
}
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_Interpreter);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::Interpreter);
|
||||
TraceLogStartEvent(logger, TraceLogger::Baseline);
|
||||
|
||||
IonExecStatus status = EnterBaseline(cx, data);
|
||||
if (status != IonExec_Ok)
|
||||
|
@ -350,8 +339,7 @@ jit::CanEnterBaselineMethod(JSContext *cx, RunState &state)
|
|||
|
||||
BaselineScript *
|
||||
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset,
|
||||
size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries)
|
||||
{
|
||||
|
@ -378,8 +366,7 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog
|
|||
if (!script)
|
||||
return nullptr;
|
||||
new (script) BaselineScript(prologueOffset, epilogueOffset,
|
||||
spsPushToggleOffset, traceLoggerEnterToggleOffset,
|
||||
traceLoggerExitToggleOffset, postDebugPrologueOffset);
|
||||
spsPushToggleOffset, postDebugPrologueOffset);
|
||||
|
||||
size_t offsetCursor = sizeof(BaselineScript);
|
||||
MOZ_ASSERT(offsetCursor == AlignBytes(sizeof(BaselineScript), DataAlignment));
|
||||
|
@ -847,90 +834,6 @@ BaselineScript::toggleSPS(bool enable)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
BaselineScript::initTraceLogger(JSRuntime *runtime, JSScript *script)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_ = TraceLogTextIdEnabled(TraceLogger_Scripts);
|
||||
traceLoggerEngineEnabled_ = TraceLogTextIdEnabled(TraceLogger_Engine);
|
||||
#endif
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(runtime);
|
||||
if (TraceLogTextIdEnabled(TraceLogger_Scripts))
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts, script);
|
||||
else
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
if (TraceLogTextIdEnabled(TraceLogger_Engine) || TraceLogTextIdEnabled(TraceLogger_Scripts)) {
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleTraceLoggerScripts(JSRuntime *runtime, JSScript *script, bool enable)
|
||||
{
|
||||
bool engineEnabled = TraceLogTextIdEnabled(TraceLogger_Engine);
|
||||
|
||||
MOZ_ASSERT(enable == !traceLoggerScriptsEnabled_);
|
||||
MOZ_ASSERT(engineEnabled == traceLoggerEngineEnabled_);
|
||||
|
||||
// Patch the logging script textId to be correct.
|
||||
// When logging log the specific textId else the global Scripts textId.
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(runtime);
|
||||
if (enable)
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts, script);
|
||||
else
|
||||
traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
if (!engineEnabled) {
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(enter);
|
||||
Assembler::ToggleToJmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
traceLoggerScriptsEnabled_ = enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleTraceLoggerEngine(bool enable)
|
||||
{
|
||||
bool scriptsEnabled = TraceLogTextIdEnabled(TraceLogger_Scripts);
|
||||
|
||||
MOZ_ASSERT(enable == !traceLoggerEngineEnabled_);
|
||||
MOZ_ASSERT(scriptsEnabled == traceLoggerScriptsEnabled_);
|
||||
|
||||
// Enable/Disable the traceLogger prologue and epilogue.
|
||||
CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_));
|
||||
CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_));
|
||||
if (!scriptsEnabled) {
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(enter);
|
||||
Assembler::ToggleToCmp(exit);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(enter);
|
||||
Assembler::ToggleToJmp(exit);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
traceLoggerEngineEnabled_ = enable;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
BaselineScript::purgeOptimizedStubs(Zone *zone)
|
||||
{
|
||||
|
@ -1038,34 +941,6 @@ jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
jit::ToggleBaselineTraceLoggerScripts(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleTraceLoggerScripts(runtime, script, enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
jit::ToggleBaselineTraceLoggerEngine(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleTraceLoggerEngine(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
MarkActiveBaselineScripts(JSRuntime *rt, const JitActivationIterator &activation)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "jit/Bailouts.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/IonMacroAssembler.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
@ -128,17 +127,6 @@ struct BaselineScript
|
|||
#endif
|
||||
uint32_t spsPushToggleOffset_;
|
||||
|
||||
// The offsets and event used for Tracelogger toggling.
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef DEBUG
|
||||
bool traceLoggerScriptsEnabled_;
|
||||
bool traceLoggerEngineEnabled_;
|
||||
# endif
|
||||
uint32_t traceLoggerEnterToggleOffset_;
|
||||
uint32_t traceLoggerExitToggleOffset_;
|
||||
TraceLoggerEvent traceLoggerScriptEvent_;
|
||||
#endif
|
||||
|
||||
// Native code offsets right after the debug prologue VM call returns, or
|
||||
// would have returned. This offset is recorded even when debug mode is
|
||||
// off to aid on-stack debug mode recompilation.
|
||||
|
@ -197,13 +185,11 @@ struct BaselineScript
|
|||
public:
|
||||
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
|
||||
BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset);
|
||||
uint32_t spsPushToggleOffset, uint32_t postDebugPrologueOffset);
|
||||
|
||||
static BaselineScript *New(JSScript *jsscript, uint32_t prologueOffset,
|
||||
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, size_t icEntries,
|
||||
uint32_t spsPushToggleOffset, size_t icEntries,
|
||||
size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries);
|
||||
|
||||
|
@ -372,16 +358,6 @@ struct BaselineScript
|
|||
|
||||
void toggleSPS(bool enable);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void initTraceLogger(JSRuntime *runtime, JSScript *script);
|
||||
void toggleTraceLoggerScripts(JSRuntime *runtime, JSScript *script, bool enable);
|
||||
void toggleTraceLoggerEngine(bool enable);
|
||||
|
||||
static size_t offsetOfTraceLoggerScriptEvent() {
|
||||
return offsetof(BaselineScript, traceLoggerScriptEvent_);
|
||||
}
|
||||
#endif
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteArrayWriteHole(uint32_t pcOffset);
|
||||
|
||||
|
@ -434,11 +410,6 @@ AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size
|
|||
void
|
||||
ToggleBaselineSPS(JSRuntime *runtime, bool enable);
|
||||
|
||||
void
|
||||
ToggleBaselineTraceLoggerScripts(JSRuntime *runtime, bool enable);
|
||||
void
|
||||
ToggleBaselineTraceLoggerEngine(JSRuntime *runtime, bool enable);
|
||||
|
||||
struct BaselineBailoutInfo
|
||||
{
|
||||
// Pointer into the current C stack, where overwriting will start.
|
||||
|
|
|
@ -2090,9 +2090,9 @@ CodeGenerator::visitOsrEntry(LOsrEntry *lir)
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger_Baseline))
|
||||
if (!emitTracelogStopEvent(TraceLogger::Baseline))
|
||||
return false;
|
||||
if (!emitTracelogStartEvent(TraceLogger_IonMonkey))
|
||||
if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -7652,7 +7652,7 @@ CodeGenerator::generate()
|
|||
if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogScriptStart())
|
||||
return false;
|
||||
if (!emitTracelogStartEvent(TraceLogger_IonMonkey))
|
||||
if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -7928,25 +7928,19 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
ionScript->copyPatchableBackedges(cx, code, patchableBackedges_.begin(), masm);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
for (uint32_t i = 0; i < patchableTraceLoggers_.length(); i++) {
|
||||
patchableTraceLoggers_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTraceLoggers_[i]),
|
||||
ImmPtr(logger),
|
||||
ImmPtr(nullptr));
|
||||
}
|
||||
|
||||
if (patchableTLScripts_.length() > 0) {
|
||||
MOZ_ASSERT(TraceLogTextIdEnabled(TraceLogger_Scripts));
|
||||
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
|
||||
ionScript->setTraceLoggerEvent(event);
|
||||
uint32_t textId = event.payload()->textId();
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void *) uintptr_t(textId)),
|
||||
ImmPtr((void *)0));
|
||||
}
|
||||
uint32_t scriptId = TraceLogCreateTextId(logger, script);
|
||||
for (uint32_t i = 0; i < patchableTLScripts_.length(); i++) {
|
||||
patchableTLScripts_[i].fixup(&masm);
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, patchableTLScripts_[i]),
|
||||
ImmPtr((void *) uintptr_t(scriptId)),
|
||||
ImmPtr((void *)0));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -539,10 +539,9 @@ jit::LazyLinkTopActivation(JSContext *cx)
|
|||
builder->remove();
|
||||
|
||||
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);
|
||||
js::TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logLink(logger, TraceLogger::IonLinking);
|
||||
|
||||
IonContext ictx(cx, &builder->alloc());
|
||||
|
||||
|
@ -1290,7 +1289,7 @@ bool
|
|||
OptimizeMIR(MIRGenerator *mir)
|
||||
{
|
||||
MIRGraph &graph = mir->graph();
|
||||
TraceLoggerThread *logger;
|
||||
TraceLogger *logger;
|
||||
if (GetIonContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetIonContext()->runtime);
|
||||
else
|
||||
|
@ -1308,7 +1307,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
return false;
|
||||
|
||||
if (!mir->compilingAsmJS()) {
|
||||
AutoTraceLog log(logger, TraceLogger_FoldTests);
|
||||
AutoTraceLog log(logger, TraceLogger::FoldTests);
|
||||
FoldTests(graph);
|
||||
IonSpewPass("Fold Tests");
|
||||
AssertBasicGraphCoherency(graph);
|
||||
|
@ -1318,7 +1317,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_SplitCriticalEdges);
|
||||
AutoTraceLog log(logger, TraceLogger::SplitCriticalEdges);
|
||||
if (!SplitCriticalEdges(graph))
|
||||
return false;
|
||||
IonSpewPass("Split Critical Edges");
|
||||
|
@ -1329,7 +1328,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_RenumberBlocks);
|
||||
AutoTraceLog log(logger, TraceLogger::RenumberBlocks);
|
||||
if (!RenumberBlocks(graph))
|
||||
return false;
|
||||
IonSpewPass("Renumber Blocks");
|
||||
|
@ -1340,7 +1339,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_DominatorTree);
|
||||
AutoTraceLog log(logger, TraceLogger::DominatorTree);
|
||||
if (!BuildDominatorTree(graph))
|
||||
return false;
|
||||
// No spew: graph not changed.
|
||||
|
@ -1350,7 +1349,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_PhiAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::PhiAnalysis);
|
||||
// Aggressive phi elimination must occur before any code elimination. If the
|
||||
// script contains a try-statement, we only compiled the try block and not
|
||||
// the catch or finally blocks, so in this case it's also invalid to use
|
||||
|
@ -1376,7 +1375,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().scalarReplacementEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
|
||||
AutoTraceLog log(logger, TraceLogger::ScalarReplacement);
|
||||
if (!ScalarReplacement(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("Scalar Replacement");
|
||||
|
@ -1387,7 +1386,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (!mir->compilingAsmJS()) {
|
||||
AutoTraceLog log(logger, TraceLogger_ApplyTypes);
|
||||
AutoTraceLog log(logger, TraceLogger::ApplyTypes);
|
||||
if (!ApplyTypeInformation(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("Apply types");
|
||||
|
@ -1402,7 +1401,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
// are not deleted, leaving them dangling. This is ok, since we'll rerun
|
||||
// AliasAnalysis, which recomputes them, before they're needed.
|
||||
if (graph.entryBlock()->info().executionMode() == ParallelExecution) {
|
||||
AutoTraceLog log(logger, TraceLogger_ParallelSafetyAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::ParallelSafetyAnalysis);
|
||||
ParallelSafetyAnalysis analysis(mir, graph);
|
||||
if (!analysis.analyze())
|
||||
return false;
|
||||
|
@ -1421,7 +1420,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
if (mir->optimizationInfo().licmEnabled() ||
|
||||
mir->optimizationInfo().gvnEnabled())
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_AliasAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::AliasAnalysis);
|
||||
AliasAnalysis analysis(mir, graph);
|
||||
if (!analysis.analyze())
|
||||
return false;
|
||||
|
@ -1444,7 +1443,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().gvnEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_GVN);
|
||||
AutoTraceLog log(logger, TraceLogger::GVN);
|
||||
if (!gvn.run(ValueNumberer::UpdateAliasAnalysis))
|
||||
return false;
|
||||
IonSpewPass("GVN");
|
||||
|
@ -1455,7 +1454,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().licmEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_LICM);
|
||||
AutoTraceLog log(logger, TraceLogger::LICM);
|
||||
// LICM can hoist instructions from conditional branches and trigger
|
||||
// repeated bailouts. Disable it if this script is known to bailout
|
||||
// frequently.
|
||||
|
@ -1472,7 +1471,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().rangeAnalysisEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_RangeAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::RangeAnalysis);
|
||||
RangeAnalysis r(mir, graph);
|
||||
if (!r.addBetaNodes())
|
||||
return false;
|
||||
|
@ -1530,7 +1529,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().loopUnrollingEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_LoopUnrolling);
|
||||
AutoTraceLog log(logger, TraceLogger::LoopUnrolling);
|
||||
|
||||
if (!UnrollLoops(graph, r.loopIterationBounds))
|
||||
return false;
|
||||
|
@ -1541,7 +1540,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().eaaEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_EffectiveAddressAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::EffectiveAddressAnalysis);
|
||||
EffectiveAddressAnalysis eaa(graph);
|
||||
if (!eaa.analyze())
|
||||
return false;
|
||||
|
@ -1553,7 +1552,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
|
||||
AutoTraceLog log(logger, TraceLogger::EliminateDeadCode);
|
||||
if (!EliminateDeadCode(mir, graph))
|
||||
return false;
|
||||
IonSpewPass("DCE");
|
||||
|
@ -1566,7 +1565,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
// Make loops contiguous. We do this after GVN/UCE and range analysis,
|
||||
// which can remove CFG edges, exposing more blocks that can be moved.
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_MakeLoopsContiguous);
|
||||
AutoTraceLog log(logger, TraceLogger::MakeLoopsContiguous);
|
||||
if (!MakeLoopsContiguous(graph))
|
||||
return false;
|
||||
IonSpewPass("Make loops contiguous");
|
||||
|
@ -1580,7 +1579,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
// depend on knowing the final order in which instructions will execute.
|
||||
|
||||
if (mir->optimizationInfo().edgeCaseAnalysisEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_EdgeCaseAnalysis);
|
||||
AutoTraceLog log(logger, TraceLogger::EdgeCaseAnalysis);
|
||||
EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
|
||||
if (!edgeCaseAnalysis.analyzeLate())
|
||||
return false;
|
||||
|
@ -1592,7 +1591,7 @@ OptimizeMIR(MIRGenerator *mir)
|
|||
}
|
||||
|
||||
if (mir->optimizationInfo().eliminateRedundantChecksEnabled()) {
|
||||
AutoTraceLog log(logger, TraceLogger_EliminateRedundantChecks);
|
||||
AutoTraceLog log(logger, TraceLogger::EliminateRedundantChecks);
|
||||
// Note: check elimination has to run after all other passes that move
|
||||
// instructions. Since check uses are replaced with the actual index,
|
||||
// code motion after this pass could incorrectly move a load or store
|
||||
|
@ -1611,7 +1610,7 @@ GenerateLIR(MIRGenerator *mir)
|
|||
{
|
||||
MIRGraph &graph = mir->graph();
|
||||
|
||||
TraceLoggerThread *logger;
|
||||
TraceLogger *logger;
|
||||
if (GetIonContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetIonContext()->runtime);
|
||||
else
|
||||
|
@ -1623,7 +1622,7 @@ GenerateLIR(MIRGenerator *mir)
|
|||
|
||||
LIRGenerator lirgen(mir, graph, *lir);
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_GenerateLIR);
|
||||
AutoTraceLog log(logger, TraceLogger::GenerateLIR);
|
||||
if (!lirgen.generate())
|
||||
return nullptr;
|
||||
IonSpewPass("Generate LIR");
|
||||
|
@ -1635,7 +1634,7 @@ GenerateLIR(MIRGenerator *mir)
|
|||
AllocationIntegrityState integrity(*lir);
|
||||
|
||||
{
|
||||
AutoTraceLog log(logger, TraceLogger_RegisterAllocation);
|
||||
AutoTraceLog log(logger, TraceLogger::RegisterAllocation);
|
||||
|
||||
switch (mir->optimizationInfo().registerAllocator()) {
|
||||
case RegisterAllocator_LSRA: {
|
||||
|
@ -1705,12 +1704,12 @@ GenerateLIR(MIRGenerator *mir)
|
|||
CodeGenerator *
|
||||
GenerateCode(MIRGenerator *mir, LIRGraph *lir)
|
||||
{
|
||||
TraceLoggerThread *logger;
|
||||
TraceLogger *logger;
|
||||
if (GetIonContext()->runtime->onMainThread())
|
||||
logger = TraceLoggerForMainThread(GetIonContext()->runtime);
|
||||
else
|
||||
logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog log(logger, TraceLogger_GenerateCode);
|
||||
AutoTraceLog log(logger, TraceLogger::GenerateCode);
|
||||
|
||||
CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir);
|
||||
if (!codegen)
|
||||
|
@ -1752,7 +1751,7 @@ AttachFinishedCompilations(JSContext *cx)
|
|||
|
||||
GlobalHelperThreadState::IonBuilderVector &finished = HelperThreadState().ionFinishedList();
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
// Incorporate any off thread compilations for the compartment which have
|
||||
// finished, failed or have been cancelled.
|
||||
|
@ -1804,9 +1803,8 @@ AttachFinishedCompilations(JSContext *cx)
|
|||
if (CodeGenerator *codegen = builder->backgroundCodegen()) {
|
||||
RootedScript script(cx, builder->script());
|
||||
IonContext ictx(cx, &builder->alloc());
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logLink(logger, TraceLogger_IonLinking);
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logLink(logger, TraceLogger::IonLinking);
|
||||
|
||||
// Root the assembler until the builder is finished below. As it
|
||||
// was constructed off thread, the assembler has not been rooted
|
||||
|
@ -1884,10 +1882,9 @@ IonCompile(JSContext *cx, JSScript *script,
|
|||
ExecutionMode executionMode, bool recompile,
|
||||
OptimizationLevel optimizationLevel)
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, script);
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, script));
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IonCompilation);
|
||||
|
||||
MOZ_ASSERT(optimizationLevel > Optimization_DontCompile);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Opcodes.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
@ -343,11 +342,6 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
|
|||
if (!optimizationInfo().inlineInterpreted())
|
||||
return InliningDecision_DontInline;
|
||||
|
||||
if (TraceLogTextIdEnabled(TraceLogger_InlinedScripts)) {
|
||||
return DontInline(nullptr, "Tracelogging of inlined scripts is enabled"
|
||||
"but Tracelogger cannot do that yet.");
|
||||
}
|
||||
|
||||
if (!target->isInterpreted())
|
||||
return DontInline(nullptr, "Non-interpreted target");
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "jit/IonOptimizationLevels.h"
|
||||
#include "jit/IonTypes.h"
|
||||
#include "js/UbiNode.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -303,9 +302,6 @@ struct IonScript
|
|||
// that contain an optimized call directly into this IonScript.
|
||||
Vector<DependentAsmJSModuleExit> *dependentAsmJSModules;
|
||||
|
||||
// The tracelogger event used to log the start/stop of this IonScript.
|
||||
TraceLoggerEvent traceLoggerScriptEvent_;
|
||||
|
||||
IonBuilder *pendingBuilder_;
|
||||
|
||||
private:
|
||||
|
@ -496,9 +492,6 @@ struct IonScript
|
|||
bool hasSPSInstrumentation() const {
|
||||
return hasSPSInstrumentation_;
|
||||
}
|
||||
void setTraceLoggerEvent(TraceLoggerEvent &event) {
|
||||
traceLoggerScriptEvent_ = event;
|
||||
}
|
||||
const uint8_t *snapshots() const {
|
||||
return reinterpret_cast<const uint8_t *>(this) + snapshots_;
|
||||
}
|
||||
|
|
|
@ -693,7 +693,7 @@ void
|
|||
HandleException(ResumeFromException *rfe)
|
||||
{
|
||||
JSContext *cx = GetJSContextFromJitCode();
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
|
||||
|
||||
|
@ -754,8 +754,8 @@ HandleException(ResumeFromException *rfe)
|
|||
JSScript *script = frames.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
|
||||
if (!frames.more()) {
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
TraceLogStopEvent(logger, TraceLogger::IonMonkey);
|
||||
TraceLogStopEvent(logger);
|
||||
break;
|
||||
}
|
||||
++frames;
|
||||
|
@ -785,8 +785,8 @@ HandleException(ResumeFromException *rfe)
|
|||
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
|
||||
return;
|
||||
|
||||
TraceLogStopEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
TraceLogStopEvent(logger, TraceLogger::Baseline);
|
||||
TraceLogStopEvent(logger);
|
||||
|
||||
// Unwind profiler pseudo-stack
|
||||
JSScript *script = iter.script();
|
||||
|
|
|
@ -1668,10 +1668,9 @@ MacroAssembler::printf(const char *output, Register value)
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
MacroAssembler::tracelogStartId(Register logger, uint32_t textId, bool force)
|
||||
MacroAssembler::tracelogStart(Register logger, uint32_t textId)
|
||||
{
|
||||
if (!force && !TraceLogTextIdEnabled(textId))
|
||||
return;
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
|
@ -1684,56 +1683,38 @@ MacroAssembler::tracelogStartId(Register logger, uint32_t textId, bool force)
|
|||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStartId(Register logger, Register textId)
|
||||
{
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
regs.takeUnchecked(textId);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStartEvent(Register logger, Register event)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLoggerThread *, const TraceLoggerEvent &) = TraceLogStartEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
regs.takeUnchecked(event);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(event);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
|
||||
MacroAssembler::tracelogStart(Register logger, Register textId)
|
||||
{
|
||||
if (!force && !TraceLogTextIdEnabled(textId))
|
||||
return;
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStartEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
regs.takeUnchecked(textId);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStop(Register logger, uint32_t textId)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
|
@ -1746,19 +1727,23 @@ MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
|
|||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
regs.add(temp);
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStopId(Register logger, Register textId)
|
||||
MacroAssembler::tracelogStop(Register logger, Register textId)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
|
||||
regs.takeUnchecked(textId);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
@ -1766,8 +1751,33 @@ MacroAssembler::tracelogStopId(Register logger, Register textId)
|
|||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
regs.add(temp);
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
#else
|
||||
tracelogStop(logger);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::tracelogStop(Register logger)
|
||||
{
|
||||
void (&TraceLogFunc)(TraceLogger*) = TraceLogStopEvent;
|
||||
|
||||
PushRegsInMask(RegisterSet::Volatile());
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
regs.takeUnchecked(logger);
|
||||
|
||||
Register temp = regs.takeGeneral();
|
||||
|
||||
setupUnalignedABICall(1, temp);
|
||||
passABIArg(logger);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
regs.add(temp);
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
|
|
@ -1207,11 +1207,11 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
void printf(const char *output, Register value);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void tracelogStartId(Register logger, uint32_t textId, bool force = false);
|
||||
void tracelogStartId(Register logger, Register textId);
|
||||
void tracelogStartEvent(Register logger, Register event);
|
||||
void tracelogStopId(Register logger, uint32_t textId, bool force = false);
|
||||
void tracelogStopId(Register logger, Register textId);
|
||||
void tracelogStart(Register logger, uint32_t textId);
|
||||
void tracelogStart(Register logger, Register textId);
|
||||
void tracelogStop(Register logger, uint32_t textId);
|
||||
void tracelogStop(Register logger, Register textId);
|
||||
void tracelogStop(Register logger);
|
||||
#endif
|
||||
|
||||
#define DISPATCH_FLOATING_POINT_OP(method, type, arg1d, arg1f, arg2) \
|
||||
|
|
|
@ -778,9 +778,9 @@ DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *p
|
|||
if (!DebugEpilogue(cx, frame, pc, true)) {
|
||||
// DebugEpilogue popped the frame by updating jitTop, so run the stop event
|
||||
// here before we enter the exception handler.
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger::Baseline);
|
||||
TraceLogStopEvent(logger); // Leave script.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ CodeGeneratorARM::generateEpilogue()
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger_IonMonkey))
|
||||
if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
if (!emitTracelogScriptStop())
|
||||
return false;
|
||||
|
|
|
@ -30,10 +30,7 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &all
|
|||
icLoadLabels_(),
|
||||
pushedBeforeCall_(0),
|
||||
inCall_(false),
|
||||
spsPushToggleOffset_(),
|
||||
traceLoggerEnterToggleOffset_(),
|
||||
traceLoggerExitToggleOffset_(),
|
||||
traceLoggerScriptTextIdOffset_()
|
||||
spsPushToggleOffset_()
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
|
|
@ -68,9 +68,6 @@ class BaselineCompilerShared
|
|||
mozilla::DebugOnly<bool> inCall_;
|
||||
|
||||
CodeOffsetLabel spsPushToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerEnterToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerExitToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerScriptTextIdOffset_;
|
||||
|
||||
BaselineCompilerShared(JSContext *cx, TempAllocator &alloc, JSScript *script);
|
||||
|
||||
|
|
|
@ -1011,7 +1011,7 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
|
|||
#endif
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (!emitTracelogStartEvent(TraceLogger_VM))
|
||||
if (!emitTracelogStartEvent(TraceLogger::VM))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
@ -1056,7 +1056,7 @@ CodeGeneratorShared::callVM(const VMFunction &fun, LInstruction *ins, const Regi
|
|||
// ... frame ...
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (!emitTracelogStopEvent(TraceLogger_VM))
|
||||
if (!emitTracelogStopEvent(TraceLogger::VM))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
@ -1402,9 +1402,6 @@ CodeGeneratorShared::computeDivisionConstants(int d) {
|
|||
bool
|
||||
CodeGeneratorShared::emitTracelogScript(bool isStart)
|
||||
{
|
||||
if (!TraceLogTextIdEnabled(TraceLogger_Scripts))
|
||||
return true;
|
||||
|
||||
Label done;
|
||||
|
||||
RegisterSet regs = RegisterSet::Volatile();
|
||||
|
@ -1417,7 +1414,7 @@ CodeGeneratorShared::emitTracelogScript(bool isStart)
|
|||
if (!patchableTraceLoggers_.append(patchLogger))
|
||||
return false;
|
||||
|
||||
Address enabledAddress(logger, TraceLoggerThread::offsetOfEnabled());
|
||||
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
|
||||
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
|
||||
|
||||
masm.Push(script);
|
||||
|
@ -1427,9 +1424,9 @@ CodeGeneratorShared::emitTracelogScript(bool isStart)
|
|||
return false;
|
||||
|
||||
if (isStart)
|
||||
masm.tracelogStartId(logger, script);
|
||||
masm.tracelogStart(logger, script);
|
||||
else
|
||||
masm.tracelogStopId(logger, script);
|
||||
masm.tracelogStop(logger, script);
|
||||
|
||||
masm.Pop(script);
|
||||
|
||||
|
@ -1455,13 +1452,18 @@ CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
|
|||
if (!patchableTraceLoggers_.append(patchLocation))
|
||||
return false;
|
||||
|
||||
Address enabledAddress(logger, TraceLoggerThread::offsetOfEnabled());
|
||||
Address enabledAddress(logger, TraceLogger::offsetOfEnabled());
|
||||
masm.branch32(Assembler::Equal, enabledAddress, Imm32(0), &done);
|
||||
|
||||
if (isStart)
|
||||
masm.tracelogStartId(logger, textId);
|
||||
else
|
||||
masm.tracelogStopId(logger, textId);
|
||||
if (isStart) {
|
||||
masm.tracelogStart(logger, textId);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
masm.tracelogStop(logger, textId);
|
||||
#else
|
||||
masm.tracelogStop(logger);
|
||||
#endif
|
||||
}
|
||||
|
||||
masm.bind(&done);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ CodeGeneratorX86Shared::generateEpilogue()
|
|||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (gen->info().executionMode() == SequentialExecution) {
|
||||
if (!emitTracelogStopEvent(TraceLogger_IonMonkey))
|
||||
if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
|
||||
return false;
|
||||
if (!emitTracelogScriptStop())
|
||||
return false;
|
||||
|
|
|
@ -3605,7 +3605,7 @@ GCHelperState::work()
|
|||
MOZ_ASSERT(!thread);
|
||||
thread = PR_GetCurrentThread();
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForCurrentThread();
|
||||
TraceLogger *logger = TraceLoggerForCurrentThread();
|
||||
|
||||
switch (state()) {
|
||||
|
||||
|
@ -3614,7 +3614,7 @@ GCHelperState::work()
|
|||
break;
|
||||
|
||||
case SWEEPING: {
|
||||
AutoTraceLog logSweeping(logger, TraceLogger_GCSweeping);
|
||||
AutoTraceLog logSweeping(logger, TraceLogger::GCSweeping);
|
||||
doSweep(lock);
|
||||
MOZ_ASSERT(state() == SWEEPING);
|
||||
break;
|
||||
|
@ -3638,8 +3638,8 @@ BackgroundAllocTask::BackgroundAllocTask(JSRuntime *rt, ChunkPool &pool)
|
|||
/* virtual */ void
|
||||
BackgroundAllocTask::run()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logAllocation(logger, TraceLogger_GCAllocation);
|
||||
TraceLogger *logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logAllocation(logger, TraceLogger::GCAllocation);
|
||||
|
||||
AutoLockGC lock(runtime);
|
||||
while (!cancel_ && runtime->gc.wantBackgroundAllocation(lock)) {
|
||||
|
@ -6249,8 +6249,8 @@ GCRuntime::collect(bool incremental, SliceBudget &budget, JSGCInvocationKind gck
|
|||
if (rt->mainThread.suppressGC)
|
||||
return;
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logGC(logger, TraceLogger_GC);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logGC(logger, TraceLogger::GC);
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (deterministicOnly && !IsDeterministicGCReason(reason))
|
||||
|
@ -6456,8 +6456,8 @@ GCRuntime::minorGC(JS::gcreason::Reason reason)
|
|||
{
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
minorGCRequested = false;
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logMinorGC(logger, TraceLogger_MinorGC);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
|
||||
nursery.collect(rt, reason, nullptr);
|
||||
MOZ_ASSERT_IF(!rt->mainThread.suppressGC, nursery.isEmpty());
|
||||
#endif
|
||||
|
@ -6470,8 +6470,8 @@ GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
|
|||
// objects as needing pretenuring.
|
||||
#ifdef JSGC_GENERATIONAL
|
||||
minorGCRequested = false;
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logMinorGC(logger, TraceLogger_MinorGC);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(rt);
|
||||
AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC);
|
||||
Nursery::TypeObjectList pretenureTypes;
|
||||
nursery.collect(rt, reason, &pretenureTypes);
|
||||
for (size_t i = 0; i < pretenureTypes.length(); i++) {
|
||||
|
|
|
@ -5126,10 +5126,6 @@ template size_t
|
|||
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, FILE *fp, const char *chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, const char16_t *chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
|
|
@ -400,12 +400,6 @@ FileEscapedString(FILE *fp, JSLinearString *str, uint32_t quote)
|
|||
return PutEscapedStringImpl(nullptr, 0, fp, str, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
inline bool
|
||||
FileEscapedString(FILE *fp, const char *chars, size_t length, uint32_t quote)
|
||||
{
|
||||
return PutEscapedStringImpl(nullptr, 0, fp, chars, length, quote) != size_t(-1);
|
||||
}
|
||||
|
||||
bool
|
||||
str_match(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
|
|
|
@ -312,8 +312,6 @@ if CONFIG['MOZ_INSTRUMENTS']:
|
|||
if CONFIG['ENABLE_TRACE_LOGGING']:
|
||||
SOURCES += [
|
||||
'vm/TraceLogging.cpp',
|
||||
'vm/TraceLoggingGraph.cpp',
|
||||
'vm/TraceLoggingTypes.cpp',
|
||||
]
|
||||
|
||||
if not CONFIG['ENABLE_ION']:
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/DebuggerMemory.h"
|
||||
#include "vm/SPSProfiler.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
@ -45,6 +44,7 @@ using js::frontend::IsIdentifier;
|
|||
using mozilla::ArrayLength;
|
||||
using mozilla::Maybe;
|
||||
|
||||
|
||||
/*** Forward declarations ************************************************************************/
|
||||
|
||||
extern const Class DebuggerFrame_class;
|
||||
|
@ -359,13 +359,7 @@ Debugger::Debugger(JSContext *cx, NativeObject *dbg)
|
|||
scripts(cx),
|
||||
sources(cx),
|
||||
objects(cx),
|
||||
environments(cx),
|
||||
#ifdef NIGHTLY_BUILD
|
||||
traceLoggerLastDrainedId(0),
|
||||
traceLoggerLastDrainedIteration(0),
|
||||
#endif
|
||||
traceLoggerScriptedCallsLastDrainedId(0),
|
||||
traceLoggerScriptedCallsLastDrainedIteration(0)
|
||||
environments(cx)
|
||||
{
|
||||
assertSameCompartment(cx, dbg);
|
||||
|
||||
|
@ -3776,253 +3770,6 @@ Debugger::makeGlobalObjectReference(JSContext *cx, unsigned argc, Value *vp)
|
|||
return dbg->wrapDebuggeeValue(cx, args.rval());
|
||||
}
|
||||
|
||||
static bool
|
||||
DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const char *value, size_t n)
|
||||
{
|
||||
JSString *text = JS_NewStringCopyN(cx, value, n);
|
||||
if (!text)
|
||||
return false;
|
||||
|
||||
RootedValue str(cx, StringValue(text));
|
||||
return JS_DefinePropertyById(cx, obj, id, str, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef NIGHTLY_BUILD
|
||||
bool
|
||||
Debugger::setupTraceLogger(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "setupTraceLogger", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.setupTraceLogger", 1))
|
||||
return false;
|
||||
|
||||
RootedObject obj(cx, ToObject(cx, args[0]));
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
AutoIdVector ids(cx);
|
||||
if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY, &ids))
|
||||
return false;
|
||||
|
||||
if (ids.length() == 0) {
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector<uint32_t> textIds(cx);
|
||||
if (!textIds.reserve(ids.length()))
|
||||
return false;
|
||||
|
||||
Vector<bool> values(cx);
|
||||
if (!values.reserve(ids.length()))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < ids.length(); i++) {
|
||||
if (!JSID_IS_STRING(ids[i])) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSString *id = JSID_TO_STRING(ids[i]);
|
||||
JSLinearString *linear = id->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return false;
|
||||
|
||||
uint32_t textId = TLStringToTextId(linear);
|
||||
|
||||
if (!TLTextIdIsToggable(textId)) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedValue v(cx);
|
||||
if (!JSObject::getGeneric(cx, obj, obj, ids[i], &v))
|
||||
return false;
|
||||
|
||||
textIds.append(textId);
|
||||
values.append(ToBoolean(v));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(ids.length() == textIds.length());
|
||||
MOZ_ASSERT(textIds.length() == values.length());
|
||||
|
||||
for (size_t i = 0; i < textIds.length(); i++) {
|
||||
if (values[i])
|
||||
TraceLogEnableTextId(cx, textIds[i]);
|
||||
else
|
||||
TraceLogDisableTextId(cx, textIds[i]);
|
||||
}
|
||||
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::drainTraceLogger(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "drainTraceLogger", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.drainTraceLogger", 0))
|
||||
return false;
|
||||
|
||||
size_t num;
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
bool lostEvents = logger->lostEvents(dbg->traceLoggerLastDrainedIteration,
|
||||
dbg->traceLoggerLastDrainedId);
|
||||
EventEntry *events = logger->getEventsStartingAt(&dbg->traceLoggerLastDrainedIteration,
|
||||
&dbg->traceLoggerLastDrainedId,
|
||||
&num);
|
||||
|
||||
RootedObject array(cx, NewDenseEmptyArray(cx));
|
||||
JSAtom *dataAtom = Atomize(cx, "data", strlen("data"));
|
||||
if (!dataAtom)
|
||||
return false;
|
||||
RootedId dataId(cx, AtomToId(dataAtom));
|
||||
|
||||
/* Add all events to the array. */
|
||||
uint32_t index = 0;
|
||||
for (EventEntry *eventItem = events; eventItem < events + num; eventItem++, index++) {
|
||||
RootedObject item(cx, NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, cx->global()));
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
const char *eventText = logger->eventText(eventItem->textId);
|
||||
if (!DefineProperty(cx, item, dataId, eventText, strlen(eventText)))
|
||||
return false;
|
||||
|
||||
RootedValue obj(cx, ObjectValue(*item));
|
||||
if (!JS_DefineElement(cx, array, index, obj, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add "lostEvents" indicating if there are events that were lost. */
|
||||
RootedValue lost(cx, BooleanValue(lostEvents));
|
||||
if (!JS_DefineProperty(cx, array, "lostEvents", lost, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*array);
|
||||
|
||||
return true;
|
||||
}
|
||||
# endif // NIGHTLY_BUILD
|
||||
|
||||
bool
|
||||
Debugger::setupTraceLoggerScriptCalls(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "setupTraceLoggerScriptCalls", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.setupTraceLoggerScriptCalls", 0))
|
||||
return false;
|
||||
|
||||
TraceLogEnableTextId(cx, TraceLogger_Scripts);
|
||||
TraceLogEnableTextId(cx, TraceLogger_InlinedScripts);
|
||||
TraceLogDisableTextId(cx, TraceLogger_AnnotateScripts);
|
||||
|
||||
args.rval().setBoolean(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::startTraceLogger(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "startTraceLogger", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.startTraceLogger", 0))
|
||||
return false;
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEnable(logger, cx);
|
||||
|
||||
args.rval().setUndefined();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::endTraceLogger(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "endTraceLogger", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.endTraceLogger", 0))
|
||||
return false;
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerDisable(logger);
|
||||
|
||||
args.rval().setUndefined();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::drainTraceLoggerScriptCalls(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
THIS_DEBUGGER(cx, argc, vp, "drainTraceLoggerScriptCalls", args, dbg);
|
||||
if (!args.requireAtLeast(cx, "Debugger.drainTraceLoggerScriptCalls", 0))
|
||||
return false;
|
||||
|
||||
size_t num;
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
bool lostEvents = logger->lostEvents(dbg->traceLoggerScriptedCallsLastDrainedIteration,
|
||||
dbg->traceLoggerScriptedCallsLastDrainedId);
|
||||
EventEntry *events = logger->getEventsStartingAt(
|
||||
&dbg->traceLoggerScriptedCallsLastDrainedIteration,
|
||||
&dbg->traceLoggerScriptedCallsLastDrainedId,
|
||||
&num);
|
||||
|
||||
RootedObject array(cx, NewDenseEmptyArray(cx));
|
||||
RootedId fileNameId(cx, AtomToId(cx->names().fileName));
|
||||
RootedId lineNumberId(cx, AtomToId(cx->names().lineNumber));
|
||||
RootedId columnNumberId(cx, AtomToId(cx->names().columnNumber));
|
||||
JSAtom *logTypeAtom = Atomize(cx, "logType", strlen("logType"));
|
||||
if (!logTypeAtom)
|
||||
return false;
|
||||
RootedId logTypeId(cx, AtomToId(logTypeAtom));
|
||||
|
||||
/* Add all events to the array. */
|
||||
uint32_t index = 0;
|
||||
for (EventEntry *eventItem = events; eventItem < events + num; eventItem++) {
|
||||
RootedObject item(cx, NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, cx->global()));
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
uint32_t textId = eventItem->textId;
|
||||
if (textId != TraceLogger_Stop && !logger->textIdIsScriptEvent(textId))
|
||||
continue;
|
||||
|
||||
const char *type = (textId == TraceLogger_Stop) ? "Stop" : "Script";
|
||||
if (!DefineProperty(cx, item, logTypeId, type, strlen(type)))
|
||||
return false;
|
||||
|
||||
if (textId != TraceLogger_Stop) {
|
||||
const char *filename, *lineno, *colno;
|
||||
size_t filename_len, lineno_len, colno_len;
|
||||
logger->extractScriptDetails(textId, &filename, &filename_len, &lineno, &lineno_len,
|
||||
&colno, &colno_len);
|
||||
|
||||
if (!DefineProperty(cx, item, fileNameId, filename, filename_len))
|
||||
return false;
|
||||
if (!DefineProperty(cx, item, lineNumberId, lineno, lineno_len))
|
||||
return false;
|
||||
if (!DefineProperty(cx, item, columnNumberId, colno, colno_len))
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedValue obj(cx, ObjectValue(*item));
|
||||
if (!JS_DefineElement(cx, array, index, obj, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
/* Add "lostEvents" indicating if there are events that were lost. */
|
||||
RootedValue lost(cx, BooleanValue(lostEvents));
|
||||
if (!JS_DefineProperty(cx, array, "lostEvents", lost, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*array);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const JSPropertySpec Debugger::properties[] = {
|
||||
JS_PSGS("enabled", Debugger::getEnabled, Debugger::setEnabled, 0),
|
||||
JS_PSGS("onDebuggerStatement", Debugger::getOnDebuggerStatement,
|
||||
|
@ -4052,16 +3799,6 @@ const JSFunctionSpec Debugger::methods[] = {
|
|||
JS_FN("findObjects", Debugger::findObjects, 1, 0),
|
||||
JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0),
|
||||
JS_FN("makeGlobalObjectReference", Debugger::makeGlobalObjectReference, 1, 0),
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
JS_FN("setupTraceLoggerScriptCalls", Debugger::setupTraceLoggerScriptCalls, 0, 0),
|
||||
JS_FN("drainTraceLoggerScriptCalls", Debugger::drainTraceLoggerScriptCalls, 0, 0),
|
||||
JS_FN("startTraceLogger", Debugger::startTraceLogger, 0, 0),
|
||||
JS_FN("endTraceLogger", Debugger::endTraceLogger, 0, 0),
|
||||
# ifdef NIGHTLY_BUILD
|
||||
JS_FN("setupTraceLogger", Debugger::setupTraceLogger, 1, 0),
|
||||
JS_FN("drainTraceLogger", Debugger::drainTraceLogger, 0, 0),
|
||||
# endif
|
||||
#endif
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -296,17 +296,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
/* The map from debuggee Envs to Debugger.Environment instances. */
|
||||
ObjectWeakMap environments;
|
||||
|
||||
/*
|
||||
* Keep track of tracelogger last drained identifiers to know if there are
|
||||
* lost events.
|
||||
*/
|
||||
#ifdef NIGHTLY_BUILD
|
||||
uint32_t traceLoggerLastDrainedId;
|
||||
uint32_t traceLoggerLastDrainedIteration;
|
||||
#endif
|
||||
uint32_t traceLoggerScriptedCallsLastDrainedId;
|
||||
uint32_t traceLoggerScriptedCallsLastDrainedIteration;
|
||||
|
||||
class FrameRange;
|
||||
class ScriptQuery;
|
||||
class ObjectQuery;
|
||||
|
@ -405,14 +394,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
static bool findObjects(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool findAllGlobals(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool makeGlobalObjectReference(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool setupTraceLoggerScriptCalls(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool drainTraceLoggerScriptCalls(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool startTraceLogger(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool endTraceLogger(JSContext *cx, unsigned argc, Value *vp);
|
||||
#ifdef NIGHTLY_BUILD
|
||||
static bool setupTraceLogger(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool drainTraceLogger(JSContext *cx, unsigned argc, Value *vp);
|
||||
#endif
|
||||
static bool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
static const JSPropertySpec properties[];
|
||||
static const JSFunctionSpec methods[];
|
||||
|
|
|
@ -1047,10 +1047,9 @@ HelperThread::handleIonWorkload()
|
|||
ionBuilder = builder;
|
||||
ionBuilder->setPauseFlag(&pause);
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForCurrentThread();
|
||||
TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, ionBuilder->script());
|
||||
AutoTraceLog logScript(logger, event);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
|
||||
TraceLogger *logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logScript(logger, TraceLogCreateTextId(logger, ionBuilder->script()));
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IonCompilation);
|
||||
|
||||
JSRuntime *rt = ionBuilder->script()->compartment()->runtimeFromAnyThread();
|
||||
|
||||
|
@ -1118,8 +1117,8 @@ CurrentHelperThread()
|
|||
void
|
||||
js::PauseCurrentHelperThread()
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
|
||||
TraceLogger *logger = TraceLoggerForCurrentThread();
|
||||
AutoTraceLog logPaused(logger, TraceLogger::IonCompilationPaused);
|
||||
|
||||
HelperThread *thread = CurrentHelperThread();
|
||||
|
||||
|
|
|
@ -1462,10 +1462,10 @@ Interpret(JSContext *cx, RunState &state)
|
|||
RootedScript script(cx);
|
||||
SET_SCRIPT(REGS.fp()->script());
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLoggerEvent scriptEvent(logger, TraceLogger_Scripts, script);
|
||||
TraceLogStartEvent(logger, scriptEvent);
|
||||
TraceLogStartEvent(logger, TraceLogger_Interpreter);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
uint32_t scriptLogId = TraceLogCreateTextId(logger, script);
|
||||
TraceLogStartEvent(logger, scriptLogId);
|
||||
TraceLogStartEvent(logger, TraceLogger::Interpreter);
|
||||
|
||||
/*
|
||||
* Pool of rooters for use in this interpreter frame. References to these
|
||||
|
@ -1763,8 +1763,9 @@ CASE(JSOP_RETRVAL)
|
|||
if (activation.entryFrame() != REGS.fp()) {
|
||||
// Stop the engine. (No details about which engine exactly, could be
|
||||
// interpreter, Baseline or IonMonkey.)
|
||||
TraceLogStopEvent(logger, TraceLogger_Engine);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
TraceLogStopEvent(logger);
|
||||
// Stop the script. (Again no details about which script exactly.)
|
||||
TraceLogStopEvent(logger);
|
||||
|
||||
interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK);
|
||||
|
||||
|
@ -2577,11 +2578,9 @@ CASE(JSOP_FUNCALL)
|
|||
|
||||
SET_SCRIPT(REGS.fp()->script());
|
||||
|
||||
{
|
||||
TraceLoggerEvent event(logger, TraceLogger_Scripts, script);
|
||||
TraceLogStartEvent(logger, event);
|
||||
TraceLogStartEvent(logger, TraceLogger_Interpreter);
|
||||
}
|
||||
uint32_t scriptLogId = TraceLogCreateTextId(logger, script);
|
||||
TraceLogStartEvent(logger, scriptLogId);
|
||||
TraceLogStartEvent(logger, TraceLogger::Interpreter);
|
||||
|
||||
if (!REGS.fp()->prologue(cx))
|
||||
goto error;
|
||||
|
@ -3493,8 +3492,8 @@ DEFAULT()
|
|||
|
||||
gc::MaybeVerifyBarriers(cx, true);
|
||||
|
||||
TraceLogStopEvent(logger, TraceLogger_Engine);
|
||||
TraceLogStopEvent(logger, scriptEvent);
|
||||
TraceLogStopEvent(logger);
|
||||
TraceLogStopEvent(logger, scriptLogId);
|
||||
|
||||
/*
|
||||
* This path is used when it's guaranteed the method can be finished
|
||||
|
|
|
@ -458,8 +458,8 @@ bool
|
|||
RegExpShared::compile(JSContext *cx, HandleLinearString input,
|
||||
CompilationMode mode, ForceByteCodeEnum force)
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logCompile(logger, TraceLogger_IrregexpCompile);
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
AutoTraceLog logCompile(logger, TraceLogger::IrregexpCompile);
|
||||
|
||||
if (!sticky()) {
|
||||
RootedAtom pattern(cx, source);
|
||||
|
@ -548,7 +548,7 @@ RegExpRunStatus
|
|||
RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
|
||||
MatchPairs *matches)
|
||||
{
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
CompilationMode mode = matches ? Normal : MatchOnly;
|
||||
|
||||
|
@ -604,7 +604,7 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
|
|||
|
||||
RegExpRunStatus result;
|
||||
{
|
||||
AutoTraceLog logJIT(logger, TraceLogger_IrregexpExecute);
|
||||
AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
|
||||
AutoCheckCannotGC nogc;
|
||||
if (input->hasLatin1Chars()) {
|
||||
const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
|
||||
|
@ -643,7 +643,7 @@ RegExpShared::execute(JSContext *cx, HandleLinearString input, size_t start,
|
|||
return RegExpRunStatus_Error;
|
||||
|
||||
uint8_t *byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger_IrregexpExecute);
|
||||
AutoTraceLog logInterpreter(logger, TraceLogger::IrregexpExecute);
|
||||
|
||||
AutoStableStringChars inputChars(cx);
|
||||
if (!inputChars.init(cx, input))
|
||||
|
|
|
@ -54,7 +54,7 @@ class PerThreadData;
|
|||
struct ThreadSafeContext;
|
||||
class AutoKeepAtoms;
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
class TraceLoggerThread;
|
||||
class TraceLogger;
|
||||
#endif
|
||||
|
||||
/* Thread Local Storage slot for storing the runtime for a thread. */
|
||||
|
@ -537,7 +537,7 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||
irregexp::RegExpStack regexpStack;
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread *traceLogger;
|
||||
TraceLogger *traceLogger;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,6 @@
|
|||
#define TraceLogging_h
|
||||
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jslock.h"
|
||||
|
@ -16,8 +15,6 @@
|
|||
#include "js/HashTable.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/TraceLoggingGraph.h"
|
||||
#include "vm/TraceLoggingTypes.h"
|
||||
|
||||
struct JSRuntime;
|
||||
|
||||
|
@ -35,315 +32,513 @@ namespace jit {
|
|||
/*
|
||||
* Tracelogging overview.
|
||||
*
|
||||
* Tracelogging makes it possible to trace the occurence of a single event and/or
|
||||
* the start and stop of an event. This is implemented to give an as low overhead as
|
||||
* Tracelogging makes it possible to trace the timestamp of a single event and/or
|
||||
* the duration of an event. This is implemented to give an as low overhead as
|
||||
* possible so it doesn't interfere with running.
|
||||
*
|
||||
* The output of a tracelogging session is saved in /tmp/tl-data.json.
|
||||
* The format of that file is a JS array per tracelogger (=thread), with a map
|
||||
* containing:
|
||||
* - dict: Name of the file containing a json table with the log text.
|
||||
* All other files only contain a index to this table when logging.
|
||||
* - events: Name of the file containing a flat list of log events saved
|
||||
* in binary format.
|
||||
* (64bit: Time Stamp Counter, 32bit index to dict)
|
||||
* - tree: Name of the file containing the events with duration. The content
|
||||
* is already in a tree data structure. This is also saved in a
|
||||
* binary file.
|
||||
* - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
|
||||
* There are currently no other formats to save the tree.
|
||||
* - 64,64,31,1,31 signifies how many bytes are used for the different
|
||||
* parts of the tree.
|
||||
* => 64 bits: Time Stamp Counter of start of event.
|
||||
* => 64 bits: Time Stamp Counter of end of event.
|
||||
* => 31 bits: Index to dict file containing the log text.
|
||||
* => 1 bit: Boolean signifying if this entry has children.
|
||||
* When true, the child can be found just behind this entry.
|
||||
* => 32 bits: Containing the ID of the next event on the same depth
|
||||
* or 0 if there isn't an event on the same depth anymore.
|
||||
*
|
||||
* /-> The position in the file. Id is this divided by size of entry.
|
||||
* | So in this case this would be 1 (192bits per entry).
|
||||
* | /-> Indicates there are children. The
|
||||
* | | first child is located at current
|
||||
* | | ID + 1. So 1 + 1 in this case: 2.
|
||||
* | | Or 0x00180 in the tree file.
|
||||
* | | /-> Next event on the same depth is
|
||||
* | | | located at 4. So 0x00300 in the
|
||||
* | | | tree file.
|
||||
* 0x0000C0: [start, end, dictId, 1, 4]
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* 0x0: [start, end, dictId, 1, 0]
|
||||
* |
|
||||
* /----------------------------------\
|
||||
* | |
|
||||
* 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0]
|
||||
* |
|
||||
* /----------------------------------\
|
||||
* | |
|
||||
* 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0]
|
||||
*
|
||||
*
|
||||
* Logging something is done in 3 stages.
|
||||
* 1) Get the tracelogger of the current thread.
|
||||
* - TraceLoggerForMainThread(JSRuntime *)
|
||||
* - TraceLoggerForCurrentThread(); // Should NOT be used for the mainthread.
|
||||
*
|
||||
* 2) Optionally create a TraceLoggerEvent for the text that needs to get logged. This
|
||||
* 2) Optionally create a textId for the text that needs to get logged. This
|
||||
* step takes some time, so try to do this beforehand, outside the hot
|
||||
* path and don't do unnecessary repetitions, since it will criple
|
||||
* performance.
|
||||
* - TraceLoggerEvent event(logger, "foo");
|
||||
* - TraceLogCreateTextId(logger, ...);
|
||||
*
|
||||
* There are also some predefined events. They are located in
|
||||
* TraceLoggerTextId. They don't require to create an TraceLoggerEvent and
|
||||
* can also be used as an argument to these functions.
|
||||
* 3) Log the occurence of a single event:
|
||||
* - TraceLogTimestamp(logger, TraceLoggerTextId);
|
||||
* Note: it is temporarily not supported to provide an TraceLoggerEvent as
|
||||
* argument to log the occurence of a single event.
|
||||
* There are also some text IDs created beforehand. They are located in
|
||||
* Tracelogger::TextId.
|
||||
* 3) Log the timestamp of an event:
|
||||
* - TraceLogTimestamp(logger, textId);
|
||||
*
|
||||
* or log the start and stop of an event:
|
||||
* - TraceLogStartEvent(logger, TraceLoggerTextId);
|
||||
* - TraceLogStartEvent(logger, TraceLoggerEvent);
|
||||
* - TraceLogStopEvent(logger, TraceLoggerTextId);
|
||||
* - TraceLogStopEvent(logger, TraceLoggerEvent);
|
||||
* or the duration:
|
||||
* - TraceLogStartEvent(logger, textId);
|
||||
* - TraceLogStopEvent(logger, textId);
|
||||
*
|
||||
* or the start/stop of an event with a RAII class:
|
||||
* - AutoTraceLog logger(logger, TraceLoggerTextId);
|
||||
* - AutoTraceLog logger(logger, TraceLoggerEvent);
|
||||
* or the duration with a RAII class:
|
||||
* - AutoTraceLog logger(logger, textId);
|
||||
*/
|
||||
|
||||
#define TRACELOGGER_TEXT_ID_LIST(_) \
|
||||
_(Bailout) \
|
||||
_(Baseline) \
|
||||
_(BaselineCompilation) \
|
||||
_(GC) \
|
||||
_(GCAllocation) \
|
||||
_(GCSweeping) \
|
||||
_(Interpreter) \
|
||||
_(Invalidation) \
|
||||
_(IonCompilation) \
|
||||
_(IonCompilationPaused) \
|
||||
_(IonLinking) \
|
||||
_(IonMonkey) \
|
||||
_(MinorGC) \
|
||||
_(ParserCompileFunction) \
|
||||
_(ParserCompileLazy) \
|
||||
_(ParserCompileScript) \
|
||||
_(TL) \
|
||||
_(IrregexpCompile) \
|
||||
_(IrregexpExecute) \
|
||||
_(VM) \
|
||||
\
|
||||
/* Specific passes during ion compilation */ \
|
||||
_(FoldTests) \
|
||||
_(SplitCriticalEdges) \
|
||||
_(RenumberBlocks) \
|
||||
_(ScalarReplacement) \
|
||||
_(DominatorTree) \
|
||||
_(PhiAnalysis) \
|
||||
_(MakeLoopsContiguous) \
|
||||
_(ApplyTypes) \
|
||||
_(ParallelSafetyAnalysis) \
|
||||
_(AliasAnalysis) \
|
||||
_(GVN) \
|
||||
_(LICM) \
|
||||
_(RangeAnalysis) \
|
||||
_(LoopUnrolling) \
|
||||
_(EffectiveAddressAnalysis) \
|
||||
_(EliminateDeadCode) \
|
||||
_(EdgeCaseAnalysis) \
|
||||
_(EliminateRedundantChecks) \
|
||||
_(GenerateLIR) \
|
||||
_(RegisterAllocation) \
|
||||
_(GenerateCode) \
|
||||
|
||||
class AutoTraceLog;
|
||||
class TraceLoggerEventPayload;
|
||||
class TraceLoggerThread;
|
||||
|
||||
/**
|
||||
* An event that can be used to report start/stop events to TraceLogger.
|
||||
* It prepares the given info, by requesting a TraceLoggerEventPayload for the
|
||||
* given info. (Which contains the string that needs to get reported and an
|
||||
* unique id). It also increases the useCount of this payload, so it cannot
|
||||
* get removed.
|
||||
*/
|
||||
class TraceLoggerEvent {
|
||||
private:
|
||||
TraceLoggerEventPayload *payload_;
|
||||
template <class T>
|
||||
class ContinuousSpace {
|
||||
T *data_;
|
||||
uint32_t size_;
|
||||
uint32_t capacity_;
|
||||
|
||||
public:
|
||||
TraceLoggerEvent() { payload_ = nullptr; };
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId textId);
|
||||
TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId type, JSScript *script);
|
||||
TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId type,
|
||||
const JS::ReadOnlyCompileOptions &compileOptions);
|
||||
TraceLoggerEvent(TraceLoggerThread *logger, const char *text);
|
||||
~TraceLoggerEvent();
|
||||
#else
|
||||
TraceLoggerEvent (TraceLoggerThread *logger, TraceLoggerTextId textId) {}
|
||||
TraceLoggerEvent (TraceLoggerThread *logger, TraceLoggerTextId type, JSScript *script) {}
|
||||
TraceLoggerEvent (TraceLoggerThread *logger, TraceLoggerTextId type,
|
||||
const JS::ReadOnlyCompileOptions &compileOptions) {}
|
||||
TraceLoggerEvent (TraceLoggerThread *logger, const char *text) {}
|
||||
~TraceLoggerEvent() {}
|
||||
#endif
|
||||
|
||||
TraceLoggerEventPayload *payload() const {
|
||||
MOZ_ASSERT(hasPayload());
|
||||
return payload_;
|
||||
}
|
||||
bool hasPayload() const {
|
||||
return !!payload_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An internal class holding the to-report string information, together with an
|
||||
* unique id and a useCount. Whenever this useCount reaches 0, this event
|
||||
* cannot get started/stopped anymore. Though consumers might still request the
|
||||
* to-report string information.
|
||||
*/
|
||||
class TraceLoggerEventPayload {
|
||||
uint32_t textId_;
|
||||
mozilla::UniquePtr<char, JS::FreePolicy> string_;
|
||||
uint32_t uses_;
|
||||
|
||||
public:
|
||||
TraceLoggerEventPayload(uint32_t textId, char *string)
|
||||
: textId_(textId),
|
||||
string_(string),
|
||||
uses_(0)
|
||||
ContinuousSpace ()
|
||||
: data_(nullptr)
|
||||
{ }
|
||||
|
||||
uint32_t textId() {
|
||||
return textId_;
|
||||
bool init() {
|
||||
capacity_ = 64;
|
||||
size_ = 0;
|
||||
data_ = (T *) js_malloc(capacity_ * sizeof(T));
|
||||
if (!data_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
const char *string() {
|
||||
return string_.get();
|
||||
|
||||
T *data() {
|
||||
return data_;
|
||||
}
|
||||
uint32_t uses() {
|
||||
return uses_;
|
||||
|
||||
uint32_t capacity() {
|
||||
return capacity_;
|
||||
}
|
||||
void use() {
|
||||
uses_++;
|
||||
|
||||
uint32_t size() {
|
||||
return size_;
|
||||
}
|
||||
void release() {
|
||||
uses_--;
|
||||
|
||||
bool empty() {
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
uint32_t lastEntryId() {
|
||||
MOZ_ASSERT(!empty());
|
||||
return size_ - 1;
|
||||
}
|
||||
|
||||
T &lastEntry() {
|
||||
return data()[lastEntryId()];
|
||||
}
|
||||
|
||||
bool hasSpaceForAdd(uint32_t count = 1) {
|
||||
if (size_ + count <= capacity_)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ensureSpaceBeforeAdd(uint32_t count = 1) {
|
||||
if (hasSpaceForAdd(count))
|
||||
return true;
|
||||
|
||||
uint32_t nCapacity = capacity_ * 2;
|
||||
if (size_ + count > nCapacity)
|
||||
nCapacity = size_ + count;
|
||||
T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T));
|
||||
|
||||
if (!entries)
|
||||
return false;
|
||||
|
||||
data_ = entries;
|
||||
capacity_ = nCapacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
T &operator[](size_t i) {
|
||||
MOZ_ASSERT(i < size_);
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
void push(T &data) {
|
||||
MOZ_ASSERT(size_ < capacity_);
|
||||
data()[size_++] = data;
|
||||
}
|
||||
|
||||
T &pushUninitialized() {
|
||||
MOZ_ASSERT(size_ < capacity_);
|
||||
return data()[size_++];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
MOZ_ASSERT(!empty());
|
||||
size_--;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
size_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class TraceLoggerThread
|
||||
class TraceLogger
|
||||
{
|
||||
public:
|
||||
// Predefined IDs for common operations. These IDs can be used
|
||||
// without using TraceLogCreateTextId, because there are already created.
|
||||
enum TextId {
|
||||
TL_Error = 0,
|
||||
# define DEFINE_TEXT_ID(textId) textId,
|
||||
TRACELOGGER_TEXT_ID_LIST(DEFINE_TEXT_ID)
|
||||
# undef DEFINE_TEXT_ID
|
||||
LAST
|
||||
};
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
private:
|
||||
typedef HashMap<const void *,
|
||||
TraceLoggerEventPayload *,
|
||||
uint32_t,
|
||||
PointerHasher<const void *, 3>,
|
||||
SystemAllocPolicy> PointerHashMap;
|
||||
typedef HashMap<uint32_t,
|
||||
TraceLoggerEventPayload *,
|
||||
DefaultHasher<uint32_t>,
|
||||
SystemAllocPolicy> TextIdHashMap;
|
||||
|
||||
// The layout of the tree in memory and in the log file. Readable by JS
|
||||
// using TypedArrays.
|
||||
struct TreeEntry {
|
||||
uint64_t start_;
|
||||
uint64_t stop_;
|
||||
union {
|
||||
struct {
|
||||
uint32_t textId_: 31;
|
||||
uint32_t hasChildren_: 1;
|
||||
} s;
|
||||
uint32_t value_;
|
||||
} u;
|
||||
uint32_t nextId_;
|
||||
|
||||
TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
|
||||
uint32_t nextId)
|
||||
{
|
||||
start_ = start;
|
||||
stop_ = stop;
|
||||
u.s.textId_ = textId;
|
||||
u.s.hasChildren_ = hasChildren;
|
||||
nextId_ = nextId;
|
||||
}
|
||||
TreeEntry()
|
||||
{ }
|
||||
uint64_t start() {
|
||||
return start_;
|
||||
}
|
||||
uint64_t stop() {
|
||||
return stop_;
|
||||
}
|
||||
uint32_t textId() {
|
||||
return u.s.textId_;
|
||||
}
|
||||
bool hasChildren() {
|
||||
return u.s.hasChildren_;
|
||||
}
|
||||
uint32_t nextId() {
|
||||
return nextId_;
|
||||
}
|
||||
void setStart(uint64_t start) {
|
||||
start_ = start;
|
||||
}
|
||||
void setStop(uint64_t stop) {
|
||||
stop_ = stop;
|
||||
}
|
||||
void setTextId(uint32_t textId) {
|
||||
MOZ_ASSERT(textId < uint32_t(1<<31) );
|
||||
u.s.textId_ = textId;
|
||||
}
|
||||
void setHasChildren(bool hasChildren) {
|
||||
u.s.hasChildren_ = hasChildren;
|
||||
}
|
||||
void setNextId(uint32_t nextId) {
|
||||
nextId_ = nextId;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper structure for keeping track of the current entries in
|
||||
// the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
|
||||
// is used to know if a subtree doesn't need to get logged.
|
||||
struct StackEntry {
|
||||
uint32_t treeId_;
|
||||
uint32_t lastChildId_;
|
||||
struct {
|
||||
uint32_t textId_: 31;
|
||||
uint32_t active_: 1;
|
||||
} s;
|
||||
StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
|
||||
: treeId_(treeId), lastChildId_(lastChildId)
|
||||
{
|
||||
s.textId_ = 0;
|
||||
s.active_ = active;
|
||||
}
|
||||
uint32_t treeId() {
|
||||
return treeId_;
|
||||
}
|
||||
uint32_t lastChildId() {
|
||||
return lastChildId_;
|
||||
}
|
||||
uint32_t textId() {
|
||||
return s.textId_;
|
||||
}
|
||||
bool active() {
|
||||
return s.active_;
|
||||
}
|
||||
void setTreeId(uint32_t treeId) {
|
||||
treeId_ = treeId;
|
||||
}
|
||||
void setLastChildId(uint32_t lastChildId) {
|
||||
lastChildId_ = lastChildId;
|
||||
}
|
||||
void setTextId(uint32_t textId) {
|
||||
MOZ_ASSERT(textId < uint32_t(1<<31) );
|
||||
s.textId_ = textId;
|
||||
}
|
||||
void setActive(bool active) {
|
||||
s.active_ = active;
|
||||
}
|
||||
};
|
||||
|
||||
// The layout of the event log in memory and in the log file.
|
||||
// Readable by JS using TypedArrays.
|
||||
struct EventEntry {
|
||||
uint64_t time;
|
||||
uint32_t textId;
|
||||
EventEntry(uint64_t time, uint32_t textId)
|
||||
: time(time), textId(textId)
|
||||
{ }
|
||||
};
|
||||
|
||||
FILE *dictFile;
|
||||
FILE *treeFile;
|
||||
FILE *eventFile;
|
||||
|
||||
uint32_t enabled;
|
||||
bool failed;
|
||||
|
||||
mozilla::UniquePtr<TraceLoggerGraph> graph;
|
||||
uint32_t nextTextId;
|
||||
|
||||
PointerHashMap pointerMap;
|
||||
TextIdHashMap extraTextId;
|
||||
|
||||
ContinuousSpace<TreeEntry> tree;
|
||||
ContinuousSpace<StackEntry> stack;
|
||||
ContinuousSpace<EventEntry> events;
|
||||
|
||||
// Every time the events get flushed, this count is increased by one.
|
||||
// This together with events.lastEntryId(), gives an unique position.
|
||||
uint32_t iteration_;
|
||||
uint32_t treeOffset;
|
||||
|
||||
public:
|
||||
AutoTraceLog *top;
|
||||
|
||||
TraceLoggerThread();
|
||||
bool init();
|
||||
~TraceLoggerThread();
|
||||
private:
|
||||
// Helper functions that convert a TreeEntry in different endianness
|
||||
// in place.
|
||||
void entryToBigEndian(TreeEntry *entry);
|
||||
void entryToSystemEndian(TreeEntry *entry);
|
||||
|
||||
// Helper functions to get/save a tree from file.
|
||||
bool getTreeEntry(uint32_t treeId, TreeEntry *entry);
|
||||
bool saveTreeEntry(uint32_t treeId, TreeEntry *entry);
|
||||
|
||||
// Return the first StackEntry that is active.
|
||||
StackEntry &getActiveAncestor();
|
||||
|
||||
// This contains the meat of startEvent, except the test for enough space,
|
||||
// the test if tracelogger is enabled and the timestamp computation.
|
||||
bool startEvent(uint32_t id, uint64_t timestamp);
|
||||
|
||||
// Update functions that can adjust the items in the tree,
|
||||
// both in memory or already written to disk.
|
||||
bool updateHasChildren(uint32_t treeId, bool hasChildren = true);
|
||||
bool updateNextId(uint32_t treeId, uint32_t nextId);
|
||||
bool updateStop(uint32_t treeId, uint64_t timestamp);
|
||||
|
||||
// Flush the tree and events.
|
||||
bool flush();
|
||||
|
||||
public:
|
||||
TraceLogger();
|
||||
~TraceLogger();
|
||||
|
||||
bool init(uint32_t loggerId);
|
||||
void initGraph();
|
||||
|
||||
bool enable();
|
||||
bool enable(JSContext *cx);
|
||||
bool disable();
|
||||
|
||||
// Given the previous iteration and lastEntryId, return an array of events
|
||||
// (there could be lost events). At the same time update the iteration and
|
||||
// lastEntry and gives back how many events there are.
|
||||
EventEntry *getEventsStartingAt(uint32_t *lastIteration, uint32_t *lastEntryId, size_t *num) {
|
||||
EventEntry *start;
|
||||
if (iteration_ == *lastIteration) {
|
||||
MOZ_ASSERT(events.lastEntryId() >= *lastEntryId);
|
||||
*num = events.lastEntryId() - *lastEntryId;
|
||||
start = events.data() + *lastEntryId + 1;
|
||||
} else {
|
||||
*num = events.lastEntryId() + 1;
|
||||
start = events.data();
|
||||
}
|
||||
|
||||
*lastIteration = iteration_;
|
||||
*lastEntryId = events.lastEntryId();
|
||||
return start;
|
||||
}
|
||||
|
||||
// Extract the details filename, lineNumber and columnNumber out of a event
|
||||
// containing script information.
|
||||
void extractScriptDetails(uint32_t textId, const char **filename, size_t *filename_len,
|
||||
const char **lineno, size_t *lineno_len, const char **colno,
|
||||
size_t *colno_len);
|
||||
|
||||
bool lostEvents(uint32_t lastIteration, uint32_t lastEntryId) {
|
||||
// If still logging in the same iteration, there are no lost events.
|
||||
if (lastIteration == iteration_) {
|
||||
MOZ_ASSERT(lastEntryId <= events.lastEntryId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// When proceeded to the next iteration and lastEntryId points to
|
||||
// the maximum capacity there are no logs that are lost.
|
||||
if (lastIteration + 1 == iteration_ && lastEntryId == events.capacity())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *eventText(uint32_t id);
|
||||
bool textIdIsScriptEvent(uint32_t id);
|
||||
|
||||
// The createTextId functions map a unique input to a logger ID.
|
||||
// This can be used to give start and stop events. Calls to these functions should be
|
||||
// This ID can be used to log something. Calls to these functions should be
|
||||
// limited if possible, because of the overhead.
|
||||
// Note: it is not allowed to use them in logTimestamp.
|
||||
TraceLoggerEventPayload *getOrCreateEventPayload(TraceLoggerTextId textId);
|
||||
TraceLoggerEventPayload *getOrCreateEventPayload(const char *text);
|
||||
TraceLoggerEventPayload *getOrCreateEventPayload(TraceLoggerTextId type, JSScript *script);
|
||||
TraceLoggerEventPayload *getOrCreateEventPayload(TraceLoggerTextId type,
|
||||
const JS::ReadOnlyCompileOptions &script);
|
||||
private:
|
||||
TraceLoggerEventPayload *getOrCreateEventPayload(TraceLoggerTextId type, const char *filename,
|
||||
size_t lineno, size_t colno, const void *p);
|
||||
uint32_t createTextId(const char *text);
|
||||
uint32_t createTextId(JSScript *script);
|
||||
uint32_t createTextId(const JS::ReadOnlyCompileOptions &script);
|
||||
|
||||
public:
|
||||
// Log an event (no start/stop, only the timestamp is recorded).
|
||||
void logTimestamp(TraceLoggerTextId id);
|
||||
void logTimestamp(uint32_t id);
|
||||
|
||||
// Record timestamps for start and stop of an event.
|
||||
void startEvent(TraceLoggerTextId id);
|
||||
void startEvent(const TraceLoggerEvent &event);
|
||||
void stopEvent(TraceLoggerTextId id);
|
||||
void stopEvent(const TraceLoggerEvent &event);
|
||||
|
||||
// These functions are actually private and shouldn't be used in normal
|
||||
// code. They are made public so they can get used in assembly.
|
||||
void logTimestamp(uint32_t id);
|
||||
// In the stop method, the ID is only used in debug builds to test
|
||||
// correctness.
|
||||
void startEvent(uint32_t id);
|
||||
void stopEvent(uint32_t id);
|
||||
private:
|
||||
void stopEvent();
|
||||
|
||||
public:
|
||||
static unsigned offsetOfEnabled() {
|
||||
return offsetof(TraceLoggerThread, enabled);
|
||||
return offsetof(TraceLogger, enabled);
|
||||
}
|
||||
|
||||
private:
|
||||
void assertNoQuotes(const char *text) {
|
||||
#ifdef DEBUG
|
||||
const char *quote = strchr(text, '"');
|
||||
MOZ_ASSERT(!quote);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class TraceLoggerThreadState
|
||||
class TraceLogging
|
||||
{
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
typedef HashMap<PRThread *,
|
||||
TraceLoggerThread *,
|
||||
TraceLogger *,
|
||||
PointerHasher<PRThread *, 3>,
|
||||
SystemAllocPolicy> ThreadLoggerHashMap;
|
||||
typedef Vector<TraceLoggerThread *, 1, js::SystemAllocPolicy > MainThreadLoggers;
|
||||
typedef Vector<TraceLogger *, 1, js::SystemAllocPolicy > MainThreadLoggers;
|
||||
|
||||
bool initialized;
|
||||
bool enabled;
|
||||
bool enabledTextIds[TraceLogger_Last];
|
||||
bool enabledTextIds[TraceLogger::LAST];
|
||||
bool mainThreadEnabled;
|
||||
bool offThreadEnabled;
|
||||
bool graphSpewingEnabled;
|
||||
ThreadLoggerHashMap threadLoggers;
|
||||
MainThreadLoggers mainThreadLoggers;
|
||||
uint32_t loggerId;
|
||||
FILE *out;
|
||||
|
||||
public:
|
||||
uint64_t startupTime;
|
||||
PRLock *lock;
|
||||
|
||||
TraceLoggerThreadState();
|
||||
~TraceLoggerThreadState();
|
||||
TraceLogging();
|
||||
~TraceLogging();
|
||||
|
||||
TraceLoggerThread *forMainThread(JSRuntime *runtime);
|
||||
TraceLoggerThread *forMainThread(jit::CompileRuntime *runtime);
|
||||
TraceLoggerThread *forThread(PRThread *thread);
|
||||
TraceLogger *forMainThread(JSRuntime *runtime);
|
||||
TraceLogger *forMainThread(jit::CompileRuntime *runtime);
|
||||
TraceLogger *forThread(PRThread *thread);
|
||||
|
||||
bool isTextIdEnabled(uint32_t textId) {
|
||||
if (textId < TraceLogger_Last)
|
||||
if (textId < TraceLogger::LAST)
|
||||
return enabledTextIds[textId];
|
||||
return true;
|
||||
}
|
||||
void enableTextId(JSContext *cx, uint32_t textId);
|
||||
void disableTextId(JSContext *cx, uint32_t textId);
|
||||
|
||||
private:
|
||||
TraceLoggerThread *forMainThread(PerThreadData *mainThread);
|
||||
TraceLoggerThread *create();
|
||||
TraceLogger *forMainThread(PerThreadData *mainThread);
|
||||
TraceLogger *create();
|
||||
bool lazyInit();
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread *TraceLoggerForMainThread(JSRuntime *runtime);
|
||||
TraceLoggerThread *TraceLoggerForMainThread(jit::CompileRuntime *runtime);
|
||||
TraceLoggerThread *TraceLoggerForCurrentThread();
|
||||
TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime);
|
||||
TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime);
|
||||
TraceLogger *TraceLoggerForCurrentThread();
|
||||
#else
|
||||
inline TraceLoggerThread *TraceLoggerForMainThread(JSRuntime *runtime) {
|
||||
inline TraceLogger *TraceLoggerForMainThread(JSRuntime *runtime) {
|
||||
return nullptr;
|
||||
};
|
||||
inline TraceLoggerThread *TraceLoggerForMainThread(jit::CompileRuntime *runtime) {
|
||||
inline TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime) {
|
||||
return nullptr;
|
||||
};
|
||||
inline TraceLoggerThread *TraceLoggerForCurrentThread() {
|
||||
inline TraceLogger *TraceLoggerForCurrentThread() {
|
||||
return nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
inline bool TraceLoggerEnable(TraceLoggerThread *logger) {
|
||||
inline bool TraceLoggerEnable(TraceLogger *logger) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->enable();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
inline bool TraceLoggerEnable(TraceLoggerThread *logger, JSContext *cx) {
|
||||
inline bool TraceLoggerEnable(TraceLogger *logger, JSContext *cx) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->enable(cx);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
inline bool TraceLoggerDisable(TraceLoggerThread *logger) {
|
||||
inline bool TraceLoggerDisable(TraceLogger *logger) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->disable();
|
||||
|
@ -351,107 +546,78 @@ inline bool TraceLoggerDisable(TraceLoggerThread *logger) {
|
|||
return false;
|
||||
}
|
||||
|
||||
inline uint32_t TraceLogCreateTextId(TraceLogger *logger, JSScript *script) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->createTextId(script);
|
||||
#endif
|
||||
return TraceLogger::TL_Error;
|
||||
}
|
||||
inline uint32_t TraceLogCreateTextId(TraceLogger *logger,
|
||||
const JS::ReadOnlyCompileOptions &compileOptions)
|
||||
{
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->createTextId(compileOptions);
|
||||
#endif
|
||||
return TraceLogger::TL_Error;
|
||||
}
|
||||
inline uint32_t TraceLogCreateTextId(TraceLogger *logger, const char *text) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
return logger->createTextId(text);
|
||||
#endif
|
||||
return TraceLogger::TL_Error;
|
||||
}
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
bool TraceLogTextIdEnabled(uint32_t textId);
|
||||
void TraceLogEnableTextId(JSContext *cx, uint32_t textId);
|
||||
void TraceLogDisableTextId(JSContext *cx, uint32_t textId);
|
||||
#else
|
||||
inline bool TraceLogTextIdEnabled(uint32_t textId) {
|
||||
return false;
|
||||
}
|
||||
inline void TraceLogEnableTextId(JSContext *cx, uint32_t textId) {}
|
||||
inline void TraceLogDisableTextId(JSContext *cx, uint32_t textId) {}
|
||||
#endif
|
||||
inline void TraceLogTimestamp(TraceLoggerThread *logger, TraceLoggerTextId textId) {
|
||||
inline void TraceLogTimestamp(TraceLogger *logger, uint32_t textId) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->logTimestamp(textId);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStartEvent(TraceLoggerThread *logger, TraceLoggerTextId textId) {
|
||||
inline void TraceLogStartEvent(TraceLogger *logger, uint32_t textId) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->startEvent(textId);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStartEvent(TraceLoggerThread *logger, const TraceLoggerEvent &event) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->startEvent(event);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStopEvent(TraceLoggerThread *logger, TraceLoggerTextId textId) {
|
||||
inline void TraceLogStopEvent(TraceLogger *logger, uint32_t textId) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->stopEvent(textId);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStopEvent(TraceLoggerThread *logger, const TraceLoggerEvent &event) {
|
||||
inline void TraceLogStopEvent(TraceLogger *logger) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->stopEvent(event);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper functions for assembly. May not be used otherwise.
|
||||
inline void TraceLogTimestampPrivate(TraceLoggerThread *logger, uint32_t id) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->logTimestamp(id);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStartEventPrivate(TraceLoggerThread *logger, uint32_t id) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->startEvent(id);
|
||||
#endif
|
||||
}
|
||||
inline void TraceLogStopEventPrivate(TraceLoggerThread *logger, uint32_t id) {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger)
|
||||
logger->stopEvent(id);
|
||||
logger->stopEvent();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Automatic logging at the start and end of function call.
|
||||
class AutoTraceLog
|
||||
{
|
||||
class AutoTraceLog {
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
TraceLoggerThread *logger;
|
||||
union {
|
||||
const TraceLoggerEvent *event;
|
||||
TraceLoggerTextId id;
|
||||
} payload;
|
||||
bool isEvent;
|
||||
TraceLogger *logger;
|
||||
uint32_t textId;
|
||||
bool executed;
|
||||
AutoTraceLog *prev;
|
||||
|
||||
public:
|
||||
AutoTraceLog(TraceLoggerThread *logger,
|
||||
const TraceLoggerEvent &event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: logger(logger),
|
||||
isEvent(true),
|
||||
textId(textId),
|
||||
executed(false)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
payload.event = &event;
|
||||
if (logger) {
|
||||
logger->startEvent(event);
|
||||
|
||||
prev = logger->top;
|
||||
logger->top = this;
|
||||
}
|
||||
}
|
||||
|
||||
AutoTraceLog(TraceLoggerThread *logger, TraceLoggerTextId id MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: logger(logger),
|
||||
isEvent(false),
|
||||
executed(false)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
payload.id = id;
|
||||
if (logger) {
|
||||
logger->startEvent(id);
|
||||
TraceLogStartEvent(logger, textId);
|
||||
|
||||
prev = logger->top;
|
||||
logger->top = this;
|
||||
|
@ -470,10 +636,7 @@ class AutoTraceLog
|
|||
void stop() {
|
||||
if (!executed) {
|
||||
executed = true;
|
||||
if (isEvent)
|
||||
logger->stopEvent(*payload.event);
|
||||
else
|
||||
logger->stopEvent(payload.id);
|
||||
TraceLogStopEvent(logger, textId);
|
||||
}
|
||||
|
||||
if (logger->top == this)
|
||||
|
@ -481,12 +644,7 @@ class AutoTraceLog
|
|||
}
|
||||
#else
|
||||
public:
|
||||
AutoTraceLog(TraceLoggerThread *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
AutoTraceLog(TraceLoggerThread *logger,
|
||||
const TraceLoggerEvent &event MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
AutoTraceLog(TraceLogger *logger, uint32_t textId MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
@ -496,6 +654,26 @@ class AutoTraceLog
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
class AutoTraceLoggingLock
|
||||
{
|
||||
TraceLogging *logging;
|
||||
|
||||
public:
|
||||
AutoTraceLoggingLock(TraceLogging *logging MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: logging(logging)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
PR_Lock(logging->lock);
|
||||
}
|
||||
~AutoTraceLoggingLock() {
|
||||
PR_Unlock(logging->lock);
|
||||
}
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
#endif
|
||||
|
||||
} /* namedata js */
|
||||
|
||||
#endif /* TraceLogging_h */
|
||||
|
|
|
@ -1,570 +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/TraceLoggingGraph.h"
|
||||
|
||||
#include "mozilla/Endian.h"
|
||||
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#ifndef TRACE_LOG_DIR
|
||||
# if defined(_WIN32)
|
||||
# define TRACE_LOG_DIR ""
|
||||
# else
|
||||
# define TRACE_LOG_DIR "/tmp/"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using mozilla::NativeEndian;
|
||||
|
||||
TraceLoggerGraphState traceLoggersGraph;
|
||||
|
||||
class AutoTraceLoggerGraphStateLock
|
||||
{
|
||||
TraceLoggerGraphState *graph;
|
||||
|
||||
public:
|
||||
AutoTraceLoggerGraphStateLock(TraceLoggerGraphState *graph MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: graph(graph)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
PR_Lock(graph->lock);
|
||||
}
|
||||
~AutoTraceLoggerGraphStateLock() {
|
||||
PR_Unlock(graph->lock);
|
||||
}
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
TraceLoggerGraphState::TraceLoggerGraphState()
|
||||
: numLoggers(0),
|
||||
out(nullptr)
|
||||
{
|
||||
lock = PR_NewLock();
|
||||
if (!lock)
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraphState::ensureInitialized()
|
||||
{
|
||||
if (out)
|
||||
return true;
|
||||
|
||||
out = fopen(TRACE_LOG_DIR "tl-data.json", "w");
|
||||
if (!out)
|
||||
return false;
|
||||
|
||||
fprintf(out, "[");
|
||||
return true;
|
||||
}
|
||||
|
||||
TraceLoggerGraphState::~TraceLoggerGraphState()
|
||||
{
|
||||
if (out) {
|
||||
fprintf(out, "]");
|
||||
fclose(out);
|
||||
out = nullptr;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
PR_DestroyLock(lock);
|
||||
lock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TraceLoggerGraphState::nextLoggerId()
|
||||
{
|
||||
AutoTraceLoggerGraphStateLock lock(this);
|
||||
|
||||
if (!ensureInitialized()) {
|
||||
fprintf(stderr, "TraceLogging: Couldn't create the main log file.");
|
||||
return uint32_t(-1);
|
||||
}
|
||||
|
||||
if (numLoggers > 999) {
|
||||
fprintf(stderr, "TraceLogging: Can't create more than 999 different loggers.");
|
||||
return uint32_t(-1);
|
||||
}
|
||||
|
||||
if (numLoggers > 0) {
|
||||
int written = fprintf(out, ",\n");
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "TraceLogging: Error while writing.\n");
|
||||
return uint32_t(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int written = fprintf(out, "{\"tree\":\"tl-tree.%d.tl\", \"events\":\"tl-event.%d.tl\", "
|
||||
"\"dict\":\"tl-dict.%d.json\", \"treeFormat\":\"64,64,31,1,32\"}",
|
||||
numLoggers, numLoggers, numLoggers);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "TraceLogging: Error while writing.\n");
|
||||
return uint32_t(-1);
|
||||
}
|
||||
|
||||
return numLoggers++;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::init(uint64_t startTimestamp)
|
||||
{
|
||||
if (!tree.init()) {
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
if (!stack.init()) {
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t loggerId = traceLoggersGraph.nextLoggerId();
|
||||
if (loggerId == uint32_t(-1)) {
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.100.json"];
|
||||
sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%d.json", loggerId);
|
||||
dictFile = fopen(dictFilename, "w");
|
||||
if (!dictFile) {
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.100.tl"];
|
||||
sprintf(treeFilename, TRACE_LOG_DIR "tl-tree.%d.tl", loggerId);
|
||||
treeFile = fopen(treeFilename, "wb");
|
||||
if (!treeFile) {
|
||||
fclose(dictFile);
|
||||
dictFile = nullptr;
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
char eventFilename[sizeof TRACE_LOG_DIR "tl-event.100.tl"];
|
||||
sprintf(eventFilename, TRACE_LOG_DIR "tl-event.%d.tl", loggerId);
|
||||
eventFile = fopen(eventFilename, "wb");
|
||||
if (!eventFile) {
|
||||
fclose(dictFile);
|
||||
fclose(treeFile);
|
||||
dictFile = nullptr;
|
||||
treeFile = nullptr;
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the top tree node and corresponding first stack item.
|
||||
TreeEntry &treeEntry = tree.pushUninitialized();
|
||||
treeEntry.setStart(startTimestamp);
|
||||
treeEntry.setStop(0);
|
||||
treeEntry.setTextId(0);
|
||||
treeEntry.setHasChildren(false);
|
||||
treeEntry.setNextId(0);
|
||||
|
||||
StackEntry &stackEntry = stack.pushUninitialized();
|
||||
stackEntry.setTreeId(0);
|
||||
stackEntry.setLastChildId(0);
|
||||
stackEntry.setActive(true);
|
||||
|
||||
int written = fprintf(dictFile, "[");
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "TraceLogging: Error while writing.\n");
|
||||
fclose(dictFile);
|
||||
fclose(treeFile);
|
||||
fclose(eventFile);
|
||||
dictFile = nullptr;
|
||||
treeFile = nullptr;
|
||||
eventFile = nullptr;
|
||||
failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TraceLoggerGraph::~TraceLoggerGraph()
|
||||
{
|
||||
// Write dictionary to disk
|
||||
if (dictFile) {
|
||||
int written = fprintf(dictFile, "]");
|
||||
if (written < 0)
|
||||
fprintf(stderr, "TraceLogging: Error while writing.\n");
|
||||
fclose(dictFile);
|
||||
|
||||
dictFile = nullptr;
|
||||
}
|
||||
|
||||
if (!failed && treeFile) {
|
||||
// Make sure every start entry has a corresponding stop value.
|
||||
// We temporary enable logging for this. Stop doesn't need any extra data,
|
||||
// so is safe to do, even when we encountered OOM.
|
||||
enabled = 1;
|
||||
while (stack.size() > 1)
|
||||
stopEvent(0);
|
||||
enabled = 0;
|
||||
}
|
||||
|
||||
if (!failed && !flush()) {
|
||||
fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
|
||||
enabled = 0;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (treeFile) {
|
||||
fclose(treeFile);
|
||||
treeFile = nullptr;
|
||||
}
|
||||
|
||||
if (eventFile) {
|
||||
fclose(eventFile);
|
||||
eventFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::flush()
|
||||
{
|
||||
MOZ_ASSERT(!failed);
|
||||
|
||||
if (treeFile) {
|
||||
// Format data in big endian.
|
||||
for (size_t i = 0; i < tree.size(); i++)
|
||||
entryToBigEndian(&tree[i]);
|
||||
|
||||
int success = fseek(treeFile, 0, SEEK_END);
|
||||
if (success != 0)
|
||||
return false;
|
||||
|
||||
size_t bytesWritten = fwrite(tree.data(), sizeof(TreeEntry), tree.size(), treeFile);
|
||||
if (bytesWritten < tree.size())
|
||||
return false;
|
||||
|
||||
treeOffset += tree.lastEntryId();
|
||||
tree.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::entryToBigEndian(TreeEntry *entry)
|
||||
{
|
||||
entry->start_ = NativeEndian::swapToBigEndian(entry->start_);
|
||||
entry->stop_ = NativeEndian::swapToBigEndian(entry->stop_);
|
||||
uint32_t data = (entry->u.s.textId_ << 1) + entry->u.s.hasChildren_;
|
||||
entry->u.value_ = NativeEndian::swapToBigEndian(data);
|
||||
entry->nextId_ = NativeEndian::swapToBigEndian(entry->nextId_);
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::entryToSystemEndian(TreeEntry *entry)
|
||||
{
|
||||
entry->start_ = NativeEndian::swapFromBigEndian(entry->start_);
|
||||
entry->stop_ = NativeEndian::swapFromBigEndian(entry->stop_);
|
||||
|
||||
uint32_t data = NativeEndian::swapFromBigEndian(entry->u.value_);
|
||||
entry->u.s.textId_ = data >> 1;
|
||||
entry->u.s.hasChildren_ = data & 0x1;
|
||||
|
||||
entry->nextId_ = NativeEndian::swapFromBigEndian(entry->nextId_);
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::startEvent(uint32_t id, uint64_t timestamp)
|
||||
{
|
||||
if (failed || enabled == 0)
|
||||
return;
|
||||
|
||||
if (!tree.hasSpaceForAdd()) {
|
||||
if (!tree.ensureSpaceBeforeAdd()) {
|
||||
if (!flush()) {
|
||||
fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
|
||||
enabled = 0;
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!startEventInternal(id, timestamp)) {
|
||||
fprintf(stderr, "TraceLogging: Failed to start an event.\n");
|
||||
enabled = 0;
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TraceLoggerGraph::StackEntry &
|
||||
TraceLoggerGraph::getActiveAncestor()
|
||||
{
|
||||
uint32_t parentId = stack.lastEntryId();
|
||||
while (!stack[parentId].active())
|
||||
parentId--;
|
||||
return stack[parentId];
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::startEventInternal(uint32_t id, uint64_t timestamp)
|
||||
{
|
||||
if (!stack.ensureSpaceBeforeAdd())
|
||||
return false;
|
||||
|
||||
// Patch up the tree to be correct. There are two scenarios:
|
||||
// 1) Parent has no children yet. So update parent to include children.
|
||||
// 2) Parent has already children. Update last child to link to the new
|
||||
// child.
|
||||
StackEntry &parent = getActiveAncestor();
|
||||
#ifdef DEBUG
|
||||
TreeEntry entry;
|
||||
if (!getTreeEntry(parent.treeId(), &entry))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (parent.lastChildId() == 0) {
|
||||
MOZ_ASSERT(!entry.hasChildren());
|
||||
MOZ_ASSERT(parent.treeId() == tree.lastEntryId() + treeOffset);
|
||||
|
||||
if (!updateHasChildren(parent.treeId()))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(entry.hasChildren());
|
||||
|
||||
if (!updateNextId(parent.lastChildId(), tree.size() + treeOffset))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a new tree entry.
|
||||
TreeEntry &treeEntry = tree.pushUninitialized();
|
||||
treeEntry.setStart(timestamp);
|
||||
treeEntry.setStop(0);
|
||||
treeEntry.setTextId(id);
|
||||
treeEntry.setHasChildren(false);
|
||||
treeEntry.setNextId(0);
|
||||
|
||||
// Add a new stack entry.
|
||||
StackEntry &stackEntry = stack.pushUninitialized();
|
||||
stackEntry.setTreeId(tree.lastEntryId() + treeOffset);
|
||||
stackEntry.setLastChildId(0);
|
||||
stackEntry.setActive(true);
|
||||
|
||||
// Set the last child of the parent to this newly added entry.
|
||||
parent.setLastChildId(tree.lastEntryId() + treeOffset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::stopEvent(uint32_t id, uint64_t timestamp)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (id != TraceLogger_Scripts &&
|
||||
id != TraceLogger_Engine &&
|
||||
stack.size() > 1 &&
|
||||
stack.lastEntry().active())
|
||||
{
|
||||
TreeEntry entry;
|
||||
MOZ_ASSERT(getTreeEntry(stack.lastEntry().treeId(), &entry));
|
||||
MOZ_ASSERT(entry.textId() == id);
|
||||
}
|
||||
#endif
|
||||
|
||||
stopEvent(timestamp);
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::stopEvent(uint64_t timestamp)
|
||||
{
|
||||
if (enabled && stack.lastEntry().active()) {
|
||||
if (!updateStop(stack.lastEntry().treeId(), timestamp)) {
|
||||
fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
|
||||
enabled = 0;
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (stack.size() == 1) {
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
// Forcefully disable logging. We have no stack information anymore.
|
||||
logTimestamp(TraceLogger_Disable, timestamp);
|
||||
return;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::logTimestamp(uint32_t id, uint64_t timestamp)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
if (id == TraceLogger_Enable)
|
||||
enabled = true;
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (id == TraceLogger_Disable)
|
||||
disable(timestamp);
|
||||
|
||||
MOZ_ASSERT(eventFile);
|
||||
|
||||
// Format data in big endian
|
||||
timestamp = NativeEndian::swapToBigEndian(timestamp);
|
||||
id = NativeEndian::swapToBigEndian(id);
|
||||
|
||||
// The layout of the event log in the log file is:
|
||||
// [timestamp, textId]
|
||||
size_t itemsWritten = 0;
|
||||
itemsWritten += fwrite(×tamp, sizeof(uint64_t), 1, eventFile);
|
||||
itemsWritten += fwrite(&id, sizeof(uint32_t), 1, eventFile);
|
||||
if (itemsWritten < 2) {
|
||||
failed = true;
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::getTreeEntry(uint32_t treeId, TreeEntry *entry)
|
||||
{
|
||||
// Entry is still in memory
|
||||
if (treeId >= treeOffset) {
|
||||
*entry = tree[treeId - treeOffset];
|
||||
return true;
|
||||
}
|
||||
|
||||
int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
|
||||
if (success != 0)
|
||||
return false;
|
||||
|
||||
size_t itemsRead = fread((void *)entry, sizeof(TreeEntry), 1, treeFile);
|
||||
if (itemsRead < 1)
|
||||
return false;
|
||||
|
||||
entryToSystemEndian(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::saveTreeEntry(uint32_t treeId, TreeEntry *entry)
|
||||
{
|
||||
int success = fseek(treeFile, treeId * sizeof(TreeEntry), SEEK_SET);
|
||||
if (success != 0)
|
||||
return false;
|
||||
|
||||
entryToBigEndian(entry);
|
||||
|
||||
size_t itemsWritten = fwrite(entry, sizeof(TreeEntry), 1, treeFile);
|
||||
if (itemsWritten < 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::updateHasChildren(uint32_t treeId, bool hasChildren)
|
||||
{
|
||||
if (treeId < treeOffset) {
|
||||
TreeEntry entry;
|
||||
if (!getTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
entry.setHasChildren(hasChildren);
|
||||
if (!saveTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
tree[treeId - treeOffset].setHasChildren(hasChildren);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::updateNextId(uint32_t treeId, uint32_t nextId)
|
||||
{
|
||||
if (treeId < treeOffset) {
|
||||
TreeEntry entry;
|
||||
if (!getTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
entry.setNextId(nextId);
|
||||
if (!saveTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
tree[treeId - treeOffset].setNextId(nextId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerGraph::updateStop(uint32_t treeId, uint64_t timestamp)
|
||||
{
|
||||
if (treeId < treeOffset) {
|
||||
TreeEntry entry;
|
||||
if (!getTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
entry.setStop(timestamp);
|
||||
if (!saveTreeEntry(treeId, &entry))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
tree[treeId - treeOffset].setStop(timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::disable(uint64_t timestamp)
|
||||
{
|
||||
MOZ_ASSERT(enabled);
|
||||
while (stack.size() > 1)
|
||||
stopEvent(timestamp);
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::log(ContinuousSpace<EventEntry> &events)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
for (uint32_t i = 0; i < events.size(); i++) {
|
||||
if (events[i].textId == TraceLogger_Stop)
|
||||
stopEvent(events[i].time);
|
||||
else if (TLTextIdIsTreeEvent(events[i].textId))
|
||||
startEvent(events[i].textId, events[i].time);
|
||||
else
|
||||
logTimestamp(events[i].textId, events[i].time);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TraceLoggerGraph::addTextId(uint32_t id, const char *text)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
// Assume ids are given in order. Which is currently true.
|
||||
MOZ_ASSERT(id == nextTextId);
|
||||
nextTextId++;
|
||||
|
||||
if (id > 0) {
|
||||
int written = fprintf(dictFile, ",\n");
|
||||
if (written < 0) {
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!js::FileEscapedString(dictFile, text, strlen(text), '"'))
|
||||
failed = true;
|
||||
}
|
|
@ -1,255 +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 TraceLoggingGraph_h
|
||||
#define TraceLoggingGraph_h
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "jslock.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/TraceLoggingTypes.h"
|
||||
|
||||
/*
|
||||
* The output of a tracelogging session is saved in /tmp/tl-data.json.
|
||||
* The format of that file is a JS array per tracelogger (=thread), with a map
|
||||
* containing:
|
||||
* - dict: Name of the file containing a json table with the log text.
|
||||
* All other files only contain a index to this table when logging.
|
||||
* - events: Name of the file containing a flat list of log events saved
|
||||
* in binary format.
|
||||
* (64bit: Time Stamp Counter, 32bit index to dict)
|
||||
* - tree: Name of the file containing the events with duration. The content
|
||||
* is already in a tree data structure. This is also saved in a
|
||||
* binary file.
|
||||
* - treeFormat: The format used to encode the tree. By default "64,64,31,1,32".
|
||||
* There are currently no other formats to save the tree.
|
||||
* - 64,64,31,1,31 signifies how many bytes are used for the different
|
||||
* parts of the tree.
|
||||
* => 64 bits: Time Stamp Counter of start of event.
|
||||
* => 64 bits: Time Stamp Counter of end of event.
|
||||
* => 31 bits: Index to dict file containing the log text.
|
||||
* => 1 bit: Boolean signifying if this entry has children.
|
||||
* When true, the child can be found just right after this entry.
|
||||
* => 32 bits: Containing the ID of the next event on the same depth
|
||||
* or 0 if there isn't an event on the same depth anymore.
|
||||
*
|
||||
* /-> The position in the file. Id is this divided by size of entry.
|
||||
* | So in this case this would be 1 (192bits per entry).
|
||||
* | /-> Indicates there are children. The
|
||||
* | | first child is located at current
|
||||
* | | ID + 1. So 1 + 1 in this case: 2.
|
||||
* | | Or 0x00180 in the tree file.
|
||||
* | | /-> Next event on the same depth is
|
||||
* | | | located at 4. So 0x00300 in the
|
||||
* | | | tree file.
|
||||
* 0x0000C0: [start, end, dictId, 1, 4]
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
* 0x0: [start, end, dictId, 1, 0]
|
||||
* |
|
||||
* /----------------------------------\
|
||||
* | |
|
||||
* 0xC0: [start, end, dictId, 0, 2] 0x180 [start, end, dictId, 1, 0]
|
||||
* |
|
||||
* /----------------------------------\
|
||||
* | |
|
||||
* 0x240: [start, end, dictId, 0, 4] 0x300 [start, end, dictId, 0, 0]
|
||||
*/
|
||||
|
||||
class TraceLoggerGraphState
|
||||
{
|
||||
size_t numLoggers;
|
||||
|
||||
// File pointer to the "tl-data.json" file. (Explained above).
|
||||
FILE *out;
|
||||
|
||||
public:
|
||||
PRLock *lock;
|
||||
|
||||
public:
|
||||
TraceLoggerGraphState();
|
||||
~TraceLoggerGraphState();
|
||||
|
||||
uint32_t nextLoggerId();
|
||||
|
||||
private:
|
||||
bool ensureInitialized();
|
||||
};
|
||||
|
||||
class TraceLoggerGraph
|
||||
{
|
||||
// The layout of the tree in memory and in the log file. Readable by JS
|
||||
// using TypedArrays.
|
||||
struct TreeEntry {
|
||||
uint64_t start_;
|
||||
uint64_t stop_;
|
||||
union {
|
||||
struct {
|
||||
uint32_t textId_: 31;
|
||||
uint32_t hasChildren_: 1;
|
||||
} s;
|
||||
uint32_t value_;
|
||||
} u;
|
||||
uint32_t nextId_;
|
||||
|
||||
TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
|
||||
uint32_t nextId)
|
||||
{
|
||||
start_ = start;
|
||||
stop_ = stop;
|
||||
u.s.textId_ = textId;
|
||||
u.s.hasChildren_ = hasChildren;
|
||||
nextId_ = nextId;
|
||||
}
|
||||
TreeEntry()
|
||||
{ }
|
||||
uint64_t start() {
|
||||
return start_;
|
||||
}
|
||||
uint64_t stop() {
|
||||
return stop_;
|
||||
}
|
||||
uint32_t textId() {
|
||||
return u.s.textId_;
|
||||
}
|
||||
bool hasChildren() {
|
||||
return u.s.hasChildren_;
|
||||
}
|
||||
uint32_t nextId() {
|
||||
return nextId_;
|
||||
}
|
||||
void setStart(uint64_t start) {
|
||||
start_ = start;
|
||||
}
|
||||
void setStop(uint64_t stop) {
|
||||
stop_ = stop;
|
||||
}
|
||||
void setTextId(uint32_t textId) {
|
||||
MOZ_ASSERT(textId < uint32_t(1 << 31));
|
||||
u.s.textId_ = textId;
|
||||
}
|
||||
void setHasChildren(bool hasChildren) {
|
||||
u.s.hasChildren_ = hasChildren;
|
||||
}
|
||||
void setNextId(uint32_t nextId) {
|
||||
nextId_ = nextId;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper structure for keeping track of the current entries in
|
||||
// the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
|
||||
// is used to know if a subtree doesn't need to get logged.
|
||||
struct StackEntry {
|
||||
uint32_t treeId_;
|
||||
uint32_t lastChildId_;
|
||||
struct {
|
||||
uint32_t textId_: 31;
|
||||
uint32_t active_: 1;
|
||||
} s;
|
||||
StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
|
||||
: treeId_(treeId), lastChildId_(lastChildId)
|
||||
{
|
||||
s.textId_ = 0;
|
||||
s.active_ = active;
|
||||
}
|
||||
uint32_t treeId() {
|
||||
return treeId_;
|
||||
}
|
||||
uint32_t lastChildId() {
|
||||
return lastChildId_;
|
||||
}
|
||||
uint32_t textId() {
|
||||
return s.textId_;
|
||||
}
|
||||
bool active() {
|
||||
return s.active_;
|
||||
}
|
||||
void setTreeId(uint32_t treeId) {
|
||||
treeId_ = treeId;
|
||||
}
|
||||
void setLastChildId(uint32_t lastChildId) {
|
||||
lastChildId_ = lastChildId;
|
||||
}
|
||||
void setTextId(uint32_t textId) {
|
||||
MOZ_ASSERT(textId < uint32_t(1<<31));
|
||||
s.textId_ = textId;
|
||||
}
|
||||
void setActive(bool active) {
|
||||
s.active_ = active;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
TraceLoggerGraph()
|
||||
: failed(false),
|
||||
enabled(false),
|
||||
nextTextId(0)
|
||||
{ }
|
||||
~TraceLoggerGraph();
|
||||
|
||||
bool init(uint64_t timestamp);
|
||||
|
||||
// Link a textId with a particular text.
|
||||
void addTextId(uint32_t id, const char *text);
|
||||
|
||||
// Create a tree out of all the given events.
|
||||
void log(ContinuousSpace<EventEntry> &events);
|
||||
|
||||
private:
|
||||
bool failed;
|
||||
bool enabled;
|
||||
mozilla::DebugOnly<uint32_t> nextTextId;
|
||||
|
||||
FILE *dictFile;
|
||||
FILE *treeFile;
|
||||
FILE *eventFile;
|
||||
|
||||
ContinuousSpace<TreeEntry> tree;
|
||||
ContinuousSpace<StackEntry> stack;
|
||||
uint32_t treeOffset;
|
||||
|
||||
// Helper functions that convert a TreeEntry in different endianness
|
||||
// in place.
|
||||
void entryToBigEndian(TreeEntry *entry);
|
||||
void entryToSystemEndian(TreeEntry *entry);
|
||||
|
||||
// Helper functions to get/save a tree from file.
|
||||
bool getTreeEntry(uint32_t treeId, TreeEntry *entry);
|
||||
bool saveTreeEntry(uint32_t treeId, TreeEntry *entry);
|
||||
|
||||
// Return the first StackEntry that is active.
|
||||
StackEntry &getActiveAncestor();
|
||||
|
||||
// This contains the meat of startEvent, except the test for enough space,
|
||||
// the test if tracelogger is enabled and the timestamp computation.
|
||||
void startEvent(uint32_t id, uint64_t timestamp);
|
||||
bool startEventInternal(uint32_t id, uint64_t timestamp);
|
||||
|
||||
// Update functions that can adjust the items in the tree,
|
||||
// both in memory or already written to disk.
|
||||
bool updateHasChildren(uint32_t treeId, bool hasChildren = true);
|
||||
bool updateNextId(uint32_t treeId, uint32_t nextId);
|
||||
bool updateStop(uint32_t treeId, uint64_t timestamp);
|
||||
|
||||
// Flush the tree.
|
||||
bool flush();
|
||||
|
||||
// Stop a tree event.
|
||||
void stopEvent(uint32_t id, uint64_t timestamp);
|
||||
void stopEvent(uint64_t timestamp);
|
||||
|
||||
// Log an (non-tree) event.
|
||||
void logTimestamp(uint32_t id, uint64_t timestamp);
|
||||
|
||||
// Disable logging and forcefully report all not yet stopped tree events
|
||||
// as stopped.
|
||||
void disable(uint64_t timestamp);
|
||||
};
|
||||
|
||||
#endif /* TraceLoggingGraph_h */
|
|
@ -1,20 +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/TraceLoggingTypes.h"
|
||||
|
||||
class JSLinearString;
|
||||
|
||||
uint32_t
|
||||
TLStringToTextId(JSLinearString *str)
|
||||
{
|
||||
#define NAME(textId) if (js::StringEqualsAscii(str, #textId)) return TraceLogger_ ## textId;
|
||||
TRACELOGGER_TREE_ITEMS(NAME)
|
||||
TRACELOGGER_LOG_ITEMS(NAME)
|
||||
#undef NAME
|
||||
return TraceLogger_Error;
|
||||
}
|
||||
|
|
@ -1,239 +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 TraceLoggingTypes_h
|
||||
#define TraceLoggingTypes_h
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#define TRACELOGGER_TREE_ITEMS(_) \
|
||||
_(AnnotateScripts) \
|
||||
_(Baseline) \
|
||||
_(BaselineCompilation) \
|
||||
_(Engine) \
|
||||
_(GC) \
|
||||
_(GCAllocation) \
|
||||
_(GCSweeping) \
|
||||
_(Internal) \
|
||||
_(Interpreter) \
|
||||
_(InlinedScripts) \
|
||||
_(Invalidation) \
|
||||
_(IonCompilation) \
|
||||
_(IonCompilationPaused) \
|
||||
_(IonLinking) \
|
||||
_(IonMonkey) \
|
||||
_(IrregexpCompile) \
|
||||
_(IrregexpExecute) \
|
||||
_(MinorGC) \
|
||||
_(ParserCompileFunction) \
|
||||
_(ParserCompileLazy) \
|
||||
_(ParserCompileScript) \
|
||||
_(Scripts) \
|
||||
_(VM) \
|
||||
\
|
||||
/* Specific passes during ion compilation */ \
|
||||
_(FoldTests) \
|
||||
_(SplitCriticalEdges) \
|
||||
_(RenumberBlocks) \
|
||||
_(ScalarReplacement) \
|
||||
_(DominatorTree) \
|
||||
_(PhiAnalysis) \
|
||||
_(MakeLoopsContiguous) \
|
||||
_(ApplyTypes) \
|
||||
_(ParallelSafetyAnalysis) \
|
||||
_(AliasAnalysis) \
|
||||
_(GVN) \
|
||||
_(LICM) \
|
||||
_(RangeAnalysis) \
|
||||
_(LoopUnrolling) \
|
||||
_(EffectiveAddressAnalysis) \
|
||||
_(EliminateDeadCode) \
|
||||
_(EdgeCaseAnalysis) \
|
||||
_(EliminateRedundantChecks) \
|
||||
_(GenerateLIR) \
|
||||
_(RegisterAllocation) \
|
||||
_(GenerateCode)
|
||||
|
||||
#define TRACELOGGER_LOG_ITEMS(_) \
|
||||
_(Bailout) \
|
||||
_(Disable) \
|
||||
_(Enable) \
|
||||
_(Stop)
|
||||
|
||||
// Predefined IDs for common operations. These IDs can be used
|
||||
// without using TraceLogCreateTextId, because there are already created.
|
||||
enum TraceLoggerTextId {
|
||||
TraceLogger_Error = 0,
|
||||
#define DEFINE_TEXT_ID(textId) TraceLogger_ ## textId,
|
||||
TRACELOGGER_TREE_ITEMS(DEFINE_TEXT_ID)
|
||||
TraceLogger_LastTreeItem,
|
||||
TRACELOGGER_LOG_ITEMS(DEFINE_TEXT_ID)
|
||||
#undef DEFINE_TEXT_ID
|
||||
TraceLogger_Last
|
||||
};
|
||||
|
||||
inline const char *
|
||||
TLTextIdString(TraceLoggerTextId id)
|
||||
{
|
||||
switch (id) {
|
||||
case TraceLogger_Error:
|
||||
return "TraceLogger failed to process text";
|
||||
#define NAME(textId) case TraceLogger_ ## textId: return #textId;
|
||||
TRACELOGGER_TREE_ITEMS(NAME)
|
||||
TRACELOGGER_LOG_ITEMS(NAME)
|
||||
#undef NAME
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TLStringToTextId(JSLinearString *str);
|
||||
|
||||
inline bool
|
||||
TLTextIdIsToggable(uint32_t id)
|
||||
{
|
||||
if (id == TraceLogger_Error)
|
||||
return false;
|
||||
if (id == TraceLogger_Internal)
|
||||
return false;
|
||||
if (id == TraceLogger_Stop)
|
||||
return false;
|
||||
// Actually never used. But added here so it doesn't show as toggle
|
||||
if (id == TraceLogger_LastTreeItem)
|
||||
return false;
|
||||
if (id == TraceLogger_Last)
|
||||
return false;
|
||||
// Cannot toggle the logging of one engine on/off, because at the stop
|
||||
// event it is sometimes unknown which engine was running.
|
||||
if (id == TraceLogger_IonMonkey || id == TraceLogger_Baseline || id == TraceLogger_Interpreter)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
TLTextIdIsTreeEvent(uint32_t id)
|
||||
{
|
||||
// Everything between TraceLogger_Error and TraceLogger_LastTreeItem are tree events and
|
||||
// atm also every custom event.
|
||||
return (id > TraceLogger_Error && id < TraceLogger_LastTreeItem) ||
|
||||
id >= TraceLogger_Last;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class ContinuousSpace {
|
||||
T *data_;
|
||||
uint32_t size_;
|
||||
uint32_t capacity_;
|
||||
|
||||
public:
|
||||
ContinuousSpace ()
|
||||
: data_(nullptr)
|
||||
{ }
|
||||
|
||||
bool init() {
|
||||
capacity_ = 64;
|
||||
size_ = 0;
|
||||
data_ = (T *) js_malloc(capacity_ * sizeof(T));
|
||||
if (!data_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
~ContinuousSpace()
|
||||
{
|
||||
js_free(data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
T *data() {
|
||||
return data_;
|
||||
}
|
||||
|
||||
uint32_t capacity() {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
uint32_t size() {
|
||||
return size_;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
uint32_t lastEntryId() {
|
||||
MOZ_ASSERT(!empty());
|
||||
return size_ - 1;
|
||||
}
|
||||
|
||||
T &lastEntry() {
|
||||
return data()[lastEntryId()];
|
||||
}
|
||||
|
||||
bool hasSpaceForAdd(uint32_t count = 1) {
|
||||
if (size_ + count <= capacity_)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ensureSpaceBeforeAdd(uint32_t count = 1) {
|
||||
MOZ_ASSERT(data_);
|
||||
if (hasSpaceForAdd(count))
|
||||
return true;
|
||||
|
||||
uint32_t nCapacity = capacity_ * 2;
|
||||
if (size_ + count > nCapacity)
|
||||
nCapacity = size_ + count;
|
||||
T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T));
|
||||
|
||||
if (!entries)
|
||||
return false;
|
||||
|
||||
data_ = entries;
|
||||
capacity_ = nCapacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
T &operator[](size_t i) {
|
||||
MOZ_ASSERT(i < size_);
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
void push(T &data) {
|
||||
MOZ_ASSERT(size_ < capacity_);
|
||||
data()[size_++] = data;
|
||||
}
|
||||
|
||||
T &pushUninitialized() {
|
||||
MOZ_ASSERT(size_ < capacity_);
|
||||
return data()[size_++];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
MOZ_ASSERT(!empty());
|
||||
size_--;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
size_ = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// The layout of the event log in memory and in the log file.
|
||||
// Readable by JS using TypedArrays.
|
||||
struct EventEntry {
|
||||
uint64_t time;
|
||||
uint32_t textId;
|
||||
EventEntry(uint64_t time, uint32_t textId)
|
||||
: time(time), textId(textId)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* TraceLoggingTypes_h */
|
|
@ -1711,10 +1711,8 @@ class Mochitest(MochitestUtilsMixin):
|
|||
|
||||
self.setTestRoot(options)
|
||||
|
||||
# This runs on bc* and dt* jobs only
|
||||
# We need to fix tests on plain|chrome|webapprt|a11y before making this default
|
||||
# We need to ignore dt* jobs on e10s runs
|
||||
if options.browserChrome and not (options.subsuite and options.e10s):
|
||||
# Until we have all green, this only runs on bc* jobs (not dt* jobs)
|
||||
if options.browserChrome and not options.subsuite:
|
||||
options.runByDir = True
|
||||
|
||||
if not options.runByDir:
|
||||
|
|
Загрузка…
Ссылка в новой задаче