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 : *
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 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
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_iterator_h
20 : #define wasm_frame_iterator_h
21 :
22 : #include "js/ProfilingFrameIterator.h"
23 :
24 : class JSAtom;
25 :
26 : namespace js {
27 :
28 : class WasmActivation;
29 : namespace jit { class MacroAssembler; }
30 :
31 : namespace wasm {
32 :
33 : class CallSite;
34 : class Code;
35 : class CodeRange;
36 : class DebugFrame;
37 : class DebugState;
38 : class Instance;
39 : class SigIdDesc;
40 : struct Frame;
41 : struct FuncOffsets;
42 : struct CallableOffsets;
43 :
44 : // Iterates over the frames of a single WasmActivation, called synchronously
45 : // from C++ in the thread of the asm.js.
46 : //
47 : // The one exception is that this iterator may be called from the interrupt
48 : // callback which may be called asynchronously from asm.js code; in this case,
49 : // the backtrace may not be correct. That being said, we try our best printing
50 : // an informative message to the user and at least the name of the innermost
51 : // function stack frame.
52 : class FrameIterator
53 : {
54 : public:
55 : enum class Unwind { True, False };
56 :
57 : private:
58 : WasmActivation* activation_;
59 : const Code* code_;
60 : const CallSite* callsite_;
61 : const CodeRange* codeRange_;
62 : Frame* fp_;
63 : Unwind unwind_;
64 : void** unwoundAddressOfReturnAddress_;
65 :
66 : void popFrame();
67 :
68 : public:
69 : explicit FrameIterator();
70 : explicit FrameIterator(WasmActivation* activation, Unwind unwind = Unwind::False);
71 : void operator++();
72 : bool done() const;
73 : const char* filename() const;
74 : const char16_t* displayURL() const;
75 : bool mutedErrors() const;
76 : JSAtom* functionDisplayAtom() const;
77 : unsigned lineOrBytecode() const;
78 : const CodeRange* codeRange() const { return codeRange_; }
79 : Instance* instance() const;
80 : void** unwoundAddressOfReturnAddress() const;
81 : bool debugEnabled() const;
82 : DebugFrame* debugFrame() const;
83 : const CallSite* debugTrapCallsite() const;
84 : };
85 :
86 : enum class SymbolicAddress;
87 :
88 : // An ExitReason describes the possible reasons for leaving compiled wasm
89 : // code or the state of not having left compiled wasm code
90 : // (ExitReason::None). It is either a known reason, or a enumeration to a native
91 : // function that is used for better display in the profiler.
92 : class ExitReason
93 : {
94 : uint32_t payload_;
95 :
96 0 : ExitReason() {}
97 :
98 : public:
99 : enum class Fixed : uint32_t
100 : {
101 : None, // default state, the pc is in wasm code
102 : ImportJit, // fast-path call directly into JIT code
103 : ImportInterp, // slow-path call into C++ Invoke()
104 : BuiltinNative, // fast-path call directly into native C++ code
105 : Trap, // call to trap handler for the trap in WasmActivation::trap
106 : DebugTrap // call to debug trap handler
107 : };
108 :
109 0 : MOZ_IMPLICIT ExitReason(Fixed exitReason)
110 0 : : payload_(0x0 | (uint32_t(exitReason) << 1))
111 : {
112 0 : MOZ_ASSERT(isFixed());
113 0 : }
114 :
115 0 : explicit ExitReason(SymbolicAddress sym)
116 0 : : payload_(0x1 | (uint32_t(sym) << 1))
117 : {
118 0 : MOZ_ASSERT(uint32_t(sym) <= (UINT32_MAX << 1), "packing constraints");
119 0 : MOZ_ASSERT(!isFixed());
120 0 : }
121 :
122 0 : static ExitReason Decode(uint32_t payload) {
123 0 : ExitReason reason;
124 0 : reason.payload_ = payload;
125 0 : return reason;
126 : }
127 :
128 0 : static ExitReason None() { return ExitReason(ExitReason::Fixed::None); }
129 :
130 0 : bool isFixed() const { return (payload_ & 0x1) == 0; }
131 0 : bool isNone() const { return isFixed() && fixed() == Fixed::None; }
132 0 : bool isNative() const { return !isFixed() || fixed() == Fixed::BuiltinNative; }
133 :
134 0 : uint32_t encode() const {
135 0 : return payload_;
136 : }
137 0 : Fixed fixed() const {
138 0 : MOZ_ASSERT(isFixed());
139 0 : return Fixed(payload_ >> 1);
140 : }
141 0 : SymbolicAddress symbolic() const {
142 0 : MOZ_ASSERT(!isFixed());
143 0 : return SymbolicAddress(payload_ >> 1);
144 : }
145 : };
146 :
147 : // Iterates over the frames of a single WasmActivation, given an
148 : // asynchronously-interrupted thread's state.
149 : class ProfilingFrameIterator
150 : {
151 : const WasmActivation* activation_;
152 : const Code* code_;
153 : const CodeRange* codeRange_;
154 : Frame* callerFP_;
155 : void* callerPC_;
156 : void* stackAddress_;
157 : ExitReason exitReason_;
158 :
159 : void initFromExitFP();
160 :
161 : public:
162 : ProfilingFrameIterator();
163 : explicit ProfilingFrameIterator(const WasmActivation& activation);
164 : ProfilingFrameIterator(const WasmActivation& activation,
165 : const JS::ProfilingFrameIterator::RegisterState& state);
166 : void operator++();
167 0 : bool done() const { return !codeRange_; }
168 :
169 0 : void* stackAddress() const { MOZ_ASSERT(!done()); return stackAddress_; }
170 : const char* label() const;
171 : };
172 :
173 : // Prologue/epilogue code generation
174 :
175 : void
176 : GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
177 : CallableOffsets* offsets);
178 : void
179 : GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
180 : CallableOffsets* offsets);
181 : void
182 : GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
183 : FuncOffsets* offsets);
184 : void
185 : GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
186 :
187 : // Mark all instance objects live on the stack.
188 :
189 : void
190 : TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
191 :
192 : // Given a fault at pc with register fp, return the faulting instance if there
193 : // is such a plausible instance, and otherwise null.
194 :
195 : Instance*
196 : LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp);
197 :
198 : // If the innermost (active) Activation is a WasmActivation, return it.
199 :
200 : WasmActivation*
201 : ActivationIfInnermost(JSContext* cx);
202 :
203 : // Return whether the given PC is in wasm code.
204 :
205 : bool
206 : InCompiledCode(void* pc);
207 :
208 : // Describes register state and associated code at a given call frame.
209 :
210 : struct UnwindState
211 : {
212 : Frame* fp;
213 : void* pc;
214 : const Code* code;
215 : const CodeRange* codeRange;
216 0 : UnwindState() : fp(nullptr), pc(nullptr), code(nullptr), codeRange(nullptr) {}
217 : };
218 :
219 : typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
220 :
221 : // Ensures the register state at a call site is consistent: pc must be in the
222 : // code range of the code described by fp. This prevents issues when using
223 : // the values of pc/fp, especially at call sites boundaries, where the state
224 : // hasn't fully transitioned from the caller's to the callee's.
225 : //
226 : // unwoundCaller is set to true if we were in a transitional state and had to
227 : // rewind to the caller's frame instead of the current frame.
228 : //
229 : // Returns true if it was possible to get to a clear state, or false if the
230 : // frame should be ignored.
231 :
232 : bool
233 : StartUnwinding(const WasmActivation& activation, const RegisterState& registers,
234 : UnwindState* unwindState, bool* unwoundCaller);
235 :
236 : } // namespace wasm
237 : } // namespace js
238 :
239 : #endif // wasm_frame_iterator_h
|