tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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