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 vm_JitActivation_h
8 #define vm_JitActivation_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Atomics.h" // mozilla::Atomic, mozilla::Relaxed
12 #include "mozilla/Maybe.h" // mozilla::Maybe
14 #include <stddef.h> // size_t
15 #include <stdint.h> // uint8_t, uint32_t, uintptr_t
17 #include "jstypes.h" // JS_PUBLIC_API
19 #include "jit/IonTypes.h" // CHECK_OSIPOINT_REGISTERS
20 #include "jit/JSJitFrameIter.h" // js::jit::{JSJitFrameIter,RInstructionResults}
21 #ifdef CHECK_OSIPOINT_REGISTERS
22 # include "jit/Registers.h" // js::jit::RegisterDump
24 #include "jit/RematerializedFrame.h" // js::jit::RematerializedFrame
25 #include "js/GCVector.h" // JS::GCVector
26 #include "js/HashTable.h" // js::HashMap
27 #include "js/UniquePtr.h" // js::UniquePtr
28 #include "vm/Activation.h" // js::Activation
29 #include "wasm/WasmCodegenTypes.h" // js::wasm::TrapData
30 #include "wasm/WasmConstants.h" // js::wasm::Trap
31 #include "wasm/WasmFrame.h" // js::wasm::Frame
32 #include "wasm/WasmFrameIter.h" // js::wasm::{ExitReason,RegisterState,WasmFrameIter}
34 struct JS_PUBLIC_API JSContext
;
35 class JS_PUBLIC_API JSTracer
;
41 class BailoutFrameInfo
;
43 // A JitActivation is used for frames running in Baseline or Ion.
44 class JitActivation
: public Activation
{
45 // If Baseline, Ion or Wasm code is on the stack, and has called into C++,
46 // this will be aligned to an ExitFrame. The last bit indicates if it's a
47 // wasm frame (bit set to wasm::ExitOrJitEntryFPTag) or not
48 // (bit set to ~wasm::ExitOrJitEntryFPTag).
49 uint8_t* packedExitFP_
;
51 // When hasWasmExitFP(), encodedWasmExitReason_ holds ExitReason.
52 uint32_t encodedWasmExitReason_
;
54 JitActivation
* prevJitActivation_
;
56 // Rematerialized Ion frames which has info copied out of snapshots. Maps
57 // frame pointers (i.e. packedExitFP_) to a vector of rematerializations of
58 // all inline frames associated with that frame.
60 // This table is lazily initialized by calling getRematerializedFrame.
61 using RematerializedFrameVector
=
62 JS::GCVector
<js::UniquePtr
<RematerializedFrame
>>;
63 using RematerializedFrameTable
=
64 js::HashMap
<uint8_t*, RematerializedFrameVector
>;
65 js::UniquePtr
<RematerializedFrameTable
> rematerializedFrames_
;
67 // This vector is used to remember the outcome of the evaluation of recover
70 // RInstructionResults are appended into this vector when Snapshot values
71 // have to be read, or when the evaluation has to run before some mutating
72 // code. Each RInstructionResults belongs to one frame which has to bailout
73 // as soon as we get back to it.
74 using IonRecoveryMap
= Vector
<RInstructionResults
, 1>;
75 IonRecoveryMap ionRecovery_
;
77 // If we are bailing out from Ion, then this field should be a non-null
78 // pointer which references the BailoutFrameInfo used to walk the inner
79 // frames. This field is used for all newly constructed JSJitFrameIters to
80 // read the innermost frame information from this bailout data instead of
81 // reading it from the stack.
82 BailoutFrameInfo
* bailoutData_
;
84 // When profiling is enabled, these fields will be updated to reflect the
85 // last pushed frame for this activation, and if that frame has been
86 // left for a call, the native code site of the call.
87 mozilla::Atomic
<JitFrameLayout
*, mozilla::Relaxed
> lastProfilingFrame_
;
88 mozilla::Atomic
<void*, mozilla::Relaxed
> lastProfilingCallSite_
;
89 static_assert(sizeof(mozilla::Atomic
<void*, mozilla::Relaxed
>) ==
91 "Atomic should have same memory format as underlying type.");
93 // When wasm traps, the signal handler records some data for unwinding
94 // purposes. Wasm code can't trap reentrantly.
95 mozilla::Maybe
<wasm::TrapData
> wasmTrapData_
;
97 void clearRematerializedFrames();
99 #ifdef CHECK_OSIPOINT_REGISTERS
101 // Used to verify that live registers don't change between a VM call and
102 // the OsiPoint that follows it. Protected to silence Clang warning.
103 uint32_t checkRegs_
= 0;
108 explicit JitActivation(JSContext
* cx
);
111 bool isProfiling() const {
112 // All JitActivations can be profiled.
116 JitActivation
* prevJitActivation() const { return prevJitActivation_
; }
117 static size_t offsetOfPrevJitActivation() {
118 return offsetof(JitActivation
, prevJitActivation_
);
121 bool hasExitFP() const { return !!packedExitFP_
; }
122 uint8_t* jsOrWasmExitFP() const {
123 if (hasWasmExitFP()) {
124 return wasm::Frame::untagExitFP(packedExitFP_
);
126 return packedExitFP_
;
128 static size_t offsetOfPackedExitFP() {
129 return offsetof(JitActivation
, packedExitFP_
);
132 bool hasJSExitFP() const { return !hasWasmExitFP(); }
134 uint8_t* jsExitFP() const {
135 MOZ_ASSERT(hasJSExitFP());
136 return packedExitFP_
;
138 void setJSExitFP(uint8_t* fp
) { packedExitFP_
= fp
; }
140 uint8_t* packedExitFP() const { return packedExitFP_
; }
141 void setPackedExitFP(uint8_t* fp
) { packedExitFP_
= fp
; }
143 #ifdef CHECK_OSIPOINT_REGISTERS
144 void setCheckRegs(bool check
) { checkRegs_
= check
; }
145 static size_t offsetOfCheckRegs() {
146 return offsetof(JitActivation
, checkRegs_
);
148 static size_t offsetOfRegs() { return offsetof(JitActivation
, regs_
); }
151 // Look up a rematerialized frame keyed by the fp, rematerializing the
152 // frame if one doesn't already exist. A frame can only be rematerialized
153 // if an IonFrameIterator pointing to the nearest uninlined frame can be
154 // provided, as values need to be read out of snapshots.
156 // The inlineDepth must be within bounds of the frame pointed to by iter.
157 RematerializedFrame
* getRematerializedFrame(
158 JSContext
* cx
, const JSJitFrameIter
& iter
, size_t inlineDepth
= 0,
159 MaybeReadFallback::FallbackConsequence consequence
=
160 MaybeReadFallback::Fallback_Invalidate
);
162 // Look up a rematerialized frame by the fp. If inlineDepth is out of
163 // bounds of what has been rematerialized, nullptr is returned.
164 RematerializedFrame
* lookupRematerializedFrame(uint8_t* top
,
165 size_t inlineDepth
= 0);
167 // Remove all rematerialized frames associated with the fp top from the
169 void removeRematerializedFramesFromDebugger(JSContext
* cx
, uint8_t* top
);
171 bool hasRematerializedFrame(uint8_t* top
, size_t inlineDepth
= 0) {
172 return !!lookupRematerializedFrame(top
, inlineDepth
);
175 // Remove a previous rematerialization by fp.
176 void removeRematerializedFrame(uint8_t* top
);
178 void traceRematerializedFrames(JSTracer
* trc
);
180 // Register the results of on Ion frame recovery.
181 bool registerIonFrameRecovery(RInstructionResults
&& results
);
183 // Return the pointer to the Ion frame recovery, if it is already registered.
184 RInstructionResults
* maybeIonFrameRecovery(JitFrameLayout
* fp
);
186 // If an Ion frame recovery exists for the |fp| frame exists, then remove it
187 // from the activation.
188 void removeIonFrameRecovery(JitFrameLayout
* fp
);
190 void traceIonRecovery(JSTracer
* trc
);
192 // Return the bailout information if it is registered.
193 const BailoutFrameInfo
* bailoutData() const { return bailoutData_
; }
195 // Register the bailout data when it is constructed.
196 void setBailoutData(BailoutFrameInfo
* bailoutData
);
198 // Unregister the bailout data when the frame is reconstructed.
199 void cleanBailoutData();
201 static size_t offsetOfLastProfilingFrame() {
202 return offsetof(JitActivation
, lastProfilingFrame_
);
204 JitFrameLayout
* lastProfilingFrame() { return lastProfilingFrame_
; }
205 void setLastProfilingFrame(JitFrameLayout
* ptr
) { lastProfilingFrame_
= ptr
; }
207 static size_t offsetOfLastProfilingCallSite() {
208 return offsetof(JitActivation
, lastProfilingCallSite_
);
210 void* lastProfilingCallSite() { return lastProfilingCallSite_
; }
211 void setLastProfilingCallSite(void* ptr
) { lastProfilingCallSite_
= ptr
; }
213 // WebAssembly specific attributes.
214 bool hasWasmExitFP() const { return wasm::Frame::isExitFP(packedExitFP_
); }
215 wasm::Frame
* wasmExitFP() const {
216 MOZ_ASSERT(hasWasmExitFP());
217 return reinterpret_cast<wasm::Frame
*>(
218 wasm::Frame::untagExitFP(packedExitFP_
));
220 wasm::Instance
* wasmExitInstance() const {
221 return wasm::GetNearestEffectiveInstance(wasmExitFP());
223 void setWasmExitFP(const wasm::Frame
* fp
) {
225 MOZ_ASSERT(!wasm::Frame::isExitFP(fp
));
226 packedExitFP_
= wasm::Frame::addExitFPTag(fp
);
227 MOZ_ASSERT(hasWasmExitFP());
229 packedExitFP_
= nullptr;
232 wasm::ExitReason
wasmExitReason() const {
233 MOZ_ASSERT(hasWasmExitFP());
234 return wasm::ExitReason::Decode(encodedWasmExitReason_
);
236 static size_t offsetOfEncodedWasmExitReason() {
237 return offsetof(JitActivation
, encodedWasmExitReason_
);
240 void startWasmTrap(wasm::Trap trap
, uint32_t bytecodeOffset
,
241 const wasm::RegisterState
& state
);
242 void finishWasmTrap();
243 bool isWasmTrapping() const { return !!wasmTrapData_
; }
244 const wasm::TrapData
& wasmTrapData() { return *wasmTrapData_
; }
247 // A filtering of the ActivationIterator to only stop at JitActivations.
248 class JitActivationIterator
: public ActivationIterator
{
250 while (!done() && !activation_
->isJit()) {
251 ActivationIterator::operator++();
256 explicit JitActivationIterator(JSContext
* cx
) : ActivationIterator(cx
) {
260 JitActivationIterator
& operator++() {
261 ActivationIterator::operator++();
271 #endif // vm_JitActivation_h