LCOV - code coverage report
Current view: top level - js/src/jit - JitFrames.h (source / functions) Hit Total Coverage
Test: output.info Lines: 173 274 63.1 %
Date: 2017-07-14 16:53:18 Functions: 82 134 61.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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 <stdint.h>
      11             : 
      12             : #include "jscntxt.h"
      13             : #include "jsfun.h"
      14             : 
      15             : #include "jit/JitFrameIterator.h"
      16             : #include "jit/Safepoints.h"
      17             : 
      18             : namespace js {
      19             : namespace jit {
      20             : 
      21             : enum CalleeTokenTag
      22             : {
      23             :     CalleeToken_Function = 0x0, // untagged
      24             :     CalleeToken_FunctionConstructing = 0x1,
      25             :     CalleeToken_Script = 0x2
      26             : };
      27             : 
      28             : static const uintptr_t CalleeTokenMask = ~uintptr_t(0x3);
      29             : 
      30             : static inline CalleeTokenTag
      31      510574 : GetCalleeTokenTag(CalleeToken token)
      32             : {
      33      510574 :     CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
      34      510574 :     MOZ_ASSERT(tag <= CalleeToken_Script);
      35      510574 :     return tag;
      36             : }
      37             : static inline CalleeToken
      38        7695 : CalleeToToken(JSFunction* fun, bool constructing)
      39             : {
      40        7695 :     CalleeTokenTag tag = constructing ? CalleeToken_FunctionConstructing : CalleeToken_Function;
      41        7695 :     return CalleeToken(uintptr_t(fun) | uintptr_t(tag));
      42             : }
      43             : static inline CalleeToken
      44           5 : CalleeToToken(JSScript* script)
      45             : {
      46           5 :     return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
      47             : }
      48             : static inline bool
      49      263467 : CalleeTokenIsFunction(CalleeToken token)
      50             : {
      51      263467 :     CalleeTokenTag tag = GetCalleeTokenTag(token);
      52      263467 :     return tag == CalleeToken_Function || tag == CalleeToken_FunctionConstructing;
      53             : }
      54             : static inline bool
      55         141 : CalleeTokenIsConstructing(CalleeToken token)
      56             : {
      57         141 :     return GetCalleeTokenTag(token) == CalleeToken_FunctionConstructing;
      58             : }
      59             : static inline JSFunction*
      60      242839 : CalleeTokenToFunction(CalleeToken token)
      61             : {
      62      242839 :     MOZ_ASSERT(CalleeTokenIsFunction(token));
      63      242839 :     return (JSFunction*)(uintptr_t(token) & CalleeTokenMask);
      64             : }
      65             : static inline JSScript*
      66        9464 : CalleeTokenToScript(CalleeToken token)
      67             : {
      68        9464 :     MOZ_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
      69        9464 :     return (JSScript*)(uintptr_t(token) & CalleeTokenMask);
      70             : }
      71             : static inline bool
      72             : CalleeTokenIsModuleScript(CalleeToken token)
      73             : {
      74             :     CalleeTokenTag tag = GetCalleeTokenTag(token);
      75             :     return tag == CalleeToken_Script && CalleeTokenToScript(token)->module();
      76             : }
      77             : 
      78             : static inline JSScript*
      79      237475 : ScriptFromCalleeToken(CalleeToken token)
      80             : {
      81      237475 :     switch (GetCalleeTokenTag(token)) {
      82             :       case CalleeToken_Script:
      83        9464 :         return CalleeTokenToScript(token);
      84             :       case CalleeToken_Function:
      85             :       case CalleeToken_FunctionConstructing:
      86      228011 :         return CalleeTokenToFunction(token)->nonLazyScript();
      87             :     }
      88           0 :     MOZ_CRASH("invalid callee token tag");
      89             : }
      90             : 
      91             : // In between every two frames lies a small header describing both frames. This
      92             : // header, minimally, contains a returnAddress word and a descriptor word. The
      93             : // descriptor describes the size and type of the previous frame, whereas the
      94             : // returnAddress describes the address the newer frame (the callee) will return
      95             : // to. The exact mechanism in which frames are laid out is architecture
      96             : // dependent.
      97             : //
      98             : // Two special frame types exist:
      99             : // - Entry frames begin a JitActivation, and therefore there is exactly one
     100             : // per activation of EnterIon or EnterBaseline. These reuse JitFrameLayout.
     101             : // - Exit frames are necessary to leave JIT code and enter C++, and thus,
     102             : // C++ code will always begin iterating from the topmost exit frame.
     103             : 
     104             : class LSafepoint;
     105             : 
     106             : // Two-tuple that lets you look up the safepoint entry given the
     107             : // displacement of a call instruction within the JIT code.
     108             : class SafepointIndex
     109             : {
     110             :     // The displacement is the distance from the first byte of the JIT'd code
     111             :     // to the return address (of the call that the safepoint was generated for).
     112             :     uint32_t displacement_;
     113             : 
     114             :     union {
     115             :         LSafepoint* safepoint_;
     116             : 
     117             :         // Offset to the start of the encoded safepoint in the safepoint stream.
     118             :         uint32_t safepointOffset_;
     119             :     };
     120             : 
     121             : #ifdef DEBUG
     122             :     bool resolved;
     123             : #endif
     124             : 
     125             :   public:
     126         147 :     SafepointIndex(uint32_t displacement, LSafepoint* safepoint)
     127         147 :       : displacement_(displacement),
     128             :         safepoint_(safepoint)
     129             : #ifdef DEBUG
     130         147 :       , resolved(false)
     131             : #endif
     132         147 :     { }
     133             : 
     134             :     void resolve();
     135             : 
     136          43 :     LSafepoint* safepoint() {
     137          43 :         MOZ_ASSERT(!resolved);
     138          43 :         return safepoint_;
     139             :     }
     140        6860 :     uint32_t displacement() const {
     141        6860 :         return displacement_;
     142             :     }
     143        1680 :     uint32_t safepointOffset() const {
     144        1680 :         return safepointOffset_;
     145             :     }
     146             :     void adjustDisplacement(uint32_t offset) {
     147             :         MOZ_ASSERT(offset >= displacement_);
     148             :         displacement_ = offset;
     149             :     }
     150             :     inline SnapshotOffset snapshotOffset() const;
     151             :     inline bool hasSnapshotOffset() const;
     152             : };
     153             : 
     154             : class MacroAssembler;
     155             : // The OSI point is patched to a call instruction. Therefore, the
     156             : // returnPoint for an OSI call is the address immediately following that
     157             : // call instruction. The displacement of that point within the assembly
     158             : // buffer is the |returnPointDisplacement|.
     159             : class OsiIndex
     160             : {
     161             :     uint32_t callPointDisplacement_;
     162             :     uint32_t snapshotOffset_;
     163             : 
     164             :   public:
     165         134 :     OsiIndex(uint32_t callPointDisplacement, uint32_t snapshotOffset)
     166         134 :       : callPointDisplacement_(callPointDisplacement),
     167         134 :         snapshotOffset_(snapshotOffset)
     168         134 :     { }
     169             : 
     170             :     uint32_t returnPointDisplacement() const;
     171             :     uint32_t callPointDisplacement() const {
     172             :         return callPointDisplacement_;
     173             :     }
     174         840 :     uint32_t snapshotOffset() const {
     175         840 :         return snapshotOffset_;
     176             :     }
     177             : };
     178             : 
     179             : // The layout of an Ion frame on the C stack is roughly:
     180             : //      argN     _
     181             : //      ...       \ - These are jsvals
     182             : //      arg0      /
     183             : //   -3 this    _/
     184             : //   -2 callee
     185             : //   -1 descriptor
     186             : //    0 returnAddress
     187             : //   .. locals ..
     188             : 
     189             : // The descriptor is organized into four sections:
     190             : // [ frame size | has cached saved frame bit | frame header size | frame type ]
     191             : // < highest - - - - - - - - - - - - - - lowest >
     192             : static const uintptr_t FRAMETYPE_BITS = 4;
     193             : static const uintptr_t FRAME_HEADER_SIZE_SHIFT = FRAMETYPE_BITS;
     194             : static const uintptr_t FRAME_HEADER_SIZE_BITS = 3;
     195             : static const uintptr_t FRAME_HEADER_SIZE_MASK = (1 << FRAME_HEADER_SIZE_BITS) - 1;
     196             : static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << (FRAMETYPE_BITS + FRAME_HEADER_SIZE_BITS);
     197             : static const uintptr_t FRAMESIZE_SHIFT = FRAMETYPE_BITS +
     198             :                                          FRAME_HEADER_SIZE_BITS +
     199             :                                          1 /* cached saved frame bit */;
     200             : static const uintptr_t FRAMESIZE_BITS = 32 - FRAMESIZE_SHIFT;
     201             : static const uintptr_t FRAMESIZE_MASK = (1 << FRAMESIZE_BITS) - 1;
     202             : 
     203             : // Ion frames have a few important numbers associated with them:
     204             : //      Local depth:    The number of bytes required to spill local variables.
     205             : //      Argument depth: The number of bytes required to push arguments and make
     206             : //                      a function call.
     207             : //      Slack:          A frame may temporarily use extra stack to resolve cycles.
     208             : //
     209             : // The (local + argument) depth determines the "fixed frame size". The fixed
     210             : // frame size is the distance between the stack pointer and the frame header.
     211             : // Thus, fixed >= (local + argument).
     212             : //
     213             : // In order to compress guards, we create shared jump tables that recover the
     214             : // script from the stack and recover a snapshot pointer based on which jump was
     215             : // taken. Thus, we create a jump table for each fixed frame size.
     216             : //
     217             : // Jump tables are big. To control the amount of jump tables we generate, each
     218             : // platform chooses how to segregate stack size classes based on its
     219             : // architecture.
     220             : //
     221             : // On some architectures, these jump tables are not used at all, or frame
     222             : // size segregation is not needed. Thus, there is an option for a frame to not
     223             : // have any frame size class, and to be totally dynamic.
     224             : static const uint32_t NO_FRAME_SIZE_CLASS_ID = uint32_t(-1);
     225             : 
     226             : class FrameSizeClass
     227             : {
     228             :     uint32_t class_;
     229             : 
     230         590 :     explicit FrameSizeClass(uint32_t class_) : class_(class_)
     231         590 :     { }
     232             : 
     233             :   public:
     234           8 :     FrameSizeClass()
     235           8 :     { }
     236             : 
     237         578 :     static FrameSizeClass None() {
     238         578 :         return FrameSizeClass(NO_FRAME_SIZE_CLASS_ID);
     239             :     }
     240           4 :     static FrameSizeClass FromClass(uint32_t class_) {
     241           4 :         return FrameSizeClass(class_);
     242             :     }
     243             : 
     244             :     // These functions are implemented in specific CodeGenerator-* files.
     245             :     static FrameSizeClass FromDepth(uint32_t frameDepth);
     246             :     static FrameSizeClass ClassLimit();
     247             :     uint32_t frameSize() const;
     248             : 
     249           4 :     uint32_t classId() const {
     250           4 :         MOZ_ASSERT(class_ != NO_FRAME_SIZE_CLASS_ID);
     251           4 :         return class_;
     252             :     }
     253             : 
     254         196 :     bool operator ==(const FrameSizeClass& other) const {
     255         196 :         return class_ == other.class_;
     256             :     }
     257         378 :     bool operator !=(const FrameSizeClass& other) const {
     258         378 :         return class_ != other.class_;
     259             :     }
     260             : };
     261             : 
     262             : struct BaselineBailoutInfo;
     263             : 
     264             : // Data needed to recover from an exception.
     265             : struct ResumeFromException
     266             : {
     267             :     static const uint32_t RESUME_ENTRY_FRAME = 0;
     268             :     static const uint32_t RESUME_CATCH = 1;
     269             :     static const uint32_t RESUME_FINALLY = 2;
     270             :     static const uint32_t RESUME_FORCED_RETURN = 3;
     271             :     static const uint32_t RESUME_BAILOUT = 4;
     272             : 
     273             :     uint8_t* framePointer;
     274             :     uint8_t* stackPointer;
     275             :     uint8_t* target;
     276             :     uint32_t kind;
     277             : 
     278             :     // Value to push when resuming into a |finally| block.
     279             :     Value exception;
     280             : 
     281             :     BaselineBailoutInfo* bailoutInfo;
     282             : };
     283             : 
     284             : void HandleException(ResumeFromException* rfe);
     285             : 
     286             : void EnsureBareExitFrame(JSContext* cx, JitFrameLayout* frame);
     287             : 
     288             : void TraceJitActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
     289             : 
     290             : void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc);
     291             : 
     292             : static inline uint32_t
     293        5227 : EncodeFrameHeaderSize(size_t headerSize)
     294             : {
     295        5227 :     MOZ_ASSERT((headerSize % sizeof(uintptr_t)) == 0);
     296             : 
     297        5227 :     uint32_t headerSizeWords = headerSize / sizeof(uintptr_t);
     298        5227 :     MOZ_ASSERT(headerSizeWords <= FRAME_HEADER_SIZE_MASK);
     299        5227 :     return headerSizeWords;
     300             : }
     301             : 
     302             : static inline uint32_t
     303        3583 : MakeFrameDescriptor(uint32_t frameSize, FrameType type, uint32_t headerSize)
     304             : {
     305        3583 :     MOZ_ASSERT(headerSize < FRAMESIZE_MASK);
     306        3583 :     headerSize = EncodeFrameHeaderSize(headerSize);
     307        3583 :     return 0 | (frameSize << FRAMESIZE_SHIFT) | (headerSize << FRAME_HEADER_SIZE_SHIFT) | type;
     308             : }
     309             : 
     310             : // Returns the JSScript associated with the topmost JIT frame.
     311             : inline JSScript*
     312           0 : GetTopJitJSScript(JSContext* cx)
     313             : {
     314           0 :     JitFrameIterator iter(cx);
     315           0 :     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     316           0 :     ++iter;
     317             : 
     318           0 :     if (iter.isBaselineStub()) {
     319           0 :         ++iter;
     320           0 :         MOZ_ASSERT(iter.isBaselineJS());
     321             :     }
     322             : 
     323           0 :     MOZ_ASSERT(iter.isScripted());
     324           0 :     return iter.script();
     325             : }
     326             : 
     327             : #ifdef JS_CODEGEN_MIPS32
     328             : uint8_t* alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset);
     329             : #else
     330             : inline uint8_t*
     331         855 : alignDoubleSpillWithOffset(uint8_t* pointer, int32_t offset)
     332             : {
     333             :     // This is NO-OP on non-MIPS platforms.
     334         855 :     return pointer;
     335             : }
     336             : #endif
     337             : 
     338             : // Layout of the frame prefix. This assumes the stack architecture grows down.
     339             : // If this is ever not the case, we'll have to refactor.
     340             : class CommonFrameLayout
     341             : {
     342             :     uint8_t* returnAddress_;
     343             :     uintptr_t descriptor_;
     344             : 
     345             :     static const uintptr_t FrameTypeMask = (1 << FRAMETYPE_BITS) - 1;
     346             : 
     347             :   public:
     348          12 :     static size_t offsetOfDescriptor() {
     349          12 :         return offsetof(CommonFrameLayout, descriptor_);
     350             :     }
     351             :     uintptr_t descriptor() const {
     352             :         return descriptor_;
     353             :     }
     354          20 :     static size_t offsetOfReturnAddress() {
     355          20 :         return offsetof(CommonFrameLayout, returnAddress_);
     356             :     }
     357       43293 :     FrameType prevType() const {
     358       43293 :         return FrameType(descriptor_ & FrameTypeMask);
     359             :     }
     360             :     void changePrevType(FrameType type) {
     361             :         descriptor_ &= ~FrameTypeMask;
     362             :         descriptor_ |= type;
     363             :     }
     364       43293 :     size_t prevFrameLocalSize() const {
     365       43293 :         return descriptor_ >> FRAMESIZE_SHIFT;
     366             :     }
     367       20063 :     size_t headerSize() const {
     368             :         return sizeof(uintptr_t) *
     369       20063 :             ((descriptor_ >> FRAME_HEADER_SIZE_SHIFT) & FRAME_HEADER_SIZE_MASK);
     370             :     }
     371           0 :     bool hasCachedSavedFrame() const {
     372           0 :         return descriptor_ & HASCACHEDSAVEDFRAME_BIT;
     373             :     }
     374           0 :     void setHasCachedSavedFrame() {
     375           0 :         descriptor_ |= HASCACHEDSAVEDFRAME_BIT;
     376           0 :     }
     377       20063 :     uint8_t* returnAddress() const {
     378       20063 :         return returnAddress_;
     379             :     }
     380           0 :     void setReturnAddress(uint8_t* addr) {
     381           0 :         returnAddress_ = addr;
     382           0 :     }
     383             : };
     384             : 
     385             : class JitFrameLayout : public CommonFrameLayout
     386             : {
     387             :     CalleeToken calleeToken_;
     388             :     uintptr_t numActualArgs_;
     389             : 
     390             :   public:
     391       39490 :     CalleeToken calleeToken() const {
     392       39490 :         return calleeToken_;
     393             :     }
     394           0 :     void replaceCalleeToken(CalleeToken calleeToken) {
     395           0 :         calleeToken_ = calleeToken;
     396           0 :     }
     397             : 
     398      234226 :     static size_t offsetOfCalleeToken() {
     399      234226 :         return offsetof(JitFrameLayout, calleeToken_);
     400             :     }
     401         825 :     static size_t offsetOfNumActualArgs() {
     402         825 :         return offsetof(JitFrameLayout, numActualArgs_);
     403             :     }
     404       12591 :     static size_t offsetOfThis() {
     405       12591 :         return sizeof(JitFrameLayout);
     406             :     }
     407           0 :     static size_t offsetOfEvalNewTarget() {
     408           0 :         return sizeof(JitFrameLayout);
     409             :     }
     410       11630 :     static size_t offsetOfActualArgs() {
     411       11630 :         return offsetOfThis() + sizeof(Value);
     412             :     }
     413       11628 :     static size_t offsetOfActualArg(size_t arg) {
     414       11628 :         return offsetOfActualArgs() + arg * sizeof(Value);
     415             :     }
     416             : 
     417             :     Value thisv() {
     418             :         MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
     419             :         return argv()[0];
     420             :     }
     421           1 :     Value* argv() {
     422           1 :         MOZ_ASSERT(CalleeTokenIsFunction(calleeToken()));
     423           1 :         return (Value*)(this + 1);
     424             :     }
     425           0 :     uintptr_t numActualArgs() const {
     426           0 :         return numActualArgs_;
     427             :     }
     428             : 
     429             :     // Computes a reference to a stack or argument slot, where a slot is a
     430             :     // distance from the base frame pointer, as would be used for LStackSlot
     431             :     // or LArgument.
     432             :     uintptr_t* slotRef(SafepointSlotEntry where);
     433             : 
     434         118 :     static inline size_t Size() {
     435         118 :         return sizeof(JitFrameLayout);
     436             :     }
     437             : };
     438             : 
     439             : class RectifierFrameLayout : public JitFrameLayout
     440             : {
     441             :   public:
     442          12 :     static inline size_t Size() {
     443          12 :         return sizeof(RectifierFrameLayout);
     444             :     }
     445             : };
     446             : 
     447             : class IonICCallFrameLayout : public CommonFrameLayout
     448             : {
     449             :   protected:
     450             :     // Pointer to root the stub's JitCode.
     451             :     JitCode* stubCode_;
     452             : 
     453             :   public:
     454           0 :     JitCode** stubCode() {
     455           0 :         return &stubCode_;
     456             :     }
     457           4 :     static size_t Size() {
     458           4 :         return sizeof(IonICCallFrameLayout);
     459             :     }
     460             : };
     461             : 
     462             : // GC related data used to keep alive data surrounding the Exit frame.
     463             : class ExitFooterFrame
     464             : {
     465             :     const VMFunction* function_;
     466             :     JitCode* jitCode_;
     467             : 
     468             :   public:
     469        2613 :     static inline size_t Size() {
     470        2613 :         return sizeof(ExitFooterFrame);
     471             :     }
     472         388 :     inline JitCode* jitCode() const {
     473         388 :         return jitCode_;
     474             :     }
     475          97 :     inline JitCode** addressOfJitCode() {
     476          97 :         return &jitCode_;
     477             :     }
     478          19 :     inline const VMFunction* function() const {
     479          19 :         return function_;
     480             :     }
     481             : 
     482             :     // This should only be called for function()->outParam == Type_Handle
     483             :     template <typename T>
     484          15 :     T* outParam() {
     485          15 :         uint8_t* address = reinterpret_cast<uint8_t*>(this);
     486          15 :         address = alignDoubleSpillWithOffset(address, sizeof(intptr_t));
     487          15 :         return reinterpret_cast<T*>(address - sizeof(T));
     488             :     }
     489             : };
     490             : 
     491             : class NativeExitFrameLayout;
     492             : class IonOOLNativeExitFrameLayout;
     493             : class IonOOLPropertyOpExitFrameLayout;
     494             : class IonOOLProxyExitFrameLayout;
     495             : class IonDOMExitFrameLayout;
     496             : 
     497             : enum ExitFrameTokenValues
     498             : {
     499             :     CallNativeExitFrameLayoutToken        = 0x0,
     500             :     ConstructNativeExitFrameLayoutToken   = 0x1,
     501             :     IonDOMExitFrameLayoutGetterToken      = 0x2,
     502             :     IonDOMExitFrameLayoutSetterToken      = 0x3,
     503             :     IonDOMMethodExitFrameLayoutToken      = 0x4,
     504             :     IonOOLNativeExitFrameLayoutToken      = 0x5,
     505             :     IonOOLPropertyOpExitFrameLayoutToken  = 0x6,
     506             :     IonOOLSetterOpExitFrameLayoutToken    = 0x7,
     507             :     IonOOLProxyExitFrameLayoutToken       = 0x8,
     508             :     LazyLinkExitFrameLayoutToken          = 0xFE,
     509             :     ExitFrameLayoutBareToken              = 0xFF
     510             : };
     511             : 
     512             : // this is the frame layout when we are exiting ion code, and about to enter platform ABI code
     513             : class ExitFrameLayout : public CommonFrameLayout
     514             : {
     515          19 :     inline uint8_t* top() {
     516          19 :         return reinterpret_cast<uint8_t*>(this + 1);
     517             :     }
     518             : 
     519             :   public:
     520             :     // Pushed for "bare" fake exit frames that have no GC things on stack to be
     521             :     // traced.
     522         253 :     static JitCode* BareToken() { return (JitCode*)ExitFrameLayoutBareToken; }
     523             : 
     524        5777 :     static inline size_t Size() {
     525        5777 :         return sizeof(ExitFrameLayout);
     526             :     }
     527        1024 :     static inline size_t SizeWithFooter() {
     528        1024 :         return Size() + ExitFooterFrame::Size();
     529             :     }
     530             : 
     531         549 :     inline ExitFooterFrame* footer() {
     532         549 :         uint8_t* sp = reinterpret_cast<uint8_t*>(this);
     533         549 :         return reinterpret_cast<ExitFooterFrame*>(sp - ExitFooterFrame::Size());
     534             :     }
     535             : 
     536             :     // argBase targets the point which precedes the exit frame. Arguments of VM
     537             :     // each wrapper are pushed before the exit frame.  This correspond exactly
     538             :     // to the value of the argBase register of the generateVMWrapper function.
     539          19 :     inline uint8_t* argBase() {
     540          19 :         MOZ_ASSERT(footer()->jitCode() != nullptr);
     541          19 :         return top();
     542             :     }
     543             : 
     544             :     inline bool isWrapperExit() {
     545             :         return footer()->function() != nullptr;
     546             :     }
     547         175 :     inline bool isBareExit() {
     548         175 :         return footer()->jitCode() == BareToken();
     549             :     }
     550             : 
     551             :     // See the various exit frame layouts below.
     552         151 :     template <typename T> inline bool is() {
     553         151 :         return footer()->jitCode() == T::Token();
     554             :     }
     555           5 :     template <typename T> inline T* as() {
     556           5 :         MOZ_ASSERT(this->is<T>());
     557           5 :         return reinterpret_cast<T*>(footer());
     558             :     }
     559             : };
     560             : 
     561             : // Cannot inherit implementation since we need to extend the top of
     562             : // ExitFrameLayout.
     563             : class NativeExitFrameLayout
     564             : {
     565             :   protected: // only to silence a clang warning about unused private fields
     566             :     ExitFooterFrame footer_;
     567             :     ExitFrameLayout exit_;
     568             :     uintptr_t argc_;
     569             : 
     570             :     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     571             :     // compiler may add some padding between the fields.
     572             :     uint32_t loCalleeResult_;
     573             :     uint32_t hiCalleeResult_;
     574             : 
     575             :   public:
     576           9 :     static inline size_t Size() {
     577           9 :         return sizeof(NativeExitFrameLayout);
     578             :     }
     579             : 
     580          86 :     static size_t offsetOfResult() {
     581          86 :         return offsetof(NativeExitFrameLayout, loCalleeResult_);
     582             :     }
     583           5 :     inline Value* vp() {
     584           5 :         return reinterpret_cast<Value*>(&loCalleeResult_);
     585             :     }
     586           5 :     inline uintptr_t argc() const {
     587           5 :         return argc_;
     588             :     }
     589             : };
     590             : 
     591             : class CallNativeExitFrameLayout : public NativeExitFrameLayout
     592             : {
     593             :   public:
     594          29 :     static JitCode* Token() { return (JitCode*)CallNativeExitFrameLayoutToken; }
     595             : };
     596             : 
     597             : class ConstructNativeExitFrameLayout : public NativeExitFrameLayout
     598             : {
     599             :   public:
     600          24 :     static JitCode* Token() { return (JitCode*)ConstructNativeExitFrameLayoutToken; }
     601             : };
     602             : 
     603             : template<>
     604             : inline bool
     605          29 : ExitFrameLayout::is<NativeExitFrameLayout>()
     606             : {
     607          29 :     return is<CallNativeExitFrameLayout>() || is<ConstructNativeExitFrameLayout>();
     608             : }
     609             : 
     610             : class IonOOLNativeExitFrameLayout
     611             : {
     612             :   protected: // only to silence a clang warning about unused private fields
     613             :     ExitFooterFrame footer_;
     614             :     ExitFrameLayout exit_;
     615             : 
     616             :     // pointer to root the stub's JitCode
     617             :     JitCode* stubCode_;
     618             : 
     619             :     uintptr_t argc_;
     620             : 
     621             :     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     622             :     // compiler may add some padding between the fields.
     623             :     uint32_t loCalleeResult_;
     624             :     uint32_t hiCalleeResult_;
     625             : 
     626             :     // Split Value for |this| and args above.
     627             :     uint32_t loThis_;
     628             :     uint32_t hiThis_;
     629             : 
     630             :   public:
     631          19 :     static JitCode* Token() { return (JitCode*)IonOOLNativeExitFrameLayoutToken; }
     632             : 
     633           0 :     static inline size_t Size(size_t argc) {
     634             :         // The frame accounts for the callee/result and |this|, so we only need args.
     635           0 :         return sizeof(IonOOLNativeExitFrameLayout) + (argc * sizeof(Value));
     636             :     }
     637             : 
     638           0 :     static size_t offsetOfResult() {
     639           0 :         return offsetof(IonOOLNativeExitFrameLayout, loCalleeResult_);
     640             :     }
     641             : 
     642           0 :     inline JitCode** stubCode() {
     643           0 :         return &stubCode_;
     644             :     }
     645           0 :     inline Value* vp() {
     646           0 :         return reinterpret_cast<Value*>(&loCalleeResult_);
     647             :     }
     648           0 :     inline Value* thisp() {
     649           0 :         return reinterpret_cast<Value*>(&loThis_);
     650             :     }
     651           0 :     inline uintptr_t argc() const {
     652           0 :         return argc_;
     653             :     }
     654             : };
     655             : 
     656             : class IonOOLPropertyOpExitFrameLayout
     657             : {
     658             :   protected:
     659             :     ExitFooterFrame footer_;
     660             :     ExitFrameLayout exit_;
     661             : 
     662             :     // Object for HandleObject
     663             :     JSObject* obj_;
     664             : 
     665             :     // id for HandleId
     666             :     jsid id_;
     667             : 
     668             :     // space for MutableHandleValue result
     669             :     // use two uint32_t so compiler doesn't align.
     670             :     uint32_t vp0_;
     671             :     uint32_t vp1_;
     672             : 
     673             :     // pointer to root the stub's JitCode
     674             :     JitCode* stubCode_;
     675             : 
     676             :   public:
     677          19 :     static JitCode* Token() { return (JitCode*)IonOOLPropertyOpExitFrameLayoutToken; }
     678             : 
     679             :     static inline size_t Size() {
     680             :         return sizeof(IonOOLPropertyOpExitFrameLayout);
     681             :     }
     682             : 
     683             :     static size_t offsetOfObject() {
     684             :         return offsetof(IonOOLPropertyOpExitFrameLayout, obj_);
     685             :     }
     686             : 
     687             :     static size_t offsetOfId() {
     688             :         return offsetof(IonOOLPropertyOpExitFrameLayout, id_);
     689             :     }
     690             : 
     691             :     static size_t offsetOfResult() {
     692             :         return offsetof(IonOOLPropertyOpExitFrameLayout, vp0_);
     693             :     }
     694             : 
     695           0 :     inline JitCode** stubCode() {
     696           0 :         return &stubCode_;
     697             :     }
     698           0 :     inline Value* vp() {
     699           0 :         return reinterpret_cast<Value*>(&vp0_);
     700             :     }
     701           0 :     inline jsid* id() {
     702           0 :         return &id_;
     703             :     }
     704           0 :     inline JSObject** obj() {
     705           0 :         return &obj_;
     706             :     }
     707             : };
     708             : 
     709             : class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
     710             : {
     711             :   protected: // only to silence a clang warning about unused private fields
     712             :     JS::ObjectOpResult result_;
     713             : 
     714             :   public:
     715          19 :     static JitCode* Token() { return (JitCode*)IonOOLSetterOpExitFrameLayoutToken; }
     716             : 
     717             :     static size_t offsetOfObjectOpResult() {
     718             :         return offsetof(IonOOLSetterOpExitFrameLayout, result_);
     719             :     }
     720             : 
     721             :     static size_t Size() {
     722             :         return sizeof(IonOOLSetterOpExitFrameLayout);
     723             :     }
     724             : };
     725             : 
     726             : // ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
     727             : // ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
     728             : // ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
     729             : //                  bool strict)
     730             : class IonOOLProxyExitFrameLayout
     731             : {
     732             :   protected: // only to silence a clang warning about unused private fields
     733             :     ExitFooterFrame footer_;
     734             :     ExitFrameLayout exit_;
     735             : 
     736             :     // The proxy object.
     737             :     JSObject* proxy_;
     738             : 
     739             :     // id for HandleId
     740             :     jsid id_;
     741             : 
     742             :     // space for MutableHandleValue result
     743             :     // use two uint32_t so compiler doesn't align.
     744             :     uint32_t vp0_;
     745             :     uint32_t vp1_;
     746             : 
     747             :     // pointer to root the stub's JitCode
     748             :     JitCode* stubCode_;
     749             : 
     750             :   public:
     751          19 :     static JitCode* Token() { return (JitCode*)IonOOLProxyExitFrameLayoutToken; }
     752             : 
     753           0 :     static inline size_t Size() {
     754           0 :         return sizeof(IonOOLProxyExitFrameLayout);
     755             :     }
     756             : 
     757           0 :     static size_t offsetOfResult() {
     758           0 :         return offsetof(IonOOLProxyExitFrameLayout, vp0_);
     759             :     }
     760             : 
     761           0 :     inline JitCode** stubCode() {
     762           0 :         return &stubCode_;
     763             :     }
     764           0 :     inline Value* vp() {
     765           0 :         return reinterpret_cast<Value*>(&vp0_);
     766             :     }
     767           0 :     inline jsid* id() {
     768           0 :         return &id_;
     769             :     }
     770           0 :     inline JSObject** proxy() {
     771           0 :         return &proxy_;
     772             :     }
     773             : };
     774             : 
     775             : class IonDOMExitFrameLayout
     776             : {
     777             :   protected: // only to silence a clang warning about unused private fields
     778             :     ExitFooterFrame footer_;
     779             :     ExitFrameLayout exit_;
     780             :     JSObject* thisObj;
     781             : 
     782             :     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     783             :     // compiler may add some padding between the fields.
     784             :     uint32_t loCalleeResult_;
     785             :     uint32_t hiCalleeResult_;
     786             : 
     787             :   public:
     788          19 :     static JitCode* GetterToken() { return (JitCode*)IonDOMExitFrameLayoutGetterToken; }
     789          19 :     static JitCode* SetterToken() { return (JitCode*)IonDOMExitFrameLayoutSetterToken; }
     790             : 
     791           0 :     static inline size_t Size() {
     792           0 :         return sizeof(IonDOMExitFrameLayout);
     793             :     }
     794             : 
     795           0 :     static size_t offsetOfResult() {
     796           0 :         return offsetof(IonDOMExitFrameLayout, loCalleeResult_);
     797             :     }
     798           0 :     inline Value* vp() {
     799           0 :         return reinterpret_cast<Value*>(&loCalleeResult_);
     800             :     }
     801           0 :     inline JSObject** thisObjAddress() {
     802           0 :         return &thisObj;
     803             :     }
     804             :     inline bool isMethodFrame();
     805             : };
     806             : 
     807             : struct IonDOMMethodExitFrameLayoutTraits;
     808             : 
     809             : class IonDOMMethodExitFrameLayout
     810             : {
     811             :   protected: // only to silence a clang warning about unused private fields
     812             :     ExitFooterFrame footer_;
     813             :     ExitFrameLayout exit_;
     814             :     // This must be the last thing pushed, so as to stay common with
     815             :     // IonDOMExitFrameLayout.
     816             :     JSObject* thisObj_;
     817             :     Value* argv_;
     818             :     uintptr_t argc_;
     819             : 
     820             :     // We need to split the Value into 2 fields of 32 bits, otherwise the C++
     821             :     // compiler may add some padding between the fields.
     822             :     uint32_t loCalleeResult_;
     823             :     uint32_t hiCalleeResult_;
     824             : 
     825             :     friend struct IonDOMMethodExitFrameLayoutTraits;
     826             : 
     827             :   public:
     828          19 :     static JitCode* Token() { return (JitCode*)IonDOMMethodExitFrameLayoutToken; }
     829             : 
     830           0 :     static inline size_t Size() {
     831           0 :         return sizeof(IonDOMMethodExitFrameLayout);
     832             :     }
     833             : 
     834           0 :     static size_t offsetOfResult() {
     835           0 :         return offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_);
     836             :     }
     837             : 
     838           0 :     inline Value* vp() {
     839             :         // The code in visitCallDOMNative depends on this static assert holding
     840             :         JS_STATIC_ASSERT(offsetof(IonDOMMethodExitFrameLayout, loCalleeResult_) ==
     841             :                          (offsetof(IonDOMMethodExitFrameLayout, argc_) + sizeof(uintptr_t)));
     842           0 :         return reinterpret_cast<Value*>(&loCalleeResult_);
     843             :     }
     844             :     inline JSObject** thisObjAddress() {
     845             :         return &thisObj_;
     846             :     }
     847           0 :     inline uintptr_t argc() {
     848           0 :         return argc_;
     849             :     }
     850             : };
     851             : 
     852             : inline bool
     853           0 : IonDOMExitFrameLayout::isMethodFrame()
     854             : {
     855           0 :     return footer_.jitCode() == IonDOMMethodExitFrameLayout::Token();
     856             : }
     857             : 
     858             : template <>
     859             : inline bool
     860          19 : ExitFrameLayout::is<IonDOMExitFrameLayout>()
     861             : {
     862          19 :     JitCode* code = footer()->jitCode();
     863             :     return
     864          38 :         code == IonDOMExitFrameLayout::GetterToken() ||
     865          38 :         code == IonDOMExitFrameLayout::SetterToken() ||
     866          38 :         code == IonDOMMethodExitFrameLayout::Token();
     867             : }
     868             : 
     869             : template <>
     870             : inline IonDOMExitFrameLayout*
     871           0 : ExitFrameLayout::as<IonDOMExitFrameLayout>()
     872             : {
     873           0 :     MOZ_ASSERT(is<IonDOMExitFrameLayout>());
     874           0 :     return reinterpret_cast<IonDOMExitFrameLayout*>(footer());
     875             : }
     876             : 
     877             : struct IonDOMMethodExitFrameLayoutTraits {
     878             :     static const size_t offsetOfArgcFromArgv =
     879             :         offsetof(IonDOMMethodExitFrameLayout, argc_) -
     880             :         offsetof(IonDOMMethodExitFrameLayout, argv_);
     881             : };
     882             : 
     883             : // Cannot inherit implementation since we need to extend the top of
     884             : // ExitFrameLayout.
     885             : class LazyLinkExitFrameLayout
     886             : {
     887             :   protected: // silence clang warning about unused private fields
     888             :     JitCode* stubCode_;
     889             :     ExitFooterFrame footer_;
     890             :     JitFrameLayout exit_;
     891             : 
     892             :   public:
     893          22 :     static JitCode* Token() { return (JitCode*) LazyLinkExitFrameLayoutToken; }
     894             : 
     895             :     static inline size_t Size() {
     896             :         return sizeof(LazyLinkExitFrameLayout);
     897             :     }
     898             : 
     899           0 :     inline JitCode** stubCode() {
     900           0 :         return &stubCode_;
     901             :     }
     902           3 :     inline JitFrameLayout* jsFrame() {
     903           3 :         return &exit_;
     904             :     }
     905           3 :     static size_t offsetOfExitFrame() {
     906           3 :         return offsetof(LazyLinkExitFrameLayout, exit_);
     907             :     }
     908             : };
     909             : 
     910             : template <>
     911             : inline LazyLinkExitFrameLayout*
     912           3 : ExitFrameLayout::as<LazyLinkExitFrameLayout>()
     913             : {
     914           3 :     MOZ_ASSERT(is<LazyLinkExitFrameLayout>());
     915           3 :     uint8_t* sp = reinterpret_cast<uint8_t*>(this);
     916           3 :     sp -= LazyLinkExitFrameLayout::offsetOfExitFrame();
     917           3 :     return reinterpret_cast<LazyLinkExitFrameLayout*>(sp);
     918             : }
     919             : 
     920             : class ICStub;
     921             : 
     922             : class JitStubFrameLayout : public CommonFrameLayout
     923             : {
     924             :     // Info on the stack
     925             :     //
     926             :     // --------------------
     927             :     // |JitStubFrameLayout|
     928             :     // +------------------+
     929             :     // | - Descriptor     | => Marks end of JitFrame_IonJS
     930             :     // | - returnaddres   |
     931             :     // +------------------+
     932             :     // | - StubPtr        | => First thing pushed in a stub only when the stub will do
     933             :     // --------------------    a vmcall. Else we cannot have JitStubFrame. But technically
     934             :     //                         not a member of the layout.
     935             : 
     936             :   public:
     937           0 :     static size_t Size() {
     938           0 :         return sizeof(JitStubFrameLayout);
     939             :     }
     940             : 
     941          22 :     static inline int reverseOffsetOfStubPtr() {
     942          22 :         return -int(sizeof(void*));
     943             :     }
     944             : 
     945          22 :     inline ICStub* maybeStubPtr() {
     946          22 :         uint8_t* fp = reinterpret_cast<uint8_t*>(this);
     947          22 :         return *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr());
     948             :     }
     949             : };
     950             : 
     951             : class BaselineStubFrameLayout : public JitStubFrameLayout
     952             : {
     953             :     // Info on the stack
     954             :     //
     955             :     // -------------------------
     956             :     // |BaselineStubFrameLayout|
     957             :     // +-----------------------+
     958             :     // | - Descriptor          | => Marks end of JitFrame_BaselineJS
     959             :     // | - returnaddres        |
     960             :     // +-----------------------+
     961             :     // | - StubPtr             | => First thing pushed in a stub only when the stub will do
     962             :     // +-----------------------+    a vmcall. Else we cannot have BaselineStubFrame.
     963             :     // | - FramePtr            | => Baseline stubs also need to push the frame ptr when doing
     964             :     // -------------------------    a vmcall.
     965             :     //                              Technically these last two variables are not part of the
     966             :     //                              layout.
     967             : 
     968             :   public:
     969         385 :     static inline size_t Size() {
     970         385 :         return sizeof(BaselineStubFrameLayout);
     971             :     }
     972             : 
     973           0 :     static inline int reverseOffsetOfSavedFramePtr() {
     974           0 :         return -int(2 * sizeof(void*));
     975             :     }
     976             : 
     977           0 :     void* reverseSavedFramePtr() {
     978           0 :         uint8_t* addr = ((uint8_t*) this) + reverseOffsetOfSavedFramePtr();
     979           0 :         return *(void**)addr;
     980             :     }
     981             : 
     982           0 :     inline void setStubPtr(ICStub* stub) {
     983           0 :         uint8_t* fp = reinterpret_cast<uint8_t*>(this);
     984           0 :         *reinterpret_cast<ICStub**>(fp + reverseOffsetOfStubPtr()) = stub;
     985           0 :     }
     986             : };
     987             : 
     988             : // An invalidation bailout stack is at the stack pointer for the callee frame.
     989             : class InvalidationBailoutStack
     990             : {
     991             :     RegisterDump::FPUArray fpregs_;
     992             :     RegisterDump::GPRArray regs_;
     993             :     IonScript*  ionScript_;
     994             :     uint8_t*      osiPointReturnAddress_;
     995             : 
     996             :   public:
     997           0 :     uint8_t* sp() const {
     998           0 :         return (uint8_t*) this + sizeof(InvalidationBailoutStack);
     999             :     }
    1000             :     JitFrameLayout* fp() const;
    1001           0 :     MachineState machine() {
    1002           0 :         return MachineState::FromBailout(regs_, fpregs_);
    1003             :     }
    1004             : 
    1005           0 :     IonScript* ionScript() const {
    1006           0 :         return ionScript_;
    1007             :     }
    1008           0 :     uint8_t* osiPointReturnAddress() const {
    1009           0 :         return osiPointReturnAddress_;
    1010             :     }
    1011             :     static size_t offsetOfFpRegs() {
    1012             :         return offsetof(InvalidationBailoutStack, fpregs_);
    1013             :     }
    1014             :     static size_t offsetOfRegs() {
    1015             :         return offsetof(InvalidationBailoutStack, regs_);
    1016             :     }
    1017             : 
    1018             :     void checkInvariants() const;
    1019             : };
    1020             : 
    1021             : void
    1022             : GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes);
    1023             : 
    1024             : CalleeToken
    1025             : TraceCalleeToken(JSTracer* trc, CalleeToken token);
    1026             : 
    1027             : // Baseline requires one slot for this/argument type checks.
    1028             : static const uint32_t MinJITStackSize = 1;
    1029             : 
    1030             : } /* namespace jit */
    1031             : } /* namespace js */
    1032             : 
    1033             : #endif /* jit_JitFrames_h */

Generated by: LCOV version 1.13