Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 21 Nov 2014 08:27:29 +0100
changeset 216796 5ba06e4f49e8af5d49a1752a32afccfd1a170a4b
parent 216795 e5b26d5a9a5214502071a04abb9a1969b83f37eb (current diff)
parent 216790 7b56755a63ba48c3316536d8eaa1508d02da67cb (diff)
child 216823 23ca43337c3f5db036d1cbb72b291460c37ba055
child 216878 053710e85e28144e4c8fe9e1a4b8ce3011815311
push id27863
push usercbook@mozilla.com
push dateFri, 21 Nov 2014 10:56:43 +0000
treeherdermozilla-central@5ba06e4f49e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone36.0a1
first release with
nightly linux32
5ba06e4f49e8 / 36.0a1 / 20141121030201 / files
nightly linux64
5ba06e4f49e8 / 36.0a1 / 20141121030201 / files
nightly mac
5ba06e4f49e8 / 36.0a1 / 20141121030201 / files
nightly win32
5ba06e4f49e8 / 36.0a1 / 20141121030201 / files
nightly win64
5ba06e4f49e8 / 36.0a1 / 20141121030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
js/src/jit-test/tests/tracelogger/drainTraceLogger.js
js/src/jit-test/tests/tracelogger/setupTraceLogger.js
js/src/vm/TraceLoggingGraph.cpp
js/src/vm/TraceLoggingGraph.h
js/src/vm/TraceLoggingTypes.cpp
js/src/vm/TraceLoggingTypes.h
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1699,27 +1699,27 @@ TimesAccessed(JSContext *cx, unsigned ar
     args.rval().setInt32(++accessed);
     return true;
 }
 
 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;
 }
 
 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;
 }
 
 #ifdef DEBUG
 static bool
 DumpObject(JSContext *cx, unsigned argc, jsval *vp)
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2980,26 +2980,26 @@ fi # COMPILE_ENVIRONMENT
 AC_SUBST(MOZ_OPTIMIZE)
 AC_SUBST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST(MOZ_OPTIMIZE_LDFLAGS)
 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
 
 dnl ========================================================
 dnl = Disable treating compiler warnings as errors
 dnl ========================================================
 if test -z "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
    WARNINGS_AS_ERRORS=''
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -215,24 +215,24 @@ frontend::CompileScript(ExclusiveContext
                         JSString *source_ /* = nullptr */,
                         unsigned staticLevel /* = 0 */,
                         SourceCompressionTask *extraSct /* = nullptr */)
 {
     MOZ_ASSERT(srcBuf.get());
 
     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
      * and non-zero static level requires callerFrame.
      */
     MOZ_ASSERT_IF(evalCaller, options.compileAndGo);
     MOZ_ASSERT_IF(evalCaller, options.forEval);
     MOZ_ASSERT_IF(staticLevel != 0, evalCaller);
@@ -470,20 +470,20 @@ frontend::CompileLazyFunction(JSContext 
     CompileOptions options(cx, lazy->version());
     options.setMutedErrors(lazy->mutedErrors())
            .setFileAndLine(lazy->source()->filename(), lazy->lineno())
            .setColumn(lazy->column())
            .setCompileAndGo(true)
            .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);
     if (!parser.checkOptions())
         return false;
 
     uint32_t staticLevel = lazy->staticLevel(cx);
 
@@ -528,20 +528,20 @@ frontend::CompileLazyFunction(JSContext 
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
 static bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyCompileOptions &options,
                     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.
 
     if (!CheckLength(cx, srcBuf))
         return false;
 
     RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
deleted file mode 100644
--- a/js/src/jit-test/tests/tracelogger/drainTraceLogger.js
+++ /dev/null
@@ -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));
-}
deleted file mode 100644
--- a/js/src/jit-test/tests/tracelogger/setupTraceLogger.js
+++ /dev/null
@@ -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");
-}
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -36,18 +36,18 @@ jit::Bailout(BailoutStack *sp, BaselineB
                "Fake jitTop pointer should be within the first page.");
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, sp);
     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());
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
     bool poppedLastSPSFrame = false;
     uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
@@ -102,18 +102,18 @@ jit::InvalidationBailout(InvalidationBai
 
     // We don't have an exit frame.
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->runtime());
     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());
 
     // Note: the frame size must be computed before we return from this function.
     *frameSizeOut = iter.frameSize();
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1342,19 +1342,19 @@ jit::BailoutIonToBaseline(JSContext *cx,
                           const ExceptionBailoutInfo *excInfo, bool *poppedLastSPSFrameOut)
 {
     MOZ_ASSERT(bailoutInfo != nullptr);
     MOZ_ASSERT(*bailoutInfo == nullptr);
 
     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.
     //      BaselineStub - Baseline calling into Ion.
     //      Entry - Interpreter or other calling into Ion.
     //      Rectifier - Arguments rectifier calling into Ion.
     MOZ_ASSERT(iter.isBailoutJS());
     FrameType prevFrameType = iter.prevType();
@@ -1455,22 +1455,18 @@ jit::BailoutIonToBaseline(JSContext *cx,
 
     gc::AutoSuppressGC suppress(cx);
 
     while (true) {
         // Skip recover instructions as they are already recovered by |initInstructionResults|.
         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);
 
         // If we are bailing out to a catch or finally block in this frame,
         // pass excInfo to InitFromBailout and don't unpack any other frames.
         bool handleException = (catchingException && excInfo->frameNo() == frameNo);
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -76,20 +76,19 @@ MethodStatus
 BaselineCompiler::compile()
 {
     JitSpew(JitSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
             script->filename(), script->lineno(), script);
 
     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;
 
     // Pin analysis info during compilation.
     types::AutoEnterAnalysis autoEnterAnalysis(cx);
 
     MOZ_ASSERT(!script->hasBaselineScript());
@@ -173,31 +172,25 @@ BaselineCompiler::compile()
     }
 
     if (pcEntries.oom())
         return Method_Error;
 
     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.
     size_t bytecodeTypeMapEntries = script->nTypeSets() + 1;
 
     mozilla::UniquePtr<BaselineScript, JS::DeletePolicy<BaselineScript> > baselineScript(
         BaselineScript::New(script, prologueOffset_.offset(),
                             epilogueOffset_.offset(),
                             spsPushToggleOffset_.offset(),
-                            traceLoggerEnterToggleOffset_.offset(),
-                            traceLoggerExitToggleOffset_.offset(),
                             postDebugPrologueOffset_.offset(),
                             icEntries_.length(),
                             pcMappingIndexEntries.length(),
                             pcEntries.length(),
                             bytecodeTypeMapEntries,
                             yieldOffsets_.length()));
     if (!baselineScript)
         return Method_Error;
@@ -243,21 +236,16 @@ BaselineCompiler::compile()
     // All barriers are emitted off-by-default, toggle them on if needed.
     if (cx->zone()->needsIncrementalBarrier())
         baselineScript->toggleBarriers(true);
 
     // All SPS instrumentation is emitted toggled off.  Toggle them on if needed.
     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);
 
     // The last entry in the last index found, and is used to avoid binary
     // searches for the sought entry when queries are in linear order.
     bytecodeMap[script->nTypeSets()] = 0;
 
     baselineScript->copyYieldEntries(script, yieldOffsets_);
@@ -380,18 +368,23 @@ BaselineCompiler::emitPrologue()
         emitInitializeLocals(frame.nvars(), UndefinedValue());
     if (frame.nlexicals() > 0)
         emitInitializeLocals(frame.nlexicals(), MagicValue(JS_UNINITIALIZED_LEXICAL));
 
     if (needsEarlyStackCheck())
         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
     // the scope chain is initialized.
     prologueOffset_ = CodeOffsetLabel(masm.currentOffset());
 
     // Initialize the scope chain before any operation that may
     // call into the VM and trigger a GC.
@@ -421,18 +414,25 @@ BaselineCompiler::emitEpilogue()
 {
     // Record the offset of the epilogue, so we can do early return from
     // Debugger handlers during on-stack recompile.
     epilogueOffset_ = CodeOffsetLabel(masm.currentOffset());
 
     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
     emitSPSPop();
 
     masm.mov(BaselineFrameReg, BaselineStackReg);
     masm.pop(BaselineFrameReg);
 
@@ -762,74 +762,16 @@ BaselineCompiler::emitDebugTrap()
     ICEntry icEntry(script->pcToOffset(pc), ICEntry::Kind_DebugTrap);
     icEntry.setReturnOffset(CodeOffsetLabel(masm.currentOffset()));
     if (!icEntries_.append(icEntry))
         return false;
 
     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()
 {
     // Enter the IC, guarded by a toggled jump (initially disabled).
     Label noPush;
     CodeOffsetLabel toggleOffset = masm.toggledJump(&noPush);
     MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
     ICProfiler_Fallback::Compiler compiler(cx);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -245,18 +245,16 @@ class BaselineCompiler : public Baseline
     }
 
     bool emitStackCheck(bool earlyCheck=false);
     bool emitInterruptCheck();
     bool emitWarmUpCounterIncrement(bool allowOsr=true);
     bool emitArgumentTypeChecks();
     bool emitDebugPrologue();
     bool emitDebugTrap();
-    bool emitTraceLoggerEnter();
-    bool emitTraceLoggerExit();
     bool emitSPSPush();
     void emitSPSPop();
 
     bool initScopeChain();
 
     void storeValue(const StackValue *source, const Address &dest,
                     const ValueOperand &scratch);
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -36,37 +36,26 @@ PCMappingSlotInfo::ToSlotLocation(const 
         MOZ_ASSERT(stackVal->reg() == R1);
         return SlotInR1;
     }
     MOZ_ASSERT(stackVal->kind() != StackValue::Stack);
     return SlotIgnore;
 }
 
 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_(),
     prologueOffset_(prologueOffset),
     epilogueOffset_(epilogueOffset),
 #ifdef DEBUG
     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)
 { }
 
 static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000;
 
 static bool
 CheckFrame(InterpreterFrame *fp)
@@ -196,19 +185,19 @@ jit::EnterBaselineAtBranch(JSContext *cx
 
         // For eval function frames, set the callee token to the enclosing function.
         if (fp->isFunctionFrame())
             data.calleeToken = CalleeToToken(&fp->callee(), /* constructing = */ false);
         else
             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)
         return status;
 
     fp->setReturnValue(data.result);
     return IonExec_Ok;
 }
@@ -345,18 +334,17 @@ jit::CanEnterBaselineMethod(JSContext *c
     }
 
     RootedScript script(cx, state.script());
     return CanEnterBaselineJIT(cx, script, /* osrFrame = */ nullptr);
 };
 
 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)
 {
     static const unsigned DataAlignment = sizeof(uintptr_t);
 
     size_t icEntriesSize = icEntries * sizeof(ICEntry);
     size_t pcMappingIndexEntriesSize = pcMappingIndexEntries * sizeof(PCMappingIndexEntry);
     size_t bytecodeTypeMapSize = bytecodeTypeMapEntries * sizeof(uint32_t);
@@ -373,18 +361,17 @@ BaselineScript::New(JSScript *jsscript, 
                         paddedPCMappingSize +
                         paddedBytecodeTypesMapSize +
                         paddedYieldEntriesSize;
 
     BaselineScript *script = jsscript->zone()->pod_malloc_with_extra<BaselineScript, uint8_t>(allocBytes);
     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));
 
     script->icEntriesOffset_ = offsetCursor;
     script->icEntries_ = icEntries;
     offsetCursor += paddedICEntriesSize;
 
