From df02b37be75846301a4a2f4cd332f49cd440b5d4 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 23 Feb 2015 20:33:56 -0800 Subject: [PATCH] Bug 1129780 - Report the youngest sampled frame's line number if it has optimization info. (r=djvj) --- js/public/TrackedOptimizationInfo.h | 3 +- js/src/jit/JitcodeMap.cpp | 99 ++++++++++++++++++++--------- js/src/jit/JitcodeMap.h | 33 ++++++++++ js/src/jit/OptimizationTracking.cpp | 8 ++- tools/profiler/ProfileEntry.cpp | 6 +- 5 files changed, 115 insertions(+), 34 deletions(-) diff --git a/js/public/TrackedOptimizationInfo.h b/js/public/TrackedOptimizationInfo.h index bfe1cfd1eff8..aa2ce4d0c92a 100644 --- a/js/public/TrackedOptimizationInfo.h +++ b/js/public/TrackedOptimizationInfo.h @@ -279,7 +279,8 @@ struct ForEachTrackedOptimizationAttemptOp JS_PUBLIC_API(void) ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr, - ForEachTrackedOptimizationAttemptOp &op); + ForEachTrackedOptimizationAttemptOp &op, + JSScript **scriptOut, jsbytecode **pcOut); struct ForEachTrackedOptimizationTypeInfoOp { diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp index 1d9d8621bdd8..ed5b529a2dc6 100644 --- a/js/src/jit/JitcodeMap.cpp +++ b/js/src/jit/JitcodeMap.cpp @@ -20,19 +20,28 @@ namespace js { namespace jit { + +static inline JitcodeRegionEntry +RegionAtAddr(const JitcodeGlobalEntry::IonEntry &entry, void *ptr, + uint32_t *ptrOffset) +{ + MOZ_ASSERT(entry.containsPointer(ptr)); + *ptrOffset = reinterpret_cast(ptr) - + reinterpret_cast(entry.nativeStartAddr()); + + uint32_t regionIdx = entry.regionTable()->findRegionEntry(*ptrOffset); + MOZ_ASSERT(regionIdx < entry.regionTable()->numRegions()); + + return entry.regionTable()->regionEntry(regionIdx); +} + bool JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results, uint32_t *depth) const { - MOZ_ASSERT(containsPointer(ptr)); - uint32_t ptrOffset = reinterpret_cast(ptr) - - reinterpret_cast(nativeStartAddr()); - - uint32_t regionIdx = regionTable()->findRegionEntry(ptrOffset); - MOZ_ASSERT(regionIdx < regionTable()->numRegions()); - - JitcodeRegionEntry region = regionTable()->regionEntry(regionIdx); + uint32_t ptrOffset; + JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset); *depth = region.scriptDepth(); JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator(); @@ -61,15 +70,10 @@ JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr, const char **results, uint32_t maxResults) const { - MOZ_ASSERT(containsPointer(ptr)); MOZ_ASSERT(maxResults >= 1); - uint32_t ptrOffset = reinterpret_cast(ptr) - - reinterpret_cast(nativeStartAddr()); - uint32_t regionIdx = regionTable()->findRegionEntry(ptrOffset); - MOZ_ASSERT(regionIdx < regionTable()->numRegions()); - - JitcodeRegionEntry region = regionTable()->regionEntry(regionIdx); + uint32_t ptrOffset; + JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset); JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator(); MOZ_ASSERT(locationIter.hasMore()); @@ -88,6 +92,23 @@ JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr, return count; } +void +JitcodeGlobalEntry::IonEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const +{ + uint32_t ptrOffset; + JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset); + + JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator(); + MOZ_ASSERT(locationIter.hasMore()); + uint32_t scriptIdx, pcOffset; + locationIter.readNext(&scriptIdx, &pcOffset); + pcOffset = region.findPcOffset(ptrOffset, pcOffset); + + *script = getScript(scriptIdx); + *pc = (*script)->offsetToPC(pcOffset); +} + void JitcodeGlobalEntry::IonEntry::destroy() { @@ -155,6 +176,16 @@ JitcodeGlobalEntry::BaselineEntry::callStackAtAddr(JSRuntime *rt, void *ptr, return 1; } +void +JitcodeGlobalEntry::BaselineEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, + jsbytecode **pc) const +{ + uint8_t *addr = reinterpret_cast(ptr); + *script = script_; + *pc = script_->baselineScript()->approximatePcForNativeAddress(script_, addr); +} + void JitcodeGlobalEntry::BaselineEntry::destroy() { @@ -164,19 +195,25 @@ JitcodeGlobalEntry::BaselineEntry::destroy() str_ = nullptr; } +static inline void +RejoinEntry(JSRuntime *rt, const JitcodeGlobalEntry::IonCacheEntry &cache, + void *ptr, JitcodeGlobalEntry *entry) +{ + MOZ_ASSERT(cache.containsPointer(ptr)); + + // There must exist an entry for the rejoin addr if this entry exists. + JitRuntime *jitrt = rt->jitRuntime(); + jitrt->getJitcodeGlobalTable()->lookupInfallible(cache.rejoinAddr(), entry, rt); + MOZ_ASSERT(entry->isIon()); +} + bool JitcodeGlobalEntry::IonCacheEntry::callStackAtAddr(JSRuntime *rt, void *ptr, BytecodeLocationVector &results, uint32_t *depth) const { - MOZ_ASSERT(containsPointer(ptr)); - - // There must exist an entry for the rejoin addr if this entry exists. - JitRuntime *jitrt = rt->jitRuntime(); JitcodeGlobalEntry entry; - jitrt->getJitcodeGlobalTable()->lookupInfallible(rejoinAddr(), &entry, rt); - MOZ_ASSERT(entry.isIon()); - + RejoinEntry(rt, *this, ptr, &entry); return entry.callStackAtAddr(rt, rejoinAddr(), results, depth); } @@ -185,17 +222,21 @@ JitcodeGlobalEntry::IonCacheEntry::callStackAtAddr(JSRuntime *rt, void *ptr, const char **results, uint32_t maxResults) const { - MOZ_ASSERT(containsPointer(ptr)); - - // There must exist an entry for the rejoin addr if this entry exists. - JitRuntime *jitrt = rt->jitRuntime(); JitcodeGlobalEntry entry; - jitrt->getJitcodeGlobalTable()->lookupInfallible(rejoinAddr(), &entry, rt); - MOZ_ASSERT(entry.isIon()); - + RejoinEntry(rt, *this, ptr, &entry); return entry.callStackAtAddr(rt, rejoinAddr(), results, maxResults); } +void +JitcodeGlobalEntry::IonCacheEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, + jsbytecode **pc) const +{ + JitcodeGlobalEntry entry; + RejoinEntry(rt, *this, ptr, &entry); + return entry.youngestFrameLocationAtAddr(rt, ptr, script, pc); +} + static int ComparePointers(const void *a, const void *b) { const uint8_t *a_ptr = reinterpret_cast(a); diff --git a/js/src/jit/JitcodeMap.h b/js/src/jit/JitcodeMap.h index 96ebc3e62708..837ae1ac6e3c 100644 --- a/js/src/jit/JitcodeMap.h +++ b/js/src/jit/JitcodeMap.h @@ -210,6 +210,9 @@ class JitcodeGlobalEntry uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results, uint32_t maxResults) const; + void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const; + bool hasTrackedOptimizations() const { return !!optsRegionTable_; } @@ -278,6 +281,9 @@ class JitcodeGlobalEntry uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results, uint32_t maxResults) const; + + void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const; }; struct IonCacheEntry : public BaseEntry @@ -302,6 +308,9 @@ class JitcodeGlobalEntry uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results, uint32_t maxResults) const; + + void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const; }; // Dummy entries are created for jitcode generated when profiling is not turned on, @@ -326,6 +335,13 @@ class JitcodeGlobalEntry { return 0; } + + void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const + { + *script = nullptr; + *pc = nullptr; + } }; // QueryEntry is never stored in the table, just used for queries @@ -551,6 +567,23 @@ class JitcodeGlobalEntry return false; } + void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr, + JSScript **script, jsbytecode **pc) const + { + switch (kind()) { + case Ion: + return ionEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc); + case Baseline: + return baselineEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc); + case IonCache: + return ionCacheEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc); + case Dummy: + return dummyEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc); + default: + MOZ_CRASH("Invalid JitcodeGlobalEntry kind."); + } + } + // Figure out the number of the (JSScript *, jsbytecode *) pairs that are active // at this location. uint32_t lookupInlineCallDepth(void *ptr); diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index db1bcaee16b8..dce2b1aa6550 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -1123,11 +1123,13 @@ IonBuilder::trackInlineSuccessUnchecked(InliningStatus status) JS_PUBLIC_API(void) JS::ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr, - ForEachTrackedOptimizationAttemptOp &op) + ForEachTrackedOptimizationAttemptOp &op, + JSScript **scriptOut, jsbytecode **pcOut) { JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable(); JitcodeGlobalEntry entry; table->lookupInfallible(addr, &entry, rt); + entry.youngestFrameLocationAtAddr(rt, addr, scriptOut, pcOut); Maybe index = entry.trackedOptimizationIndexAtAddr(addr); entry.trackedOptimizationAttempts(index.value()).forEach(op); } @@ -1143,7 +1145,7 @@ InterpretedFunctionFilenameAndLineNumber(JSFunction *fun, const char **filename, source = fun->lazyScript()->maybeForwardedScriptSource(); *lineno = fun->lazyScript()->lineno(); } - *filename = source->introducerFilename(); + *filename = source->filename(); } static JSFunction * @@ -1224,7 +1226,7 @@ class ForEachTypeInfoAdapter : public IonTrackedOptimizationsTypeInfo::ForEachOp if (tracked.hasAllocationSite()) { JSScript *script = tracked.script; op_.readType("alloc site", buf, - script->maybeForwardedScriptSource()->introducerFilename(), + script->maybeForwardedScriptSource()->filename(), PCToLineNumber(script, script->offsetToPC(tracked.offset))); return; } diff --git a/tools/profiler/ProfileEntry.cpp b/tools/profiler/ProfileEntry.cpp index 81c7f21c0d8c..4ec25b9880aa 100644 --- a/tools/profiler/ProfileEntry.cpp +++ b/tools/profiler/ProfileEntry.cpp @@ -400,13 +400,17 @@ void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JS // 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); + JS::ForEachTrackedOptimizationAttempt(rt, pc, attemptOp, + &optsScript, &optsPC); b.EndArray(); + b.NameValue("optsLine", JS_PCToLineNumber(optsScript, optsPC)); } } b.EndObject();