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