@@ -842,100 +829,16 @@ BaselineScript::toggleSPS(bool enable)
         Assembler::ToggleToCmp(pushToggleLocation);
     else
         Assembler::ToggleToJmp(pushToggleLocation);
 #ifdef DEBUG
     spsOn_ = 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)
 {
     JitSpew(JitSpew_BaselineIC, "Purging optimized stubs");
 
     for (size_t i = 0; i < numICEntries(); i++) {
         ICEntry &entry = icEntry(i);
         if (!entry.hasStub())
@@ -1033,44 +936,16 @@ jit::ToggleBaselineSPS(JSRuntime *runtim
             JSScript *script = i.get<JSScript>();
             if (!script->hasBaselineScript())
                 continue;
             script->baselineScript()->toggleSPS(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)
 {
     for (jit::JitFrameIterator iter(activation); !iter.done(); ++iter) {
         switch (iter.type()) {
           case JitFrame_BaselineJS:
             iter.script()->baselineScript()->setActive();
             break;
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -11,17 +11,16 @@
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 
 #include "ds/LifoAlloc.h"
 #include "jit/Bailouts.h"
 #include "jit/IonCode.h"
 #include "jit/IonMacroAssembler.h"
-#include "vm/TraceLogging.h"
 
 namespace js {
 namespace jit {
 
 class StackValue;
 class ICEntry;
 class ICStub;
 
@@ -123,27 +122,16 @@ struct BaselineScript
     uint32_t epilogueOffset_;
 
     // The offsets for the toggledJump instructions for SPS update ICs.
 #ifdef DEBUG
     mozilla::DebugOnly<bool> spsOn_;
 #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.
     //
     // We don't need one for the debug epilogue because that always happens
     // right before the epilogue, so we just use the epilogue offset.
     uint32_t postDebugPrologueOffset_;
 
@@ -192,23 +180,21 @@ struct BaselineScript
 
     // For generator scripts, we store the native code address for each yield
     // instruction.
     uint32_t yieldEntriesOffset_;
 
   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);
 
     static void Trace(JSTracer *trc, BaselineScript *script);
     static void Destroy(FreeOp *fop, BaselineScript *script);
 
     void purgeOptimizedStubs(Zone *zone);
 
@@ -367,26 +353,16 @@ struct BaselineScript
   public:
     // Toggle debug traps (used for breakpoints and step mode) in the script.
     // If |pc| is nullptr, toggle traps for all ops in the script. Else, only
     // toggle traps at |pc|.
     void toggleDebugTraps(JSScript *script, jsbytecode *pc);
 
     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);
 
     static size_t offsetOfFlags() {
         return offsetof(BaselineScript, flags_);
     }
     static size_t offsetOfYieldEntriesOffset() {
         return offsetof(BaselineScript, yieldEntriesOffset_);
@@ -429,21 +405,16 @@ FinishDiscardBaselineScript(FreeOp *fop,
 
 void
 AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size_t *data,
                       size_t *fallbackStubs);
 
 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.
     uint8_t *incomingStack;
 
     // The top and bottom heapspace addresses of the reconstructed stack
     // which will be copied to the bottom.
     uint8_t *copyStackTop;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2085,19 +2085,19 @@ bool
 CodeGenerator::visitOsrEntry(LOsrEntry *lir)
 {
     // Remember the OSR entry offset into the code buffer.
     masm.flushBuffer();
     setOsrEntryOffset(masm.size());
 
 #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
 
     // Allocate the full frame for this function
     // Note we have a new entry here. So we reset MacroAssembler::framePushed()
     // to 0, before reserving the stack.
     MOZ_ASSERT(masm.framePushed() == frameSize());
@@ -7647,17 +7647,17 @@ CodeGenerator::generate()
         return false;
 
     masm.bind(&skipPrologue);
 
 #ifdef JS_TRACE_LOGGING
     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
         if (!emitTracelogScriptStart())
             return false;
-        if (!emitTracelogStartEvent(TraceLogger_IonMonkey))
+        if (!emitTracelogStartEvent(TraceLogger::IonMonkey))
             return false;
     }
 #endif
 
 #ifdef DEBUG
     // Assert that the argument types are correct.
     if (!generateArgumentsChecks(/* bailout = */ false))
         return false;
@@ -7923,35 +7923,29 @@ CodeGenerator::link(JSContext *cx, types
     if (graph.numConstants())
         ionScript->copyConstants(graph.constantPool());
     if (callTargets.length() > 0)
         ionScript->copyCallTargetEntries(callTargets.begin());
     if (patchableBackedges_.length() > 0)
         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
 
     switch (executionMode) {
       case SequentialExecution:
         // The correct state for prebarriers is unknown until the end of compilation,
         // since a GC can occur during code generation. All barriers are emitted
         // off-by-default, and are toggled on here if necessary.
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -534,20 +534,19 @@ jit::LazyLinkTopActivation(JSContext *cx
 
     types::AutoEnterAnalysis enterTypes(cx);
     RootedScript script(cx, builder->script());
 
     // Remove from pending.
     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());
 
         // Root the assembler until the builder is finished below. As it
         // was constructed off thread, the assembler has not been rooted
         // previously, though any GC activity would discard the builder.
         codegen->masm.constructRoot(cx);
 
@@ -1285,17 +1284,17 @@ jit::ToggleBarriers(JS::Zone *zone, bool
 
 namespace js {
 namespace jit {
 
 bool
 OptimizeMIR(MIRGenerator *mir)
 {
     MIRGraph &graph = mir->graph();
-    TraceLoggerThread *logger;
+    TraceLogger *logger;
     if (GetIonContext()->runtime->onMainThread())
         logger = TraceLoggerForMainThread(GetIonContext()->runtime);
     else
         logger = TraceLoggerForCurrentThread();
 
     if (!mir->compilingAsmJS()) {
         if (!MakeMRegExpHoistable(graph))
             return false;
@@ -1303,59 +1302,59 @@ OptimizeMIR(MIRGenerator *mir)
 
     IonSpewPass("BuildSSA");
     AssertBasicGraphCoherency(graph);
 
     if (mir->shouldCancel("Start"))
         return false;
 
     if (!mir->compilingAsmJS()) {
-        AutoTraceLog log(logger, TraceLogger_FoldTests);
+        AutoTraceLog log(logger, TraceLogger::FoldTests);
         FoldTests(graph);
         IonSpewPass("Fold Tests");
         AssertBasicGraphCoherency(graph);
 
         if (mir->shouldCancel("Fold Tests"))
             return false;
     }
 
     {
-        AutoTraceLog log(logger, TraceLogger_SplitCriticalEdges);
+        AutoTraceLog log(logger, TraceLogger::SplitCriticalEdges);
         if (!SplitCriticalEdges(graph))
             return false;
         IonSpewPass("Split Critical Edges");
         AssertGraphCoherency(graph);
 
         if (mir->shouldCancel("Split Critical Edges"))
             return false;
     }
 
     {
-        AutoTraceLog log(logger, TraceLogger_RenumberBlocks);
+        AutoTraceLog log(logger, TraceLogger::RenumberBlocks);
         if (!RenumberBlocks(graph))
             return false;
         IonSpewPass("Renumber Blocks");
         AssertGraphCoherency(graph);
 
         if (mir->shouldCancel("Renumber Blocks"))
             return false;
     }
 
     {
-        AutoTraceLog log(logger, TraceLogger_DominatorTree);
+        AutoTraceLog log(logger, TraceLogger::DominatorTree);
         if (!BuildDominatorTree(graph))
             return false;
         // No spew: graph not changed.
 
         if (mir->shouldCancel("Dominator Tree"))
             return false;
     }
 
     {
-        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
         // aggressive phi elimination.
         Observability observability = graph.hasTryBlock()
                                       ? ConservativeObservability
                                       : AggressiveObservability;
         if (!EliminatePhis(mir, graph, observability))
@@ -1371,43 +1370,43 @@ OptimizeMIR(MIRGenerator *mir)
         AssertExtendedGraphCoherency(graph);
         // No spew: graph not changed.
 
         if (mir->shouldCancel("Phi reverse mapping"))
             return false;
     }
 
     if (mir->optimizationInfo().scalarReplacementEnabled()) {
-        AutoTraceLog log(logger, TraceLogger_ScalarReplacement);
+        AutoTraceLog log(logger, TraceLogger::ScalarReplacement);
         if (!ScalarReplacement(mir, graph))
             return false;
         IonSpewPass("Scalar Replacement");
         AssertGraphCoherency(graph);
 
         if (mir->shouldCancel("Scalar Replacement"))
             return false;
     }
 
     if (!mir->compilingAsmJS()) {
-        AutoTraceLog log(logger, TraceLogger_ApplyTypes);
+        AutoTraceLog log(logger, TraceLogger::ApplyTypes);
         if (!ApplyTypeInformation(mir, graph))
             return false;
         IonSpewPass("Apply types");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("Apply types"))
             return false;
     }
 
     // Parallel Safety Analysis. Note that this may delete blocks containing
     // instructions pointed to by the dependency() field of instructions which
     // 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;
         IonSpewPass("Parallel Safety Analysis");
         AssertExtendedGraphCoherency(graph);
         if (mir->shouldCancel("Parallel Safety Analysis"))
             return false;
     }
@@ -1416,17 +1415,17 @@ OptimizeMIR(MIRGenerator *mir)
     if (!gvn.init())
         return false;
 
     // Alias analysis is required for LICM and GVN so that we don't move
     // loads across stores.
     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;
         IonSpewPass("Alias analysis");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("Alias analysis"))
             return false;
@@ -1439,45 +1438,45 @@ OptimizeMIR(MIRGenerator *mir)
                 return false;
 
             if (mir->shouldCancel("Eliminate dead resume point operands"))
                 return false;
         }
     }
 
     if (mir->optimizationInfo().gvnEnabled()) {
-        AutoTraceLog log(logger, TraceLogger_GVN);
+        AutoTraceLog log(logger, TraceLogger::GVN);
         if (!gvn.run(ValueNumberer::UpdateAliasAnalysis))
             return false;
         IonSpewPass("GVN");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("GVN"))
             return false;
     }
 
     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.
         JSScript *script = mir->info().script();
         if (!script || !script->hadFrequentBailouts()) {
             if (!LICM(mir, graph))
                 return false;
             IonSpewPass("LICM");
             AssertExtendedGraphCoherency(graph);
 
             if (mir->shouldCancel("LICM"))
                 return false;
         }
     }
 
     if (mir->optimizationInfo().rangeAnalysisEnabled()) {
-        AutoTraceLog log(logger, TraceLogger_RangeAnalysis);
+        AutoTraceLog log(logger, TraceLogger::RangeAnalysis);
         RangeAnalysis r(mir, graph);
         if (!r.addBetaNodes())
             return false;
         IonSpewPass("Beta");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("RA Beta"))
             return false;
@@ -1525,79 +1524,79 @@ OptimizeMIR(MIRGenerator *mir)
             IonSpewPass("Truncate Doubles");
             AssertExtendedGraphCoherency(graph);
 
             if (mir->shouldCancel("Truncate Doubles"))
                 return false;
         }
 
         if (mir->optimizationInfo().loopUnrollingEnabled()) {
-            AutoTraceLog log(logger, TraceLogger_LoopUnrolling);
+            AutoTraceLog log(logger, TraceLogger::LoopUnrolling);
 
             if (!UnrollLoops(graph, r.loopIterationBounds))
                 return false;
 
             IonSpewPass("Unroll Loops");
             AssertExtendedGraphCoherency(graph);
         }
     }
 
     if (mir->optimizationInfo().eaaEnabled()) {
-        AutoTraceLog log(logger, TraceLogger_EffectiveAddressAnalysis);
+        AutoTraceLog log(logger, TraceLogger::EffectiveAddressAnalysis);
         EffectiveAddressAnalysis eaa(graph);
         if (!eaa.analyze())
             return false;
         IonSpewPass("Effective Address Analysis");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("Effective Address Analysis"))
             return false;
     }
 
     {
-        AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
+        AutoTraceLog log(logger, TraceLogger::EliminateDeadCode);
         if (!EliminateDeadCode(mir, graph))
             return false;
         IonSpewPass("DCE");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("DCE"))
             return false;
     }
 
     // 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");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("Make loops contiguous"))
             return false;
     }
 
     // Passes after this point must not move instructions; these analyses
     // 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;
         IonSpewPass("Edge Case Analysis (Late)");
         AssertGraphCoherency(graph);
 
         if (mir->shouldCancel("Edge Case Analysis (Late)"))
             return false;
     }
 
     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
         // before its bounds check.
         if (!EliminateRedundantChecks(graph))
             return false;
         IonSpewPass("Bounds Check Elimination");
         AssertGraphCoherency(graph);
@@ -1606,41 +1605,41 @@ OptimizeMIR(MIRGenerator *mir)
     return true;
 }
 
 LIRGraph *
 GenerateLIR(MIRGenerator *mir)
 {
     MIRGraph &graph = mir->graph();
 
-    TraceLoggerThread *logger;
+    TraceLogger *logger;
     if (GetIonContext()->runtime->onMainThread())
         logger = TraceLoggerForMainThread(GetIonContext()->runtime);
     else
         logger = TraceLoggerForCurrentThread();
 
     LIRGraph *lir = mir->alloc().lifoAlloc()->new_<LIRGraph>(&graph);
     if (!lir || !lir->init())
         return nullptr;
 
     LIRGenerator lirgen(mir, graph, *lir);
     {
-        AutoTraceLog log(logger, TraceLogger_GenerateLIR);
+        AutoTraceLog log(logger, TraceLogger::GenerateLIR);
         if (!lirgen.generate())
             return nullptr;
         IonSpewPass("Generate LIR");
 
         if (mir->shouldCancel("Generate LIR"))
             return nullptr;
     }
 
     AllocationIntegrityState integrity(*lir);
 
     {
-        AutoTraceLog log(logger, TraceLogger_RegisterAllocation);
+        AutoTraceLog log(logger, TraceLogger::RegisterAllocation);
 
         switch (mir->optimizationInfo().registerAllocator()) {
           case RegisterAllocator_LSRA: {
 #ifdef DEBUG
             if (!integrity.record())
                 return nullptr;
 #endif
 
@@ -1700,22 +1699,22 @@ GenerateLIR(MIRGenerator *mir)
     }
 
     return lir;
 }
 
 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)
         return nullptr;
 
     if (!codegen->generate()) {
         js_delete(codegen);
         return nullptr;
@@ -1747,17 +1746,17 @@ AttachFinishedCompilations(JSContext *cx
     if (!ion)
         return;
 
     types::AutoEnterAnalysis enterTypes(cx);
     AutoLockHelperThreadState lock;
 
     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.
     while (true) {
         IonBuilder *builder = nullptr;
 
         // Find a finished builder for the compartment.
         for (size_t i = 0; i < finished.length(); i++) {
@@ -1799,19 +1798,18 @@ AttachFinishedCompilations(JSContext *cx
                 HelperThreadState().ionLazyLinkList().insertFront(builder);
                 continue;
             }
         }
 
         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
             // previously, though any GC activity would discard the builder.
             codegen->masm.constructRoot(cx);
 
             bool success;
             {
@@ -1879,20 +1877,19 @@ TrackPropertiesForSingletonScopes(JSCont
 }
 
 static AbortReason
 IonCompile(JSContext *cx, JSScript *script,
            BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
            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);
 
     // Make sure the script's canonical function isn't lazy. We can't de-lazify
     // it in a helper thread.
     script->ensureNonLazyCanonicalFunction(cx);
 
     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -16,17 +16,16 @@
 #include "jit/Ion.h"
 #include "jit/IonOptimizationLevels.h"
 #include "jit/JitSpewer.h"
 #include "jit/Lowering.h"
 #include "jit/MIRGraph.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Opcodes.h"
 #include "vm/RegExpStatics.h"
-#include "vm/TraceLogging.h"
 
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "jit/CompileInfo-inl.h"
 #include "jit/ExecutionMode-inl.h"
@@ -338,21 +337,16 @@ IonBuilder::DontInline(JSScript *targetS
 }
 
 IonBuilder::InliningDecision
 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");
 
     // Allow constructing lazy scripts when performing the definite properties
     // analysis, as baseline has not been used to warm the caller up yet.
     if (target->isInterpreted() && info().executionMode() == DefinitePropertiesAnalysis) {
         RootedScript script(analysisContext, target->getOrCreateScript(analysisContext));
         if (!script)
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -14,17 +14,16 @@
 #include "jsinfer.h"
 #include "jstypes.h"
 
 #include "gc/Heap.h"
 #include "jit/ExecutableAllocator.h"
 #include "jit/IonOptimizationLevels.h"
 #include "jit/IonTypes.h"
 #include "js/UbiNode.h"
-#include "vm/TraceLogging.h"
 
 namespace js {
 
 class AsmJSModule;
 
 namespace jit {
 
 class MacroAssembler;
@@ -298,19 +297,16 @@ struct IonScript
     // Number of times we tried to enter this script via OSR but failed due to
     // a LOOPENTRY pc other than osrPc_.
     uint32_t osrPcMismatchCounter_;
 
     // If non-null, the list of AsmJSModules
     // 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:
     inline uint8_t *bottomBuffer() {
         return reinterpret_cast<uint8_t *>(this);
     }
     inline const uint8_t *bottomBuffer() const {
         return reinterpret_cast<const uint8_t *>(this);
@@ -491,19 +487,16 @@ struct IonScript
         hasSPSInstrumentation_ = true;
     }
     void clearHasSPSInstrumentation() {
         hasSPSInstrumentation_ = false;
     }
     bool hasSPSInstrumentation() const {
         return hasSPSInstrumentation_;
     }
-    void setTraceLoggerEvent(TraceLoggerEvent &event) {
-        traceLoggerScriptEvent_ = event;
-    }
     const uint8_t *snapshots() const {
         return reinterpret_cast<const uint8_t *>(this) + snapshots_;
     }
     size_t snapshotsListSize() const {
         return snapshotsListSize_;
     }
     size_t snapshotsRVATableSize() const {
         return snapshotsRVATableSize_;
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -690,17 +690,17 @@ struct AutoDeleteDebugModeOSRInfo
     explicit AutoDeleteDebugModeOSRInfo(BaselineFrame *frame) : frame(frame) { MOZ_ASSERT(frame); }
     ~AutoDeleteDebugModeOSRInfo() { frame->deleteDebugModeOSRInfo(); }
 };
 
 void
 HandleException(ResumeFromException *rfe)
 {
     JSContext *cx = GetJSContextFromJitCode();
-    TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
+    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
 
     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
 
     JitSpew(JitSpew_IonInvalidate, "handling exception");
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
@@ -751,18 +751,18 @@ HandleException(ResumeFromException *rfe
 
                 // When profiling, each frame popped needs a notification that
                 // the function has exited, so invoke the probe that a function
                 // is exiting.
 
                 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;
             }
 
             if (invalidated)
                 ionScript->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
 
@@ -782,18 +782,18 @@ HandleException(ResumeFromException *rfe
             //
             // We cannot delete it immediately because of the call to
             // iter.baselineScriptAndPc below.
             AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(iter.baselineFrame());
 
             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();
             probes::ExitScript(cx, script, script->functionNonDelazifying(),
                                iter.baselineFrame()->hasPushedSPSFrame());
             // After this point, any pushed SPS frame would have been popped if it needed
             // to be.  Unset the flag here so that if we call DebugEpilogue below,
             // it doesn't try to pop the SPS frame again.
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1663,116 +1663,126 @@ MacroAssembler::printf(const char *outpu
     passABIArg(value);
     callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, Printf1_));
 
     PopRegsInMask(RegisterSet::Volatile());
 }
 
 #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());
 
     RegisterSet regs = RegisterSet::Volatile();
     regs.takeUnchecked(logger);
 
     Register temp = regs.takeGeneral();
 
     setupUnalignedABICall(2, temp);
     passABIArg(logger);
     move32(Imm32(textId), temp);
     passABIArg(temp);
-    callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
+    callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
 
     PopRegsInMask(RegisterSet::Volatile());
 }
 
 void
-MacroAssembler::tracelogStartId(Register logger, Register textId)
+MacroAssembler::tracelogStart(Register logger, Register textId)
 {
+    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 *, TraceLogStartEventPrivate));
+    callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
+
+    regs.add(temp);
 
     PopRegsInMask(RegisterSet::Volatile());
 }
 
 void
-MacroAssembler::tracelogStartEvent(Register logger, Register event)
+MacroAssembler::tracelogStop(Register logger, uint32_t textId)
 {
-    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)
-{
-    if (!force && !TraceLogTextIdEnabled(textId))
-        return;
+    void (&TraceLogFunc)(TraceLogger*, uint32_t) = TraceLogStopEvent;
 
     PushRegsInMask(RegisterSet::Volatile());
 
     RegisterSet regs = RegisterSet::Volatile();
     regs.takeUnchecked(logger);
 
     Register temp = regs.takeGeneral();
 
     setupUnalignedABICall(2, temp);
     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();
 
     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());
 }
 #endif
 
 void
 MacroAssembler::convertInt32ValueToDouble(const Address &address, Register scratch, Label *done)
 {
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -1202,21 +1202,21 @@ class MacroAssembler : public MacroAssem
 
     void finish();
 
     void assumeUnreachable(const char *output);
     void printf(const char *output);
     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)    \
     MOZ_ASSERT(IsFloatingPointType(type));                              \
     if (type == MIRType_Double)                                         \
         method##Double(arg1d, arg2);                                    \
     else                                                                \
         method##Float32(arg1f, arg2);                                   \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -773,19 +773,19 @@ DebugPrologue(JSContext *cx, BaselineFra
 }
 
 bool
 DebugEpilogueOnBaselineReturn(JSContext *cx, BaselineFrame *frame, jsbytecode *pc)
 {
     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;
     }
 
     return true;
 }
 
 bool
 DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -52,17 +52,17 @@ CodeGeneratorARM::generatePrologue()
 bool
 CodeGeneratorARM::generateEpilogue()
 {
     MOZ_ASSERT(!gen->compilingAsmJS());
     masm.bind(&returnLabel_);
 
 #ifdef JS_TRACE_LOGGING
     if (gen->info().executionMode() == SequentialExecution) {
-        if (!emitTracelogStopEvent(TraceLogger_IonMonkey))
+        if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
             return false;
         if (!emitTracelogScriptStop())
             return false;
     }
 #endif
 
     masm.freeStack(frameSize());
     MOZ_ASSERT(masm.framePushed() == 0);
--- a/js/src/jit/shared/BaselineCompiler-shared.cpp
+++ b/js/src/jit/shared/BaselineCompiler-shared.cpp
@@ -25,20 +25,17 @@ BaselineCompilerShared::BaselineCompiler
     analysis_(alloc, script),
     frame(script, masm),
     stubSpace_(),
     icEntries_(),
     pcMappingEntries_(),
     icLoadLabels_(),
     pushedBeforeCall_(0),
     inCall_(false),
-    spsPushToggleOffset_(),
-    traceLoggerEnterToggleOffset_(),
-    traceLoggerExitToggleOffset_(),
-    traceLoggerScriptTextIdOffset_()
+    spsPushToggleOffset_()
 { }
 
 bool
 BaselineCompilerShared::callVM(const VMFunction &fun, CallVMPhase phase)
 {
     JitCode *code = cx->runtime()->jitRuntime()->getVMWrapper(fun);
     if (!code)
         return false;
--- a/js/src/jit/shared/BaselineCompiler-shared.h
+++ b/js/src/jit/shared/BaselineCompiler-shared.h
@@ -63,19 +63,16 @@ class BaselineCompilerShared
         CodeOffsetLabel label;
     };
     js::Vector<ICLoadLabel, 16, SystemAllocPolicy> icLoadLabels_;
 
     uint32_t pushedBeforeCall_;
     mozilla::DebugOnly<bool> inCall_;
 
     CodeOffsetLabel spsPushToggleOffset_;
-    CodeOffsetLabel traceLoggerEnterToggleOffset_;
-    CodeOffsetLabel traceLoggerExitToggleOffset_;
-    CodeOffsetLabel traceLoggerScriptTextIdOffset_;
 
     BaselineCompilerShared(JSContext *cx, TempAllocator &alloc, JSScript *script);
 
     ICEntry *allocateICEntry(ICStub *stub, ICEntry::Kind kind) {
         if (!stub)
             return nullptr;
 
         // Create the entry and add it to the vector.
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1006,17 +1006,17 @@ CodeGeneratorShared::callVM(const VMFunc
     if (ins->mirRaw()) {
         MOZ_ASSERT(ins->mirRaw()->isInstruction());
         MInstruction *mir = ins->mirRaw()->toInstruction();
         MOZ_ASSERT_IF(mir->needsResumePoint(), mir->resumePoint());
     }
 #endif
 
 #ifdef JS_TRACE_LOGGING
-    if (!emitTracelogStartEvent(TraceLogger_VM))
+    if (!emitTracelogStartEvent(TraceLogger::VM))
         return false;
 #endif
 
     // Stack is:
     //    ... frame ...
     //    [args]
 #ifdef DEBUG
     MOZ_ASSERT(pushedArgs_ == fun.explicitArgs);
@@ -1051,17 +1051,17 @@ CodeGeneratorShared::callVM(const VMFunc
     int framePop = sizeof(IonExitFrameLayout) - sizeof(void*);
 
     // Pop arguments from framePushed.
     masm.implicitPop(fun.explicitStackSlots() * sizeof(void *) + framePop);
     // Stack is:
     //    ... frame ...
 
 #ifdef JS_TRACE_LOGGING
-    if (!emitTracelogStopEvent(TraceLogger_VM))
+    if (!emitTracelogStopEvent(TraceLogger::VM))
         return false;
 #endif
 
     return true;
 }
 
 class OutOfLineTruncateSlow : public OutOfLineCodeBase<CodeGeneratorShared>
 {
@@ -1397,44 +1397,41 @@ CodeGeneratorShared::computeDivisionCons
 }
 
 
 #ifdef JS_TRACE_LOGGING
 
 bool
 CodeGeneratorShared::emitTracelogScript(bool isStart)
 {
-    if (!TraceLogTextIdEnabled(TraceLogger_Scripts))
-        return true;
-
     Label done;
 
     RegisterSet regs = RegisterSet::Volatile();
     Register logger = regs.takeGeneral();
     Register script = regs.takeGeneral();
 
     masm.Push(logger);
 
     CodeOffsetLabel patchLogger = masm.movWithPatch(ImmPtr(nullptr), logger);
     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);
 
     CodeOffsetLabel patchScript = masm.movWithPatch(ImmWord(0), script);
     if (!patchableTLScripts_.append(patchScript))
         return false;
 
     if (isStart)
-        masm.tracelogStartId(logger, script);
+        masm.tracelogStart(logger, script);
     else
-        masm.tracelogStopId(logger, script);
+        masm.tracelogStop(logger, script);
 
     masm.Pop(script);
 
     masm.bind(&done);
 
     masm.Pop(logger);
     return true;
 }
@@ -1450,23 +1447,28 @@ CodeGeneratorShared::emitTracelogTree(bo
     Register logger = regs.takeGeneral();
 
     masm.Push(logger);
 
     CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger);
     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);
 
     masm.Pop(logger);
     return true;
 }
 #endif
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -53,17 +53,17 @@ bool
 CodeGeneratorX86Shared::generateEpilogue()
 {
     MOZ_ASSERT(!gen->compilingAsmJS());
 
     masm.bind(&returnLabel_);
 
 #ifdef JS_TRACE_LOGGING
     if (gen->info().executionMode() == SequentialExecution) {
-        if (!emitTracelogStopEvent(TraceLogger_IonMonkey))
+        if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
             return false;
         if (!emitTracelogScriptStop())
             return false;
     }
 #endif
 
     // Pop the stack we allocated at the start of the function.
     masm.freeStack(frameSize());
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3600,26 +3600,26 @@ GCHelperState::work()
 {
     MOZ_ASSERT(CanUseExtraThreads());
 
     AutoLockGC lock(rt);
 
     MOZ_ASSERT(!thread);
     thread = PR_GetCurrentThread();
 
-    TraceLoggerThread *logger = TraceLoggerForCurrentThread();
+    TraceLogger *logger = TraceLoggerForCurrentThread();
 
     switch (state()) {
 
       case IDLE:
         MOZ_CRASH("GC helper triggered on idle state");
         break;
 
       case SWEEPING: {
-        AutoTraceLog logSweeping(logger, TraceLogger_GCSweeping);
+        AutoTraceLog logSweeping(logger, TraceLogger::GCSweeping);
         doSweep(lock);
         MOZ_ASSERT(state() == SWEEPING);
         break;
       }
 
     }
 
     setState(IDLE);
@@ -3633,18 +3633,18 @@ BackgroundAllocTask::BackgroundAllocTask
     chunkPool_(pool),
     enabled_(CanUseExtraThreads() && GetCPUCount() >= 2)
 {
 }
 
 /* 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)) {
         Chunk *chunk;
         {
             AutoUnlockGC unlock(lock);
             chunk = Chunk::allocate(runtime);
             if (!chunk)
@@ -6244,18 +6244,18 @@ GCRuntime::collect(bool incremental, Sli
     MOZ_ALWAYS_TRUE(!rt->isHeapBusy());
 
     /* The engine never locks across anything that could GC. */
     MOZ_ASSERT(!rt->currentThreadHasExclusiveAccess());
 
     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))
         return;
 #endif
 
     MOZ_ASSERT_IF(!incremental || !budget.isUnlimited(), JSGC_INCREMENTAL);
 
@@ -6451,32 +6451,32 @@ GCRuntime::onOutOfMallocMemory(const Aut
     decommitAllWithoutUnlocking(lock);
 }
 
 void
 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
 }
 
 void
 GCRuntime::minorGC(JSContext *cx, JS::gcreason::Reason reason)
 {
     // Alternate to the runtime-taking form above which allows marking type
     // 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++) {
         if (pretenureTypes[i]->canPreTenure())
             pretenureTypes[i]->setShouldPreTenure(cx);
     }
     MOZ_ASSERT_IF(!rt->mainThread.suppressGC, nursery.isEmpty());
 #endif
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -5122,20 +5122,16 @@ js::PutEscapedStringImpl(char *buffer, s
     return n;
 }
 
 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);
 
 template size_t
 js::PutEscapedString(char *buffer, size_t bufferSize, const Latin1Char *chars, size_t length,
                      uint32_t quote);
 
 template size_t
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -395,22 +395,16 @@ PutEscapedString(char *buffer, size_t bu
  * will quote the output.
 */
 inline bool
 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);
 
 bool
 str_search(JSContext *cx, unsigned argc, Value *vp);
 
 bool
 str_split(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -307,18 +307,16 @@ if CONFIG['JS_POSIX_NSPR']:
 if CONFIG['MOZ_INSTRUMENTS']:
     SOURCES += [
         'devtools/Instruments.cpp',
     ]
 
 if CONFIG['ENABLE_TRACE_LOGGING']:
     SOURCES += [
         'vm/TraceLogging.cpp',
-        'vm/TraceLoggingGraph.cpp',
-        'vm/TraceLoggingTypes.cpp',
     ]
 
 if not CONFIG['ENABLE_ION']:
     UNIFIED_SOURCES += [
         'jit/none/Trampoline-none.cpp'
     ]
 elif CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
     UNIFIED_SOURCES += [
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -21,17 +21,16 @@
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineJIT.h"
 #include "js/GCAPI.h"
 #include "js/UbiNodeTraverse.h"
 #include "js/Vector.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/DebuggerMemory.h"
 #include "vm/SPSProfiler.h"
-#include "vm/TraceLogging.h"
 #include "vm/WrapperObject.h"
 
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
 #include "jsscriptinlines.h"
 
@@ -40,16 +39,17 @@
 
 using namespace js;
 
 using JS::dbg::Builder;
 using js::frontend::IsIdentifier;
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
+
 /*** Forward declarations ************************************************************************/
 
 extern const Class DebuggerFrame_class;
 
 enum {
     JSSLOT_DEBUGFRAME_OWNER,
     JSSLOT_DEBUGFRAME_ARGUMENTS,
     JSSLOT_DEBUGFRAME_ONSTEP_HANDLER,
@@ -354,23 +354,17 @@ Debugger::Debugger(JSContext *cx, Native
     trackingAllocationSites(false),
     allocationSamplingProbability(1.0),
     allocationsLogLength(0),
     maxAllocationsLogLength(DEFAULT_MAX_ALLOCATIONS_LOG_LENGTH),
     frames(cx->runtime()),
     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);
 
     cx->runtime()->debuggerList.insertBack(this);
     JS_INIT_CLIST(&breakpoints);
     JS_INIT_CLIST(&onNewGlobalObjectWatchersLink);
 }
 
@@ -3771,263 +3765,16 @@ Debugger::makeGlobalObjectReference(JSCo
     Rooted<GlobalObject *> global(cx, dbg->unwrapDebuggeeArgument(cx, args[0]));
     if (!global)
         return false;
 
     args.rval().setObject(*global);
     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,
             Debugger::setOnDebuggerStatement, 0),
     JS_PSGS("onExceptionUnwind", Debugger::getOnExceptionUnwind,
             Debugger::setOnExceptionUnwind, 0),
     JS_PSGS("onNewScript", Debugger::getOnNewScript, Debugger::setOnNewScript, 0),
     JS_PSGS("onNewPromise", Debugger::getOnNewPromise, Debugger::setOnNewPromise, 0),
@@ -4047,26 +3794,16 @@ const JSFunctionSpec Debugger::methods[]
     JS_FN("hasDebuggee", Debugger::hasDebuggee, 1, 0),
     JS_FN("getDebuggees", Debugger::getDebuggees, 0, 0),
     JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
     JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 0, 0),
     JS_FN("findScripts", Debugger::findScripts, 1, 0),
     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
 };
 
 
 /*** Debugger.Script *****************************************************************************/
 
 static inline JSScript *
 GetScriptReferent(JSObject *obj)
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -291,27 +291,16 @@ class Debugger : private mozilla::Linked
 
     /* The map from debuggee objects to their Debugger.Object instances. */
     typedef DebuggerWeakMap<PreBarrieredObject, RelocatablePtrObject> ObjectWeakMap;
     ObjectWeakMap objects;
 
     /* 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;
 
     bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj);
     void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global, GlobalObjectSet::Enum *debugEnum);
 
     /*
@@ -400,24 +389,16 @@ class Debugger : private mozilla::Linked
     static bool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static bool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
     static bool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
     static bool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
     static bool findScripts(JSContext *cx, unsigned argc, Value *vp);
     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[];
 
     static bool getNewestAbstractFramePtr(JSContext *cx);
     static bool updateExecutionObservabilityOfFrames(JSContext *cx, const ExecutionObservableSet &obs,
                                                      IsObserving observing);
     static bool updateExecutionObservabilityOfScripts(JSContext *cx, const ExecutionObservableSet &obs,
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -1042,20 +1042,19 @@ HelperThread::handleIonWorkload()
     if (HelperThread *other = HelperThreadState().lowestPriorityUnpausedIonCompileAtThreshold()) {
         MOZ_ASSERT(other->ionBuilder && !other->pause);
         other->pause = true;
     }
 
     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();
 
     {
         AutoUnlockHelperThreadState unlock;
         PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
                                               ionBuilder->script()->runtimeFromAnyThread());
         jit::IonContext ictx(jit::CompileRuntime::get(rt),
@@ -1113,18 +1112,18 @@ CurrentHelperThread()
     }
     MOZ_ASSERT(thread);
     return thread;
 }
 
 void
 js::PauseCurrentHelperThread()
 {
-    TraceLoggerThread *logger = TraceLoggerForCurrentThread();
-    AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
+    TraceLogger *logger = TraceLoggerForCurrentThread();
+    AutoTraceLog logPaused(logger, TraceLogger::IonCompilationPaused);
 
     HelperThread *thread = CurrentHelperThread();
 
     AutoLockHelperThreadState lock;
     while (thread->pause)
         HelperThreadState().wait(GlobalHelperThreadState::PAUSE);
 }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1457,20 +1457,20 @@ Interpret(JSContext *cx, RunState &state
         return false;
 
     InterpreterActivation activation(state, cx, entryFrame);
 
     /* The script is used frequently, so keep a local copy. */
     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
      * are used for local variables within interpreter cases. This avoids
      * creating new rooters each time an interpreter case is entered, and also
      * correctness pitfalls due to incorrect compilation of destructor calls
      * around computed gotos.
      */
