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"
44 struct CallableOffsets
;
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
59 enum class Unwind
{ True
, False
};
60 static constexpr uint32_t ColumnBit
= 1u << 31;
63 jit::JitActivation
* activation_
;
65 const CodeRange
* codeRange_
;
66 unsigned lineOrBytecode_
;
69 uint8_t* unwoundIonCallerFP_
;
70 jit::FrameType unwoundIonFrameType_
;
72 void** unwoundAddressOfReturnAddress_
;
73 uint8_t* resumePCinCurrentFrame_
;
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
; }
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.
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
127 ExitReason() : ExitReason(Fixed::None
) {}
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
) {
144 reason
.payload_
= payload
;
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
{
174 const CodeRange
* codeRange_
;
178 uint8_t* unwoundIonCallerFP_
;
179 ExitReason exitReason_
;
181 void initFromExitFP(const Frame
* fp
);
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
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
);
200 bool done() const { return !codeRange_
&& exitReason_
.isNone(); }
202 void* stackAddress() const {
204 return stackAddress_
;
206 uint8_t* unwoundIonCallerFP() const {
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.
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
);
269 #endif // wasm_frame_iter_h