123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 */
|