@@ -1758,18 +1758,19 @@ CASE(JSOP_RETRVAL)
     CHECK_BRANCH();
 
   successful_return_continuation:
     interpReturnOK = true;
   return_continuation:
     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);
 
         REGS.fp()->epilogue(cx);
 
   jit_return_pop_frame:
 
         activation.popInlineFrame(REGS.fp());
@@ -2572,21 +2573,19 @@ CASE(JSOP_FUNCALL)
     if (!activation.pushInlineFrame(args, funScript, initial))
         goto error;
 
     if (newType)
         REGS.fp()->setUseNewType();
 
     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;
 
     switch (Debugger::onEnterFrame(cx, REGS.fp())) {
       case JSTRAP_CONTINUE:
         break;
       case JSTRAP_RETURN:
@@ -3488,18 +3487,18 @@ DEFAULT()
 
   exit:
     interpReturnOK = Debugger::onLeaveFrame(cx, REGS.fp(), interpReturnOK);
 
     REGS.fp()->epilogue(cx);
 
     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
      * inside the JIT.
      */
   leave_on_safe_point:
 
     if (interpReturnOK)
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -453,18 +453,18 @@ RegExpShared::trace(JSTracer *trc)
             MarkJitCode(trc, &compilation.jitCode, "RegExpShared code");
     }
 }
 
 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);
         return compile(cx, pattern, input, mode, force);
     }
 
     /*
      * The sticky case we implement hackily by prepending a caret onto the front
@@ -543,17 +543,17 @@ RegExpShared::compileIfNecessary(JSConte
         return true;
     return compile(cx, input, mode, force);
 }
 
 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;
 
     /* Compile the code at point-of-use. */
     if (!compileIfNecessary(cx, input, mode, DontForceByteCode))
         return RegExpRunStatus_Error;
 
     /*
@@ -599,17 +599,17 @@ RegExpShared::execute(JSContext *cx, Han
 
     do {
         jit::JitCode *code = compilation(mode, input->hasLatin1Chars()).jitCode;
         if (!code)
             break;
 
         RegExpRunStatus result;
         {
-            AutoTraceLog logJIT(logger, TraceLogger_IrregexpExecute);
+            AutoTraceLog logJIT(logger, TraceLogger::IrregexpExecute);
             AutoCheckCannotGC nogc;
             if (input->hasLatin1Chars()) {
                 const Latin1Char *chars = input->latin1Chars(nogc) + charsOffset;
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             } else {
                 const char16_t *chars = input->twoByteChars(nogc) + charsOffset;
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             }
@@ -638,17 +638,17 @@ RegExpShared::execute(JSContext *cx, Han
         return RegExpRunStatus_Success;
     } while (false);
 
     // Compile bytecode for the RegExp if necessary.
     if (!compileIfNecessary(cx, input, mode, ForceByteCode))
         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))
         return RegExpRunStatus_Error;
 
     RegExpRunStatus result;
     if (inputChars.isLatin1()) {
         const Latin1Char *chars = inputChars.latin1Range().start().get() + charsOffset;
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -49,17 +49,17 @@
 #endif
 
 namespace js {
 
 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. */
 extern mozilla::ThreadLocal<PerThreadData*> TlsPerThreadData;
 
 } // namespace js
 
 struct DtoaState;
