Bug 1639153 - Part 4: Untie frame iteration from Frame::tls. r=lth
[gecko.git] / js / src / wasm / WasmFrameIter.h
blobdd32ec50f6b7952296b66cb8da1a3679ac076929
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:
4 * Copyright 2014 Mozilla Foundation
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #ifndef wasm_frame_iter_h
20 #define wasm_frame_iter_h
22 #include "js/ProfilingFrameIterator.h"
23 #include "js/TypeDecls.h"
24 #include "wasm/WasmTypes.h"
26 namespace js {
28 namespace jit {
29 class MacroAssembler;
30 struct Register;
31 class Label;
32 enum class FrameType;
33 } // namespace jit
35 namespace wasm {
37 class Code;
38 class CodeRange;
39 class DebugFrame;
40 class FuncTypeIdDesc;
41 class Instance;
42 class ModuleSegment;
44 struct CallableOffsets;
45 struct FuncOffsets;
46 class Frame;
48 using RegisterState = JS::ProfilingFrameIterator::RegisterState;
50 // Iterates over a linear group of wasm frames of a single wasm JitActivation,
51 // called synchronously from C++ in the wasm thread. It will stop at the first
52 // frame that is not of the same kind, or at the end of an activation.
54 // If you want to handle every kind of frames (including JS jit frames), use
55 // JitFrameIter.
57 class WasmFrameIter {
58 public:
59 enum class Unwind { True, False };
60 static constexpr uint32_t ColumnBit = 1u << 31;
62 private:
63 jit::JitActivation* activation_;
64 const Code* code_;
65 const CodeRange* codeRange_;
66 unsigned lineOrBytecode_;
67 Frame* fp_;
68 TlsData* tls_;
69 uint8_t* unwoundIonCallerFP_;
70 jit::FrameType unwoundIonFrameType_;
71 Unwind unwind_;
72 void** unwoundAddressOfReturnAddress_;
73 uint8_t* resumePCinCurrentFrame_;
75 void popFrame();
77 public:
78 // See comment above this class definition.
79 explicit WasmFrameIter(jit::JitActivation* activation, Frame* fp = nullptr);
80 const jit::JitActivation* activation() const { return activation_; }
81 void setUnwind(Unwind unwind) { unwind_ = unwind; }
82 void operator++();
83 bool done() const;
84 const char* filename() const;
85 const char16_t* displayURL() const;
86 bool mutedErrors() const;
87 JSAtom* functionDisplayAtom() const;
88 unsigned lineOrBytecode() const;
89 uint32_t funcIndex() const;
90 unsigned computeLine(uint32_t* column) const;
91 const CodeRange* codeRange() const { return codeRange_; }
92 Instance* instance() const;
93 void** unwoundAddressOfReturnAddress() const;
94 bool debugEnabled() const;
95 DebugFrame* debugFrame() const;
96 jit::FrameType unwoundIonFrameType() const;
97 uint8_t* unwoundIonCallerFP() const { return unwoundIonCallerFP_; }
98 Frame* frame() const { return fp_; }
99 TlsData* tls() const { return tls_; }
101 // Returns the address of the next instruction that will execute in this
102 // frame, once control returns to this frame.
103 uint8_t* resumePCinCurrentFrame() const;
106 enum class SymbolicAddress;
108 // An ExitReason describes the possible reasons for leaving compiled wasm
109 // code or the state of not having left compiled wasm code
110 // (ExitReason::None). It is either a known reason, or a enumeration to a native
111 // function that is used for better display in the profiler.
112 class ExitReason {
113 public:
114 enum class Fixed : uint32_t {
115 None, // default state, the pc is in wasm code
116 FakeInterpEntry, // slow-path entry call from C++ WasmCall()
117 ImportJit, // fast-path call directly into JIT code
118 ImportInterp, // slow-path call into C++ Invoke()
119 BuiltinNative, // fast-path call directly into native C++ code
120 Trap, // call to trap handler
121 DebugTrap // call to debug trap handler
124 private:
125 uint32_t payload_;
127 ExitReason() : ExitReason(Fixed::None) {}
129 public:
130 MOZ_IMPLICIT ExitReason(Fixed exitReason)
131 : payload_(0x0 | (uint32_t(exitReason) << 1)) {
132 MOZ_ASSERT(isFixed());
133 MOZ_ASSERT_IF(isNone(), payload_ == 0);
136 explicit ExitReason(SymbolicAddress sym)
137 : payload_(0x1 | (uint32_t(sym) << 1)) {
138 MOZ_ASSERT(uint32_t(sym) <= (UINT32_MAX << 1), "packing constraints");
139 MOZ_ASSERT(!isFixed());
142 static ExitReason Decode(uint32_t payload) {
143 ExitReason reason;
144 reason.payload_ = payload;
145 return reason;
148 static ExitReason None() { return ExitReason(ExitReason::Fixed::None); }
150 bool isFixed() const { return (payload_ & 0x1) == 0; }
151 bool isNone() const { return isFixed() && fixed() == Fixed::None; }
152 bool isNative() const {
153 return !isFixed() || fixed() == Fixed::BuiltinNative;
155 bool isInterpEntry() const {
156 return isFixed() && fixed() == Fixed::FakeInterpEntry;
159 uint32_t encode() const { return payload_; }
160 Fixed fixed() const {
161 MOZ_ASSERT(isFixed());
162 return Fixed(payload_ >> 1);
164 SymbolicAddress symbolic() const {
165 MOZ_ASSERT(!isFixed());
166 return SymbolicAddress(payload_ >> 1);
170 // Iterates over the frames of a single wasm JitActivation, given an
171 // asynchronously-profiled thread's state.
172 class ProfilingFrameIterator {
173 const Code* code_;
174 const CodeRange* codeRange_;
175 uint8_t* callerFP_;
176 void* callerPC_;
177 void* stackAddress_;
178 uint8_t* unwoundIonCallerFP_;
179 ExitReason exitReason_;
181 void initFromExitFP(const Frame* fp);
183 public:
184 ProfilingFrameIterator();
186 // Start unwinding at a non-innermost activation that has necessarily been
187 // exited from wasm code (and thus activation.hasWasmExitFP).
188 explicit ProfilingFrameIterator(const jit::JitActivation& activation);
190 // Start unwinding at a group of wasm frames after unwinding an inner group
191 // of JSJit frames.
192 explicit ProfilingFrameIterator(const Frame* fp);
194 // Start unwinding at the innermost activation given the register state when
195 // the thread was suspended.
196 ProfilingFrameIterator(const jit::JitActivation& activation,
197 const RegisterState& state);
199 void operator++();
200 bool done() const { return !codeRange_ && exitReason_.isNone(); }
202 void* stackAddress() const {
203 MOZ_ASSERT(!done());
204 return stackAddress_;
206 uint8_t* unwoundIonCallerFP() const {
207 MOZ_ASSERT(done());
208 return unwoundIonCallerFP_;
210 const char* label() const;
213 // Prologue/epilogue code generation
215 void SetExitFP(jit::MacroAssembler& masm, ExitReason reason,
216 jit::Register scratch);
217 void ClearExitFP(jit::MacroAssembler& masm, jit::Register scratch);
219 void GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed,
220 ExitReason reason, CallableOffsets* offsets);
221 void GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
222 ExitReason reason, CallableOffsets* offsets);
224 void GenerateJitExitPrologue(jit::MacroAssembler& masm, unsigned framePushed,
225 CallableOffsets* offsets);
226 void GenerateJitExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
227 CallableOffsets* offsets);
229 void GenerateJitEntryPrologue(jit::MacroAssembler& masm, Offsets* offsets);
231 void GenerateFunctionPrologue(jit::MacroAssembler& masm,
232 const FuncTypeIdDesc& funcTypeId,
233 const mozilla::Maybe<uint32_t>& tier1FuncIndex,
234 FuncOffsets* offsets);
235 void GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
236 FuncOffsets* offsets);
238 // Iterates through frames for either possible cross-instance call or an entry
239 // stub to obtain tls that corresponds to the passed fp.
240 TlsData* GetNearestEffectiveTls(Frame* fp);
242 // Describes register state and associated code at a given call frame.
244 struct UnwindState {
245 uint8_t* fp;
246 void* pc;
247 const Code* code;
248 const CodeRange* codeRange;
249 UnwindState() : fp(nullptr), pc(nullptr), code(nullptr), codeRange(nullptr) {}
252 // Ensures the register state at a call site is consistent: pc must be in the
253 // code range of the code described by fp. This prevents issues when using
254 // the values of pc/fp, especially at call sites boundaries, where the state
255 // hasn't fully transitioned from the caller's to the callee's.
257 // unwoundCaller is set to true if we were in a transitional state and had to
258 // rewind to the caller's frame instead of the current frame.
260 // Returns true if it was possible to get to a clear state, or false if the
261 // frame should be ignored.
263 bool StartUnwinding(const RegisterState& registers, UnwindState* unwindState,
264 bool* unwoundCaller);
266 } // namespace wasm
267 } // namespace js
269 #endif // wasm_frame_iter_h