Bug 1143802 - Forward jit level information to profiler frontend. r=shu
authorKannan Vijayan <kvijayan@mozilla.com>
Fri, 20 Mar 2015 13:50:23 -0400
changeset 263622 e080ca1e7044b7227a407bc40fe44282036eecdd
parent 263621 bda9c6920e5663f2d90544fb7f604a9ddf8d3c53
child 263623 3abdf236d4f203d290faedbc8a064d728f945d5c
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1143802
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1143802 - Forward jit level information to profiler frontend. r=shu
js/public/ProfilingFrameIterator.h
js/src/jit/JitcodeMap.cpp
tools/profiler/ProfileEntry.cpp
tools/profiler/TableTicker.cpp
--- a/js/public/ProfilingFrameIterator.h
+++ b/js/public/ProfilingFrameIterator.h
@@ -118,16 +118,19 @@ class JS_PUBLIC_API(ProfilingFrameIterat
     void iteratorConstruct();
     void iteratorDestroy();
     bool iteratorDone();
 
     bool isAsmJS() const;
     bool isJit() const;
 };
 
+extern JS_PUBLIC_API(ProfilingFrameIterator::FrameKind)
+GetProfilingFrameKindFromNativeAddr(JSRuntime *runtime, void *pc, bool *hasOptInfo);
+
 JS_FRIEND_API(bool)
 IsProfilingEnabledForRuntime(JSRuntime *runtime);
 
 /**
  * After each sample run, this method should be called with the latest sample
  * buffer generation, and the lapCount.  It will update corresponding fields on
  * JSRuntime.
  *
--- a/js/src/jit/JitcodeMap.cpp
+++ b/js/src/jit/JitcodeMap.cpp
@@ -1497,8 +1497,31 @@ JitcodeIonTable::WriteIonTable(CompactBu
     *tableOffsetOut = tableOffset;
     *numRegionsOut = runOffsets.length();
     return true;
 }
 
 
 } // namespace jit
 } // namespace js
+
+
+JS_PUBLIC_API(JS::ProfilingFrameIterator::FrameKind)
+JS::GetProfilingFrameKindFromNativeAddr(JSRuntime *rt, void *addr, bool *hasOptInfo)
+{
+    MOZ_ASSERT(hasOptInfo);
+    *hasOptInfo = false;
+
+    JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable();
+    JitcodeGlobalEntry entry;
+    table->lookupInfallible(addr, &entry, rt);
+    MOZ_ASSERT(entry.isIon() || entry.isIonCache() || entry.isBaseline());
+
+    if (false && entry.hasTrackedOptimizations()) {
+        mozilla::Maybe<uint8_t> index = entry.trackedOptimizationIndexAtAddr(addr);
+        *hasOptInfo = index.isSome();
+    }
+
+    if (entry.isBaseline())
+        return JS::ProfilingFrameIterator::Frame_Baseline;
+
+    return JS::ProfilingFrameIterator::Frame_Ion;
+}
--- a/tools/profiler/ProfileEntry.cpp
+++ b/tools/profiler/ProfileEntry.cpp
@@ -6,16 +6,17 @@
 #include <ostream>
 #include <sstream>
 #include "platform.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 // JS
 #include "jsapi.h"
+#include "js/ProfilingFrameIterator.h"
 #include "js/TrackedOptimizationInfo.h"
 
 // JSON
 #include "JSStreamWriter.h"
 
 // Self
 #include "ProfileEntry.h"
 
@@ -403,25 +404,36 @@ void ProfileBuffer::StreamSamplesToJSObj
                           mEntries[readAheadPos].mTagName == 'J') {
                         void* pc = mEntries[readAheadPos].mTagPtr;
 
                         // TODOshu: cannot stream tracked optimization info if
                         // the JS engine has already shut down when streaming.
                         if (rt) {
                           JSScript *optsScript;
                           jsbytecode *optsPC;
-                          b.Name("opts");
-                          b.BeginArray();
-                            StreamOptimizationTypeInfoOp typeInfoOp(b);
-                            JS::ForEachTrackedOptimizationTypeInfo(rt, pc, typeInfoOp);
-                            StreamOptimizationAttemptsOp attemptOp(b);
-                            JS::ForEachTrackedOptimizationAttempt(rt, pc, attemptOp,
-                                                                  &optsScript, &optsPC);
-                          b.EndArray();
-                          b.NameValue("optsLine", JS_PCToLineNumber(optsScript, optsPC));
+                          bool hasOptInfo = false;
+                          JS::ProfilingFrameIterator::FrameKind frameKind =
+                            JS::GetProfilingFrameKindFromNativeAddr(rt, pc, &hasOptInfo);
+                          MOZ_ASSERT(frameKind == JS::ProfilingFrameIterator::Frame_Ion ||
+                                     frameKind == JS::ProfilingFrameIterator::Frame_Baseline);
+                          const char *jitLevelString =
+                            (frameKind == JS::ProfilingFrameIterator::Frame_Ion) ? "ion"
+                                                                                 : "baseline";
+                          b.NameValue("implementation", jitLevelString);
+                          if (hasOptInfo) {
+                              b.Name("opts");
+                              b.BeginArray();
+                                StreamOptimizationTypeInfoOp typeInfoOp(b);
+                                JS::ForEachTrackedOptimizationTypeInfo(rt, pc, typeInfoOp);
+                                StreamOptimizationAttemptsOp attemptOp(b);
+                                JS::ForEachTrackedOptimizationAttempt(rt, pc, attemptOp,
+                                                                      &optsScript, &optsPC);
+                              b.EndArray();
+                              b.NameValue("optsLine", JS_PCToLineNumber(optsScript, optsPC));
+                          }
                         }
                       }
                     b.EndObject();
                   }
                   framePos = (framePos + incBy) % mEntrySize;
                 }
               b.EndArray();
             }
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -585,17 +585,31 @@ void mergeStacksIntoProfile(ThreadProfil
     // Check to see if JS jit stack frame is top-most
     if (jsStackAddr > nativeStackAddr) {
       MOZ_ASSERT(jsIndex >= 0);
       addDynamicTag(aProfile, 'c', jsFrames[jsIndex].label);
 
       // Stringifying optimization information is delayed until streaming
       // time. To re-lookup the entry in the JitcodeGlobalTable, we need to
       // store the JIT code address ('J') in the circular buffer.
-      if (jsFrames[jsIndex].hasTrackedOptimizations) {
+      //
+      // Note that we cannot do this when we are sychronously sampling the
+      // current thread; that is, when called from profiler_get_backtrace. The
+      // captured backtrace is usually externally stored for an indeterminate
+      // amount of time, such as in nsRefreshDriver. Problematically, the
+      // stored backtrace may be alive across a GC during which the profiler
+      // itself is disabled. In that case, the JS engine is free to discard
+      // its JIT code. This means that if we inserted such 'J' entries into
+      // the buffer, nsRefreshDriver would now be holding on to a backtrace
+      // with stale JIT code return addresses.
+      MOZ_ASSERT_IF(jsFrames[jsIndex].hasTrackedOptimizations,
+                    jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Ion);
+      if (!aSample->isSamplingCurrentThread &&
+          (jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Ion ||
+           jsFrames[jsIndex].kind == JS::ProfilingFrameIterator::Frame_Baseline)) {
         aProfile.addTag(ProfileEntry('J', jsFrames[jsIndex].returnAddress));
       }
 
       jsIndex--;
       continue;
     }
 
     // If we reach here, there must be a native stack entry and it must be the