ProfilingFrameIterator.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef js_ProfilingFrameIterator_h
  6. #define js_ProfilingFrameIterator_h
  7. #include "mozilla/Alignment.h"
  8. #include "mozilla/Maybe.h"
  9. #include "jsbytecode.h"
  10. #include "js/GCAPI.h"
  11. #include "js/TypeDecls.h"
  12. #include "js/Utility.h"
  13. struct JSContext;
  14. struct JSRuntime;
  15. class JSScript;
  16. namespace js {
  17. class Activation;
  18. namespace jit {
  19. class JitActivation;
  20. class JitProfilingFrameIterator;
  21. class JitcodeGlobalEntry;
  22. } // namespace jit
  23. namespace wasm {
  24. class ProfilingFrameIterator;
  25. } // namespace wasm
  26. } // namespace js
  27. namespace JS {
  28. struct ForEachTrackedOptimizationAttemptOp;
  29. struct ForEachTrackedOptimizationTypeInfoOp;
  30. // This iterator can be used to walk the stack of a thread suspended at an
  31. // arbitrary pc. To provide acurate results, profiling must have been enabled
  32. // (via EnableRuntimeProfilingStack) before executing the callstack being
  33. // unwound.
  34. //
  35. // Note that the caller must not do anything that could cause GC to happen while
  36. // the iterator is alive, since this could invalidate Ion code and cause its
  37. // contents to become out of date.
  38. class JS_PUBLIC_API(ProfilingFrameIterator)
  39. {
  40. JSRuntime* rt_;
  41. uint32_t sampleBufferGen_;
  42. js::Activation* activation_;
  43. // When moving past a JitActivation, we need to save the prevJitTop
  44. // from it to use as the exit-frame pointer when the next caller jit
  45. // activation (if any) comes around.
  46. void* savedPrevJitTop_;
  47. JS::AutoCheckCannotGC nogc_;
  48. static const unsigned StorageSpace = 8 * sizeof(void*);
  49. mozilla::AlignedStorage<StorageSpace> storage_;
  50. js::wasm::ProfilingFrameIterator& wasmIter() {
  51. MOZ_ASSERT(!done());
  52. MOZ_ASSERT(isWasm());
  53. return *reinterpret_cast<js::wasm::ProfilingFrameIterator*>(storage_.addr());
  54. }
  55. const js::wasm::ProfilingFrameIterator& wasmIter() const {
  56. MOZ_ASSERT(!done());
  57. MOZ_ASSERT(isWasm());
  58. return *reinterpret_cast<const js::wasm::ProfilingFrameIterator*>(storage_.addr());
  59. }
  60. js::jit::JitProfilingFrameIterator& jitIter() {
  61. MOZ_ASSERT(!done());
  62. MOZ_ASSERT(isJit());
  63. return *reinterpret_cast<js::jit::JitProfilingFrameIterator*>(storage_.addr());
  64. }
  65. const js::jit::JitProfilingFrameIterator& jitIter() const {
  66. MOZ_ASSERT(!done());
  67. MOZ_ASSERT(isJit());
  68. return *reinterpret_cast<const js::jit::JitProfilingFrameIterator*>(storage_.addr());
  69. }
  70. void settle();
  71. bool hasSampleBufferGen() const {
  72. return sampleBufferGen_ != UINT32_MAX;
  73. }
  74. public:
  75. struct RegisterState
  76. {
  77. RegisterState() : pc(nullptr), sp(nullptr), lr(nullptr) {}
  78. void* pc;
  79. void* sp;
  80. void* lr;
  81. };
  82. ProfilingFrameIterator(JSContext* cx, const RegisterState& state,
  83. uint32_t sampleBufferGen = UINT32_MAX);
  84. ~ProfilingFrameIterator();
  85. void operator++();
  86. bool done() const { return !activation_; }
  87. // Assuming the stack grows down (we do), the return value:
  88. // - always points into the stack
  89. // - is weakly monotonically increasing (may be equal for successive frames)
  90. // - will compare greater than newer native and psuedo-stack frame addresses
  91. // and less than older native and psuedo-stack frame addresses
  92. void* stackAddress() const;
  93. enum FrameKind
  94. {
  95. Frame_Baseline,
  96. Frame_Ion,
  97. Frame_Wasm
  98. };
  99. struct Frame
  100. {
  101. FrameKind kind;
  102. void* stackAddress;
  103. void* returnAddress;
  104. void* activation;
  105. UniqueChars label;
  106. };
  107. bool isWasm() const;
  108. bool isJit() const;
  109. uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const;
  110. mozilla::Maybe<Frame> getPhysicalFrameWithoutLabel() const;
  111. private:
  112. mozilla::Maybe<Frame> getPhysicalFrameAndEntry(js::jit::JitcodeGlobalEntry* entry) const;
  113. void iteratorConstruct(const RegisterState& state);
  114. void iteratorConstruct();
  115. void iteratorDestroy();
  116. bool iteratorDone();
  117. };
  118. JS_FRIEND_API(bool)
  119. IsProfilingEnabledForContext(JSContext* cx);
  120. /**
  121. * After each sample run, this method should be called with the latest sample
  122. * buffer generation, and the lapCount. It will update corresponding fields on
  123. * JSRuntime.
  124. *
  125. * See fields |profilerSampleBufferGen|, |profilerSampleBufferLapCount| on
  126. * JSRuntime for documentation about what these values are used for.
  127. */
  128. JS_FRIEND_API(void)
  129. UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation,
  130. uint32_t lapCount);
  131. struct ForEachProfiledFrameOp
  132. {
  133. // A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated
  134. // lookups on JitcodeGlobalTable.
  135. class MOZ_STACK_CLASS FrameHandle
  136. {
  137. friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr,
  138. ForEachProfiledFrameOp& op);
  139. JSRuntime* rt_;
  140. js::jit::JitcodeGlobalEntry& entry_;
  141. void* addr_;
  142. void* canonicalAddr_;
  143. const char* label_;
  144. uint32_t depth_;
  145. mozilla::Maybe<uint8_t> optsIndex_;
  146. FrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, void* addr,
  147. const char* label, uint32_t depth);
  148. void updateHasTrackedOptimizations();
  149. public:
  150. const char* label() const { return label_; }
  151. uint32_t depth() const { return depth_; }
  152. bool hasTrackedOptimizations() const { return optsIndex_.isSome(); }
  153. void* canonicalAddress() const { return canonicalAddr_; }
  154. JS_PUBLIC_API(ProfilingFrameIterator::FrameKind) frameKind() const;
  155. JS_PUBLIC_API(void) forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op,
  156. JSScript** scriptOut,
  157. jsbytecode** pcOut) const;
  158. JS_PUBLIC_API(void)
  159. forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const;
  160. };
  161. // Called once per frame.
  162. virtual void operator()(const FrameHandle& frame) = 0;
  163. };
  164. JS_PUBLIC_API(void)
  165. ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op);
  166. } // namespace JS
  167. #endif /* js_ProfilingFrameIterator_h */