@@ -532,17 +532,17 @@ class PerThreadData : public PerThreadDa
     // For read-only JIT use:
     void *addressOfJitStackLimit() { return &jitStackLimit_; }
     static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); }
 
     // Information about the heap allocated backtrack stack used by RegExp JIT code.
     irregexp::RegExpStack regexpStack;
 
 #ifdef JS_TRACE_LOGGING
-    TraceLoggerThread   *traceLogger;
+    TraceLogger         *traceLogger;
 #endif
 
   private:
     friend class js::Activation;
     friend class js::ActivationIterator;
     friend class js::jit::JitActivation;
     friend class js::AsmJSActivation;
 #ifdef DEBUG
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -2,37 +2,39 @@
  * 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/TraceLogging.h"
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/Endian.h"
 
 #include <string.h>
 
 #include "jsapi.h"
-#include "jsprf.h"
 #include "jsscript.h"
 
-#include "jit/BaselineJIT.h"
 #include "jit/CompileWrappers.h"
 #include "vm/Runtime.h"
-#include "vm/TraceLoggingGraph.h"
 
 #include "jit/IonFrames-inl.h"
 
 using namespace js;
 using namespace js::jit;
-
-using mozilla::DebugOnly;
 using mozilla::NativeEndian;
 
-TraceLoggerThreadState traceLoggers;
+#ifndef TRACE_LOG_DIR
+# if defined(_WIN32)
+#  define TRACE_LOG_DIR ""
+# else
+#  define TRACE_LOG_DIR "/tmp/"
+# endif
+#endif
 
 #if defined(_WIN32)
 #include <intrin.h>
 static __inline uint64_t
 rdtsc(void)
 {
     return __rdtsc();
 }
