Line data Source code
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 :
7 : #ifndef js_ProfilingFrameIterator_h
8 : #define js_ProfilingFrameIterator_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/Maybe.h"
12 :
13 : #include "jsbytecode.h"
14 : #include "js/GCAPI.h"
15 : #include "js/TypeDecls.h"
16 : #include "js/Utility.h"
17 :
18 : struct JSContext;
19 : struct JSRuntime;
20 : class JSScript;
21 :
22 : namespace js {
23 : class Activation;
24 : namespace jit {
25 : class JitActivation;
26 : class JitProfilingFrameIterator;
27 : class JitcodeGlobalEntry;
28 : } // namespace jit
29 : namespace wasm {
30 : class ProfilingFrameIterator;
31 : } // namespace wasm
32 : } // namespace js
33 :
34 : namespace JS {
35 :
36 : struct ForEachTrackedOptimizationAttemptOp;
37 : struct ForEachTrackedOptimizationTypeInfoOp;
38 :
39 : // This iterator can be used to walk the stack of a thread suspended at an
40 : // arbitrary pc. To provide accurate results, profiling must have been enabled
41 : // (via EnableRuntimeProfilingStack) before executing the callstack being
42 : // unwound.
43 : //
44 : // Note that the caller must not do anything that could cause GC to happen while
45 : // the iterator is alive, since this could invalidate Ion code and cause its
46 : // contents to become out of date.
47 : class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
48 : {
49 : JSContext* cx_;
50 : uint32_t sampleBufferGen_;
51 : js::Activation* activation_;
52 :
53 : static const unsigned StorageSpace = 8 * sizeof(void*);
54 : alignas(void*) unsigned char storage_[StorageSpace];
55 :
56 0 : void* storage() { return storage_; }
57 0 : const void* storage() const { return storage_; }
58 :
59 0 : js::wasm::ProfilingFrameIterator& wasmIter() {
60 0 : MOZ_ASSERT(!done());
61 0 : MOZ_ASSERT(isWasm());
62 0 : return *static_cast<js::wasm::ProfilingFrameIterator*>(storage());
63 : }
64 0 : const js::wasm::ProfilingFrameIterator& wasmIter() const {
65 0 : MOZ_ASSERT(!done());
66 0 : MOZ_ASSERT(isWasm());
67 0 : return *static_cast<const js::wasm::ProfilingFrameIterator*>(storage());
68 : }
69 :
70 0 : js::jit::JitProfilingFrameIterator& jitIter() {
71 0 : MOZ_ASSERT(!done());
72 0 : MOZ_ASSERT(isJit());
73 0 : return *static_cast<js::jit::JitProfilingFrameIterator*>(storage());
74 : }
75 :
76 0 : const js::jit::JitProfilingFrameIterator& jitIter() const {
77 0 : MOZ_ASSERT(!done());
78 0 : MOZ_ASSERT(isJit());
79 0 : return *static_cast<const js::jit::JitProfilingFrameIterator*>(storage());
80 : }
81 :
82 : void settle();
83 :
84 0 : bool hasSampleBufferGen() const {
85 0 : return sampleBufferGen_ != UINT32_MAX;
86 : }
87 :
88 : public:
89 : struct RegisterState
90 : {
91 0 : RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {}
92 : void* pc;
93 : void* sp;
94 : void* fp;
95 : void* lr;
96 : };
97 :
98 : ProfilingFrameIterator(JSContext* cx, const RegisterState& state,
99 : uint32_t sampleBufferGen = UINT32_MAX);
100 : ~ProfilingFrameIterator();
101 : void operator++();
102 0 : bool done() const { return !activation_; }
103 :
104 : // Assuming the stack grows down (we do), the return value:
105 : // - always points into the stack
106 : // - is weakly monotonically increasing (may be equal for successive frames)
107 : // - will compare greater than newer native and psuedo-stack frame addresses
108 : // and less than older native and psuedo-stack frame addresses
109 : void* stackAddress() const;
110 :
111 : enum FrameKind
112 : {
113 : Frame_Baseline,
114 : Frame_Ion,
115 : Frame_Wasm
116 : };
117 :
118 : struct Frame
119 : {
120 : FrameKind kind;
121 : void* stackAddress;
122 : void* returnAddress;
123 : void* activation;
124 : const char* label;
125 : } JS_HAZ_GC_INVALIDATED;
126 :
127 : bool isWasm() const;
128 : bool isJit() const;
129 :
130 : uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const;
131 :
132 : mozilla::Maybe<Frame> getPhysicalFrameWithoutLabel() const;
133 :
134 : private:
135 : mozilla::Maybe<Frame> getPhysicalFrameAndEntry(js::jit::JitcodeGlobalEntry* entry) const;
136 :
137 : void iteratorConstruct(const RegisterState& state);
138 : void iteratorConstruct();
139 : void iteratorDestroy();
140 : bool iteratorDone();
141 : } JS_HAZ_GC_INVALIDATED;
142 :
143 : JS_FRIEND_API(bool)
144 : IsProfilingEnabledForContext(JSContext* cx);
145 :
146 : /**
147 : * After each sample run, this method should be called with the latest sample
148 : * buffer generation, and the lapCount. It will update corresponding fields on
149 : * JSRuntime.
150 : *
151 : * See fields |profilerSampleBufferGen|, |profilerSampleBufferLapCount| on
152 : * JSRuntime for documentation about what these values are used for.
153 : */
154 : JS_FRIEND_API(void)
155 : UpdateJSContextProfilerSampleBufferGen(JSContext* cx, uint32_t generation,
156 : uint32_t lapCount);
157 :
158 0 : struct ForEachProfiledFrameOp
159 : {
160 : // A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated
161 : // lookups on JitcodeGlobalTable.
162 0 : class MOZ_STACK_CLASS FrameHandle
163 : {
164 : friend JS_PUBLIC_API(void) ForEachProfiledFrame(JSContext* cx, void* addr,
165 : ForEachProfiledFrameOp& op);
166 :
167 : JSRuntime* rt_;
168 : js::jit::JitcodeGlobalEntry& entry_;
169 : void* addr_;
170 : void* canonicalAddr_;
171 : const char* label_;
172 : uint32_t depth_;
173 : mozilla::Maybe<uint8_t> optsIndex_;
174 :
175 : FrameHandle(JSRuntime* rt, js::jit::JitcodeGlobalEntry& entry, void* addr,
176 : const char* label, uint32_t depth);
177 :
178 : void updateHasTrackedOptimizations();
179 :
180 : public:
181 0 : const char* label() const { return label_; }
182 0 : uint32_t depth() const { return depth_; }
183 0 : bool hasTrackedOptimizations() const { return optsIndex_.isSome(); }
184 0 : void* canonicalAddress() const { return canonicalAddr_; }
185 :
186 : JS_PUBLIC_API(ProfilingFrameIterator::FrameKind) frameKind() const;
187 : JS_PUBLIC_API(void) forEachOptimizationAttempt(ForEachTrackedOptimizationAttemptOp& op,
188 : JSScript** scriptOut,
189 : jsbytecode** pcOut) const;
190 :
191 : JS_PUBLIC_API(void)
192 : forEachOptimizationTypeInfo(ForEachTrackedOptimizationTypeInfoOp& op) const;
193 : };
194 :
195 : // Called once per frame.
196 : virtual void operator()(const FrameHandle& frame) = 0;
197 : };
198 :
199 : JS_PUBLIC_API(void)
200 : ForEachProfiledFrame(JSContext* cx, void* addr, ForEachProfiledFrameOp& op);
201 :
202 : } // namespace JS
203 :
204 : #endif /* js_ProfilingFrameIterator_h */
|