summaryrefslogtreecommitdiffstats
path: root/js/public/ProfilingStack.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/public/ProfilingStack.h')
-rw-r--r--js/public/ProfilingStack.h208
1 files changed, 208 insertions, 0 deletions
diff --git a/js/public/ProfilingStack.h b/js/public/ProfilingStack.h
new file mode 100644
index 000000000..aeed349e8
--- /dev/null
+++ b/js/public/ProfilingStack.h
@@ -0,0 +1,208 @@
+/* -*- 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 js_ProfilingStack_h
+#define js_ProfilingStack_h
+
+#include "jsbytecode.h"
+#include "jstypes.h"
+#include "js/TypeDecls.h"
+
+#include "js/Utility.h"
+
+struct JSRuntime;
+class JSTracer;
+
+namespace js {
+
+// A call stack can be specified to the JS engine such that all JS entry/exits
+// to functions push/pop an entry to/from the specified stack.
+//
+// For more detailed information, see vm/SPSProfiler.h.
+//
+class ProfileEntry
+{
+ // All fields are marked volatile to prevent the compiler from re-ordering
+ // instructions. Namely this sequence:
+ //
+ // 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.
+ const char * volatile string;
+
+ // 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_;
+
+ public:
+ // 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.
+ 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.
+ OSR = 0x08,
+
+ // Union of all flags.
+ ALL = IS_CPP_ENTRY|FRAME_LABEL_COPY|BEGIN_PSEUDO_JS|OSR,
+
+ // Mask for removing all flags except the category information.
+ CATEGORY_MASK = ~ALL
+ };
+
+ // Keep these in sync with devtools/client/performance/modules/categories.js
+ enum class Category : uint32_t {
+ OTHER = 0x10,
+ CSS = 0x20,
+ JS = 0x40,
+ GC = 0x80,
+ CC = 0x100,
+ NETWORK = 0x200,
+ GRAPHICS = 0x400,
+ STORAGE = 0x800,
+ EVENTS = 0x1000,
+
+ FIRST = OTHER,
+ LAST = EVENTS
+ };
+
+ static_assert((static_cast<int>(Category::FIRST) & Flags::ALL) == 0,
+ "The category bitflags should not intersect with the other flags!");
+
+ // All of these methods are marked with the 'volatile' keyword because SPS's
+ // representation of the stack is stored such that all ProfileEntry
+ // instances are volatile. These methods would not be available unless they
+ // were marked as volatile as well.
+
+ 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 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;
+ lineOrPcOffset = static_cast<int32_t>(aLine);
+ }
+
+ void setFlag(uint32_t flag) volatile {
+ MOZ_ASSERT(flag != IS_CPP_ENTRY);
+ flags_ |= flag;
+ }
+ void unsetFlag(uint32_t flag) volatile {
+ MOZ_ASSERT(flag != IS_CPP_ENTRY);
+ flags_ &= ~flag;
+ }
+ bool hasFlag(uint32_t flag) const volatile {
+ return bool(flags_ & flag);
+ }
+
+ uint32_t flags() const volatile {
+ return flags_;
+ }
+
+ uint32_t category() const volatile {
+ return flags_ & CATEGORY_MASK;
+ }
+ void setCategory(Category c) volatile {
+ MOZ_ASSERT(c >= Category::FIRST);
+ MOZ_ASSERT(c <= Category::LAST);
+ flags_ &= ~CATEGORY_MASK;
+ setFlag(static_cast<uint32_t>(c));
+ }
+
+ void setOSR() volatile {
+ MOZ_ASSERT(isJs());
+ setFlag(OSR);
+ }
+ void unsetOSR() volatile {
+ MOZ_ASSERT(isJs());
+ unsetFlag(OSR);
+ }
+ bool isOSR() const volatile {
+ return hasFlag(OSR);
+ }
+
+ void* stackAddress() const volatile {
+ MOZ_ASSERT(!isJs());
+ return spOrScript;
+ }
+ JS_PUBLIC_API(JSScript*) script() const volatile;
+ uint32_t line() const volatile {
+ MOZ_ASSERT(!isJs());
+ return static_cast<uint32_t>(lineOrPcOffset);
+ }
+
+ // Note that the pointer returned might be invalid.
+ JSScript* rawScript() const volatile {
+ MOZ_ASSERT(isJs());
+ return (JSScript*)spOrScript;
+ }
+
+ // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
+ JS_FRIEND_API(jsbytecode*) pc() const volatile;
+ JS_FRIEND_API(void) setPC(jsbytecode* pc) volatile;
+
+ void trace(JSTracer* trc);
+
+ // The offset of a pc into a script's code can actually be 0, so to
+ // signify a nullptr pc, use a -1 index. This is checked against in
+ // pc() and setPC() to set/get the right pc.
+ static const int32_t NullPCOffset = -1;
+
+ static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); }
+ static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); }
+ static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); }
+ static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); }
+};
+
+JS_FRIEND_API(void)
+SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size,
+ uint32_t max);
+
+JS_FRIEND_API(void)
+EnableContextProfilingStack(JSContext* cx, bool enabled);
+
+JS_FRIEND_API(void)
+RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*));
+
+JS_FRIEND_API(jsbytecode*)
+ProfilingGetPC(JSContext* cx, JSScript* script, void* ip);
+
+} // namespace js
+
+#endif /* js_ProfilingStack_h */