--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1178,19 +1178,19 @@ FullGCTimerFired(nsITimer* aTimer, void*
//static
void
nsJSContext::GarbageCollectNow(JS::gcreason::Reason aReason,
IsIncremental aIncremental,
IsShrinking aShrinking,
int64_t aSliceMillis)
{
- PROFILER_LABEL_PRINTF("nsJSContext", "GarbageCollectNow",
- js::ProfileEntry::Category::GC,
- "%s", JS::gcreason::ExplainReason(aReason));
+ PROFILER_LABEL_DYNAMIC("nsJSContext", "GarbageCollectNow",
+ js::ProfileEntry::Category::GC,
+ JS::gcreason::ExplainReason(aReason));
MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
KillGCTimer();
// Reset sPendingLoadCount in case the timer that fired was a
// timer we scheduled due to a normal GC timer firing while
// documents were loading. If this happens we're waiting for a
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1270,20 +1270,19 @@ EventListenerManager::HandleEventInterna
if (profiler_is_active()) {
#ifdef MOZ_GECKO_PROFILER
// Add a profiler label and a profiler marker for the actual
// dispatch of the event.
// This is a very hot code path, so we need to make sure not to
// do this extra work when we're not profiling.
nsAutoString typeStr;
(*aDOMEvent)->GetType(typeStr);
- PROFILER_LABEL_PRINTF("EventListenerManager", "HandleEventInternal",
- js::ProfileEntry::Category::EVENTS,
- "%s",
- NS_LossyConvertUTF16toASCII(typeStr).get());
+ PROFILER_LABEL_DYNAMIC("EventListenerManager", "HandleEventInternal",
+ js::ProfileEntry::Category::EVENTS,
+ NS_LossyConvertUTF16toASCII(typeStr));
TimeStamp startTime = TimeStamp::Now();
rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
TimeStamp endTime = TimeStamp::Now();
uint16_t phase;
(*aDOMEvent)->GetEventPhase(&phase);
PROFILER_MARKER_PAYLOAD("DOMEvent",
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1127,29 +1127,29 @@ RasterImage::RequestDecodeForSizeInterna
static bool
LaunchDecodingTask(IDecodingTask* aTask,
RasterImage* aImage,
uint32_t aFlags,
bool aHaveSourceData)
{
if (aHaveSourceData) {
+ nsCString uri(aImage->GetURIString());
+
// If we have all the data, we can sync decode if requested.
if (aFlags & imgIContainer::FLAG_SYNC_DECODE) {
- PROFILER_LABEL_PRINTF("DecodePool", "SyncRunIfPossible",
- js::ProfileEntry::Category::GRAPHICS,
- "%s", aImage->GetURIString().get());
+ PROFILER_LABEL_DYNAMIC("DecodePool", "SyncRunIfPossible",
+ js::ProfileEntry::Category::GRAPHICS, uri.get());
DecodePool::Singleton()->SyncRunIfPossible(aTask);
return true;
}
if (aFlags & imgIContainer::FLAG_SYNC_DECODE_IF_FAST) {
- PROFILER_LABEL_PRINTF("DecodePool", "SyncRunIfPreferred",
- js::ProfileEntry::Category::GRAPHICS,
- "%s", aImage->GetURIString().get());
+ PROFILER_LABEL_DYNAMIC("DecodePool", "SyncRunIfPreferred",
+ js::ProfileEntry::Category::GRAPHICS, uri.get());
return DecodePool::Singleton()->SyncRunIfPreferred(aTask);
}
}
// Perform an async decode. We also take this path if we don't have all the
// source data yet, since sync decoding is impossible in that situation.
DecodePool::Singleton()->AsyncRun(aTask);
return false;
--- a/js/public/ProfilingStack.h
+++ b/js/public/ProfilingStack.h
@@ -31,19 +31,24 @@ class ProfileEntry
// entry[size] = ...;
// size++;
//
// If the size modification were somehow reordered before the stores, then
// if a sample were taken it would be examining bogus information.
//
// A ProfileEntry represents both a C++ profile entry and a JS one.
- // Descriptive string of this entry.
+ // Descriptive string of this entry. Can be a static string or a dynamic
+ // string. If it's a dynamic string (which will need to be copied during
+ // sampling), then isCopyLabel() needs to return true.
const char * volatile string;
+ // An additional descriptive string of this entry. Can be null.
+ const char * volatile dynamicString;
+
// Stack pointer for non-JS entries, the script pointer otherwise.
void * volatile spOrScript;
// Line number for non-JS entries, the bytecode offset otherwise.
int32_t volatile lineOrPcOffset;
// General purpose storage describing this frame.
uint32_t volatile flags_;
@@ -52,18 +57,18 @@ class ProfileEntry
// These traits are bit masks. Make sure they're powers of 2.
enum Flags : uint32_t {
// Indicate whether a profile entry represents a CPP frame. If not set,
// a JS frame is assumed by default. You're not allowed to publicly
// change the frame type. Instead, initialize the ProfileEntry as either
// a JS or CPP frame with `initJsFrame` or `initCppFrame` respectively.
IS_CPP_ENTRY = 0x01,
- // Indicate that copying the frame label is not necessary when taking a
- // sample of the pseudostack.
+ // Indicates that the label string is not a static string and needs to
+ // be copied during sampling.
FRAME_LABEL_COPY = 0x02,
// This ProfileEntry is a dummy entry indicating the start of a run
// of JS pseudostack entries.
BEGIN_PSEUDO_JS = 0x04,
// This flag is used to indicate that an interpreter JS entry has OSR-ed
// into baseline.
@@ -103,16 +108,19 @@ class ProfileEntry
bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); }
bool isJs() const volatile { return !isCpp(); }
bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); }
void setLabel(const char* aString) volatile { string = aString; }
const char* label() const volatile { return string; }
+ void setDynamicString(const char* aDynamicString) volatile { dynamicString = aDynamicString; }
+ const char* getDynamicString() const volatile { return dynamicString; }
+
void initJsFrame(JSScript* aScript, jsbytecode* aPc) volatile {
flags_ = 0;
spOrScript = aScript;
setPC(aPc);
}
void initCppFrame(void* aSp, uint32_t aLine) volatile {
flags_ = IS_CPP_ENTRY;
spOrScript = aSp;
--- a/js/src/vm/GeckoProfiler.cpp
+++ b/js/src/vm/GeckoProfiler.cpp
@@ -284,16 +284,17 @@ GeckoProfiler::push(const char* string,
MOZ_ASSERT(entry.flags() == js::ProfileEntry::IS_CPP_ENTRY);
}
else {
entry.initJsFrame(script, pc);
MOZ_ASSERT(entry.flags() == 0);
}
entry.setLabel(string);
+ entry.setDynamicString(nullptr);
entry.setCategory(category);
// Track if mLabel needs a copy.
if (copy)
entry.setFlag(js::ProfileEntry::FRAME_LABEL_COPY);
else
entry.unsetFlag(js::ProfileEntry::FRAME_LABEL_COPY);
}
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -3043,26 +3043,24 @@ ElementRestyler::ComputeStyleChangeFor(n
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData,
nsTArray<ContextToClear>&
aContextsToClear,
nsTArray<RefPtr<nsStyleContext>>&
aSwappedStructOwners)
{
nsIContent* content = aFrame->GetContent();
- nsAutoCString localDescriptor;
+ std::string elemDesc;
if (profiler_is_active() && content) {
- std::string elemDesc = ToString(*content);
- localDescriptor.Assign(elemDesc.c_str());
+ elemDesc = ToString(*content);
}
- PROFILER_LABEL_PRINTF("ElementRestyler", "ComputeStyleChangeFor",
- js::ProfileEntry::Category::CSS,
- content ? "Element: %s" : "%s",
- content ? localDescriptor.get() : "");
+ PROFILER_LABEL_DYNAMIC("ElementRestyler", "ComputeStyleChangeFor",
+ js::ProfileEntry::Category::CSS,
+ content ? elemDesc.c_str() : "<unknown>");
if (aMinChange) {
aChangeList->AppendChange(aFrame, content, aMinChange);
}
NS_ASSERTION(!aFrame->GetPrevContinuation(),
"must start with the first continuation");
// We want to start with this frame and walk all its next-in-flows,
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4083,18 +4083,18 @@ PresShell::DoFlushPendingNotifications(m
"Content",
"ContentAndNotify",
"Style",
"InterruptibleLayout",
"Layout",
"Display"
};
- PROFILER_LABEL_PRINTF("PresShell", "Flush",
- js::ProfileEntry::Category::GRAPHICS, "(FlushType::%s)",
+ PROFILER_LABEL_DYNAMIC("PresShell", "Flush",
+ js::ProfileEntry::Category::GRAPHICS,
flushTypeNames[flushType]);
#endif
#ifdef ACCESSIBILITY
#ifdef DEBUG
nsAccessibilityService* accService = GetAccService();
if (accService) {
NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
@@ -6352,19 +6352,19 @@ PresShell::Paint(nsView* aViewToP
uint32_t aFlags)
{
#ifdef MOZ_GECKO_PROFILER
nsIURI* uri = mDocument->GetDocumentURI();
nsIDocument* contentRoot = GetPrimaryContentDocument();
if (contentRoot) {
uri = contentRoot->GetDocumentURI();
}
- PROFILER_LABEL_PRINTF("PresShell", "Paint",
- js::ProfileEntry::Category::GRAPHICS, "(%s)",
- uri ? uri->GetSpecOrDefault().get() : "N/A");
+ nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
+ PROFILER_LABEL_DYNAMIC("PresShell", "Paint",
+ js::ProfileEntry::Category::GRAPHICS, Move(uriString));
#endif
Maybe<js::AutoAssertNoContentJS> nojs;
// On Android, Flash can call into content JS during painting, so we can't
// assert there. However, we don't rely on this assertion on Android because
// we don't paint while JS is running.
#if !defined(MOZ_WIDGET_ANDROID)
@@ -9171,19 +9171,19 @@ PresShell::DoReflow(nsIFrame* target, bo
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
while (parent) {
nsSVGEffects::InvalidateDirectRenderingObservers(parent);
parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
}
#ifdef MOZ_GECKO_PROFILER
nsIURI* uri = mDocument->GetDocumentURI();
- PROFILER_LABEL_PRINTF("PresShell", "DoReflow",
- js::ProfileEntry::Category::GRAPHICS, "(%s)",
- uri ? uri->GetSpecOrDefault().get() : "N/A");
+ nsCString uriString = uri ? uri->GetSpecOrDefault() : NS_LITERAL_CSTRING("N/A");
+ PROFILER_LABEL_DYNAMIC("PresShell", "DoReflow",
+ js::ProfileEntry::Category::GRAPHICS, Move(uriString));
#endif
nsDocShell* docShell = static_cast<nsDocShell*>(GetPresContext()->GetDocShell());
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
if (isTimelineRecording) {
timelines->AddMarkerForDocShell(docShell, "Reflow", MarkerTracingType::START);
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -109,18 +109,18 @@ RestyleTracker::DoProcessRestyles()
{
nsAutoCString docURL("N/A");
if (profiler_is_active()) {
nsIURI *uri = Document()->GetDocumentURI();
if (uri) {
docURL = uri->GetSpecOrDefault();
}
}
- PROFILER_LABEL_PRINTF("RestyleTracker", "ProcessRestyles",
- js::ProfileEntry::Category::CSS, "(%s)", docURL.get());
+ PROFILER_LABEL_DYNAMIC("RestyleTracker", "ProcessRestyles",
+ js::ProfileEntry::Category::CSS, docURL.get());
nsDocShell* docShell = static_cast<nsDocShell*>(mRestyleManager->PresContext()->GetDocShell());
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
// Create a AnimationsWithDestroyedFrame during restyling process to
// stop animations and transitions on elements that have no frame at the end
// of the restyling process.
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -6002,18 +6002,18 @@ FrameLayerBuilder::PaintItems(nsTArray<C
for (uint32_t i = 0; i < aItems.Length(); ++i) {
ClippedDisplayItem* cdi = &aItems[i];
nsRect paintRect = cdi->mItem->GetVisibleRect().Intersect(boundRect);
if (paintRect.IsEmpty())
continue;
#ifdef MOZ_DUMP_PAINTING
- PROFILER_LABEL_PRINTF("DisplayList", "Draw",
- js::ProfileEntry::Category::GRAPHICS, "%s", cdi->mItem->Name());
+ PROFILER_LABEL_DYNAMIC("DisplayList", "Draw",
+ js::ProfileEntry::Category::GRAPHICS, cdi->mItem->Name());
#else
PROFILER_LABEL("DisplayList", "Draw",
js::ProfileEntry::Category::GRAPHICS);
#endif
// If the new desired clip state is different from the current state,
// update the clip.
const DisplayItemClip* clip = &cdi->mItem->GetClip();
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -406,33 +406,44 @@ AddDynamicCodeLocationTag(ProfileBuffer*
memcpy(text, &aStr[j], len);
j += sizeof(void*) / sizeof(char);
// Cast to *((void**) to pass the text data to a void*.
aBuffer->addTag(ProfileBufferEntry::EmbeddedString(*((void**)(&text[0]))));
}
}
+static const int SAMPLER_MAX_STRING_LENGTH = 128;
+
static void
AddPseudoEntry(ProfileBuffer* aBuffer, volatile js::ProfileEntry& entry,
PseudoStack* stack, void* lastpc)
{
// Pseudo-frames with the BEGIN_PSEUDO_JS flag are just annotations and
// should not be recorded in the profile.
if (entry.hasFlag(js::ProfileEntry::BEGIN_PSEUDO_JS)) {
return;
}
int lineno = -1;
// First entry has kind CodeLocation. Check for magic pointer bit 1 to
// indicate copy.
const char* sampleLabel = entry.label();
-
- if (entry.isCopyLabel()) {
+ const char* dynamicString = entry.getDynamicString();
+ char combinedStringBuffer[SAMPLER_MAX_STRING_LENGTH];
+
+ if (entry.isCopyLabel() || dynamicString) {
+ if (dynamicString) {
+ int bytesWritten =
+ SprintfLiteral(combinedStringBuffer, "%s %s", sampleLabel, dynamicString);
+ if (bytesWritten > 0) {
+ sampleLabel = combinedStringBuffer;
+ }
+ }
// Store the string using 1 or more EmbeddedString tags.
// That will happen to the preceding tag.
AddDynamicCodeLocationTag(aBuffer, sampleLabel);
if (entry.isJs()) {
JSScript* script = entry.script();
if (script) {
if (!entry.pc()) {
// The JIT only allows the top-most entry to have a nullptr pc.
@@ -2862,21 +2873,38 @@ profiler_get_backtrace_noalloc(char *out
if (!pseudoStack) {
return;
}
volatile js::ProfileEntry *pseudoFrames = pseudoStack->mStack;
uint32_t pseudoCount = pseudoStack->stackSize();
for (uint32_t i = 0; i < pseudoCount; i++) {
- size_t len = strlen(pseudoFrames[i].label());
- if (output + len >= bound)
- break;
- strcpy(output, pseudoFrames[i].label());
- output += len;
+ const char* label = pseudoFrames[i].label();
+ const char* dynamicString = pseudoFrames[i].getDynamicString();
+ size_t labelLength = strlen(label);
+ if (dynamicString) {
+ // Put the label, a space, and the dynamic string into output.
+ size_t dynamicStringLength = strlen(dynamicString);
+ if (output + labelLength + 1 + dynamicStringLength >= bound) {
+ break;
+ }
+ strcpy(output, label);
+ output += labelLength;
+ *output++ = ' ';
+ strcpy(output, dynamicString);
+ output += dynamicStringLength;
+ } else {
+ // Only put the label into output.
+ if (output + labelLength >= bound) {
+ break;
+ }
+ strcpy(output, label);
+ output += labelLength;
+ }
*output++ = '\0';
*output = '\0';
}
}
static void
locked_profiler_add_marker(PS::LockRef aLock, const char* aMarker,
ProfilerMarkerPayload* aPayload)
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -22,16 +22,17 @@
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "js/TypeDecls.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
+#include "nsString.h"
namespace mozilla {
class TimeStamp;
namespace dom {
class Promise;
} // namespace dom
@@ -61,30 +62,44 @@ using UniqueProfilerBacktrace =
// Use these for functions below that must be visible whether the profiler is
// enabled or not. When the profiler is disabled they are static inline
// functions (with a simple return value if they are non-void) that should be
// optimized away during compilation.
#define PROFILER_FUNC(decl, rv) static inline decl { return rv; }
#define PROFILER_FUNC_VOID(decl) static inline void decl {}
-// Insert a RAII in this scope to active a pseudo label. Any samples collected
-// in this scope will contain this annotation. For dynamic strings use
-// PROFILER_LABEL_PRINTF. Arguments must be string literals.
+// Insert an RAII object in this scope to enter a pseudo stack frame. Any
+// samples collected in this scope will contain this label in their pseudo
+// stack. The name_space and info arguments must be string literals.
+// Use PROFILER_LABEL_DYNAMIC if you want to add additional / dynamic
+// information to the pseudo stack frame.
#define PROFILER_LABEL(name_space, info, category) do {} while (0)
// Similar to PROFILER_LABEL, PROFILER_LABEL_FUNC will push/pop the enclosing
// functon name as the pseudostack label.
#define PROFILER_LABEL_FUNC(category) do {} while (0)
-// Format a dynamic string as a pseudo label. These labels will a considerable
-// storage size in the circular buffer compared to regular labels. This function
-// can be used to annotate custom information such as URL for the resource being
-// decoded or the size of the paint.
-#define PROFILER_LABEL_PRINTF(name_space, info, category, format, ...) do {} while (0)
+// Enter a pseudo stack frame in this scope and associate it with an
+// additional string.
+// This macro generates an RAII object. This RAII object stores the str
+// pointer in a field; it does not copy the string. This means that the string
+// you pass to this macro needs to live at least until the end of the current
+// scope.
+// If the profiler samples the current thread and walks the pseudo stack while
+// this RAII object is on the stack, it will copy the supplied string into the
+// profile buffer. So there's one string copy operation, and it happens at
+// sample time.
+// Compare this to the plain PROFILER_LABEL macro, which only accepts literal
+// strings: When the pseudo stack frames generated by PROFILER_LABEL are
+// sampled, no string copy needs to be made because the profile buffer can
+// just store the raw pointers to the literal strings. Consequently,
+// PROFILER_LABEL frames take up considerably less space in the profile buffer
+// than PROFILER_LABEL_DYNAMIC frames.
+#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) do {} while (0)
// Insert a marker in the profile timeline. This is useful to delimit something
// important happening such as the first paint. Unlike profiler_label that are
// only recorded if a sample is collected while it is active, marker will always
// be collected.
#define PROFILER_MARKER(info) do {} while (0)
#define PROFILER_MARKER_PAYLOAD(info, payload) do { mozilla::UniquePtr<ProfilerMarkerPayload> payloadDeletor(payload); } while (0)
@@ -95,17 +110,17 @@ using UniqueProfilerBacktrace =
// we want the class and function name but can't easily get that using preprocessor macros
// __func__ doesn't have the class name and __PRETTY_FUNCTION__ has the parameters
#define PROFILER_LABEL(name_space, info, category) MOZ_PLATFORM_TRACING(name_space "::" info) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__)
#define PROFILER_LABEL_FUNC(category) MOZ_PLATFORM_TRACING(SAMPLE_FUNCTION_NAME) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(SAMPLE_FUNCTION_NAME, category, __LINE__)
-#define PROFILER_LABEL_PRINTF(name_space, info, category, ...) MOZ_PLATFORM_TRACING(name_space "::" info) mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__, __VA_ARGS__)
+#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) MOZ_PLATFORM_TRACING(name_space "::" info) mozilla::SamplerStackFrameDynamicRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, category, __LINE__, str)
#define PROFILER_MARKER(info) profiler_add_marker(info)
#define PROFILER_MARKER_PAYLOAD(info, payload) profiler_add_marker(info, payload)
#endif // defined(MOZ_GECKO_PROFILER)
// These functions are defined whether the profiler is enabled or not.
@@ -338,27 +353,28 @@ extern ProfilerState* gPS;
# endif
#endif
// Returns a handle to pass on exit. This can check that we are popping the
// correct callstack. Operates the same whether the profiler is active or not.
static inline void*
profiler_call_enter(const char* aInfo,
js::ProfileEntry::Category aCategory,
- void *aFrameAddress, bool aCopy, uint32_t line)
+ void *aFrameAddress, bool aCopy, uint32_t line,
+ const char* aAnnotationString = nullptr)
{
// This function runs both on and off the main thread.
MOZ_RELEASE_ASSERT(gPS);
PseudoStack* stack = tlsPseudoStack.get();
if (!stack) {
return stack;
}
- stack->push(aInfo, aCategory, aFrameAddress, aCopy, line);
+ stack->push(aInfo, aCategory, aFrameAddress, aCopy, line, aAnnotationString);
// The handle is meant to support future changes but for now it is simply
// used to avoid having to call tlsPseudoStack.get() in profiler_call_exit().
return stack;
}
static inline void
profiler_call_exit(void* aHandle)
@@ -472,45 +488,51 @@ public:
~SamplerStackFrameRAII() {
profiler_call_exit(mHandle);
}
private:
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
void* mHandle;
};
-static const int SAMPLER_MAX_STRING = 128;
-class MOZ_RAII SamplerStackFramePrintfRAII {
+class MOZ_RAII SamplerStackFrameDynamicRAII {
public:
- // We only copy the strings at save time, so to take multiple parameters we'd
- // need to copy them then.
- SamplerStackFramePrintfRAII(const char *aInfo,
- js::ProfileEntry::Category aCategory, uint32_t line, const char *aFormat, ...)
- : mHandle(nullptr)
+ SamplerStackFrameDynamicRAII(const char* aInfo,
+ js::ProfileEntry::Category aCategory, uint32_t aLine,
+ const char* aDynamicString)
+ {
+ mHandle = Enter(aInfo, aCategory, aLine, aDynamicString);
+ }
+
+ // An alternative constructor that accepts an rvalue string and moves it
+ // into this object (without copying!).
+ SamplerStackFrameDynamicRAII(const char* aInfo,
+ js::ProfileEntry::Category aCategory, uint32_t aLine,
+ nsCString&& aDynamicString)
+ : mDynamicStorage(aDynamicString)
+ {
+ mHandle = Enter(aInfo, aCategory, aLine, mDynamicStorage.get());
+ }
+
+ ~SamplerStackFrameDynamicRAII() {
+ profiler_call_exit(mHandle);
+ }
+
+private:
+ void* Enter(const char* aInfo, js::ProfileEntry::Category aCategory,
+ uint32_t aLine, const char* aDynamicString)
{
if (profiler_is_active_and_not_in_privacy_mode()) {
- va_list args;
- va_start(args, aFormat);
- char buff[SAMPLER_MAX_STRING];
-
- // We have to use separate printfs because we're using the vargs.
- VsprintfLiteral(buff, aFormat, args);
- SprintfLiteral(mDest, "%s %s", aInfo, buff);
-
- mHandle = profiler_call_enter(mDest, aCategory, this, true, line);
- va_end(args);
+ return profiler_call_enter(aInfo, aCategory, this, true, aLine, aDynamicString);
} else {
- mHandle = profiler_call_enter(aInfo, aCategory, this, false, line);
+ return profiler_call_enter(aInfo, aCategory, this, false, aLine);
}
}
- ~SamplerStackFramePrintfRAII() {
- profiler_call_exit(mHandle);
- }
-private:
- char mDest[SAMPLER_MAX_STRING];
+
+ nsCString mDynamicStorage;
void* mHandle;
};
} // namespace mozilla
inline PseudoStack*
profiler_get_pseudo_stack(void)
{
--- a/tools/profiler/public/PseudoStack.h
+++ b/tools/profiler/public/PseudoStack.h
@@ -244,33 +244,35 @@ public:
// Unless the profiled thread was in the middle of changing the list when
// we interrupted it - in that case, accessList() will return null.
return mPendingMarkers.accessList();
}
void push(const char* aName, js::ProfileEntry::Category aCategory,
uint32_t line)
{
- push(aName, aCategory, nullptr, false, line);
+ push(aName, aCategory, nullptr, false, line, nullptr);
}
void push(const char* aName, js::ProfileEntry::Category aCategory,
- void* aStackAddress, bool aCopy, uint32_t line)
+ void* aStackAddress, bool aCopy, uint32_t line,
+ const char* aDynamicString)
{
if (size_t(mStackPointer) >= mozilla::ArrayLength(mStack)) {
mStackPointer++;
return;
}
volatile js::ProfileEntry& entry = mStack[mStackPointer];
// Make sure we increment the pointer after the name has been written such
// that mStack is always consistent.
entry.initCppFrame(aStackAddress, line);
entry.setLabel(aName);
+ entry.setDynamicString(aDynamicString);
MOZ_ASSERT(entry.flags() == js::ProfileEntry::IS_CPP_ENTRY);
entry.setCategory(aCategory);
// Track if mLabel needs a copy.
if (aCopy) {
entry.setFlag(js::ProfileEntry::FRAME_LABEL_COPY);
} else {
entry.unsetFlag(js::ProfileEntry::FRAME_LABEL_COPY);