ProfilingStack.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sts=4 et sw=4 tw=99:
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #ifndef js_ProfilingStack_h
  7. #define js_ProfilingStack_h
  8. #include "jsbytecode.h"
  9. #include "jstypes.h"
  10. #include "js/TypeDecls.h"
  11. #include "js/Utility.h"
  12. struct JSRuntime;
  13. class JSTracer;
  14. namespace js {
  15. // A call stack can be specified to the JS engine such that all JS entry/exits
  16. // to functions push/pop an entry to/from the specified stack.
  17. //
  18. // For more detailed information, see vm/SPSProfiler.h.
  19. //
  20. class ProfileEntry
  21. {
  22. // All fields are marked volatile to prevent the compiler from re-ordering
  23. // instructions. Namely this sequence:
  24. //
  25. // entry[size] = ...;
  26. // size++;
  27. //
  28. // If the size modification were somehow reordered before the stores, then
  29. // if a sample were taken it would be examining bogus information.
  30. //
  31. // A ProfileEntry represents both a C++ profile entry and a JS one.
  32. // Descriptive string of this entry.
  33. const char * volatile string;
  34. // Stack pointer for non-JS entries, the script pointer otherwise.
  35. void * volatile spOrScript;
  36. // Line number for non-JS entries, the bytecode offset otherwise.
  37. int32_t volatile lineOrPcOffset;
  38. // General purpose storage describing this frame.
  39. uint32_t volatile flags_;
  40. public:
  41. // These traits are bit masks. Make sure they're powers of 2.
  42. enum Flags : uint32_t {
  43. // Indicate whether a profile entry represents a CPP frame. If not set,
  44. // a JS frame is assumed by default. You're not allowed to publicly
  45. // change the frame type. Instead, initialize the ProfileEntry as either
  46. // a JS or CPP frame with `initJsFrame` or `initCppFrame` respectively.
  47. IS_CPP_ENTRY = 0x01,
  48. // Indicate that copying the frame label is not necessary when taking a
  49. // sample of the pseudostack.
  50. FRAME_LABEL_COPY = 0x02,
  51. // This ProfileEntry is a dummy entry indicating the start of a run
  52. // of JS pseudostack entries.
  53. BEGIN_PSEUDO_JS = 0x04,
  54. // This flag is used to indicate that an interpreter JS entry has OSR-ed
  55. // into baseline.
  56. OSR = 0x08,
  57. // Union of all flags.
  58. ALL = IS_CPP_ENTRY|FRAME_LABEL_COPY|BEGIN_PSEUDO_JS|OSR,
  59. // Mask for removing all flags except the category information.
  60. CATEGORY_MASK = ~ALL
  61. };
  62. // Keep these in sync with devtools/client/performance/modules/categories.js
  63. enum class Category : uint32_t {
  64. OTHER = 0x10,
  65. CSS = 0x20,
  66. JS = 0x40,
  67. GC = 0x80,
  68. CC = 0x100,
  69. NETWORK = 0x200,
  70. GRAPHICS = 0x400,
  71. STORAGE = 0x800,
  72. EVENTS = 0x1000,
  73. FIRST = OTHER,
  74. LAST = EVENTS
  75. };
  76. static_assert((static_cast<int>(Category::FIRST) & Flags::ALL) == 0,
  77. "The category bitflags should not intersect with the other flags!");
  78. // All of these methods are marked with the 'volatile' keyword because SPS's
  79. // representation of the stack is stored such that all ProfileEntry
  80. // instances are volatile. These methods would not be available unless they
  81. // were marked as volatile as well.
  82. bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); }
  83. bool isJs() const volatile { return !isCpp(); }
  84. bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); }
  85. void setLabel(const char* aString) volatile { string = aString; }
  86. const char* label() const volatile { return string; }
  87. void initJsFrame(JSScript* aScript, jsbytecode* aPc) volatile {
  88. flags_ = 0;
  89. spOrScript = aScript;
  90. setPC(aPc);
  91. }
  92. void initCppFrame(void* aSp, uint32_t aLine) volatile {
  93. flags_ = IS_CPP_ENTRY;
  94. spOrScript = aSp;
  95. lineOrPcOffset = static_cast<int32_t>(aLine);
  96. }
  97. void setFlag(uint32_t flag) volatile {
  98. MOZ_ASSERT(flag != IS_CPP_ENTRY);
  99. flags_ |= flag;
  100. }
  101. void unsetFlag(uint32_t flag) volatile {
  102. MOZ_ASSERT(flag != IS_CPP_ENTRY);
  103. flags_ &= ~flag;
  104. }
  105. bool hasFlag(uint32_t flag) const volatile {
  106. return bool(flags_ & flag);
  107. }
  108. uint32_t flags() const volatile {
  109. return flags_;
  110. }
  111. uint32_t category() const volatile {
  112. return flags_ & CATEGORY_MASK;
  113. }
  114. void setCategory(Category c) volatile {
  115. MOZ_ASSERT(c >= Category::FIRST);
  116. MOZ_ASSERT(c <= Category::LAST);
  117. flags_ &= ~CATEGORY_MASK;
  118. setFlag(static_cast<uint32_t>(c));
  119. }
  120. void setOSR() volatile {
  121. MOZ_ASSERT(isJs());
  122. setFlag(OSR);
  123. }
  124. void unsetOSR() volatile {
  125. MOZ_ASSERT(isJs());
  126. unsetFlag(OSR);
  127. }
  128. bool isOSR() const volatile {
  129. return hasFlag(OSR);
  130. }
  131. void* stackAddress() const volatile {
  132. MOZ_ASSERT(!isJs());
  133. return spOrScript;
  134. }
  135. JSScript* script() const volatile;
  136. uint32_t line() const volatile {
  137. MOZ_ASSERT(!isJs());
  138. return static_cast<uint32_t>(lineOrPcOffset);
  139. }
  140. // Note that the pointer returned might be invalid.
  141. JSScript* rawScript() const volatile {
  142. MOZ_ASSERT(isJs());
  143. return (JSScript*)spOrScript;
  144. }
  145. // We can't know the layout of JSScript, so look in vm/SPSProfiler.cpp.
  146. JS_FRIEND_API(jsbytecode*) pc() const volatile;
  147. JS_FRIEND_API(void) setPC(jsbytecode* pc) volatile;
  148. void trace(JSTracer* trc);
  149. // The offset of a pc into a script's code can actually be 0, so to
  150. // signify a nullptr pc, use a -1 index. This is checked against in
  151. // pc() and setPC() to set/get the right pc.
  152. static const int32_t NullPCOffset = -1;
  153. static size_t offsetOfLabel() { return offsetof(ProfileEntry, string); }
  154. static size_t offsetOfSpOrScript() { return offsetof(ProfileEntry, spOrScript); }
  155. static size_t offsetOfLineOrPcOffset() { return offsetof(ProfileEntry, lineOrPcOffset); }
  156. static size_t offsetOfFlags() { return offsetof(ProfileEntry, flags_); }
  157. };
  158. JS_FRIEND_API(void)
  159. SetContextProfilingStack(JSContext* cx, ProfileEntry* stack, uint32_t* size,
  160. uint32_t max);
  161. JS_FRIEND_API(void)
  162. EnableContextProfilingStack(JSContext* cx, bool enabled);
  163. JS_FRIEND_API(void)
  164. RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*));
  165. JS_FRIEND_API(jsbytecode*)
  166. ProfilingGetPC(JSContext* cx, JSScript* script, void* ip);
  167. } // namespace js
  168. #endif /* js_ProfilingStack_h */