@@ -68,506 +70,674 @@ rdtsc(void)
             : "=r"(upper),"=r"(lower),"=r"(tmp)
             );
     result = upper;
     result = result<<32;
     result = result|lower;
 
     return result;
 }
-#else
-static __inline__ uint64_t
-rdtsc(void)
-{
-    return 0;
-}
 #endif
 
-class AutoTraceLoggerThreadStateLock
-{
-  TraceLoggerThreadState *logging;
+TraceLogging traceLoggers;
 
-  public:
-    AutoTraceLoggerThreadStateLock(TraceLoggerThreadState *logging MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : logging(logging)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        PR_Lock(logging->lock);
-    }
-    ~AutoTraceLoggerThreadStateLock() {
-        PR_Unlock(logging->lock);
-    }
-  private:
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+static const char* const text[] =
+{
+    "TraceLogger failed to process text",
+#define NAME(x) #x,
+    TRACELOGGER_TEXT_ID_LIST(NAME)
+#undef NAME
 };
 
-TraceLoggerThread::TraceLoggerThread()
-  : enabled(0),
-    failed(false),
-    graph(),
-    iteration_(0),
-    top(nullptr)
+TraceLogger::TraceLogger()
+ : enabled(0),
+   failed(false),
+   nextTextId(0),
+   treeOffset(0),
+   top(nullptr)
 { }
 
 bool
-TraceLoggerThread::init()
+TraceLogger::init(uint32_t loggerId)
 {
     if (!pointerMap.init())
         return false;
-    if (!extraTextId.init())
+    if (!tree.init())
+        return false;
+    if (!stack.init())
         return false;
     if (!events.init())
         return false;
 
-    // Minimum amount of capacity needed for operation to allow flushing.
-    // Flushing requires space for the actual event and two spaces to log the
-    // start and stop of flushing.
-    if (!events.ensureSpaceBeforeAdd(3))
+    MOZ_ASSERT(loggerId <= 999);
+
+    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)
         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;
+        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;
+        return false;
+    }
+
+    uint64_t start = rdtsc() - traceLoggers.startupTime;
+
+    TreeEntry &treeEntry = tree.pushUninitialized();
+    treeEntry.setStart(start);
+    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");
+
+    // Eagerly create the default textIds, to match their Tracelogger::TextId.
+    for (uint32_t i = 0; i < LAST; i++) {
+        mozilla::DebugOnly<uint32_t> textId = createTextId(text[i]);
+        MOZ_ASSERT(textId == i);
+    }
+
     enabled = 1;
-    logTimestamp(TraceLogger_Enable);
-
     return true;
 }
 
-void
-TraceLoggerThread::initGraph()
-{
-    // Create a graph. I don't like this is called reset, but it locks the
-    // graph into the UniquePtr. So it gets deleted when TraceLoggerThread
-    // is destructed.
-    graph.reset(js_new<TraceLoggerGraph>());
-    if (!graph.get())
-        return;
-
-    uint64_t start = rdtsc() - traceLoggers.startupTime;
-    if (!graph->init(start)) {
-        graph = nullptr;
-        return;
-    }
-
-    // Report the textIds to the graph.
-    for (uint32_t i = 0; i < TraceLogger_LastTreeItem; i++) {
-        TraceLoggerTextId id = TraceLoggerTextId(i);
-        graph->addTextId(i, TLTextIdString(id));
-    }
-    graph->addTextId(TraceLogger_LastTreeItem, "TraceLogger internal");
-    for (uint32_t i = TraceLogger_LastTreeItem + 1; i < TraceLogger_Last; i++) {
-        TraceLoggerTextId id = TraceLoggerTextId(i);
-        graph->addTextId(i, TLTextIdString(id));
-    }
-}
-
-TraceLoggerThread::~TraceLoggerThread()
-{
-    if (graph.get()) {
-        if (!failed)
-            graph->log(events);
-        graph = nullptr;
-    }
-
-    for (TextIdHashMap::Range r = extraTextId.all(); !r.empty(); r.popFront())
-        js_delete(r.front().value());
-    extraTextId.finish();
-    pointerMap.finish();
-}
-
 bool
-TraceLoggerThread::enable()
+TraceLogger::enable()
 {
     if (enabled > 0) {
         enabled++;
         return true;
     }
 
     if (failed)
         return false;
 
     enabled = 1;
-    logTimestamp(TraceLogger_Enable);
-
     return true;
 }
 
 bool
-TraceLoggerThread::enable(JSContext *cx)
+TraceLogger::enable(JSContext *cx)
 {
     if (!enable())
         return false;
 
     if (enabled == 1) {
         // Get the top Activation to log the top script/pc (No inlined frames).
-        ActivationIterator iter(cx->runtime());
-        Activation *act = iter.activation();
+        Activation *act = cx->mainThread().activation();
+        while (act && (act->cx() != cx || (act->isJit() && !act->asJit()->isActive())))
+            act = act->prev();
 
         if (!act) {
             failed = true;
             enabled = 0;
             return false;
         }
 
         JSScript *script = nullptr;
         int32_t engine = 0;
 
         if (act->isJit()) {
-            JitFrameIterator it(iter);
+            JSRuntime *rt = cx->runtime();
+
+            JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution);
 
-            while (!it.isScripted() && !it.done())
+            MOZ_ASSERT(it.type() == JitFrame_Exit);
+            ++it;
+
+            if (it.type() == JitFrame_Rectifier ||
+                it.type() == JitFrame_Unwound_Rectifier)
+            {
                 ++it;
-
-            MOZ_ASSERT(!it.done());
-            MOZ_ASSERT(it.isIonJS() || it.isBaselineJS());
+                MOZ_ASSERT(it.type() == JitFrame_BaselineStub ||
+                           it.type() == JitFrame_BaselineJS ||
+                           it.type() == JitFrame_IonJS);
+            }
+            if (it.type() == JitFrame_BaselineStub ||
+                it.type() == JitFrame_Unwound_BaselineStub)
+            {
+                ++it;
+                MOZ_ASSERT(it.type() == JitFrame_BaselineJS);
+            }
 
             script = it.script();
-            engine = it.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
+            engine = it.isIonJS() ? IonMonkey : Baseline;
         } else {
             MOZ_ASSERT(act->isInterpreter());
             InterpreterFrame *fp = act->asInterpreter()->current();
             MOZ_ASSERT(!fp->runningInJit());
 
             script = fp->script();
-            engine = TraceLogger_Interpreter;
+            engine = Interpreter;
             if (script->compartment() != cx->compartment()) {
                 failed = true;
                 enabled = 0;
                 return false;
             }
         }
 
-        TraceLoggerEvent event(this, TraceLogger_Scripts, script);
-        startEvent(event);
+        startEvent(createTextId(script));
         startEvent(engine);
     }
 
     return true;
 }
 
 bool
-TraceLoggerThread::disable()
+TraceLogger::disable()
 {
     if (failed)
         return false;
 
     if (enabled == 0)
         return true;
 
     if (enabled > 1) {
         enabled--;
         return true;
     }
 
-    logTimestamp(TraceLogger_Disable);
+    MOZ_ASSERT(enabled == 1);
+    while (stack.size() > 1)
+        stopEvent();
+
     enabled = 0;
 
     return true;
 }
 
-const char *
-TraceLoggerThread::eventText(uint32_t id)
+bool
+TraceLogger::flush()
 {
-    if (id < TraceLogger_Last)
-        return TLTextIdString(static_cast<TraceLoggerTextId>(id));
+    MOZ_ASSERT(!failed);
+
+    if (treeFile) {
+        // Format data in big endian.
+        for (size_t i = 0; i < tree.size(); i++)
+            entryToBigEndian(&tree[i]);
 
-    TextIdHashMap::Ptr p = extraTextId.lookup(id);
-    MOZ_ASSERT(p);
+        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;
 
-    return p->value()->string();
-}
+        treeOffset += tree.lastEntryId();
+        tree.clear();
+    }
 
-bool
-TraceLoggerThread::textIdIsScriptEvent(uint32_t id)
-{
-    if (id < TraceLogger_Last)
-        return false;
+    if (eventFile) {
+        // Format data in big endian
+        for (size_t i = 0; i < events.size(); i++) {
+            events[i].time = NativeEndian::swapToBigEndian(events[i].time);
+            events[i].textId = NativeEndian::swapToBigEndian(events[i].textId);
+        }
 
-    // Currently this works by checking if text begins with "script".
-    const char *str = eventText(id);
-    return EqualChars(str, "script", 6);
+        size_t bytesWritten = fwrite(events.data(), sizeof(EventEntry), events.size(), eventFile);
+        if (bytesWritten < events.size())
+            return false;
+        events.clear();
+    }
+
+    return true;
 }
 
