1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
7 #ifndef js_ProfilingFrameIterator_h
8 #define js_ProfilingFrameIterator_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
14 #include "js/TypeDecls.h"
15 #include "js/Utility.h"
21 class JSJitProfilingFrameIterator
;
22 class JitcodeGlobalEntry
;
25 class ProfilingFrameIterator
;
31 // This iterator can be used to walk the stack of a thread suspended at an
32 // arbitrary pc. To provide accurate results, profiling must have been enabled
33 // (via EnableRuntimeProfilingStack) before executing the callstack being
36 // Note that the caller must not do anything that could cause GC to happen while
37 // the iterator is alive, since this could invalidate Ion code and cause its
38 // contents to become out of date.
39 class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator
{
41 enum class Kind
: bool { JSJit
, Wasm
};
45 mozilla::Maybe
<uint64_t> samplePositionInProfilerBuffer_
;
46 js::Activation
* activation_
;
49 static const unsigned StorageSpace
= 8 * sizeof(void*);
50 alignas(void*) unsigned char storage_
[StorageSpace
];
52 void* storage() { return storage_
; }
53 const void* storage() const { return storage_
; }
55 js::wasm::ProfilingFrameIterator
& wasmIter() {
58 return *static_cast<js::wasm::ProfilingFrameIterator
*>(storage());
60 const js::wasm::ProfilingFrameIterator
& wasmIter() const {
63 return *static_cast<const js::wasm::ProfilingFrameIterator
*>(storage());
66 js::jit::JSJitProfilingFrameIterator
& jsJitIter() {
68 MOZ_ASSERT(isJSJit());
69 return *static_cast<js::jit::JSJitProfilingFrameIterator
*>(storage());
72 const js::jit::JSJitProfilingFrameIterator
& jsJitIter() const {
74 MOZ_ASSERT(isJSJit());
75 return *static_cast<const js::jit::JSJitProfilingFrameIterator
*>(storage());
82 struct RegisterState
{
83 RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {}
90 ProfilingFrameIterator(
91 JSContext
* cx
, const RegisterState
& state
,
92 const mozilla::Maybe
<uint64_t>& samplePositionInProfilerBuffer
=
94 ~ProfilingFrameIterator();
96 bool done() const { return !activation_
; }
98 // Assuming the stack grows down (we do), the return value:
99 // - always points into the stack
100 // - is weakly monotonically increasing (may be equal for successive frames)
101 // - will compare greater than newer native and psuedo-stack frame addresses
102 // and less than older native and psuedo-stack frame addresses
103 void* stackAddress() const;
106 Frame_BaselineInterpreter
,
116 void* returnAddress_
;
117 jsbytecode
* interpreterPC_
;
120 void* endStackAddress
;
122 JSScript
* interpreterScript
;
126 void* returnAddress() const {
127 MOZ_ASSERT(kind
!= Frame_BaselineInterpreter
);
128 return returnAddress_
;
130 jsbytecode
* interpreterPC() const {
131 MOZ_ASSERT(kind
== Frame_BaselineInterpreter
);
132 return interpreterPC_
;
134 } JS_HAZ_GC_INVALIDATED
;
137 bool isJSJit() const;
139 uint32_t extractStack(Frame
* frames
, uint32_t offset
, uint32_t end
) const;
141 mozilla::Maybe
<Frame
> getPhysicalFrameWithoutLabel() const;
144 mozilla::Maybe
<Frame
> getPhysicalFrameAndEntry(
145 js::jit::JitcodeGlobalEntry
* entry
) const;
147 void iteratorConstruct(const RegisterState
& state
);
148 void iteratorConstruct();
149 void iteratorDestroy();
151 } JS_HAZ_GC_INVALIDATED
;
153 JS_FRIEND_API
bool IsProfilingEnabledForContext(JSContext
* cx
);
156 * After each sample run, this method should be called with the current buffer
157 * position at which the buffer contents start. This will update the
158 * corresponding field on the JSRuntime.
160 * See the field |profilerSampleBufferRangeStart| on JSRuntime for documentation
161 * about what this value is used for.
163 JS_FRIEND_API
void SetJSContextProfilerSampleBufferRangeStart(
164 JSContext
* cx
, uint64_t rangeStart
);
166 class ProfiledFrameRange
;
168 // A handle to the underlying JitcodeGlobalEntry, so as to avoid repeated
169 // lookups on JitcodeGlobalTable.
170 class MOZ_STACK_CLASS ProfiledFrameHandle
{
171 friend class ProfiledFrameRange
;
174 js::jit::JitcodeGlobalEntry
& entry_
;
176 void* canonicalAddr_
;
180 ProfiledFrameHandle(JSRuntime
* rt
, js::jit::JitcodeGlobalEntry
& entry
,
181 void* addr
, const char* label
, uint32_t depth
);
184 const char* label() const { return label_
; }
185 uint32_t depth() const { return depth_
; }
186 void* canonicalAddress() const { return canonicalAddr_
; }
188 JS_PUBLIC_API
ProfilingFrameIterator::FrameKind
frameKind() const;
190 JS_PUBLIC_API
uint64_t realmID() const;
193 class ProfiledFrameRange
{
197 Iter(const ProfiledFrameRange
& range
, uint32_t index
)
198 : range_(range
), index_(index
) {}
200 JS_PUBLIC_API ProfiledFrameHandle
operator*() const;
202 // Provide the bare minimum of iterator methods that are needed for
203 // C++ ranged for loops.
208 bool operator==(const Iter
& rhs
) { return index_
== rhs
.index_
; }
209 bool operator!=(const Iter
& rhs
) { return !(*this == rhs
); }
212 const ProfiledFrameRange
& range_
;
216 Iter
begin() const { return Iter(*this, 0); }
217 Iter
end() const { return Iter(*this, depth_
); }
220 friend JS_PUBLIC_API ProfiledFrameRange
GetProfiledFrames(JSContext
* cx
,
223 ProfiledFrameRange(JSRuntime
* rt
, void* addr
,
224 js::jit::JitcodeGlobalEntry
* entry
)
225 : rt_(rt
), addr_(addr
), entry_(entry
), depth_(0) {}
229 js::jit::JitcodeGlobalEntry
* entry_
;
230 // Assume maximum inlining depth is <64
231 const char* labels_
[64];
235 // Returns a range that can be iterated over using C++ ranged for loops.
236 JS_PUBLIC_API ProfiledFrameRange
GetProfiledFrames(JSContext
* cx
, void* addr
);
240 #endif /* js_ProfilingFrameIterator_h */