tor-browser

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

JitFrames.h (26054B)


      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 jit_JitFrames_h
      8 #define jit_JitFrames_h
      9 
     10 #include "mozilla/Assertions.h"
     11 
     12 #include <stddef.h>
     13 #include <stdint.h>
     14 
     15 #include "jit/CalleeToken.h"
     16 #include "jit/MachineState.h"
     17 #include "jit/Registers.h"
     18 #include "js/Id.h"
     19 #include "js/TypeDecls.h"
     20 #include "js/Value.h"
     21 
     22 namespace js {
     23 
     24 namespace wasm {
     25 class Instance;
     26 }
     27 
     28 namespace jit {
     29 
     30 enum class FrameType;
     31 enum class VMFunctionId;
     32 class IonScript;
     33 class JitActivation;
     34 class JitFrameLayout;
     35 struct SafepointSlotEntry;
     36 struct VMFunctionData;
     37 
     38 // [SMDOC] JIT Frame Layout
     39 //
     40 // Frame Headers:
     41 //
     42 // In between every two frames lies a small header describing both frames. This
     43 // header, minimally, contains a returnAddress word and a descriptor word (See
     44 // CommonFrameLayout). The descriptor describes the type of the older (caller)
     45 // frame, whereas the returnAddress describes the address the newer (callee)
     46 // frame will return to. For JitFrameLayout, the descriptor also stores the
     47 // number of arguments passed from the caller to the callee frame.
     48 //
     49 // Special Frames:
     50 //
     51 // Two special frame types exist:
     52 // - Entry frames begin a JitActivation, and therefore there is exactly one
     53 //   per activation of EnterJit or EnterBaseline. These reuse JitFrameLayout.
     54 // - Exit frames are necessary to leave JIT code and enter C++, and thus,
     55 //   C++ code will always begin iterating from the topmost exit frame.
     56 //
     57 // Approximate Layout:
     58 //
     59 // The layout of an Ion frame on the C stack is roughly:
     60 //      argN     _
     61 //      ...       \ - These are jsvals
     62 //      arg0      /
     63 //   -3 this    _/
     64 //   -2 callee
     65 //   -1 descriptor
     66 //    0 returnAddress
     67 //   .. locals ..
     68 
     69 // [SMDOC] Frame Descriptor Layout
     70 //
     71 // A frame descriptor word has the following data:
     72 //
     73 //    high bits: [ numActualArgs |
     74 //                 has-inlined-icscript bit |
     75 //                 has-cached-saved-frame bit |
     76 //    low bits:    frame type ]
     77 //
     78 
     79 // * numActualArgs: for JitFrameLayout, the number of arguments passed by the
     80 //   caller.
     81 // * HasInlinedICScript: Set when passing a private ICScript to a trial-inlined
     82 //   script.
     83 // * HasCachedSavedFrame: Used to power the LiveSavedFrameCache optimization.
     84 //   See the comment in Activation.h
     85 // * Frame Type: BaselineJS, Exit, etc. (jit::FrameType)
     86 //
     87 
     88 class FrameDescriptor {
     89 public:
     90  static const uint32_t TypeBits = 4;
     91  static const uint32_t TypeMask = (1 << TypeBits) - 1;
     92  static const uint32_t HasCachedSavedFrame = 1 << TypeBits;
     93  static const uint32_t HasInlinedICScript = 1 << (TypeBits + 1);
     94  static const uint32_t NumActualArgsShift = TypeBits + 2;
     95 
     96  explicit FrameDescriptor(FrameType type) : raw_(uint32_t(type)) {}
     97  FrameDescriptor(FrameType type, uint32_t argc, bool hasInlined = false)
     98      : raw_(argc << NumActualArgsShift | uint32_t(type)) {
     99    if (hasInlined) {
    100      setHasInlinedICScript();
    101    }
    102    MOZ_ASSERT(numActualArgs() == argc, "argc must fit in descriptor");
    103  }
    104 
    105  FrameType type() const { return FrameType(raw_ & TypeMask); }
    106  void changeType(FrameType type) {
    107    raw_ &= ~TypeMask;
    108    raw_ |= uintptr_t(type);
    109  }
    110 
    111  uint32_t numActualArgs() const { return raw_ >> NumActualArgsShift; }
    112 
    113  bool hasCachedSavedFrame() const { return raw_ & HasCachedSavedFrame; }
    114  void setHasCachedSavedFrame() { raw_ |= HasCachedSavedFrame; }
    115  void clearHasCachedSavedFrame() { raw_ &= ~HasCachedSavedFrame; }
    116 
    117  bool hasInlinedICScript() const { return raw_ & HasInlinedICScript; }
    118  void setHasInlinedICScript() { raw_ |= HasInlinedICScript; }
    119 
    120  uint32_t value() const {
    121    MOZ_ASSERT(raw_ == uint32_t(raw_));
    122    return raw_;
    123  }
    124 
    125 private:
    126  uintptr_t raw_;
    127 };
    128 
    129 static inline uint32_t MakeFrameDescriptor(FrameType type) {
    130  FrameDescriptor descriptor(type);
    131  return descriptor.value();
    132 }
    133 
    134 // For JitFrameLayout, the descriptor also stores the number of arguments passed
    135 // by the caller. Note that |type| is the type of the *older* frame and |argc|
    136 // is the number of arguments passed to the *newer* frame.
    137 static inline uint32_t MakeFrameDescriptorForJitCall(FrameType type,
    138                                                     uint32_t argc) {
    139  FrameDescriptor descriptor(type, argc);
    140  return descriptor.value();
    141 }
    142 
    143 struct BaselineBailoutInfo;
    144 
    145 enum class ExceptionResumeKind : int32_t {
    146  // There is no exception handler in this activation.
    147  // Return from the entry frame.
    148  EntryFrame,
    149 
    150  // The exception was caught in baseline.
    151  // Restore state and jump to the catch block.
    152  Catch,
    153 
    154  // A finally block must be executed in baseline.
    155  // Stash the exception on the stack and jump to the finally block.
    156  Finally,
    157 
    158  // We are forcing an early return with a specific return value.
    159  // This is used by the debugger and when closing generators.
    160  // Immediately return from the current frame with the given value.
    161  ForcedReturnBaseline,
    162  ForcedReturnIon,
    163 
    164  // This frame is currently executing in Ion, but we must bail out
    165  // to baseline before handling the exception.
    166  // Jump to the bailout tail stub.
    167  Bailout,
    168 
    169  // Return to the wasm interpreter entry frame.
    170  WasmInterpEntry,
    171 
    172  // The exception was caught by a wasm catch handler.
    173  // Restore state and jump to it.
    174  WasmCatch
    175 };
    176 
    177 // Data needed to recover from an exception.
    178 struct ResumeFromException {
    179  uint8_t* framePointer;
    180  uint8_t* stackPointer;
    181  uint8_t* target;
    182  ExceptionResumeKind kind;
    183  wasm::Instance* instance;
    184 
    185  // Value to push when resuming into a |finally| block.
    186  // Also used by Wasm to send the exception object to the throw stub.
    187  JS::Value exception;
    188 
    189  // Exception stack to push when resuming into a |finally| block.
    190  JS::Value exceptionStack;
    191 
    192  BaselineBailoutInfo* bailoutInfo;
    193 
    194  static size_t offsetOfFramePointer() {
    195    return offsetof(ResumeFromException, framePointer);
    196  }
    197  static size_t offsetOfStackPointer() {
    198    return offsetof(ResumeFromException, stackPointer);
    199  }
    200  static size_t offsetOfTarget() {
    201    return offsetof(ResumeFromException, target);
    202  }
    203  static size_t offsetOfKind() { return offsetof(ResumeFromException, kind); }
    204  static size_t offsetOfInstance() {
    205    return offsetof(ResumeFromException, instance);
    206  }
    207  static size_t offsetOfException() {
    208    return offsetof(ResumeFromException, exception);
    209  }
    210  static size_t offsetOfExceptionStack() {
    211    return offsetof(ResumeFromException, exceptionStack);
    212  }
    213  static size_t offsetOfBailoutInfo() {
    214    return offsetof(ResumeFromException, bailoutInfo);
    215  }
    216 };
    217 
    218 #if defined(JS_CODEGEN_ARM64)
    219 static_assert(sizeof(ResumeFromException) % 16 == 0,
    220              "ResumeFromException should be aligned");
    221 #endif
    222 
    223 void HandleException(ResumeFromException* rfe);
    224 
    225 void EnsureUnwoundJitExitFrame(JitActivation* act, JitFrameLayout* frame);
    226 
    227 void TraceJitActivations(JSContext* cx, JSTracer* trc);
    228 
    229 // Trace weak pointers in baseline stubs in activations for zones that are
    230 // currently being swept.
    231 void TraceWeakJitActivationsInSweepingZones(JSContext* cx, JSTracer* trc);
    232 
    233 void UpdateJitActivationsForMinorGC(JSRuntime* rt);
    234 void UpdateJitActivationsForCompactingGC(JSRuntime* rt);
    235 
    236 // Returns the JSScript associated with the topmost JIT frame.
    237 JSScript* GetTopJitJSScript(JSContext* cx);
    238 
    239 #if defined(JS_CODEGEN_ARM64)
    240 uint8_t* alignDoubleSpill(uint8_t* pointer);
    241 #else
    242 inline uint8_t* alignDoubleSpill(uint8_t* pointer) {
    243  // This is a no-op on most platforms.
    244  return pointer;
    245 }
    246 #endif
    247 
    248 // Layout of the frame prefix. This assumes the stack architecture grows down.
    249 // If this is ever not the case, we'll have to refactor.
    250 class CommonFrameLayout {
    251  uint8_t* callerFramePtr_;
    252  uint8_t* returnAddress_;
    253  FrameDescriptor descriptor_;
    254 
    255 public:
    256  static constexpr size_t offsetOfDescriptor() {
    257    return offsetof(CommonFrameLayout, descriptor_);
    258  }
    259  FrameDescriptor descriptor() const { return descriptor_; }
    260  static constexpr size_t offsetOfReturnAddress() {
    261    return offsetof(CommonFrameLayout, returnAddress_);
    262  }
    263  FrameType prevType() const { return descriptor_.type(); }
    264  void changePrevType(FrameType type) { descriptor_.changeType(type); }
    265  bool hasCachedSavedFrame() const { return descriptor_.hasCachedSavedFrame(); }
    266  void setHasCachedSavedFrame() { descriptor_.setHasCachedSavedFrame(); }
    267  void clearHasCachedSavedFrame() { descriptor_.clearHasCachedSavedFrame(); }
    268  uint8_t* returnAddress() const { return returnAddress_; }
    269  void setReturnAddress(uint8_t* addr) { returnAddress_ = addr; }
    270 
    271  uint8_t* callerFramePtr() const { return callerFramePtr_; }
    272  static constexpr size_t offsetOfCallerFramePtr() {
    273    return offsetof(CommonFrameLayout, callerFramePtr_);
    274  }
    275  static constexpr size_t bytesPoppedAfterCall() {
    276    // The return address and frame pointer are popped by the callee/call.
    277    return 2 * sizeof(void*);
    278  }
    279 };
    280 
    281 class JitFrameLayout : public CommonFrameLayout {
    282  CalleeToken calleeToken_;
    283 
    284 public:
    285  CalleeToken calleeToken() const { return calleeToken_; }
    286  void replaceCalleeToken(CalleeToken calleeToken) {
    287    calleeToken_ = calleeToken;
    288  }
    289 
    290  static constexpr size_t offsetOfCalleeToken() {
    291    return offsetof(JitFrameLayout, calleeToken_);
    292  }
    293  static constexpr size_t offsetOfThis() { return sizeof(JitFrameLayout); }
    294  static constexpr size_t offsetOfActualArgs() {
    295    return offsetOfThis() + sizeof(JS::Value);
    296  }
    297  static constexpr size_t offsetOfActualArg(size_t arg) {
    298    return offsetOfActualArgs() + arg * sizeof(JS::Value);
    299  }
    300 
    301  JS::Value& thisv() {
    302    MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
    303    return thisAndActualArgs()[0];
    304  }
    305  JS::Value* thisAndActualArgs() {
    306    MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
    307    return (JS::Value*)(this + 1);
    308  }
    309  JS::Value* actualArgs() { return thisAndActualArgs() + 1; }
    310  uintptr_t numActualArgs() const { return descriptor().numActualArgs(); }
    311 
    312  // Computes a reference to a stack or argument slot, where a slot is a
    313  // distance from the base frame pointer, as would be used for LStackSlot
    314  // or LArgument.
    315  uintptr_t* slotRef(SafepointSlotEntry where);
    316 
    317  static inline size_t Size() { return sizeof(JitFrameLayout); }
    318 };
    319 
    320 class BaselineInterpreterEntryFrameLayout : public JitFrameLayout {
    321 public:
    322  static inline size_t Size() {
    323    return sizeof(BaselineInterpreterEntryFrameLayout);
    324  }
    325 };
    326 
    327 class TrampolineNativeFrameLayout : public JitFrameLayout {
    328 public:
    329  static inline size_t Size() { return sizeof(TrampolineNativeFrameLayout); }
    330 
    331  template <typename T>
    332  T* getFrameData() {
    333    uint8_t* raw = reinterpret_cast<uint8_t*>(this) - sizeof(T);
    334    return reinterpret_cast<T*>(raw);
    335  }
    336 };
    337 
    338 class WasmToJSJitFrameLayout : public JitFrameLayout {
    339 public:
    340  static inline size_t Size() { return sizeof(WasmToJSJitFrameLayout); }
    341 };
    342 
    343 class IonICCallFrameLayout : public CommonFrameLayout {
    344 protected:
    345  // Pointer to root the stub's JitCode.
    346  JitCode* stubCode_;
    347 
    348 public:
    349  static constexpr size_t LocallyTracedValueOffset = sizeof(void*);
    350 
    351  JitCode** stubCode() { return &stubCode_; }
    352  static size_t Size() { return sizeof(IonICCallFrameLayout); }
    353 
    354  inline Value* locallyTracedValuePtr(size_t index) {
    355    uint8_t* fp = reinterpret_cast<uint8_t*>(this);
    356    return reinterpret_cast<Value*>(fp - LocallyTracedValueOffset -
    357                                    index * sizeof(Value));
    358  }
    359 };
    360 
    361 enum class ExitFrameType : uint8_t {
    362  CallNative = 0x0,
    363  ConstructNative = 0x1,
    364  IonDOMGetter = 0x2,
    365  IonDOMSetter = 0x3,
    366  IonDOMMethod = 0x4,
    367  IonOOLNative = 0x5,
    368  IonOOLProxy = 0x6,
    369  WasmGenericJitEntry = 0x7,
    370  DirectWasmJitCall = 0x8,
    371  UnwoundJit = 0x9,
    372  InterpreterStub = 0xA,
    373  LazyLink = 0xB,
    374  Bare = 0xC,
    375 
    376  // This must be the last value in this enum. See ExitFooterFrame::data_.
    377  VMFunction = 0xD
    378 };
    379 
    380 // GC related data used to keep alive data surrounding the Exit frame.
    381 class ExitFooterFrame {
    382  // Stores either the ExitFrameType or, for a VMFunction call,
    383  // `ExitFrameType::VMFunction + VMFunctionId`.
    384  uintptr_t data_;
    385 
    386 #ifdef DEBUG
    387  void assertValidVMFunctionId() const;
    388 #else
    389  void assertValidVMFunctionId() const {}
    390 #endif
    391 
    392 public:
    393  static constexpr size_t Size() { return sizeof(ExitFooterFrame); }
    394  void setUnwoundJitExitFrame() {
    395    data_ = uintptr_t(ExitFrameType::UnwoundJit);
    396  }
    397  ExitFrameType type() const {
    398    if (data_ >= uintptr_t(ExitFrameType::VMFunction)) {
    399      return ExitFrameType::VMFunction;
    400    }
    401    return ExitFrameType(data_);
    402  }
    403  VMFunctionId functionId() const {
    404    MOZ_ASSERT(type() == ExitFrameType::VMFunction);
    405    assertValidVMFunctionId();
    406    return static_cast<VMFunctionId>(data_ - size_t(ExitFrameType::VMFunction));
    407  }
    408 
    409  // This should only be called for function()->outParam == Type_Handle
    410  template <typename T>
    411  T* outParam() {
    412    uint8_t* address = reinterpret_cast<uint8_t*>(this);
    413    return reinterpret_cast<T*>(address - sizeof(T));
    414  }
    415 };
    416 
    417 class NativeExitFrameLayout;
    418 class IonOOLNativeExitFrameLayout;
    419 class IonOOLProxyExitFrameLayout;
    420 class IonDOMExitFrameLayout;
    421 
    422 // this is the frame layout when we are exiting ion code, and about to enter
    423 // platform ABI code
    424 class ExitFrameLayout : public CommonFrameLayout {
    425  inline uint8_t* top() { return reinterpret_cast<uint8_t*>(this + 1); }
    426 
    427 public:
    428  static constexpr size_t Size() { return sizeof(ExitFrameLayout); }
    429  static constexpr size_t SizeWithFooter() {
    430    return Size() + ExitFooterFrame::Size();
    431  }
    432 
    433  inline ExitFooterFrame* footer() {
    434    uint8_t* sp = reinterpret_cast<uint8_t*>(this);
    435    return reinterpret_cast<ExitFooterFrame*>(sp - ExitFooterFrame::Size());
    436  }
    437 
    438  // argBase targets the point which precedes the exit frame. Arguments of VM
    439  // each wrapper are pushed before the exit frame.  This correspond exactly
    440  // to the value of the argBase register of the generateVMWrapper function.
    441  inline uint8_t* argBase() {
    442    MOZ_ASSERT(isWrapperExit());
    443    return top();
    444  }
    445 
    446  inline bool isWrapperExit() {
    447    return footer()->type() == ExitFrameType::VMFunction;
    448  }
    449  inline bool isBareExit() { return footer()->type() == ExitFrameType::Bare; }
    450  inline bool isUnwoundJitExit() {
    451    return footer()->type() == ExitFrameType::UnwoundJit;
    452  }
    453 
    454  // See the various exit frame layouts below.
    455  template <typename T>
    456  inline bool is() {
    457    return footer()->type() == T::Type();
    458  }
    459  template <typename T>
    460  inline T* as() {
    461    MOZ_ASSERT(this->is<T>());
    462    return reinterpret_cast<T*>(footer());
    463  }
    464 };
    465 
    466 // Cannot inherit implementation since we need to extend the top of
    467 // ExitFrameLayout.
    468 class NativeExitFrameLayout {
    469 protected:  // only to silence a clang warning about unused private fields
    470  ExitFooterFrame footer_;
    471  ExitFrameLayout exit_;
    472  uintptr_t argc_;
    473 
    474  // We need to split the Value into 2 fields of 32 bits, otherwise the C++
    475  // compiler may add some padding between the fields.
    476  uint32_t loCalleeResult_;
    477  uint32_t hiCalleeResult_;
    478 
    479 public:
    480  static inline size_t Size() { return sizeof(NativeExitFrameLayout); }
    481 
    482  static size_t offsetOfResult() {
    483    return offsetof(NativeExitFrameLayout, loCalleeResult_);
    484  }
    485  inline JS::Value* vp() {
    486    return reinterpret_cast<JS::Value*>(&loCalleeResult_);
    487  }
    488  inline uintptr_t argc() const { return argc_; }
    489 };
    490 
    491 class CallNativeExitFrameLayout : public NativeExitFrameLayout {
    492 public:
    493  static ExitFrameType Type() { return ExitFrameType::CallNative; }
    494 };
    495 
    496 class ConstructNativeExitFrameLayout : public NativeExitFrameLayout {
    497 public:
    498  static ExitFrameType Type() { return ExitFrameType::ConstructNative; }
    499 };
    500 
    501 template <>
    502 inline bool ExitFrameLayout::is<NativeExitFrameLayout>() {
    503  return is<CallNativeExitFrameLayout>() ||
    504         is<ConstructNativeExitFrameLayout>();
    505 }
    506 
    507 class IonOOLNativeExitFrameLayout {
    508 protected:  // only to silence a clang warning about unused private fields
    509  ExitFooterFrame footer_;
    510  ExitFrameLayout exit_;
    511 
    512  // pointer to root the stub's JitCode
    513  JitCode* stubCode_;
    514 
    515  uintptr_t argc_;
    516 
    517  // We need to split the Value into 2 fields of 32 bits, otherwise the C++
    518  // compiler may add some padding between the fields.
    519  uint32_t loCalleeResult_;
    520  uint32_t hiCalleeResult_;
    521 
    522  // Split Value for |this| and args above.
    523  uint32_t loThis_;
    524  uint32_t hiThis_;
    525 
    526 public:
    527  static ExitFrameType Type() { return ExitFrameType::IonOOLNative; }
    528 
    529  static inline size_t Size(size_t argc) {
    530    // The frame accounts for the callee/result and |this|, so we only need
    531    // args.
    532    return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(JS::Value));
    533  }
    534 
    535  static size_t offsetOfResult() {
    536    return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_);
    537  }
    538 
    539  inline JitCode** stubCode() { return &stubCode_; }
    540  inline JS::Value* vp() {
    541    return reinterpret_cast<JS::Value*>(&loCalleeResult_);
    542  }
    543  inline JS::Value* thisp() { return reinterpret_cast<JS::Value*>(&loThis_); }
    544  inline uintptr_t argc() const { return argc_; }
    545 };
    546 
    547 // ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id,
    548 //                  MutableHandleValue vp)
    549 // ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id,
    550 //                   MutableHandleValue vp)
    551 // ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id,
    552 //                  MutableHandleValue vp, bool strict)
    553 class IonOOLProxyExitFrameLayout {
    554 protected:  // only to silence a clang warning about unused private fields
    555  ExitFooterFrame footer_;
    556  ExitFrameLayout exit_;
    557 
    558  // The proxy object.
    559  JSObject* proxy_;
    560 
    561  // id for HandleId
    562  jsid id_;
    563 
    564  // space for MutableHandleValue result
    565  // use two uint32_t so compiler doesn't align.
    566  uint32_t vp0_;
    567  uint32_t vp1_;
    568 
    569  // pointer to root the stub's JitCode
    570  JitCode* stubCode_;
    571 
    572 public:
    573  static ExitFrameType Type() { return ExitFrameType::IonOOLProxy; }
    574 
    575  static inline size_t Size() { return sizeof(IonOOLProxyExitFrameLayout); }
    576 
    577  static size_t offsetOfResult() {
    578    return offsetof(IonOOLProxyExitFrameLayout, vp0_);
    579  }
    580 
    581  inline JitCode** stubCode() { return &stubCode_; }
    582  inline JS::Value* vp() { return reinterpret_cast<JS::Value*>(&vp0_); }
    583  inline jsid* id() { return &id_; }
    584  inline JSObject** proxy() { return &proxy_; }
    585 };
    586 
    587 class IonDOMExitFrameLayout {
    588 protected:  // only to silence a clang warning about unused private fields
    589  ExitFooterFrame footer_;
    590  ExitFrameLayout exit_;
    591  JSObject* thisObj;
    592 
    593  // We need to split the Value into 2 fields of 32 bits, otherwise the C++
    594  // compiler may add some padding between the fields.
    595  uint32_t loCalleeResult_;
    596  uint32_t hiCalleeResult_;
    597 
    598 public:
    599  static ExitFrameType GetterType() { return ExitFrameType::IonDOMGetter; }
    600  static ExitFrameType SetterType() { return ExitFrameType::IonDOMSetter; }
    601 
    602  static inline size_t Size() { return sizeof(IonDOMExitFrameLayout); }
    603 
    604  static size_t offsetOfResult() {
    605    return offsetof(IonDOMExitFrameLayout, loCalleeResult_);
    606  }
    607  inline JS::Value* vp() {
    608    return reinterpret_cast<JS::Value*>(&loCalleeResult_);
    609  }
    610  inline JSObject** thisObjAddress() { return &thisObj; }
    611  inline bool isMethodFrame();
    612 };
    613 
    614 struct IonDOMMethodExitFrameLayoutTraits;
    615 
    616 class IonDOMMethodExitFrameLayout {
    617 protected:  // only to silence a clang warning about unused private fields
    618  ExitFooterFrame footer_;
    619  ExitFrameLayout exit_;
    620  // This must be the last thing pushed, so as to stay common with
    621  // IonDOMExitFrameLayout.
    622  JSObject* thisObj_;
    623  JS::Value* argv_;
    624  uintptr_t argc_;
    625 
    626  // We need to split the Value into 2 fields of 32 bits, otherwise the C++
    627  // compiler may add some padding between the fields.
    628  uint32_t loCalleeResult_;
    629  uint32_t hiCalleeResult_;
    630 
    631  friend struct IonDOMMethodExitFrameLayoutTraits;
    632 
    633 public:
    634  static ExitFrameType Type() { return ExitFrameType::IonDOMMethod; }
    635 
    636  static inline size_t Size() { return sizeof(IonDOMMethodExitFrameLayout); }
    637 
    638  static size_t offsetOfResult() {
    639    return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_);
    640  }
    641 
    642  inline JS::Value* vp() {
    643    // The code in visitCallDOMNative depends on this static assert holding
    644    static_assert(
    645        offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) ==
    646        (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
    647    return reinterpret_cast<JS::Value*>(&loCalleeResult_);
    648  }
    649  inline JSObject** thisObjAddress() { return &thisObj_; }
    650  inline uintptr_t argc() { return argc_; }
    651 };
    652 
    653 inline bool IonDOMExitFrameLayout::isMethodFrame() {
    654  return footer_.type() == IonDOMMethodExitFrameLayout::Type();
    655 }
    656 
    657 template <>
    658 inline bool ExitFrameLayout::is<IonDOMExitFrameLayout>() {
    659  ExitFrameType type = footer()->type();
    660  return type == IonDOMExitFrameLayout::GetterType() ||
    661         type == IonDOMExitFrameLayout::SetterType() ||
    662         type == IonDOMMethodExitFrameLayout::Type();
    663 }
    664 
    665 template <>
    666 inline IonDOMExitFrameLayout* ExitFrameLayout::as<IonDOMExitFrameLayout>() {
    667  MOZ_ASSERT(is<IonDOMExitFrameLayout>());
    668  return reinterpret_cast<IonDOMExitFrameLayout*>(footer());
    669 }
    670 
    671 struct IonDOMMethodExitFrameLayoutTraits {
    672  static const size_t offsetOfArgcFromArgv =
    673      offsetof(IonDOMMethodExitFrameLayout, argc_) -
    674      offsetof(IonDOMMethodExitFrameLayout, argv_);
    675 };
    676 
    677 // Cannot inherit implementation since we need to extend the top of
    678 // ExitFrameLayout.
    679 class CalledFromJitExitFrameLayout {
    680 protected:  // silence clang warning about unused private fields
    681  ExitFooterFrame footer_;
    682  JitFrameLayout exit_;
    683 
    684 public:
    685  static inline size_t Size() { return sizeof(CalledFromJitExitFrameLayout); }
    686  inline JitFrameLayout* jsFrame() { return &exit_; }
    687  static size_t offsetOfExitFrame() {
    688    return offsetof(CalledFromJitExitFrameLayout, exit_);
    689  }
    690 };
    691 
    692 class LazyLinkExitFrameLayout : public CalledFromJitExitFrameLayout {
    693 public:
    694  static ExitFrameType Type() { return ExitFrameType::LazyLink; }
    695 };
    696 
    697 class InterpreterStubExitFrameLayout : public CalledFromJitExitFrameLayout {
    698 public:
    699  static ExitFrameType Type() { return ExitFrameType::InterpreterStub; }
    700 };
    701 
    702 class WasmGenericJitEntryFrameLayout : CalledFromJitExitFrameLayout {
    703 public:
    704  static ExitFrameType Type() { return ExitFrameType::WasmGenericJitEntry; }
    705 };
    706 
    707 template <>
    708 inline bool ExitFrameLayout::is<CalledFromJitExitFrameLayout>() {
    709  return is<InterpreterStubExitFrameLayout>() ||
    710         is<LazyLinkExitFrameLayout>() || is<WasmGenericJitEntryFrameLayout>();
    711 }
    712 
    713 template <>
    714 inline CalledFromJitExitFrameLayout*
    715 ExitFrameLayout::as<CalledFromJitExitFrameLayout>() {
    716  MOZ_ASSERT(is<CalledFromJitExitFrameLayout>());
    717  uint8_t* sp = reinterpret_cast<uint8_t*>(this);
    718  sp -= CalledFromJitExitFrameLayout::offsetOfExitFrame();
    719  return reinterpret_cast<CalledFromJitExitFrameLayout*>(sp);
    720 }
    721 
    722 class DirectWasmJitCallFrameLayout {
    723 protected:  // silence clang warning about unused private fields
    724  ExitFooterFrame footer_;
    725  ExitFrameLayout exit_;
    726 
    727 public:
    728  static ExitFrameType Type() { return ExitFrameType::DirectWasmJitCall; }
    729 };
    730 
    731 class ICStub;
    732 
    733 class BaselineStubFrameLayout : public CommonFrameLayout {
    734  // Info on the stack
    735  //
    736  // +-------------------------------------------+
    737  // |BaselineStubFrameLayout                    |
    738  // +-------------------------------------------+
    739  // | - Descriptor                              | <= Marks end of
    740  // | - Return address                          |    FrameType::BaselineJS
    741  // | - CallerFramePtr                          | <= Frame pointer points here
    742  // +-------------------------------------------+
    743  // | - StubPtr                                 | <= Technically these fields
    744  // | - InlinedICScript or LocallyTracedValue   |    precede the FrameLayout in
    745  // |                      LocallyTracedValue...|    memory.
    746  // +-------------------------------------------+
    747  //
    748  // StubPtr is always present (but can be null; see generateDebugTrapHandler).
    749  // InlinedICScript is only present if the HasInlinedICScript flag is set in
    750  // the callee's frame descriptor (not shown in this diagram). Alternatively,
    751  // we support up to 255 locally traced values (with the count stored in
    752  // stub->jitCode()->localTracingSlots()).
    753 public:
    754  static constexpr size_t ICStubOffset = sizeof(void*);
    755  static constexpr int ICStubOffsetFromFP = -int(ICStubOffset);
    756  static constexpr int InlinedICScriptOffsetFromFP = 2 * -int(sizeof(void*));
    757  static constexpr size_t LocallyTracedValueOffset = 2 * sizeof(void*);
    758 
    759  static inline size_t Size() { return sizeof(BaselineStubFrameLayout); }
    760 
    761  ICStub* maybeStubPtr() {
    762    uint8_t* fp = reinterpret_cast<uint8_t*>(this);
    763    return *reinterpret_cast<ICStub**>(fp - ICStubOffset);
    764  }
    765  void setStubPtr(ICStub* stub) {
    766    MOZ_ASSERT(stub);
    767    uint8_t* fp = reinterpret_cast<uint8_t*>(this);
    768    *reinterpret_cast<ICStub**>(fp - ICStubOffset) = stub;
    769  }
    770 
    771  inline Value* locallyTracedValuePtr(size_t index) {
    772    uint8_t* fp = reinterpret_cast<uint8_t*>(this);
    773    return reinterpret_cast<Value*>(fp - LocallyTracedValueOffset -
    774                                    index * sizeof(Value));
    775  }
    776 };
    777 
    778 // An invalidation bailout stack is at the stack pointer for the callee frame.
    779 class InvalidationBailoutStack {
    780  RegisterDump::FPUArray fpregs_;
    781  RegisterDump::GPRArray regs_;
    782  IonScript* ionScript_;
    783  uint8_t* osiPointReturnAddress_;
    784 
    785 public:
    786  uint8_t* sp() const {
    787    return (uint8_t*)this + sizeof(InvalidationBailoutStack);
    788  }
    789  JitFrameLayout* fp() const;
    790  MachineState machine() { return MachineState::FromBailout(regs_, fpregs_); }
    791 
    792  IonScript* ionScript() const { return ionScript_; }
    793  uint8_t* osiPointReturnAddress() const { return osiPointReturnAddress_; }
    794  static size_t offsetOfFpRegs() {
    795    return offsetof(InvalidationBailoutStack, fpregs_);
    796  }
    797  static size_t offsetOfRegs() {
    798    return offsetof(InvalidationBailoutStack, regs_);
    799  }
    800 
    801  void checkInvariants() const;
    802 };
    803 
    804 // Baseline requires one slot for this/argument type checks.
    805 static const uint32_t MinJITStackSize = 1;
    806 
    807 } /* namespace jit */
    808 } /* namespace js */
    809 
    810 #endif /* jit_JitFrames_h */