-void
-TraceLoggerThread::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)
+TraceLogger::~TraceLogger()
 {
-    MOZ_ASSERT(textIdIsScriptEvent(textId));
-
-    const char *script = eventText(textId);
+    // Write dictionary to disk
+    if (dictFile) {
+        int written = fprintf(dictFile, "]");
+        if (written < 0)
+            fprintf(stderr, "TraceLogging: Error while writing.\n");
+        fclose(dictFile);
 
-    // Get the start of filename (remove 'script ' at the start).
-    MOZ_ASSERT(EqualChars(script, "script ", 7));
-    *filename = script + 7;
+        dictFile = nullptr;
+    }
 
-    // Get the start of lineno and colno.
-    *lineno = script;
-    *colno = script;
-    const char *next = script - 1;
-    while ((next = strchr(next + 1, ':'))) {
-        *lineno = *colno;
-        *colno = next;
+    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();
+        enabled = 0;
     }
 
-    MOZ_ASSERT(*lineno && *lineno != script);
-    MOZ_ASSERT(*colno && *colno != script);
+    if (!failed && !flush()) {
+        fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
+        enabled = 0;
+        failed = true;
+    }
 
-    // Remove the ':' at the front.
-    *lineno = *lineno + 1;
-    *colno = *colno + 1;
+    if (treeFile) {
+        fclose(treeFile);
+        treeFile = nullptr;
+    }
 
-    *filename_len = *lineno - *filename - 1;
-    *lineno_len = *colno - *lineno - 1;
-    *colno_len = strlen(*colno);
+    if (eventFile) {
+        fclose(eventFile);
+        eventFile = nullptr;
+    }
 }
 
-TraceLoggerEventPayload *
-TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId textId)
+uint32_t
+TraceLogger::createTextId(const char *text)
 {
-    TextIdHashMap::AddPtr p = extraTextId.lookupForAdd(textId);
-    if (p)
-        return p->value();
-
-    TraceLoggerEventPayload *payload = js_new<TraceLoggerEventPayload>(textId, (char *)nullptr);
+    assertNoQuotes(text);
 
-    if (!extraTextId.add(p, textId, payload))
-        return nullptr;
-
-    return payload;
-}
-
-TraceLoggerEventPayload *
-TraceLoggerThread::getOrCreateEventPayload(const char *text)
-{
     PointerHashMap::AddPtr p = pointerMap.lookupForAdd((const void *)text);
     if (p)
         return p->value();
 
-    size_t len = strlen(text);
-    char *str = js_pod_malloc<char>(len + 1);
-    if (!str)
-        return nullptr;
-
-    DebugOnly<size_t> ret = JS_snprintf(str, len + 1, "%s", text);
-    MOZ_ASSERT(ret == len);
-
-    uint32_t textId = extraTextId.count() + TraceLogger_Last;
+    uint32_t textId = nextTextId++;
+    if (!pointerMap.add(p, text, textId))
+        return TraceLogger::TL_Error;
 
-    TraceLoggerEventPayload *payload = js_new<TraceLoggerEventPayload>(textId, str);
-    if (!payload) {
-        js_free(str);
-        return nullptr;
-    }
+    int written;
+    if (textId > 0)
+        written = fprintf(dictFile, ",\n\"%s\"", text);
+    else
+        written = fprintf(dictFile, "\"%s\"", text);
 
-    if (!extraTextId.putNew(textId, payload)) {
-        js_delete(payload);
-        return nullptr;
-    }
+    if (written < 0)
+        return TraceLogger::TL_Error;
 
-    if (!pointerMap.add(p, text, payload))
-        return nullptr;
-
-    if (graph.get())
-        graph->addTextId(textId, str);
-
-    return payload;
+    return textId;
 }
 
