JitActivation.h (10804B)
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/. */ 6 7 #ifndef vm_JitActivation_h 8 #define vm_JitActivation_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT 11 #include "mozilla/Atomics.h" // mozilla::Atomic, mozilla::Relaxed 12 #include "mozilla/Maybe.h" // mozilla::Maybe 13 14 #include <stddef.h> // size_t 15 #include <stdint.h> // uint8_t, uint32_t, uintptr_t 16 17 #include "jstypes.h" // JS_PUBLIC_API 18 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 23 #endif 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} 33 #include "wasm/WasmPI.h" // js::wasm::SuspenderObject 34 35 struct JS_PUBLIC_API JSContext; 36 class JS_PUBLIC_API JSTracer; 37 38 namespace js { 39 40 namespace jit { 41 42 class BailoutFrameInfo; 43 44 enum class IsLeavingFrame { No, Yes }; 45 46 // A JitActivation is used for frames running in Baseline or Ion. 47 class JitActivation : public Activation { 48 // If Baseline, Ion or Wasm code is on the stack, and has called into C++, 49 // this will be aligned to an ExitFrame. The last bit indicates if it's a 50 // wasm frame (bit set to wasm::ExitOrJitEntryFPTag) or not 51 // (bit set to ~wasm::ExitOrJitEntryFPTag). 52 uint8_t* packedExitFP_; 53 54 // When hasWasmExitFP(), encodedWasmExitReason_ holds ExitReason. 55 uint32_t encodedWasmExitReason_; 56 #ifdef ENABLE_WASM_JSPI 57 // This would be a 'Rooted', except that the 'Rooted' values in the super 58 // class `Activation` conflict with the LIFO ordering that 'Rooted' requires. 59 // So instead we manually trace it. 60 JS::Rooted<wasm::SuspenderObject*> wasmExitSuspender_; 61 #endif 62 63 JitActivation* prevJitActivation_; 64 65 // Rematerialized Ion frames which has info copied out of snapshots. Maps 66 // frame pointers (i.e. packedExitFP_) to a vector of rematerializations of 67 // all inline frames associated with that frame. 68 // 69 // This table is lazily initialized by calling getRematerializedFrame. 70 using RematerializedFrameVector = 71 JS::GCVector<js::UniquePtr<RematerializedFrame>>; 72 using RematerializedFrameTable = 73 js::HashMap<uint8_t*, RematerializedFrameVector>; 74 js::UniquePtr<RematerializedFrameTable> rematerializedFrames_; 75 76 // This vector is used to remember the outcome of the evaluation of recover 77 // instructions. 78 // 79 // RInstructionResults are appended into this vector when Snapshot values 80 // have to be read, or when the evaluation has to run before some mutating 81 // code. Each RInstructionResults belongs to one frame which has to bailout 82 // as soon as we get back to it. 83 using IonRecoveryMap = Vector<RInstructionResults, 1>; 84 IonRecoveryMap ionRecovery_; 85 86 // If we are bailing out from Ion, then this field should be a non-null 87 // pointer which references the BailoutFrameInfo used to walk the inner 88 // frames. This field is used for all newly constructed JSJitFrameIters to 89 // read the innermost frame information from this bailout data instead of 90 // reading it from the stack. 91 BailoutFrameInfo* bailoutData_; 92 93 // When profiling is enabled, these fields will be updated to reflect the 94 // last pushed frame for this activation, and if that frame has been 95 // left for a call, the native code site of the call. 96 mozilla::Atomic<JitFrameLayout*, mozilla::Relaxed> lastProfilingFrame_; 97 mozilla::Atomic<void*, mozilla::Relaxed> lastProfilingCallSite_; 98 static_assert(sizeof(mozilla::Atomic<void*, mozilla::Relaxed>) == 99 sizeof(void*), 100 "Atomic should have same memory format as underlying type."); 101 102 // When wasm traps, the signal handler records some data for unwinding 103 // purposes. Wasm code can't trap reentrantly. 104 mozilla::Maybe<wasm::TrapData> wasmTrapData_; 105 106 #ifdef CHECK_OSIPOINT_REGISTERS 107 protected: 108 // Used to verify that live registers don't change between a VM call and 109 // the OsiPoint that follows it. Protected to silence Clang warning. 110 uint32_t checkRegs_ = 0; 111 RegisterDump regs_; 112 #endif 113 114 public: 115 explicit JitActivation(JSContext* cx); 116 ~JitActivation(); 117 118 void trace(JSTracer* trc); 119 120 bool isProfiling() const { 121 // All JitActivations can be profiled. 122 return true; 123 } 124 125 JitActivation* prevJitActivation() const { return prevJitActivation_; } 126 static size_t offsetOfPrevJitActivation() { 127 return offsetof(JitActivation, prevJitActivation_); 128 } 129 130 bool hasExitFP() const { return !!packedExitFP_; } 131 uint8_t* jsOrWasmExitFP() const { 132 if (hasWasmExitFP()) { 133 return wasm::Frame::untagExitFP(packedExitFP_); 134 } 135 return packedExitFP_; 136 } 137 static size_t offsetOfPackedExitFP() { 138 return offsetof(JitActivation, packedExitFP_); 139 } 140 141 bool hasJSExitFP() const { return !hasWasmExitFP(); } 142 143 uint8_t* jsExitFP() const { 144 MOZ_ASSERT(hasJSExitFP()); 145 return packedExitFP_; 146 } 147 void setJSExitFP(uint8_t* fp) { 148 packedExitFP_ = fp; 149 #ifdef ENABLE_WASM_JSPI 150 wasmExitSuspender_ = nullptr; 151 #endif 152 } 153 154 uint8_t* packedExitFP() const { return packedExitFP_; } 155 156 #ifdef CHECK_OSIPOINT_REGISTERS 157 void setCheckRegs(bool check) { checkRegs_ = check; } 158 static size_t offsetOfCheckRegs() { 159 return offsetof(JitActivation, checkRegs_); 160 } 161 static size_t offsetOfRegs() { return offsetof(JitActivation, regs_); } 162 #endif 163 164 // Look up a rematerialized frame keyed by the fp, rematerializing the 165 // frame if one doesn't already exist. A frame can only be rematerialized 166 // if an IonFrameIterator pointing to the nearest uninlined frame can be 167 // provided, as values need to be read out of snapshots. 168 // 169 // The inlineDepth must be within bounds of the frame pointed to by iter. 170 RematerializedFrame* getRematerializedFrame( 171 JSContext* cx, const JSJitFrameIter& iter, size_t inlineDepth = 0, 172 IsLeavingFrame leaving = IsLeavingFrame::No); 173 174 // Look up a rematerialized frame by the fp. If inlineDepth is out of 175 // bounds of what has been rematerialized, nullptr is returned. 176 RematerializedFrame* lookupRematerializedFrame(uint8_t* top, 177 size_t inlineDepth = 0); 178 179 // Remove all rematerialized frames associated with the fp top from the 180 // Debugger. 181 void removeRematerializedFramesFromDebugger(JSContext* cx, uint8_t* top); 182 183 bool hasRematerializedFrame(uint8_t* top, size_t inlineDepth = 0) { 184 return !!lookupRematerializedFrame(top, inlineDepth); 185 } 186 187 // Remove a previous rematerialization by fp. 188 void removeRematerializedFrame(uint8_t* top); 189 190 // Register the results of on Ion frame recovery. 191 bool registerIonFrameRecovery(RInstructionResults&& results); 192 193 // Return the pointer to the Ion frame recovery, if it is already registered. 194 RInstructionResults* maybeIonFrameRecovery(JitFrameLayout* fp); 195 196 // If an Ion frame recovery exists for the |fp| frame exists, then remove it 197 // from the activation. 198 void removeIonFrameRecovery(JitFrameLayout* fp); 199 200 // Return the bailout information if it is registered. 201 const BailoutFrameInfo* bailoutData() const { return bailoutData_; } 202 203 // Register the bailout data when it is constructed. 204 void setBailoutData(BailoutFrameInfo* bailoutData); 205 206 // Unregister the bailout data when the frame is reconstructed. 207 void cleanBailoutData(); 208 209 static size_t offsetOfLastProfilingFrame() { 210 return offsetof(JitActivation, lastProfilingFrame_); 211 } 212 JitFrameLayout* lastProfilingFrame() { return lastProfilingFrame_; } 213 void setLastProfilingFrame(JitFrameLayout* ptr) { lastProfilingFrame_ = ptr; } 214 215 static size_t offsetOfLastProfilingCallSite() { 216 return offsetof(JitActivation, lastProfilingCallSite_); 217 } 218 void* lastProfilingCallSite() { return lastProfilingCallSite_; } 219 void setLastProfilingCallSite(void* ptr) { lastProfilingCallSite_ = ptr; } 220 221 // WebAssembly specific attributes. 222 bool hasWasmExitFP() const { return wasm::Frame::isExitFP(packedExitFP_); } 223 wasm::Frame* wasmExitFP() const { 224 MOZ_ASSERT(hasWasmExitFP()); 225 return reinterpret_cast<wasm::Frame*>( 226 wasm::Frame::untagExitFP(packedExitFP_)); 227 } 228 wasm::Instance* wasmExitInstance() const { 229 return wasm::GetNearestEffectiveInstance(wasmExitFP()); 230 } 231 void setWasmExitFP(const wasm::Frame* fp, wasm::SuspenderObject* suspender) { 232 if (fp) { 233 MOZ_ASSERT(!wasm::Frame::isExitFP(fp)); 234 packedExitFP_ = wasm::Frame::addExitFPTag(fp); 235 #ifdef ENABLE_WASM_JSPI 236 wasmExitSuspender_ = suspender; 237 #endif 238 MOZ_ASSERT(hasWasmExitFP()); 239 } else { 240 MOZ_ASSERT(!suspender); 241 packedExitFP_ = nullptr; 242 #ifdef ENABLE_WASM_JSPI 243 wasmExitSuspender_ = nullptr; 244 #endif 245 } 246 } 247 wasm::ExitReason wasmExitReason() const { 248 MOZ_ASSERT(hasWasmExitFP()); 249 return wasm::ExitReason::Decode(encodedWasmExitReason_); 250 } 251 static size_t offsetOfEncodedWasmExitReason() { 252 return offsetof(JitActivation, encodedWasmExitReason_); 253 } 254 #ifdef ENABLE_WASM_JSPI 255 wasm::SuspenderObject* wasmExitSuspender() const { 256 MOZ_ASSERT(hasWasmExitFP()); 257 return wasmExitSuspender_; 258 } 259 static size_t offsetOfWasmExitSuspender() { 260 return offsetof(JitActivation, wasmExitSuspender_) + 261 Rooted<wasm::SuspenderObject*>::offsetOfPtr(); 262 } 263 #endif 264 265 void startWasmTrap(wasm::Trap trap, const wasm::TrapSite& trapSite, 266 const wasm::RegisterState& state); 267 void finishWasmTrap(bool isResuming); 268 bool isWasmTrapping() const { return !!wasmTrapData_; } 269 const wasm::TrapData& wasmTrapData() { return *wasmTrapData_; } 270 }; 271 272 // A filtering of the ActivationIterator to only stop at JitActivations. 273 class JitActivationIterator : public ActivationIterator { 274 void settle() { 275 while (!done() && !activation_->isJit()) { 276 ActivationIterator::operator++(); 277 } 278 } 279 280 public: 281 explicit JitActivationIterator(JSContext* cx) : ActivationIterator(cx) { 282 settle(); 283 } 284 285 JitActivationIterator& operator++() { 286 ActivationIterator::operator++(); 287 settle(); 288 return *this; 289 } 290 }; 291 292 } // namespace jit 293 294 } // namespace js 295 296 #endif // vm_JitActivation_h