diff --git a/js/src/jit/JitcodeMap.cpp b/js/src/jit/JitcodeMap.cpp index 6ecfddd03a6f..2554d3d6bb1a 100644 --- a/js/src/jit/JitcodeMap.cpp +++ b/js/src/jit/JitcodeMap.cpp @@ -324,29 +324,31 @@ JitcodeGlobalEntry::createScriptString(JSContext* cx, JSScript* script, size_t* const char* filenameStr = script->filename() ? script->filename() : "(null)"; size_t filenameLength = strlen(filenameStr); - // Calculate lineno length - bool hasLineno = false; - size_t linenoLength = 0; - char linenoStr[15]; + // Calculate line + column length + bool hasLineAndColumn = false; + size_t lineAndColumnLength = 0; + char lineAndColumnStr[30]; if (hasName || (script->functionNonDelazifying() || script->isForEval())) { - linenoLength = SprintfLiteral(linenoStr, "%u", script->lineno()); - hasLineno = true; + lineAndColumnLength = + SprintfLiteral(lineAndColumnStr, "%u:%u", + script->lineno(), script->column()); + hasLineAndColumn = true; } // Full profile string for scripts with functions is: - // FuncName (FileName:Lineno) + // FuncName (FileName:Lineno:Column) // Full profile string for scripts without functions is: - // FileName:Lineno - // Full profile string for scripts without functions and without linenos is: + // FileName:Lineno:Column + // Full profile string for scripts without functions and without lines is: // FileName // Calculate full string length. size_t fullLength = 0; if (hasName) { - MOZ_ASSERT(hasLineno); - fullLength = nameLength + 2 + filenameLength + 1 + linenoLength + 1; - } else if (hasLineno) { - fullLength = filenameLength + 1 + linenoLength; + MOZ_ASSERT(hasLineAndColumn); + fullLength = nameLength + 2 + filenameLength + 1 + lineAndColumnLength + 1; + } else if (hasLineAndColumn) { + fullLength = filenameLength + 1 + lineAndColumnLength; } else { fullLength = filenameLength; } @@ -370,11 +372,11 @@ JitcodeGlobalEntry::createScriptString(JSContext* cx, JSScript* script, size_t* memcpy(str + cur, filenameStr, filenameLength); cur += filenameLength; - // Fill lineno chars. - if (hasLineno) { + // Fill line + column chars. + if (hasLineAndColumn) { str[cur++] = ':'; - memcpy(str + cur, linenoStr, linenoLength); - cur += linenoLength; + memcpy(str + cur, lineAndColumnStr, lineAndColumnLength); + cur += lineAndColumnLength; } // Terminal ')' if necessary. diff --git a/js/src/vm/GeckoProfiler.cpp b/js/src/vm/GeckoProfiler.cpp index e33b05eaf87f..645b0d6f363f 100644 --- a/js/src/vm/GeckoProfiler.cpp +++ b/js/src/vm/GeckoProfiler.cpp @@ -275,12 +275,17 @@ GeckoProfilerRuntime::allocProfileString(JSScript* script, JSFunction* maybeFun) size_t lenFilename = strlen(filename); // Get the line number and its length as a string. - uint64_t lineno = script->lineno(); + uint32_t lineno = script->lineno(); size_t lenLineno = 1; - for (uint64_t i = lineno; i /= 10; lenLineno++); + for (uint32_t i = lineno; i /= 10; lenLineno++); + + // Get the column number and its length as a string. + uint32_t column = script->column(); + size_t lenColumn = 1; + for (uint32_t i = column; i /= 10; lenColumn++); // Determine the required buffer size. - size_t len = lenFilename + lenLineno + 1; // +1 for the ":" separating them. + size_t len = lenFilename + 1 + lenLineno + 1 + lenColumn; // +1 for each separator colon, ":". if (atom) { len += JS::GetDeflatedUTF8StringLength(atom) + 3; // +3 for the " (" and ")" it adds. } @@ -297,9 +302,11 @@ GeckoProfilerRuntime::allocProfileString(JSScript* script, JSFunction* maybeFun) if (!atomStr) return nullptr; - ret = snprintf(cstr.get(), len + 1, "%s (%s:%" PRIu64 ")", atomStr.get(), filename, lineno); + ret = snprintf(cstr.get(), len + 1, "%s (%s:%" PRIu32 ":%" PRIu32 ")", + atomStr.get(), filename, lineno, column); } else { - ret = snprintf(cstr.get(), len + 1, "%s:%" PRIu64, filename, lineno); + ret = snprintf(cstr.get(), len + 1, "%s:%" PRIu32 ":%" PRIu32, + filename, lineno, column); } MOZ_ASSERT(ret == len, "Computed length should match actual length!"); diff --git a/tools/profiler/core/ProfileBuffer.cpp b/tools/profiler/core/ProfileBuffer.cpp index 0ebcd11ba6e1..20124cb5be87 100644 --- a/tools/profiler/core/ProfileBuffer.cpp +++ b/tools/profiler/core/ProfileBuffer.cpp @@ -68,7 +68,8 @@ ProfileBuffer::AddStoredMarker(ProfilerMarker *aStoredMarker) void ProfileBuffer::CollectCodeLocation( - const char* aLabel, const char* aStr, int aLineNumber, + const char* aLabel, const char* aStr, + const Maybe& aLineNumber, const Maybe& aColumnNumber, const Maybe& aCategory) { AddEntry(ProfileBufferEntry::Label(aLabel)); @@ -90,8 +91,12 @@ ProfileBuffer::CollectCodeLocation( } } - if (aLineNumber != -1) { - AddEntry(ProfileBufferEntry::LineNumber(aLineNumber)); + if (aLineNumber) { + AddEntry(ProfileBufferEntry::LineNumber(*aLineNumber)); + } + + if (aColumnNumber) { + AddEntry(ProfileBufferEntry::ColumnNumber(*aColumnNumber)); } if (aCategory.isSome()) { @@ -149,7 +154,7 @@ ProfileBufferCollector::CollectJitReturnAddr(void* aAddr) void ProfileBufferCollector::CollectWasmFrame(const char* aLabel) { - mBuf.CollectCodeLocation("", aLabel, -1, Nothing()); + mBuf.CollectCodeLocation("", aLabel, Nothing(), Nothing(), Nothing()); } void @@ -163,7 +168,8 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame const char* label = aFrame.label(); const char* dynamicString = aFrame.dynamicString(); bool isChromeJSEntry = false; - int lineno = -1; + Maybe line; + Maybe column; if (aFrame.isJsFrame()) { // There are two kinds of JS frames that get pushed onto the ProfilingStack. @@ -181,7 +187,9 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame if (aFrame.script()) { isChromeJSEntry = IsChromeJSScript(aFrame.script()); if (aFrame.pc()) { - lineno = JS_PCToLineNumber(aFrame.script(), aFrame.pc()); + unsigned col = 0; + line = Some(JS_PCToLineNumber(aFrame.script(), aFrame.pc(), &col)); + column = Some(col); } } @@ -190,7 +198,7 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame } } else { MOZ_ASSERT(aFrame.isLabelFrame()); - lineno = aFrame.line(); + line = Some(aFrame.line()); } if (dynamicString) { @@ -202,6 +210,6 @@ ProfileBufferCollector::CollectProfilingStackFrame(const js::ProfilingStackFrame } } - mBuf.CollectCodeLocation(label, dynamicString, lineno, + mBuf.CollectCodeLocation(label, dynamicString, line, column, Some(aFrame.category())); } diff --git a/tools/profiler/core/ProfileBuffer.h b/tools/profiler/core/ProfileBuffer.h index 5597658a780e..16b410e776e7 100644 --- a/tools/profiler/core/ProfileBuffer.h +++ b/tools/profiler/core/ProfileBuffer.h @@ -44,7 +44,9 @@ public: uint64_t AddThreadIdEntry(int aThreadId); void CollectCodeLocation( - const char* aLabel, const char* aStr, int aLineNumber, + const char* aLabel, const char* aStr, + const mozilla::Maybe& aLineNumber, + const mozilla::Maybe& aColumnNumber, const mozilla::Maybe& aCategory); // Maximum size of a frameKey string that we'll handle. diff --git a/tools/profiler/core/ProfileBufferEntry.cpp b/tools/profiler/core/ProfileBufferEntry.cpp index 601f2c594404..23c2633bc382 100644 --- a/tools/profiler/core/ProfileBufferEntry.cpp +++ b/tools/profiler/core/ProfileBufferEntry.cpp @@ -343,6 +343,7 @@ UniqueStacks::FrameKey::NormalFrameData::operator==(const NormalFrameData& aOthe { return mLocation == aOther.mLocation && mLine == aOther.mLine && + mColumn == aOther.mColumn && mCategory == aOther.mCategory; } @@ -366,6 +367,9 @@ UniqueStacks::FrameKey::Hash() const if (data.mLine.isSome()) { hash = AddToHash(hash, *data.mLine); } + if (data.mColumn.isSome()) { + hash = AddToHash(hash, *data.mColumn); + } if (data.mCategory.isSome()) { hash = AddToHash(hash, *data.mCategory); } @@ -508,7 +512,8 @@ UniqueStacks::StreamNonJITFrame(const FrameKey& aFrame) IMPLEMENTATION = 1, OPTIMIZATIONS = 2, LINE = 3, - CATEGORY = 4 + COLUMN = 4, + CATEGORY = 5 }; AutoArraySchemaWriter writer(mFrameTableWriter, *mUniqueStrings); @@ -518,6 +523,9 @@ UniqueStacks::StreamNonJITFrame(const FrameKey& aFrame) if (data.mLine.isSome()) { writer.IntElement(LINE, *data.mLine); } + if (data.mColumn.isSome()) { + writer.IntElement(COLUMN, *data.mColumn); + } if (data.mCategory.isSome()) { writer.IntElement(CATEGORY, *data.mCategory); } @@ -626,7 +634,8 @@ StreamJITFrame(JSContext* aContext, SpliceableJSONWriter& aWriter, IMPLEMENTATION = 1, OPTIMIZATIONS = 2, LINE = 3, - CATEGORY = 4 + COLUMN = 4, + CATEGORY = 5 }; AutoArraySchemaWriter writer(aWriter, aUniqueStrings); @@ -1019,6 +1028,12 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, e.Next(); } + Maybe column; + if (e.Has() && e.Get().IsColumnNumber()) { + column = Some(unsigned(e.Get().u.mInt)); + e.Next(); + } + Maybe category; if (e.Has() && e.Get().IsCategory()) { category = Some(unsigned(e.Get().u.mInt)); @@ -1026,7 +1041,7 @@ ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, } stack = aUniqueStacks.AppendFrame( - stack, UniqueStacks::FrameKey(strbuf.get(), line, category)); + stack, UniqueStacks::FrameKey(strbuf.get(), line, column, category)); } else if (e.Get().IsJitReturnAddr()) { numFrames++; diff --git a/tools/profiler/core/ProfileBufferEntry.h b/tools/profiler/core/ProfileBufferEntry.h index 5e9e957e87da..ba83671a6b43 100644 --- a/tools/profiler/core/ProfileBufferEntry.h +++ b/tools/profiler/core/ProfileBufferEntry.h @@ -38,6 +38,7 @@ class ProfilerMarker; macro(DynamicStringFragment, char*) /* char[kNumChars], really */ \ macro(JitReturnAddr, void*) \ macro(LineNumber, int) \ + macro(ColumnNumber, int) \ macro(NativeLeafAddr, void*) \ macro(Marker, ProfilerMarker*) \ macro(Pause, double) \ @@ -224,8 +225,9 @@ public: } FrameKey(const char* aLocation, const mozilla::Maybe& aLine, + const mozilla::Maybe& aColumn, const mozilla::Maybe& aCategory) - : mData(NormalFrameData{ nsCString(aLocation), aLine, aCategory }) + : mData(NormalFrameData{ nsCString(aLocation), aLine, aColumn, aCategory }) { } @@ -244,6 +246,7 @@ public: nsCString mLocation; mozilla::Maybe mLine; + mozilla::Maybe mColumn; mozilla::Maybe mCategory; }; struct JITFrameData { @@ -396,7 +399,8 @@ private: // "implementation": 1, /* index into stringTable */ // "optimizations": 2, /* arbitrary JSON */ // "line": 3, /* number */ -// "category": 4 /* number */ +// "column": 4, /* number */ +// "category": 5 /* number */ // }, // "data": // [ diff --git a/tools/profiler/core/ProfiledThreadData.cpp b/tools/profiler/core/ProfiledThreadData.cpp index 6a338f30fdad..47abf1efcd83 100644 --- a/tools/profiler/core/ProfiledThreadData.cpp +++ b/tools/profiler/core/ProfiledThreadData.cpp @@ -87,6 +87,7 @@ ProfiledThreadData::StreamJSON(const ProfileBuffer& aBuffer, JSContext* aCx, schema.WriteField("implementation"); schema.WriteField("optimizations"); schema.WriteField("line"); + schema.WriteField("column"); schema.WriteField("category"); } diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index 057ee55680c9..4eb9d8425c91 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -1627,7 +1627,7 @@ StreamMetaJSCustomObject(PSLockRef aLock, SpliceableJSONWriter& aWriter, { MOZ_RELEASE_ASSERT(CorePS::Exists() && ActivePS::Exists(aLock)); - aWriter.IntProperty("version", 11); + aWriter.IntProperty("version", 12); // The "startTime" field holds the number of milliseconds since midnight // January 1, 1970 GMT. This grotty code computes (Now - (Now - @@ -1824,7 +1824,8 @@ CollectJavaThreadProfileData() parentFrameWasIdleFrame = false; } - buffer->CollectCodeLocation("", frameNameString.get(), -1, category); + buffer->CollectCodeLocation("", frameNameString.get(), Nothing(), + Nothing(), category); } sampleId++; }