-TraceLoggerEventPayload *
-TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, const char *filename,
-                                           size_t lineno, size_t colno, const void *ptr)
+uint32_t
+TraceLogger::createTextId(JSScript *script)
 {
-    MOZ_ASSERT(type == TraceLogger_Scripts || type == TraceLogger_AnnotateScripts ||
-               type == TraceLogger_InlinedScripts);
+    if (!script->filename())
+        return createTextId("");
 
-    if (!filename)
-        filename = "<unknown>";
+    assertNoQuotes(script->filename());
 
-    // Only log scripts when enabled otherwise return the global Scripts textId,
-    // which will get filtered out.
-    if (!traceLoggers.isTextIdEnabled(type))
-        return getOrCreateEventPayload(type);
-
-    PointerHashMap::AddPtr p = pointerMap.lookupForAdd(ptr);
+    PointerHashMap::AddPtr p = pointerMap.lookupForAdd(script);
     if (p)
         return p->value();
 
-    // Compute the length of the string to create.
-    size_t lenFilename = strlen(filename);
-    size_t lenLineno = 1;
-    for (size_t i = lineno; i /= 10; lenLineno++);
-    size_t lenColno = 1;
-    for (size_t i = colno; i /= 10; lenColno++);
+    uint32_t textId = nextTextId++;
+    if (!pointerMap.add(p, script, textId))
+        return TraceLogger::TL_Error;
 
-    size_t len = 7 + lenFilename + 1 + lenLineno + 1 + lenColno;
-    char *str = js_pod_malloc<char>(len + 1);
-    if (!str)
-        return nullptr;
-
-    DebugOnly<size_t> ret =
-        JS_snprintf(str, len + 1, "script %s:%u:%u", filename, lineno, colno);
-    MOZ_ASSERT(ret == len);
-
-    uint32_t textId = extraTextId.count() + TraceLogger_Last;
-    TraceLoggerEventPayload *payload = js_new<TraceLoggerEventPayload>(textId, str);
-    if (!payload) {
-        js_free(str);
-        return nullptr;
+    int written;
+    if (textId > 0) {
+        written = fprintf(dictFile, ",\n\"script %s:%u:%u\"", script->filename(),
+                          (unsigned)script->lineno(), (unsigned)script->column());
+    } else {
+        written = fprintf(dictFile, "\"script %s:%u:%u\"", script->filename(),
+                          (unsigned)script->lineno(), (unsigned)script->column());
     }
 
-    if (!extraTextId.putNew(textId, payload)) {
-        js_delete(payload);
-        return nullptr;
+    if (written < 0)
+        return TraceLogger::TL_Error;
+
+    return textId;
+}
+
+uint32_t
+TraceLogger::createTextId(const JS::ReadOnlyCompileOptions &compileOptions)
+{
+    if (!compileOptions.filename())
+        return createTextId("");
+
+    assertNoQuotes(compileOptions.filename());
+
+    PointerHashMap::AddPtr p = pointerMap.lookupForAdd(&compileOptions);
+    if (p)
+        return p->value();
+
+    uint32_t textId = nextTextId++;
+    if (!pointerMap.add(p, &compileOptions, textId))
+        return TraceLogger::TL_Error;
+
+    int written;
+    if (textId > 0) {
+        written = fprintf(dictFile, ",\n\"script %s:%d:%d\"", compileOptions.filename(),
+                          compileOptions.lineno, compileOptions.column);
+    } else {
+        written = fprintf(dictFile, "\"script %s:%d:%d\"", compileOptions.filename(),
+                          compileOptions.lineno, compileOptions.column);
     }
 
-    if (!pointerMap.add(p, ptr, payload))
-        return nullptr;
-
-    if (graph.get())
-        graph->addTextId(textId, str);
-
-    return payload;
-}
+    if (written < 0)
+        return TraceLogger::TL_Error;
 
-TraceLoggerEventPayload *
-TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type, JSScript *script)
-{
-    return getOrCreateEventPayload(type, script->filename(), script->lineno(), script->column(),
-                                   script);
-}
-
-TraceLoggerEventPayload *
-TraceLoggerThread::getOrCreateEventPayload(TraceLoggerTextId type,
-                                           const JS::ReadOnlyCompileOptions &script)
-{
-    return getOrCreateEventPayload(type, script.filename(), script.lineno, script.column, &script);
+    return textId;
 }
 
 void
-TraceLoggerThread::startEvent(TraceLoggerTextId id) {
-    startEvent(uint32_t(id));
-}
-
-void
-TraceLoggerThread::startEvent(const TraceLoggerEvent &event) {
-    if (!event.hasPayload()) {
-        startEvent(TraceLogger_Error);
-        return;
-    }
-    startEvent(event.payload()->textId());
-}
-
-void
-TraceLoggerThread::startEvent(uint32_t id)
-{
-    MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
-    if (!traceLoggers.isTextIdEnabled(id))
-       return;
-
-    logTimestamp(id);
-}
-
-void
-TraceLoggerThread::stopEvent(TraceLoggerTextId id) {
-    stopEvent(uint32_t(id));
-}
-
-void
-TraceLoggerThread::stopEvent(const TraceLoggerEvent &event) {
-    if (!event.hasPayload()) {
-        stopEvent(TraceLogger_Error);
-        return;
-    }
-    stopEvent(event.payload()->textId());
-}
-
-void
-TraceLoggerThread::stopEvent(uint32_t id)
-{
-    MOZ_ASSERT(TLTextIdIsTreeEvent(id) || id == TraceLogger_Error);
-    if (!traceLoggers.isTextIdEnabled(id))
-        return;
-
-    logTimestamp(TraceLogger_Stop);
-}
-
-void
-TraceLoggerThread::logTimestamp(TraceLoggerTextId id)
-{
-    logTimestamp(uint32_t(id));
-}
-
-void
-TraceLoggerThread::logTimestamp(uint32_t id)
+TraceLogger::logTimestamp(uint32_t id)
 {
     if (enabled == 0)
         return;
 
     if (!events.ensureSpaceBeforeAdd()) {
-        uint64_t start = 0;
-
-        if (graph.get()) {
-            start = rdtsc() - traceLoggers.startupTime;
-            graph->log(events);
-        }
-
-        iteration_++;
-        events.clear();
-
-        // Log the time it took to flush the events as being from the
-        // Tracelogger.
-        if (graph.get()) {
-            MOZ_ASSERT(events.capacity() > 2);
-            EventEntry &entryStart = events.pushUninitialized();
-            entryStart.time = start;
-            entryStart.textId = TraceLogger_Internal;
-
-            EventEntry &entryStop = events.pushUninitialized();
-            entryStop.time = rdtsc() - traceLoggers.startupTime;
-            entryStop.textId = TraceLogger_Stop;
-        }
-
-        // Free all TextEvents that have no uses anymore.
-        for (TextIdHashMap::Enum e(extraTextId); !e.empty(); e.popFront()) {
-            if (e.front().value()->uses() == 0) {
-                js_delete(e.front().value());
-                e.removeFront();
-            }
-        }
+        fprintf(stderr, "TraceLogging: Disabled a tracelogger due to OOM.\n");
+        enabled = 0;
+        return;
     }
 
-    uint64_t time = graph.get() ? rdtsc() - traceLoggers.startupTime : 0;
+    uint64_t time = rdtsc() - traceLoggers.startupTime;
 
     EventEntry &entry = events.pushUninitialized();
     entry.time = time;
     entry.textId = id;
 }
 
-TraceLoggerThreadState::TraceLoggerThreadState()
+void
+TraceLogger::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
+TraceLogger::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_);
+}
+
+bool
+TraceLogger::getTreeEntry(uint32_t treeId, TreeEntry *entry)
+{
+    // Entry is still in memory
+    if (treeId >= treeOffset) {
+        *entry = tree[treeId];
+        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
+TraceLogger::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
+TraceLogger::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
+TraceLogger::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
+TraceLogger::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
+TraceLogger::startEvent(uint32_t id)
+{
+    if (failed || enabled == 0)
+        return;
+
+    if (!tree.hasSpaceForAdd()){
+        uint64_t start = rdtsc() - traceLoggers.startupTime;
+        if (!tree.ensureSpaceBeforeAdd()) {
+            if (!flush()) {
+                fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
+                enabled = 0;
+                failed = true;
+                return;
+            }
+        }
+
+        // Log the time it took to flush the events as being from the
+        // Tracelogger.
+        if (!startEvent(TraceLogger::TL, start)) {
+            fprintf(stderr, "TraceLogging: Failed to start an event.\n");
+            enabled = 0;
+            failed = true;
+            return;
+        }
+        stopEvent();
+    }
+
+    uint64_t start = rdtsc() - traceLoggers.startupTime;
+    if (!startEvent(id, start)) {
+        fprintf(stderr, "TraceLogging: Failed to start an event.\n");
+        enabled = 0;
+        failed = true;
+        return;
+    }
+}
+
+TraceLogger::StackEntry &
+TraceLogger::getActiveAncestor()
+{
+    uint32_t parentId = stack.lastEntryId();
+    while (!stack[parentId].active())
+        parentId--;
+    return stack[parentId];
+}
+
+bool
+TraceLogger::startEvent(uint32_t id, uint64_t timestamp)
+{
+    if (!stack.ensureSpaceBeforeAdd())
+        return false;
+
+    // When a textId is disabled, a stack entry still needs to be pushed,
+    // together with an annotation that nothing needs to get done when receiving
+    // the stop event.
+    if (!traceLoggers.isTextIdEnabled(id)) {
+        StackEntry &stackEntry = stack.pushUninitialized();
+        stackEntry.setActive(false);
+        return true;
+    }
+
+    // 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
+TraceLogger::stopEvent(uint32_t id)
+{
+#ifdef DEBUG
+    if (stack.size() > 1) {
+        TreeEntry entry;
+        MOZ_ASSERT_IF(stack.lastEntry().active(), getTreeEntry(stack.lastEntry().treeId(), &entry));
+        MOZ_ASSERT_IF(stack.lastEntry().active(), entry.textId() == id);
+    }
+#endif
+    stopEvent();
+}
+
+void
+TraceLogger::stopEvent()
+{
+    if (enabled > 0 && stack.lastEntry().active()) {
+        uint64_t stop = rdtsc() - traceLoggers.startupTime;
+        if (!updateStop(stack.lastEntry().treeId(), stop)) {
+            fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
+            enabled = 0;
+            failed = true;
+            return;
+        }
+    }
+    if (stack.size() == 1) {
+        if (enabled == 0)
+            return;
+
+        // Forcefully disable logging. We have no stack information anymore.
+        enabled = 1;
+        disable();
+        return;
+    }
+    stack.pop();
+}
+
+TraceLogging::TraceLogging()
 {
     initialized = false;
     enabled = 0;
-    mainThreadEnabled = false;
-    offThreadEnabled = false;
-    graphSpewingEnabled = false;
+    mainThreadEnabled = true;
+    offThreadEnabled = true;
+    loggerId = 0;
 
     lock = PR_NewLock();
     if (!lock)
         MOZ_CRASH();
 }
 
-TraceLoggerThreadState::~TraceLoggerThreadState()
+TraceLogging::~TraceLogging()
 {
+    if (out) {
+        fprintf(out, "]");
+        fclose(out);
+        out = nullptr;
+    }
+
     for (size_t i = 0; i < mainThreadLoggers.length(); i++)
-        js_delete(mainThreadLoggers[i]);
+        delete mainThreadLoggers[i];
 
     mainThreadLoggers.clear();
 
     if (threadLoggers.initialized()) {
         for (ThreadLoggerHashMap::Range r = threadLoggers.all(); !r.empty(); r.popFront())
-            js_delete(r.front().value());
+            delete r.front().value();
 
         threadLoggers.finish();
     }
 
     if (lock) {
         PR_DestroyLock(lock);
         lock = nullptr;
     }
@@ -584,23 +754,28 @@ ContainsFlag(const char *str, const char
         if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ','))
             return true;
         index = strstr(index + flaglen, flag);
     }
     return false;
 }
 
 bool
-TraceLoggerThreadState::lazyInit()
+TraceLogging::lazyInit()
 {
     if (initialized)
         return enabled > 0;
 
     initialized = true;
 
+    out = fopen(TRACE_LOG_DIR "tl-data.json", "w");
+    if (!out)
+        return false;
+    fprintf(out, "[");
+
     if (!threadLoggers.init())
         return false;
 
     const char *env = getenv("TLLOG");
     if (!env)
         env = "";
 
     if (strstr(env, "help")) {
@@ -610,309 +785,211 @@ TraceLoggerThreadState::lazyInit()
             "usage: TLLOG=option,option,option,... where options can be:\n"
             "\n"
             "Collections:\n"
             "  Default        Output all default\n"
             "  IonCompiler    Output all information about compilation\n"
             "\n"
             "Specific log items:\n"
         );
-        for (uint32_t i = 1; i < TraceLogger_Last; i++) {
-            TraceLoggerTextId id = TraceLoggerTextId(i);
-            if (!TLTextIdIsToggable(id))
-                continue;
-            printf("  %s\n", TLTextIdString(id));
+        for (uint32_t i = 1; i < TraceLogger::LAST; i++) {
+            printf("  %s\n", text[i]);
         }
         printf("\n");
         exit(0);
         /*NOTREACHED*/
     }
 
-    for (uint32_t i = 1; i < TraceLogger_Last; i++) {
-        TraceLoggerTextId id = TraceLoggerTextId(i);
-        if (TLTextIdIsToggable(id))
-            enabledTextIds[i] = ContainsFlag(env, TLTextIdString(id));
-        else
-            enabledTextIds[i] = true;
+    for (uint32_t i = 1; i < TraceLogger::LAST; i++)
+        enabledTextIds[i] = ContainsFlag(env, text[i]);
+
+    enabledTextIds[TraceLogger::TL_Error] = true;
+    enabledTextIds[TraceLogger::TL] = true;
+
+    if (ContainsFlag(env, "Default") || strlen(env) == 0) {
+        enabledTextIds[TraceLogger::Bailout] = true;
+        enabledTextIds[TraceLogger::Baseline] = true;
+        enabledTextIds[TraceLogger::BaselineCompilation] = true;
+        enabledTextIds[TraceLogger::GC] = true;
+        enabledTextIds[TraceLogger::GCAllocation] = true;
+        enabledTextIds[TraceLogger::GCSweeping] = true;
+        enabledTextIds[TraceLogger::Interpreter] = true;
+        enabledTextIds[TraceLogger::IonCompilation] = true;
+        enabledTextIds[TraceLogger::IonLinking] = true;
+        enabledTextIds[TraceLogger::IonMonkey] = true;
+        enabledTextIds[TraceLogger::MinorGC] = true;
+        enabledTextIds[TraceLogger::ParserCompileFunction] = true;
+        enabledTextIds[TraceLogger::ParserCompileLazy] = true;
+        enabledTextIds[TraceLogger::ParserCompileScript] = true;
+        enabledTextIds[TraceLogger::IrregexpCompile] = true;
+        enabledTextIds[TraceLogger::IrregexpExecute] = true;
     }
 
-    if (ContainsFlag(env, "Default")) {
-        enabledTextIds[TraceLogger_AnnotateScripts] = true;
-        enabledTextIds[TraceLogger_Bailout] = true;
-        enabledTextIds[TraceLogger_Baseline] = true;
-        enabledTextIds[TraceLogger_BaselineCompilation] = true;
-        enabledTextIds[TraceLogger_GC] = true;
-        enabledTextIds[TraceLogger_GCAllocation] = true;
-        enabledTextIds[TraceLogger_GCSweeping] = true;
-        enabledTextIds[TraceLogger_Interpreter] = true;
-        enabledTextIds[TraceLogger_IonCompilation] = true;
-        enabledTextIds[TraceLogger_IonLinking] = true;
-        enabledTextIds[TraceLogger_IonMonkey] = true;
-        enabledTextIds[TraceLogger_MinorGC] = true;
-        enabledTextIds[TraceLogger_ParserCompileFunction] = true;
-        enabledTextIds[TraceLogger_ParserCompileLazy] = true;
-        enabledTextIds[TraceLogger_ParserCompileScript] = true;
-        enabledTextIds[TraceLogger_IrregexpCompile] = true;
-        enabledTextIds[TraceLogger_IrregexpExecute] = true;
-        enabledTextIds[TraceLogger_Scripts] = true;
-        enabledTextIds[TraceLogger_Engine] = true;
+    if (ContainsFlag(env, "IonCompiler") || strlen(env) == 0) {
+        enabledTextIds[TraceLogger::IonCompilation] = true;
+        enabledTextIds[TraceLogger::IonLinking] = true;
+        enabledTextIds[TraceLogger::FoldTests] = true;
+        enabledTextIds[TraceLogger::SplitCriticalEdges] = true;
+        enabledTextIds[TraceLogger::RenumberBlocks] = true;
+        enabledTextIds[TraceLogger::DominatorTree] = true;
+        enabledTextIds[TraceLogger::PhiAnalysis] = true;
+        enabledTextIds[TraceLogger::ApplyTypes] = true;
+        enabledTextIds[TraceLogger::ParallelSafetyAnalysis] = true;
+        enabledTextIds[TraceLogger::AliasAnalysis] = true;
+        enabledTextIds[TraceLogger::GVN] = true;
+        enabledTextIds[TraceLogger::LICM] = true;
+        enabledTextIds[TraceLogger::RangeAnalysis] = true;
+        enabledTextIds[TraceLogger::LoopUnrolling] = true;
+        enabledTextIds[TraceLogger::EffectiveAddressAnalysis] = true;
+        enabledTextIds[TraceLogger::EliminateDeadCode] = true;
+        enabledTextIds[TraceLogger::EdgeCaseAnalysis] = true;
+        enabledTextIds[TraceLogger::EliminateRedundantChecks] = true;
+        enabledTextIds[TraceLogger::GenerateLIR] = true;
+        enabledTextIds[TraceLogger::RegisterAllocation] = true;
+        enabledTextIds[TraceLogger::GenerateCode] = true;
     }
 
-    if (ContainsFlag(env, "IonCompiler")) {
-        enabledTextIds[TraceLogger_IonCompilation] = true;
-        enabledTextIds[TraceLogger_IonLinking] = true;
-        enabledTextIds[TraceLogger_FoldTests] = true;
-        enabledTextIds[TraceLogger_SplitCriticalEdges] = true;
-        enabledTextIds[TraceLogger_RenumberBlocks] = true;
-        enabledTextIds[TraceLogger_DominatorTree] = true;
-        enabledTextIds[TraceLogger_PhiAnalysis] = true;
-        enabledTextIds[TraceLogger_ApplyTypes] = true;
-        enabledTextIds[TraceLogger_ParallelSafetyAnalysis] = true;
-        enabledTextIds[TraceLogger_AliasAnalysis] = true;
-        enabledTextIds[TraceLogger_GVN] = true;
-        enabledTextIds[TraceLogger_LICM] = true;
-        enabledTextIds[TraceLogger_RangeAnalysis] = true;
-        enabledTextIds[TraceLogger_LoopUnrolling] = true;
-        enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true;
-        enabledTextIds[TraceLogger_EliminateDeadCode] = true;
-        enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true;
-        enabledTextIds[TraceLogger_EliminateRedundantChecks] = true;
-        enabledTextIds[TraceLogger_GenerateLIR] = true;
-        enabledTextIds[TraceLogger_RegisterAllocation] = true;
-        enabledTextIds[TraceLogger_GenerateCode] = true;
-        enabledTextIds[TraceLogger_Scripts] = true;
-    }
-
-    enabledTextIds[TraceLogger_Interpreter] = enabledTextIds[TraceLogger_Engine];
-    enabledTextIds[TraceLogger_Baseline] = enabledTextIds[TraceLogger_Engine];
-    enabledTextIds[TraceLogger_IonMonkey] = enabledTextIds[TraceLogger_Engine];
-
     const char *options = getenv("TLOPTIONS");
     if (options) {
         if (strstr(options, "help")) {
             fflush(nullptr);
             printf(
                 "\n"
                 "usage: TLOPTIONS=option,option,option,... where options can be:\n"
                 "\n"
-                "  EnableMainThread        Start logging the main thread immediately.\n"
-                "  EnableOffThread         Start logging helper threads immediately.\n"
-                "  EnableGraph             Enable spewing the tracelogging graph to a file.\n"
+                "  DisableMainThread        Don't start logging the mainThread automatically.\n"
+                "  DisableOffThread         Don't start logging the off mainThread automatically.\n"
             );
             printf("\n");
             exit(0);
             /*NOTREACHED*/
         }
 
-        if (strstr(options, "EnableMainThread"))
-           mainThreadEnabled = true;
-        if (strstr(options, "EnableOffThread"))
-           offThreadEnabled = true;
-        if (strstr(options, "EnableGraph"))
-           graphSpewingEnabled = true;
+        if (strstr(options, "DisableMainThread"))
+           mainThreadEnabled = false;
+        if (strstr(options, "DisableOffThread"))
+           offThreadEnabled = false;
     }
 
     startupTime = rdtsc();
     enabled = 1;
     return true;
 }
 
-void
-TraceLoggerThreadState::enableTextId(JSContext *cx, uint32_t textId)
-{
-    MOZ_ASSERT(TLTextIdIsToggable(textId));
-
-    if (enabledTextIds[textId])
-        return;
-
-    enabledTextIds[textId] = true;
-    if (textId == TraceLogger_Engine) {
-        enabledTextIds[TraceLogger_IonMonkey] = true;
-        enabledTextIds[TraceLogger_Baseline] = true;
-        enabledTextIds[TraceLogger_Interpreter] = true;
-    }
-
-    ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
-
-    if (textId == TraceLogger_Scripts)
-        jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), true);
-    if (textId == TraceLogger_Engine)
-        jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), true);
-
-}
-void
-TraceLoggerThreadState::disableTextId(JSContext *cx, uint32_t textId)
-{
-    MOZ_ASSERT(TLTextIdIsToggable(textId));
-
-    if (!enabledTextIds[textId])
-        return;
-
-    enabledTextIds[textId] = false;
-    if (textId == TraceLogger_Engine) {
-        enabledTextIds[TraceLogger_IonMonkey] = false;
-        enabledTextIds[TraceLogger_Baseline] = false;
-        enabledTextIds[TraceLogger_Interpreter] = false;
-    }
-
-    ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
-
-    if (textId == TraceLogger_Scripts)
-        jit::ToggleBaselineTraceLoggerScripts(cx->runtime(), false);
-    if (textId == TraceLogger_Engine)
-        jit::ToggleBaselineTraceLoggerEngine(cx->runtime(), false);
-}
-
-
-TraceLoggerThread *
+TraceLogger *
 js::TraceLoggerForMainThread(CompileRuntime *runtime)
 {
     return traceLoggers.forMainThread(runtime);
 }
 
