Source code

Revision control

Other Tools

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
*
4
* Copyright 2014 Mozilla Foundation
5
*
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
9
*
11
*
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.
17
*/
18
19
#ifndef wasm_frame_iter_h
20
#define wasm_frame_iter_h
21
22
#include "js/ProfilingFrameIterator.h"
23
#include "js/TypeDecls.h"
24
#include "wasm/WasmTypes.h"
25
26
namespace js {
27
28
namespace jit {
29
class MacroAssembler;
30
struct Register;
31
class Label;
32
enum class FrameType;
33
} // namespace jit
34
35
namespace wasm {
36
37
class Code;
38
class CodeRange;
39
class DebugFrame;
40
class FuncTypeIdDesc;
41
class Instance;
42
class ModuleSegment;
43
44
struct CallableOffsets;
45
struct FuncOffsets;
46
struct Frame;
47
48
typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
49
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.
53
//
54
// If you want to handle every kind of frames (including JS jit frames), use
55
// JitFrameIter.
56
57
class WasmFrameIter {
58
public:
59
enum class Unwind { True, False };
60
static constexpr uint32_t ColumnBit = 1u << 31;
61
62
private:
63
jit::JitActivation* activation_;
64
const Code* code_;
65
const CodeRange* codeRange_;
66
unsigned lineOrBytecode_;
67
Frame* fp_;
68
uint8_t* unwoundIonCallerFP_;
69
jit::FrameType unwoundIonFrameType_;
70
Unwind unwind_;
71
void** unwoundAddressOfReturnAddress_;
72
uint8_t* resumePCinCurrentFrame_;
73
74
void popFrame();
75
76
public:
77
// See comment above this class definition.
78
explicit WasmFrameIter(jit::JitActivation* activation, Frame* fp = nullptr);
79
const jit::JitActivation* activation() const { return activation_; }
80
void setUnwind(Unwind unwind) { unwind_ = unwind; }
81
void operator++();
82
bool done() const;
83
const char* filename() const;
84
const char16_t* displayURL() const;
85
bool mutedErrors() const;
86
JSAtom* functionDisplayAtom() const;
87
unsigned lineOrBytecode() const;
88
uint32_t funcIndex() const;
89
unsigned computeLine(uint32_t* column) const;
90
const CodeRange* codeRange() const { return codeRange_; }
91
Instance* instance() const;
92
void** unwoundAddressOfReturnAddress() const;
93
bool debugEnabled() const;
94
DebugFrame* debugFrame() const;
95
jit::FrameType unwoundIonFrameType() const;
96
uint8_t* unwoundIonCallerFP() const { return unwoundIonCallerFP_; }
97
Frame* frame() const { return fp_; }
98
99
// Returns the address of the next instruction that will execute in this
100
// frame, once control returns to this frame.
101
uint8_t* resumePCinCurrentFrame() const;
102
};
103
104
enum class SymbolicAddress;
105
106
// An ExitReason describes the possible reasons for leaving compiled wasm
107
// code or the state of not having left compiled wasm code
108
// (ExitReason::None). It is either a known reason, or a enumeration to a native
109
// function that is used for better display in the profiler.
110
class ExitReason {
111
public:
112
enum class Fixed : uint32_t {
113
None, // default state, the pc is in wasm code
114
FakeInterpEntry, // slow-path entry call from C++ WasmCall()
115
ImportJit, // fast-path call directly into JIT code
116
ImportInterp, // slow-path call into C++ Invoke()
117
BuiltinNative, // fast-path call directly into native C++ code
118
Trap, // call to trap handler
119
DebugTrap // call to debug trap handler
120
};
121
122
private:
123
uint32_t payload_;
124
125
ExitReason() : ExitReason(Fixed::None) {}
126
127
public:
128
MOZ_IMPLICIT ExitReason(Fixed exitReason)
129
: payload_(0x0 | (uint32_t(exitReason) << 1)) {
130
MOZ_ASSERT(isFixed());
131
MOZ_ASSERT_IF(isNone(), payload_ == 0);
132
}
133
134
explicit ExitReason(SymbolicAddress sym)
135
: payload_(0x1 | (uint32_t(sym) << 1)) {
136
MOZ_ASSERT(uint32_t(sym) <= (UINT32_MAX << 1), "packing constraints");
137
MOZ_ASSERT(!isFixed());
138
}
139
140
static ExitReason Decode(uint32_t payload) {
141
ExitReason reason;
142
reason.payload_ = payload;
143
return reason;
144
}
145
146
static ExitReason None() { return ExitReason(ExitReason::Fixed::None); }
147
148
bool isFixed() const { return (payload_ & 0x1) == 0; }
149
bool isNone() const { return isFixed() && fixed() == Fixed::None; }
150
bool isNative() const {
151
return !isFixed() || fixed() == Fixed::BuiltinNative;
152
}
153
bool isInterpEntry() const {
154
return isFixed() && fixed() == Fixed::FakeInterpEntry;
155
}
156
157
uint32_t encode() const { return payload_; }
158
Fixed fixed() const {
159
MOZ_ASSERT(isFixed());
160
return Fixed(payload_ >> 1);
161
}
162
SymbolicAddress symbolic() const {
163
MOZ_ASSERT(!isFixed());
164
return SymbolicAddress(payload_ >> 1);
165
}
166
};
167
168
// Iterates over the frames of a single wasm JitActivation, given an
169
// asynchronously-profiled thread's state.
170
class ProfilingFrameIterator {
171
const Code* code_;
172
const CodeRange* codeRange_;
173
Frame* callerFP_;
174
void* callerPC_;
175
void* stackAddress_;
176
uint8_t* unwoundIonCallerFP_;
177
ExitReason exitReason_;
178
179
void initFromExitFP(const Frame* fp);
180
181
public:
182
ProfilingFrameIterator();
183
184
// Start unwinding at a non-innermost activation that has necessarily been
185
// exited from wasm code (and thus activation.hasWasmExitFP).
186
explicit ProfilingFrameIterator(const jit::JitActivation& activation);
187
188
// Start unwinding at a group of wasm frames after unwinding an inner group
189
// of JSJit frames.
190
explicit ProfilingFrameIterator(const Frame* fp);
191
192
// Start unwinding at the innermost activation given the register state when
193
// the thread was suspended.
194
ProfilingFrameIterator(const jit::JitActivation& activation,
195
const RegisterState& state);
196
197
void operator++();
198
bool done() const { return !codeRange_ && exitReason_.isNone(); }
199
200
void* stackAddress() const {
201
MOZ_ASSERT(!done());
202
return stackAddress_;
203
}
204
uint8_t* unwoundIonCallerFP() const {
205
MOZ_ASSERT(done());
206
return unwoundIonCallerFP_;
207
}
208
const char* label() const;
209
};
210
211
// Prologue/epilogue code generation
212
213
void SetExitFP(jit::MacroAssembler& masm, ExitReason reason,
214
jit::Register scratch);
215
void ClearExitFP(jit::MacroAssembler& masm, jit::Register scratch);
216
217
void GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed,
218
ExitReason reason, CallableOffsets* offsets);
219
void GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
220
ExitReason reason, CallableOffsets* offsets);
221
222
void GenerateJitExitPrologue(jit::MacroAssembler& masm, unsigned framePushed,
223
CallableOffsets* offsets);
224
void GenerateJitExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
225
CallableOffsets* offsets);
226
227
void GenerateJitEntryPrologue(jit::MacroAssembler& masm, Offsets* offsets);
228
229
void GenerateFunctionPrologue(jit::MacroAssembler& masm,
230
const FuncTypeIdDesc& funcTypeId,
231
const mozilla::Maybe<uint32_t>& tier1FuncIndex,
232
FuncOffsets* offsets);
233
void GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed,
234
FuncOffsets* offsets);
235
236
// Describes register state and associated code at a given call frame.
237
238
struct UnwindState {
239
Frame* fp;
240
void* pc;
241
const Code* code;
242
const CodeRange* codeRange;
243
UnwindState() : fp(nullptr), pc(nullptr), code(nullptr), codeRange(nullptr) {}
244
};
245
246
// Ensures the register state at a call site is consistent: pc must be in the
247
// code range of the code described by fp. This prevents issues when using
248
// the values of pc/fp, especially at call sites boundaries, where the state
249
// hasn't fully transitioned from the caller's to the callee's.
250
//
251
// unwoundCaller is set to true if we were in a transitional state and had to
252
// rewind to the caller's frame instead of the current frame.
253
//
254
// Returns true if it was possible to get to a clear state, or false if the
255
// frame should be ignored.
256
257
bool StartUnwinding(const RegisterState& registers, UnwindState* unwindState,
258
bool* unwoundCaller);
259
260
// Bit set as the lowest bit of a frame pointer, used in two different mutually
261
// exclusive situations:
262
// - either it's a low bit tag in a FramePointer value read from the
263
// Frame::callerFP of an inner wasm frame. This indicates the previous call
264
// frame has been set up by a JIT caller that directly called into a wasm
265
// function's body. This is only stored in Frame::callerFP for a wasm frame
266
// called from JIT code, and thus it can not appear in a JitActivation's
267
// exitFP.
268
// - or it's the low big tag set when exiting wasm code in JitActivation's
269
// exitFP.
270
271
constexpr uintptr_t ExitOrJitEntryFPTag = 0x1;
272
273
} // namespace wasm
274
} // namespace js
275
276
#endif // wasm_frame_iter_h