-TraceLoggerThread *
-TraceLoggerThreadState::forMainThread(CompileRuntime *runtime)
+TraceLogger *
+TraceLogging::forMainThread(CompileRuntime *runtime)
 {
     return forMainThread(runtime->mainThread());
 }
 
-TraceLoggerThread *
+TraceLogger *
 js::TraceLoggerForMainThread(JSRuntime *runtime)
 {
     return traceLoggers.forMainThread(runtime);
 }
 
-TraceLoggerThread *
-TraceLoggerThreadState::forMainThread(JSRuntime *runtime)
+TraceLogger *
+TraceLogging::forMainThread(JSRuntime *runtime)
 {
     return forMainThread(&runtime->mainThread);
 }
 
-TraceLoggerThread *
-TraceLoggerThreadState::forMainThread(PerThreadData *mainThread)
+TraceLogger *
+TraceLogging::forMainThread(PerThreadData *mainThread)
 {
     if (!mainThread->traceLogger) {
-        AutoTraceLoggerThreadStateLock lock(this);
+        AutoTraceLoggingLock lock(this);
 
         if (!lazyInit())
             return nullptr;
 
-        TraceLoggerThread *logger = create();
-        if (!logger)
+        TraceLogger *logger = create();
+        mainThread->traceLogger = logger;
+
+        if (!mainThreadLoggers.append(logger))
             return nullptr;
 
-        if (!mainThreadLoggers.append(logger)) {
-            js_delete(logger);
-            return nullptr;
-        }
-
-        mainThread->traceLogger = logger;
         if (!mainThreadEnabled)
             logger->disable();
     }
 
     return mainThread->traceLogger;
 }
 
-TraceLoggerThread *
+TraceLogger *
 js::TraceLoggerForCurrentThread()
 {
     PRThread *thread = PR_GetCurrentThread();
     return traceLoggers.forThread(thread);
 }
 
-TraceLoggerThread *
-TraceLoggerThreadState::forThread(PRThread *thread)
+TraceLogger *
+TraceLogging::forThread(PRThread *thread)
 {
-    AutoTraceLoggerThreadStateLock lock(this);
+    AutoTraceLoggingLock lock(this);
 
     if (!lazyInit())
         return nullptr;
 
     ThreadLoggerHashMap::AddPtr p = threadLoggers.lookupForAdd(thread);
     if (p)
         return p->value();
 
-    TraceLoggerThread *logger = create();
+    TraceLogger *logger = create();
     if (!logger)
         return nullptr;
 
     if (!threadLoggers.add(p, thread, logger)) {
-        js_delete(logger);
+        delete logger;
         return nullptr;
     }
 
-    if (graphSpewingEnabled)
-        logger->initGraph();
-
     if (!offThreadEnabled)
         logger->disable();
 
     return logger;
 }
 
-TraceLoggerThread *
-TraceLoggerThreadState::create()
+TraceLogger *
+TraceLogging::create()
 {
-    TraceLoggerThread *logger = js_new<TraceLoggerThread>();
+    if (loggerId > 999) {
+        fprintf(stderr, "TraceLogging: Can't create more than 999 different loggers.");
+        return nullptr;
+    }
+
+    if (loggerId > 0) {
+        int written = fprintf(out, ",\n");
+        if (written < 0)
+            fprintf(stderr, "TraceLogging: Error while writing.\n");
+    }
+
+    loggerId++;
+
+    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\"}",
+                          loggerId, loggerId, loggerId);
+    if (written < 0)
+        fprintf(stderr, "TraceLogging: Error while writing.\n");
+
+
+    TraceLogger *logger = new TraceLogger();
     if (!logger)
         return nullptr;
 
-    if (!logger->init()) {
-        js_delete(logger);
+    if (!logger->init(loggerId)) {
+        delete logger;
         return nullptr;
     }
 
     return logger;
 }
 
 bool
 js::TraceLogTextIdEnabled(uint32_t textId)
 {
     return traceLoggers.isTextIdEnabled(textId);
 }
-
-void
-js::TraceLogEnableTextId(JSContext *cx, uint32_t textId)
-{
-    traceLoggers.enableTextId(cx, textId);
-}
-void
-js::TraceLogDisableTextId(JSContext *cx, uint32_t textId)
-{
-    traceLoggers.disableTextId(cx, textId);
-}
-
-TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId textId)
-{
-    payload_ = logger->getOrCreateEventPayload(textId);
-    if (payload_)
-        payload_->use();
-}
-
-TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId type,
-                                   JSScript *script)
-{
-    payload_ = logger->getOrCreateEventPayload(type, script);
-    if (payload_)
-        payload_->use();
-}
-
-TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread *logger, TraceLoggerTextId type,
-                                   const JS::ReadOnlyCompileOptions &compileOptions)
-{
-    payload_ = logger->getOrCreateEventPayload(type, compileOptions);
-    if (payload_)
-        payload_->use();
-}
-
-TraceLoggerEvent::TraceLoggerEvent(TraceLoggerThread *logger, const char *text)
-{
-    payload_ = logger->getOrCreateEventPayload(text);
-    if (payload_)
-        payload_->use();
-}
-
-TraceLoggerEvent::~TraceLoggerEvent()
-{
-    if (payload_)
-        payload_->release();
-}
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -3,26 +3,23 @@
  * 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 TraceLogging_h
 #define TraceLogging_h
 
 #include "mozilla/GuardObjects.h"
-#include "mozilla/UniquePtr.h"
 
 #include "jsalloc.h"
 #include "jslock.h"
 
 #include "js/HashTable.h"
 #include "js/TypeDecls.h"
 #include "js/Vector.h"
-#include "vm/TraceLoggingGraph.h"
-#include "vm/TraceLoggingTypes.h"
 
 struct JSRuntime;
 
 namespace JS {
     class ReadOnlyCompileOptions;
 }
 
 namespace js {
@@ -30,433 +27,602 @@ class PerThreadData;
 
 namespace jit {
     class CompileRuntime;
 }
 
 /*
  * 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 the duration:
+ *    - TraceLogStartEvent(logger, textId);
+ *    - TraceLogStopEvent(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 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
+    ContinuousSpace ()
+     : data_(nullptr)
+    { }
+
+    bool init() {
+        capacity_ = 64;
+        size_ = 0;
+        data_ = (T *) js_malloc(capacity_ * sizeof(T));
+        if (!data_)
+            return false;
+
+        return true;
+    }
+
+    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()];
+    }
 
-    TraceLoggerEventPayload *payload() const {
-        MOZ_ASSERT(hasPayload());
-        return payload_;
+    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;
     }
-    bool hasPayload() const {
-        return !!payload_;
+
+    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;
     }
 };
 
-/**
- * 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_;
-
+class TraceLogger
+{
   public:
-    TraceLoggerEventPayload(uint32_t textId, char *string)
-      : textId_(textId),
-        string_(string),
-        uses_(0)
-    { }
+    // 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
+    };
 
-    uint32_t textId() {
-        return textId_;
-    }
-    const char *string() {
-        return string_.get();
-    }
-    uint32_t uses() {
-        return uses_;
-    }
-    void use() {
-        uses_++;
-    }
-    void release() {
-        uses_--;
-    }
-};
-
-class TraceLoggerThread
-{
 #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();
-        }
+    // The createTextId functions map a unique input to a logger ID.
+    // This ID can be used to log something. Calls to these functions should be
+    // limited if possible, because of the overhead.
+    uint32_t createTextId(const char *text);
+    uint32_t createTextId(JSScript *script);
+    uint32_t createTextId(const JS::ReadOnlyCompileOptions &script);
+
+    // Log an event (no start/stop, only the timestamp is recorded).
+    void logTimestamp(uint32_t id);
 
-        *lastIteration = iteration_;
-        *lastEntryId = events.lastEntryId();
-        return start;
+    // Record timestamps for start and stop of an event.
+    // 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);
+    void stopEvent();
+
+    static unsigned offsetOfEnabled() {
+        return offsetof(TraceLogger, enabled);
     }
 
-    // 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
-    // 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);
-
-  public:
-    // Log an event (no start/stop, only the timestamp is recorded).
-    void logTimestamp(TraceLoggerTextId 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);
-    void startEvent(uint32_t id);
-    void stopEvent(uint32_t id);
-  private:
-    void stopEvent();
-
-  public:
-    static unsigned offsetOfEnabled() {
-        return offsetof(TraceLoggerThread, enabled);
+    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();
 #endif
     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) {
-#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) {
+inline void TraceLogStopEvent(TraceLogger *logger) {
 #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;
         }
     }
 
     ~AutoTraceLog()
     {
@@ -465,37 +631,49 @@ class AutoTraceLog
                 logger->top->stop();
             stop();
         }
     }
   private:
     void stop() {
         if (!executed) {
             executed = true;
-            if (isEvent)
-                logger->stopEvent(*payload.event);
-            else
-                logger->stopEvent(payload.id);
+            TraceLogStopEvent(logger, textId);
         }
 
         if (logger->top == this)
             logger->top = prev;
     }
 #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;
     }
 #endif
 
   private:
     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 */
deleted file mode 100644
--- a/js/src/vm/TraceLoggingGraph.cpp
+++ /dev/null
@@ -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(&timestamp, 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;
-}
deleted file mode 100644
--- a/js/src/vm/TraceLoggingGraph.h
+++ /dev/null
@@ -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 */
deleted file mode 100644
--- a/js/src/vm/TraceLoggingTypes.cpp
+++ /dev/null
@@ -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;
-}
-
deleted file mode 100644
--- a/js/src/vm/TraceLoggingTypes.h
+++ /dev/null
@@ -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 */
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1706,20 +1706,18 @@ class Mochitest(MochitestUtilsMixin):
 
     return result
 
   def runTests(self, options, onLaunch=None):
     """ Prepare, configure, run tests and cleanup """
 
     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:
       return self.runMochitests(options, onLaunch)
 
     # code for --run-by-dir
     dirs = self.getDirectories(options)