js/src/jit/BaselineBailouts.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "jsprf.h"
     8 #include "jit/arm/Simulator-arm.h"
     9 #include "jit/BaselineIC.h"
    10 #include "jit/BaselineJIT.h"
    11 #include "jit/CompileInfo.h"
    12 #include "jit/IonSpewer.h"
    13 #include "jit/Recover.h"
    14 #include "jit/RematerializedFrame.h"
    16 #include "vm/ArgumentsObject.h"
    17 #include "vm/Debugger.h"
    18 #include "vm/TraceLogging.h"
    20 #include "jsscriptinlines.h"
    22 #include "jit/IonFrames-inl.h"
    24 using namespace js;
    25 using namespace js::jit;
    27 // BaselineStackBuilder may reallocate its buffer if the current one is too
    28 // small. To avoid dangling pointers, BufferPointer represents a pointer into
    29 // this buffer as a pointer to the header and a fixed offset.
    30 template <typename T>
    31 class BufferPointer
    32 {
    33     BaselineBailoutInfo **header_;
    34     size_t offset_;
    35     bool heap_;
    37   public:
    38     BufferPointer(BaselineBailoutInfo **header, size_t offset, bool heap)
    39       : header_(header), offset_(offset), heap_(heap)
    40     { }
    42     T *get() const {
    43         BaselineBailoutInfo *header = *header_;
    44         if (!heap_)
    45             return (T*)(header->incomingStack + offset_);
    47         uint8_t *p = header->copyStackTop - offset_;
    48         JS_ASSERT(p >= header->copyStackBottom && p < header->copyStackTop);
    49         return (T*)p;
    50     }
    52     T &operator*() const { return *get(); }
    53     T *operator->() const { return get(); }
    54 };
    56 /**
    57  * BaselineStackBuilder helps abstract the process of rebuilding the C stack on the heap.
    58  * It takes a bailout iterator and keeps track of the point on the C stack from which
    59  * the reconstructed frames will be written.
    60  *
    61  * It exposes methods to write data into the heap memory storing the reconstructed
    62  * stack.  It also exposes method to easily calculate addresses.  This includes both the
    63  * virtual address that a particular value will be at when it's eventually copied onto
    64  * the stack, as well as the current actual address of that value (whether on the heap
    65  * allocated portion being constructed or the existing stack).
    66  *
    67  * The abstraction handles transparent re-allocation of the heap memory when it
    68  * needs to be enlarged to accomodate new data.  Similarly to the C stack, the
    69  * data that's written to the reconstructed stack grows from high to low in memory.
    70  *
    71  * The lowest region of the allocated memory contains a BaselineBailoutInfo structure that
    72  * points to the start and end of the written data.
    73  */
    74 struct BaselineStackBuilder
    75 {
    76     IonBailoutIterator &iter_;
    77     IonJSFrameLayout *frame_;
    79     static size_t HeaderSize() {
    80         return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *));
    81     };
    82     size_t bufferTotal_;
    83     size_t bufferAvail_;
    84     size_t bufferUsed_;
    85     uint8_t *buffer_;
    86     BaselineBailoutInfo *header_;
    88     size_t framePushed_;
    90     BaselineStackBuilder(IonBailoutIterator &iter, size_t initialSize)
    91       : iter_(iter),
    92         frame_(static_cast<IonJSFrameLayout*>(iter.current())),
    93         bufferTotal_(initialSize),
    94         bufferAvail_(0),
    95         bufferUsed_(0),
    96         buffer_(nullptr),
    97         header_(nullptr),
    98         framePushed_(0)
    99     {
   100         JS_ASSERT(bufferTotal_ >= HeaderSize());
   101     }
   103     ~BaselineStackBuilder() {
   104         js_free(buffer_);
   105     }
   107     bool init() {
   108         JS_ASSERT(!buffer_);
   109         JS_ASSERT(bufferUsed_ == 0);
   110         buffer_ = reinterpret_cast<uint8_t *>(js_calloc(bufferTotal_));
   111         if (!buffer_)
   112             return false;
   113         bufferAvail_ = bufferTotal_ - HeaderSize();
   114         bufferUsed_ = 0;
   116         header_ = reinterpret_cast<BaselineBailoutInfo *>(buffer_);
   117         header_->incomingStack = reinterpret_cast<uint8_t *>(frame_);
   118         header_->copyStackTop = buffer_ + bufferTotal_;
   119         header_->copyStackBottom = header_->copyStackTop;
   120         header_->setR0 = 0;
   121         header_->valueR0 = UndefinedValue();
   122         header_->setR1 = 0;
   123         header_->valueR1 = UndefinedValue();
   124         header_->resumeFramePtr = nullptr;
   125         header_->resumeAddr = nullptr;
   126         header_->monitorStub = nullptr;
   127         header_->numFrames = 0;
   128         return true;
   129     }
   131     bool enlarge() {
   132         JS_ASSERT(buffer_ != nullptr);
   133         if (bufferTotal_ & mozilla::tl::MulOverflowMask<2>::value)
   134             return false;
   135         size_t newSize = bufferTotal_ * 2;
   136         uint8_t *newBuffer = reinterpret_cast<uint8_t *>(js_calloc(newSize));
   137         if (!newBuffer)
   138             return false;
   139         memcpy((newBuffer + newSize) - bufferUsed_, header_->copyStackBottom, bufferUsed_);
   140         memcpy(newBuffer, header_, sizeof(BaselineBailoutInfo));
   141         js_free(buffer_);
   142         buffer_ = newBuffer;
   143         bufferTotal_ = newSize;
   144         bufferAvail_ = newSize - (HeaderSize() + bufferUsed_);
   146         header_ = reinterpret_cast<BaselineBailoutInfo *>(buffer_);
   147         header_->copyStackTop = buffer_ + bufferTotal_;
   148         header_->copyStackBottom = header_->copyStackTop - bufferUsed_;
   149         return true;
   150     }
   152     BaselineBailoutInfo *info() {
   153         JS_ASSERT(header_ == reinterpret_cast<BaselineBailoutInfo *>(buffer_));
   154         return header_;
   155     }
   157     BaselineBailoutInfo *takeBuffer() {
   158         JS_ASSERT(header_ == reinterpret_cast<BaselineBailoutInfo *>(buffer_));
   159         buffer_ = nullptr;
   160         return header_;
   161     }
   163     void resetFramePushed() {
   164         framePushed_ = 0;
   165     }
   167     size_t framePushed() const {
   168         return framePushed_;
   169     }
   171     bool subtract(size_t size, const char *info = nullptr) {
   172         // enlarge the buffer if need be.
   173         while (size > bufferAvail_) {
   174             if (!enlarge())
   175                 return false;
   176         }
   178         // write out element.
   179         header_->copyStackBottom -= size;
   180         bufferAvail_ -= size;
   181         bufferUsed_ += size;
   182         framePushed_ += size;
   183         if (info) {
   184             IonSpew(IonSpew_BaselineBailouts,
   185                     "      SUB_%03d   %p/%p %-15s",
   186                     (int) size, header_->copyStackBottom, virtualPointerAtStackOffset(0), info);
   187         }
   188         return true;
   189     }
   191     template <typename T>
   192     bool write(const T &t) {
   193         if (!subtract(sizeof(T)))
   194             return false;
   195         memcpy(header_->copyStackBottom, &t, sizeof(T));
   196         return true;
   197     }
   199     template <typename T>
   200     bool writePtr(T *t, const char *info) {
   201         if (!write<T *>(t))
   202             return false;
   203         if (info)
   204             IonSpew(IonSpew_BaselineBailouts,
   205                     "      WRITE_PTR %p/%p %-15s %p",
   206                     header_->copyStackBottom, virtualPointerAtStackOffset(0), info, t);
   207         return true;
   208     }
   210     bool writeWord(size_t w, const char *info) {
   211         if (!write<size_t>(w))
   212             return false;
   213         if (info) {
   214             if (sizeof(size_t) == 4) {
   215                 IonSpew(IonSpew_BaselineBailouts,
   216                         "      WRITE_WRD %p/%p %-15s %08x",
   217                         header_->copyStackBottom, virtualPointerAtStackOffset(0), info, w);
   218             } else {
   219                 IonSpew(IonSpew_BaselineBailouts,
   220                         "      WRITE_WRD %p/%p %-15s %016llx",
   221                         header_->copyStackBottom, virtualPointerAtStackOffset(0), info, w);
   222             }
   223         }
   224         return true;
   225     }
   227     bool writeValue(Value val, const char *info) {
   228         if (!write<Value>(val))
   229             return false;
   230         if (info) {
   231             IonSpew(IonSpew_BaselineBailouts,
   232                     "      WRITE_VAL %p/%p %-15s %016llx",
   233                     header_->copyStackBottom, virtualPointerAtStackOffset(0), info,
   234                     *((uint64_t *) &val));
   235         }
   236         return true;
   237     }
   239     Value popValue() {
   240         JS_ASSERT(bufferUsed_ >= sizeof(Value));
   241         JS_ASSERT(framePushed_ >= sizeof(Value));
   242         bufferAvail_ += sizeof(Value);
   243         bufferUsed_ -= sizeof(Value);
   244         framePushed_ -= sizeof(Value);
   245         Value result = *((Value *) header_->copyStackBottom);
   246         header_->copyStackBottom += sizeof(Value);
   247         return result;
   248     }
   250     void popValueInto(PCMappingSlotInfo::SlotLocation loc) {
   251         JS_ASSERT(PCMappingSlotInfo::ValidSlotLocation(loc));
   252         switch(loc) {
   253           case PCMappingSlotInfo::SlotInR0:
   254             header_->setR0 = 1;
   255             header_->valueR0 = popValue();
   256             break;
   257           case PCMappingSlotInfo::SlotInR1:
   258             header_->setR1 = 1;
   259             header_->valueR1 = popValue();
   260             break;
   261           default:
   262             JS_ASSERT(loc == PCMappingSlotInfo::SlotIgnore);
   263             popValue();
   264             break;
   265         }
   266     }
   268     void setResumeFramePtr(void *resumeFramePtr) {
   269         header_->resumeFramePtr = resumeFramePtr;
   270     }
   272     void setResumeAddr(void *resumeAddr) {
   273         header_->resumeAddr = resumeAddr;
   274     }
   276     void setMonitorStub(ICStub *stub) {
   277         header_->monitorStub = stub;
   278     }
   280     template <typename T>
   281     BufferPointer<T> pointerAtStackOffset(size_t offset) {
   282         if (offset < bufferUsed_) {
   283             // Calculate offset from copyStackTop.
   284             offset = header_->copyStackTop - (header_->copyStackBottom + offset);
   285             return BufferPointer<T>(&header_, offset, /* heap = */ true);
   286         }
   288         return BufferPointer<T>(&header_, offset - bufferUsed_, /* heap = */ false);
   289     }
   291     BufferPointer<Value> valuePointerAtStackOffset(size_t offset) {
   292         return pointerAtStackOffset<Value>(offset);
   293     }
   295     inline uint8_t *virtualPointerAtStackOffset(size_t offset) {
   296         if (offset < bufferUsed_)
   297             return reinterpret_cast<uint8_t *>(frame_) - (bufferUsed_ - offset);
   298         return reinterpret_cast<uint8_t *>(frame_) + (offset - bufferUsed_);
   299     }
   301     inline IonJSFrameLayout *startFrame() {
   302         return frame_;
   303     }
   305     BufferPointer<IonJSFrameLayout> topFrameAddress() {
   306         return pointerAtStackOffset<IonJSFrameLayout>(0);
   307     }
   309     //
   310     // This method should only be called when the builder is in a state where it is
   311     // starting to construct the stack frame for the next callee.  This means that
   312     // the lowest value on the constructed stack is the return address for the previous
   313     // caller frame.
   314     //
   315     // This method is used to compute the value of the frame pointer (e.g. ebp on x86)
   316     // that would have been saved by the baseline jitcode when it was entered.  In some
   317     // cases, this value can be bogus since we can ensure that the caller would have saved
   318     // it anyway.
   319     //
   320     void *calculatePrevFramePtr() {
   321         // Get the incoming frame.
   322         BufferPointer<IonJSFrameLayout> topFrame = topFrameAddress();
   323         FrameType type = topFrame->prevType();
   325         // For IonJS and Entry frames, the "saved" frame pointer in the baseline
   326         // frame is meaningless, since Ion saves all registers before calling other ion
   327         // frames, and the entry frame saves all registers too.
   328         if (type == JitFrame_IonJS || type == JitFrame_Entry)
   329             return nullptr;
   331         // BaselineStub - Baseline calling into Ion.
   332         //  PrevFramePtr needs to point to the BaselineStubFrame's saved frame pointer.
   333         //      STACK_START_ADDR + IonJSFrameLayout::Size() + PREV_FRAME_SIZE
   334         //                      - IonBaselineStubFrameLayout::reverseOffsetOfSavedFramePtr()
   335         if (type == JitFrame_BaselineStub) {
   336             size_t offset = IonJSFrameLayout::Size() + topFrame->prevFrameLocalSize() +
   337                             IonBaselineStubFrameLayout::reverseOffsetOfSavedFramePtr();
   338             return virtualPointerAtStackOffset(offset);
   339         }
   341         JS_ASSERT(type == JitFrame_Rectifier);
   342         // Rectifier - behaviour depends on the frame preceding the rectifier frame, and
   343         // whether the arch is x86 or not.  The x86 rectifier frame saves the frame pointer,
   344         // so we can calculate it directly.  For other archs, the previous frame pointer
   345         // is stored on the stack in the frame that precedes the rectifier frame.
   346         size_t priorOffset = IonJSFrameLayout::Size() + topFrame->prevFrameLocalSize();
   347 #if defined(JS_CODEGEN_X86)
   348         // On X86, the FramePointer is pushed as the first value in the Rectifier frame.
   349         JS_ASSERT(BaselineFrameReg == FramePointer);
   350         priorOffset -= sizeof(void *);
   351         return virtualPointerAtStackOffset(priorOffset);
   352 #elif defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
   353         // On X64, ARM and MIPS, the frame pointer save location depends on
   354         // the caller of the rectifier frame.
   355         BufferPointer<IonRectifierFrameLayout> priorFrame =
   356             pointerAtStackOffset<IonRectifierFrameLayout>(priorOffset);
   357         FrameType priorType = priorFrame->prevType();
   358         JS_ASSERT(priorType == JitFrame_IonJS || priorType == JitFrame_BaselineStub);
   360         // If the frame preceding the rectifier is an IonJS frame, then once again
   361         // the frame pointer does not matter.
   362         if (priorType == JitFrame_IonJS)
   363             return nullptr;
   365         // Otherwise, the frame preceding the rectifier is a BaselineStub frame.
   366         //  let X = STACK_START_ADDR + IonJSFrameLayout::Size() + PREV_FRAME_SIZE
   367         //      X + IonRectifierFrameLayout::Size()
   368         //        + ((IonRectifierFrameLayout *) X)->prevFrameLocalSize()
   369         //        - BaselineStubFrameLayout::reverseOffsetOfSavedFramePtr()
   370         size_t extraOffset = IonRectifierFrameLayout::Size() + priorFrame->prevFrameLocalSize() +
   371                              IonBaselineStubFrameLayout::reverseOffsetOfSavedFramePtr();
   372         return virtualPointerAtStackOffset(priorOffset + extraOffset);
   373 #else
   374 #  error "Bad architecture!"
   375 #endif
   376     }
   377 };
   379 static inline bool
   380 IsInlinableFallback(ICFallbackStub *icEntry)
   381 {
   382     return icEntry->isCall_Fallback() || icEntry->isGetProp_Fallback() ||
   383            icEntry->isSetProp_Fallback();
   384 }
   386 static inline void*
   387 GetStubReturnAddress(JSContext *cx, jsbytecode *pc)
   388 {
   389     if (IsGetPropPC(pc))
   390         return cx->compartment()->jitCompartment()->baselineGetPropReturnFromIonAddr();
   391     if (IsSetPropPC(pc))
   392         return cx->compartment()->jitCompartment()->baselineSetPropReturnFromIonAddr();
   393     // This should be a call op of some kind, now.
   394     JS_ASSERT(IsCallPC(pc));
   395     return cx->compartment()->jitCompartment()->baselineCallReturnFromIonAddr();
   396 }
   398 static inline jsbytecode *
   399 GetNextNonLoopEntryPc(jsbytecode *pc)
   400 {
   401     JSOp op = JSOp(*pc);
   402     if (op == JSOP_GOTO)
   403         return pc + GET_JUMP_OFFSET(pc);
   404     if (op == JSOP_LOOPENTRY || op == JSOP_NOP || op == JSOP_LOOPHEAD)
   405         return GetNextPc(pc);
   406     return pc;
   407 }
   409 // For every inline frame, we write out the following data:
   410 //
   411 //                      |      ...      |
   412 //                      +---------------+
   413 //                      |  Descr(???)   |  --- Descr size here is (PREV_FRAME_SIZE)
   414 //                      +---------------+
   415 //                      |  ReturnAddr   |
   416 //             --       +===============+  --- OVERWRITE STARTS HERE  (START_STACK_ADDR)
   417 //             |        | PrevFramePtr  |
   418 //             |    +-> +---------------+
   419 //             |    |   |   Baseline    |
   420 //             |    |   |    Frame      |
   421 //             |    |   +---------------+
   422 //             |    |   |    Fixed0     |
   423 //             |    |   +---------------+
   424 //         +--<     |   |     ...       |
   425 //         |   |    |   +---------------+
   426 //         |   |    |   |    FixedF     |
   427 //         |   |    |   +---------------+
   428 //         |   |    |   |    Stack0     |
   429 //         |   |    |   +---------------+
   430 //         |   |    |   |     ...       |
   431 //         |   |    |   +---------------+
   432 //         |   |    |   |    StackS     |
   433 //         |   --   |   +---------------+  --- IF NOT LAST INLINE FRAME,
   434 //         +------------|  Descr(BLJS)  |  --- CALLING INFO STARTS HERE
   435 //                  |   +---------------+
   436 //                  |   |  ReturnAddr   | <-- return into main jitcode after IC
   437 //             --   |   +===============+
   438 //             |    |   |    StubPtr    |
   439 //             |    |   +---------------+
   440 //             |    +---|   FramePtr    |
   441 //             |        +---------------+
   442 //             |        |     ArgA      |
   443 //             |        +---------------+
   444 //             |        |     ...       |
   445 //         +--<         +---------------+
   446 //         |   |        |     Arg0      |
   447 //         |   |        +---------------+
   448 //         |   |        |     ThisV     |
   449 //         |   --       +---------------+
   450 //         |            |  ActualArgC   |
   451 //         |            +---------------+
   452 //         |            |  CalleeToken  |
   453 //         |            +---------------+
   454 //         +------------| Descr(BLStub) |
   455 //                      +---------------+
   456 //                      |  ReturnAddr   | <-- return into ICCall_Scripted IC
   457 //             --       +===============+ --- IF CALLEE FORMAL ARGS > ActualArgC
   458 //             |        |  UndefinedU   |
   459 //             |        +---------------+
   460 //             |        |     ...       |
   461 //             |        +---------------+
   462 //             |        |  Undefined0   |
   463 //             |        +---------------+
   464 //         +--<         |     ArgA      |
   465 //         |   |        +---------------+
   466 //         |   |        |     ...       |
   467 //         |   |        +---------------+
   468 //         |   |        |     Arg0      |
   469 //         |   |        +---------------+
   470 //         |   |        |     ThisV     |
   471 //         |   --       +---------------+
   472 //         |            |  ActualArgC   |
   473 //         |            +---------------+
   474 //         |            |  CalleeToken  |
   475 //         |            +---------------+
   476 //         +------------|  Descr(Rect)  |
   477 //                      +---------------+
   478 //                      |  ReturnAddr   | <-- return into ArgumentsRectifier after call
   479 //                      +===============+
   480 //
   481 static bool
   482 InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
   483                 HandleFunction fun, HandleScript script, IonScript *ionScript,
   484                 SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
   485                 AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
   486                 jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
   487 {
   488     MOZ_ASSERT(script->hasBaselineScript());
   490     // Are we catching an exception?
   491     bool catchingException = excInfo && excInfo->catchingException();
   493     // If we are catching an exception, we are bailing out to a catch or
   494     // finally block and this is the frame where we will resume. Usually the
   495     // expression stack should be empty in this case but there can be
   496     // iterators on the stack.
   497     uint32_t exprStackSlots;
   498     if (catchingException)
   499         exprStackSlots = excInfo->numExprSlots();
   500     else
   501         exprStackSlots = iter.numAllocations() - (script->nfixed() + CountArgSlots(script, fun));
   503     builder.resetFramePushed();
   505     // Build first baseline frame:
   506     // +===============+
   507     // | PrevFramePtr  |
   508     // +---------------+
   509     // |   Baseline    |
   510     // |    Frame      |
   511     // +---------------+
   512     // |    Fixed0     |
   513     // +---------------+
   514     // |     ...       |
   515     // +---------------+
   516     // |    FixedF     |
   517     // +---------------+
   518     // |    Stack0     |
   519     // +---------------+
   520     // |     ...       |
   521     // +---------------+
   522     // |    StackS     |
   523     // +---------------+  --- IF NOT LAST INLINE FRAME,
   524     // |  Descr(BLJS)  |  --- CALLING INFO STARTS HERE
   525     // +---------------+
   526     // |  ReturnAddr   | <-- return into main jitcode after IC
   527     // +===============+
   529     IonSpew(IonSpew_BaselineBailouts, "      Unpacking %s:%d", script->filename(), script->lineno());
   530     IonSpew(IonSpew_BaselineBailouts, "      [BASELINE-JS FRAME]");
   532     // Calculate and write the previous frame pointer value.
   533     // Record the virtual stack offset at this location.  Later on, if we end up
   534     // writing out a BaselineStub frame for the next callee, we'll need to save the
   535     // address.
   536     void *prevFramePtr = builder.calculatePrevFramePtr();
   537     if (!builder.writePtr(prevFramePtr, "PrevFramePtr"))
   538         return false;
   539     prevFramePtr = builder.virtualPointerAtStackOffset(0);
   541     // Write struct BaselineFrame.
   542     if (!builder.subtract(BaselineFrame::Size(), "BaselineFrame"))
   543         return false;
   544     BufferPointer<BaselineFrame> blFrame = builder.pointerAtStackOffset<BaselineFrame>(0);
   546     // Initialize BaselineFrame::frameSize
   547     uint32_t frameSize = BaselineFrame::Size() + BaselineFrame::FramePointerOffset +
   548                          (sizeof(Value) * (script->nfixed() + exprStackSlots));
   549     IonSpew(IonSpew_BaselineBailouts, "      FrameSize=%d", (int) frameSize);
   550     blFrame->setFrameSize(frameSize);
   552     uint32_t flags = 0;
   554     // If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
   555     // This may be wrong for the last frame of ArgumentCheck bailout, but
   556     // that will be fixed later.
   557     if (ionScript->hasSPSInstrumentation()) {
   558         if (callerPC == nullptr) {
   559             IonSpew(IonSpew_BaselineBailouts, "      Setting SPS flag on top frame!");
   560             flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
   561         } else if (js_JitOptions.profileInlineFrames) {
   562             IonSpew(IonSpew_BaselineBailouts, "      Setting SPS flag on inline frame!");
   563             flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
   564         }
   565     }
   567     // Initialize BaselineFrame's scopeChain and argsObj
   568     JSObject *scopeChain = nullptr;
   569     Value returnValue;
   570     ArgumentsObject *argsObj = nullptr;
   571     BailoutKind bailoutKind = iter.bailoutKind();
   572     if (bailoutKind == Bailout_ArgumentCheck) {
   573         // Temporary hack -- skip the (unused) scopeChain, because it could be
   574         // bogus (we can fail before the scope chain slot is set). Strip the
   575         // hasScopeChain flag and this will be fixed up later in |FinishBailoutToBaseline|,
   576         // which calls |EnsureHasScopeObjects|.
   577         IonSpew(IonSpew_BaselineBailouts, "      Bailout_ArgumentCheck! (no valid scopeChain)");
   578         iter.skip();
   580         // skip |return value|
   581         iter.skip();
   582         returnValue = UndefinedValue();
   584         // Scripts with |argumentsHasVarBinding| have an extra slot.
   585         if (script->argumentsHasVarBinding()) {
   586             IonSpew(IonSpew_BaselineBailouts,
   587                     "      Bailout_ArgumentCheck for script with argumentsHasVarBinding!"
   588                     "Using empty arguments object");
   589             iter.skip();
   590         }
   591     } else {
   592         Value v = iter.read();
   593         if (v.isObject()) {
   594             scopeChain = &v.toObject();
   595             if (fun && fun->isHeavyweight())
   596                 flags |= BaselineFrame::HAS_CALL_OBJ;
   597         } else {
   598             JS_ASSERT(v.isUndefined() || v.isMagic(JS_OPTIMIZED_OUT));
   600             // Get scope chain from function or script.
   601             if (fun) {
   602                 // If pcOffset == 0, we may have to push a new call object, so
   603                 // we leave scopeChain nullptr and enter baseline code before
   604                 // the prologue.
   605                 if (iter.pcOffset() != 0 || iter.resumeAfter())
   606                     scopeChain = fun->environment();
   607             } else {
   608                 // For global, compile-and-go scripts the scope chain is the
   609                 // script's global (Ion does not compile non-compile-and-go
   610                 // scripts). Also note that it's invalid to resume into the
   611                 // prologue in this case because the prologue expects the scope
   612                 // chain in R1 for eval and global scripts.
   613                 JS_ASSERT(!script->isForEval());
   614                 JS_ASSERT(script->compileAndGo());
   615                 scopeChain = &(script->global());
   616             }
   617         }
   619         // Make sure to add HAS_RVAL to flags here because setFlags() below
   620         // will clobber it.
   621         returnValue = iter.read();
   622         flags |= BaselineFrame::HAS_RVAL;
   624         // If script maybe has an arguments object, the third slot will hold it.
   625         if (script->argumentsHasVarBinding()) {
   626             v = iter.read();
   627             JS_ASSERT(v.isObject() || v.isUndefined() || v.isMagic(JS_OPTIMIZED_OUT));
   628             if (v.isObject())
   629                 argsObj = &v.toObject().as<ArgumentsObject>();
   630         }
   631     }
   632     IonSpew(IonSpew_BaselineBailouts, "      ScopeChain=%p", scopeChain);
   633     blFrame->setScopeChain(scopeChain);
   634     IonSpew(IonSpew_BaselineBailouts, "      ReturnValue=%016llx", *((uint64_t *) &returnValue));
   635     blFrame->setReturnValue(returnValue);
   637     // Do not need to initialize scratchValue field in BaselineFrame.
   638     blFrame->setFlags(flags);
   640     // initArgsObjUnchecked modifies the frame's flags, so call it after setFlags.
   641     if (argsObj)
   642         blFrame->initArgsObjUnchecked(*argsObj);
   644     if (fun) {
   645         // The unpacked thisv and arguments should overwrite the pushed args present
   646         // in the calling frame.
   647         Value thisv = iter.read();
   648         IonSpew(IonSpew_BaselineBailouts, "      Is function!");
   649         IonSpew(IonSpew_BaselineBailouts, "      thisv=%016llx", *((uint64_t *) &thisv));
   651         size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
   652         *builder.valuePointerAtStackOffset(thisvOffset) = thisv;
   654         JS_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun));
   655         IonSpew(IonSpew_BaselineBailouts, "      frame slots %u, nargs %u, nfixed %u",
   656                 iter.numAllocations(), fun->nargs(), script->nfixed());
   658         if (!callerPC) {
   659             // This is the first frame. Store the formals in a Vector until we
   660             // are done. Due to UCE and phi elimination, we could store an
   661             // UndefinedValue() here for formals we think are unused, but
   662             // locals may still reference the original argument slot
   663             // (MParameter/LArgument) and expect the original Value.
   664             JS_ASSERT(startFrameFormals.empty());
   665             if (!startFrameFormals.resize(fun->nargs()))
   666                 return false;
   667         }
   669         for (uint32_t i = 0; i < fun->nargs(); i++) {
   670             Value arg = iter.read();
   671             IonSpew(IonSpew_BaselineBailouts, "      arg %d = %016llx",
   672                         (int) i, *((uint64_t *) &arg));
   673             if (callerPC) {
   674                 size_t argOffset = builder.framePushed() + IonJSFrameLayout::offsetOfActualArg(i);
   675                 *builder.valuePointerAtStackOffset(argOffset) = arg;
   676             } else {
   677                 startFrameFormals[i] = arg;
   678             }
   679         }
   680     }
   682     for (uint32_t i = 0; i < script->nfixed(); i++) {
   683         Value slot = iter.read();
   684         if (!builder.writeValue(slot, "FixedValue"))
   685             return false;
   686     }
   688     // Get the pc. If we are handling an exception, resume at the pc of the
   689     // catch or finally block.
   690     jsbytecode *pc = catchingException ? excInfo->resumePC() : script->offsetToPC(iter.pcOffset());
   691     bool resumeAfter = catchingException ? false : iter.resumeAfter();
   693     JSOp op = JSOp(*pc);
   695     // Fixup inlined JSOP_FUNCALL, JSOP_FUNAPPLY, and accessors on the caller side.
   696     // On the caller side this must represent like the function wasn't inlined.
   697     uint32_t pushedSlots = 0;
   698     AutoValueVector savedCallerArgs(cx);
   699     bool needToSaveArgs = op == JSOP_FUNAPPLY || IsGetPropPC(pc) || IsSetPropPC(pc);
   700     if (iter.moreFrames() && (op == JSOP_FUNCALL || needToSaveArgs))
   701     {
   702         uint32_t inlined_args = 0;
   703         if (op == JSOP_FUNCALL)
   704             inlined_args = 2 + GET_ARGC(pc) - 1;
   705         else if (op == JSOP_FUNAPPLY)
   706             inlined_args = 2 + blFrame->numActualArgs();
   707         else
   708             inlined_args = 2 + IsSetPropPC(pc);
   710         JS_ASSERT(exprStackSlots >= inlined_args);
   711         pushedSlots = exprStackSlots - inlined_args;
   713         IonSpew(IonSpew_BaselineBailouts,
   714                 "      pushing %u expression stack slots before fixup",
   715                 pushedSlots);
   716         for (uint32_t i = 0; i < pushedSlots; i++) {
   717             Value v = iter.read();
   718             if (!builder.writeValue(v, "StackValue"))
   719                 return false;
   720         }
   722         if (op == JSOP_FUNCALL) {
   723             // When funcall got inlined and the native js_fun_call was bypassed,
   724             // the stack state is incorrect. To restore correctly it must look like
   725             // js_fun_call was actually called. This means transforming the stack
   726             // from |target, this, args| to |js_fun_call, target, this, args|
   727             // The js_fun_call is never read, so just pushing undefined now.
   728             IonSpew(IonSpew_BaselineBailouts, "      pushing undefined to fixup funcall");
   729             if (!builder.writeValue(UndefinedValue(), "StackValue"))
   730                 return false;
   731         }
   733         if (needToSaveArgs) {
   734             // When an accessor is inlined, the whole thing is a lie. There
   735             // should never have been a call there. Fix the caller's stack to
   736             // forget it ever happened.
   738             // When funapply gets inlined we take all arguments out of the
   739             // arguments array. So the stack state is incorrect. To restore
   740             // correctly it must look like js_fun_apply was actually called.
   741             // This means transforming the stack from |target, this, arg1, ...|
   742             // to |js_fun_apply, target, this, argObject|.
   743             // Since the information is never read, we can just push undefined
   744             // for all values.
   745             if (op == JSOP_FUNAPPLY) {
   746                 IonSpew(IonSpew_BaselineBailouts, "      pushing 4x undefined to fixup funapply");
   747                 if (!builder.writeValue(UndefinedValue(), "StackValue"))
   748                     return false;
   749                 if (!builder.writeValue(UndefinedValue(), "StackValue"))
   750                     return false;
   751                 if (!builder.writeValue(UndefinedValue(), "StackValue"))
   752                     return false;
   753                 if (!builder.writeValue(UndefinedValue(), "StackValue"))
   754                     return false;
   755             }
   756             // Save the actual arguments. They are needed on the callee side
   757             // as the arguments. Else we can't recover them.
   758             if (!savedCallerArgs.resize(inlined_args))
   759                 return false;
   760             for (uint32_t i = 0; i < inlined_args; i++)
   761                 savedCallerArgs[i] = iter.read();
   763             if (IsSetPropPC(pc)) {
   764                 // We would love to just save all the arguments and leave them
   765                 // in the stub frame pushed below, but we will lose the inital
   766                 // argument which the function was called with, which we must
   767                 // return to the caller, even if the setter internally modifies
   768                 // its arguments. Stash the initial argument on the stack, to be
   769                 // later retrieved by the SetProp_Fallback stub.
   770                 Value initialArg = savedCallerArgs[inlined_args - 1];
   771                 IonSpew(IonSpew_BaselineBailouts, "     pushing setter's initial argument");
   772                 if (!builder.writeValue(initialArg, "StackValue"))
   773                     return false;
   774             }
   775             pushedSlots = exprStackSlots;
   776         }
   777     }
   779     IonSpew(IonSpew_BaselineBailouts, "      pushing %u expression stack slots",
   780                                       exprStackSlots - pushedSlots);
   781     for (uint32_t i = pushedSlots; i < exprStackSlots; i++) {
   782         Value v;
   784         if (!iter.moreFrames() && i == exprStackSlots - 1 &&
   785             cx->runtime()->hasIonReturnOverride())
   786         {
   787             // If coming from an invalidation bailout, and this is the topmost
   788             // value, and a value override has been specified, don't read from the
   789             // iterator. Otherwise, we risk using a garbage value.
   790             JS_ASSERT(invalidate);
   791             iter.skip();
   792             IonSpew(IonSpew_BaselineBailouts, "      [Return Override]");
   793             v = cx->runtime()->takeIonReturnOverride();
   794         } else if (excInfo && excInfo->propagatingIonExceptionForDebugMode()) {
   795             // If we are in the middle of propagating an exception from Ion by
   796             // bailing to baseline due to debug mode, we might not have all
   797             // the stack if we are at the newest frame.
   798             //
   799             // For instance, if calling |f()| pushed an Ion frame which threw,
   800             // the snapshot expects the return value to be pushed, but it's
   801             // possible nothing was pushed before we threw. Iterators might
   802             // still be on the stack, so we can't just drop the stack.
   803             MOZ_ASSERT(cx->compartment()->debugMode());
   804             if (iter.moreFrames())
   805                 v = iter.read();
   806             else
   807                 v = MagicValue(JS_OPTIMIZED_OUT);
   808         } else {
   809             v = iter.read();
   810         }
   811         if (!builder.writeValue(v, "StackValue"))
   812             return false;
   813     }
   815     size_t endOfBaselineJSFrameStack = builder.framePushed();
   817     // If we are resuming at a LOOPENTRY op, resume at the next op to avoid
   818     // a bailout -> enter Ion -> bailout loop with --ion-eager. See also
   819     // ThunkToInterpreter.
   820     //
   821     // The algorithm below is the "tortoise and the hare" algorithm. See bug
   822     // 994444 for more explanation.
   823     if (!resumeAfter) {
   824         jsbytecode *fasterPc = pc;
   825         while (true) {
   826             pc = GetNextNonLoopEntryPc(pc);
   827             fasterPc = GetNextNonLoopEntryPc(GetNextNonLoopEntryPc(fasterPc));
   828             if (fasterPc == pc)
   829                 break;
   830         }
   831         op = JSOp(*pc);
   832     }
   834     uint32_t pcOff = script->pcToOffset(pc);
   835     bool isCall = IsCallPC(pc);
   836     BaselineScript *baselineScript = script->baselineScript();
   838 #ifdef DEBUG
   839     uint32_t expectedDepth;
   840     bool reachablePC;
   841     if (!ReconstructStackDepth(cx, script, resumeAfter ? GetNextPc(pc) : pc, &expectedDepth, &reachablePC))
   842         return false;
   844     if (reachablePC) {
   845         if (op != JSOP_FUNAPPLY || !iter.moreFrames() || resumeAfter) {
   846             if (op == JSOP_FUNCALL) {
   847                 // For fun.call(this, ...); the reconstructStackDepth will
   848                 // include the this. When inlining that is not included.
   849                 // So the exprStackSlots will be one less.
   850                 JS_ASSERT(expectedDepth - exprStackSlots <= 1);
   851             } else if (iter.moreFrames() && (IsGetPropPC(pc) || IsSetPropPC(pc))) {
   852                 // Accessors coming out of ion are inlined via a complete
   853                 // lie perpetrated by the compiler internally. Ion just rearranges
   854                 // the stack, and pretends that it looked like a call all along.
   855                 // This means that the depth is actually one *more* than expected
   856                 // by the interpreter, as there is now a JSFunction, |this| and [arg],
   857                 // rather than the expected |this| and [arg]
   858                 // Note that none of that was pushed, but it's still reflected
   859                 // in exprStackSlots.
   860                 JS_ASSERT(exprStackSlots - expectedDepth == 1);
   861             } else {
   862                 // For fun.apply({}, arguments) the reconstructStackDepth will
   863                 // have stackdepth 4, but it could be that we inlined the
   864                 // funapply. In that case exprStackSlots, will have the real
   865                 // arguments in the slots and not be 4.
   866                 JS_ASSERT(exprStackSlots == expectedDepth);
   867             }
   868         }
   869     }
   871     IonSpew(IonSpew_BaselineBailouts, "      Resuming %s pc offset %d (op %s) (line %d) of %s:%d",
   872                 resumeAfter ? "after" : "at", (int) pcOff, js_CodeName[op],
   873                 PCToLineNumber(script, pc), script->filename(), (int) script->lineno());
   874     IonSpew(IonSpew_BaselineBailouts, "      Bailout kind: %s",
   875             BailoutKindString(bailoutKind));
   876 #endif
   878     // If this was the last inline frame, or we are bailing out to a catch or
   879     // finally block in this frame, then unpacking is almost done.
   880     if (!iter.moreFrames() || catchingException) {
   881         // Last frame, so PC for call to next frame is set to nullptr.
   882         *callPC = nullptr;
   884         // If the bailout was a resumeAfter, and the opcode is monitored,
   885         // then the bailed out state should be in a position to enter
   886         // into the ICTypeMonitor chain for the op.
   887         bool enterMonitorChain = false;
   888         if (resumeAfter && (js_CodeSpec[op].format & JOF_TYPESET)) {
   889             // Not every monitored op has a monitored fallback stub, e.g.
   890             // JSOP_NEWOBJECT, which always returns the same type for a
   891             // particular script/pc location.
   892             ICEntry &icEntry = baselineScript->icEntryFromPCOffset(pcOff);
   893             ICFallbackStub *fallbackStub = icEntry.firstStub()->getChainFallback();
   894             if (fallbackStub->isMonitoredFallback())
   895                 enterMonitorChain = true;
   896         }
   898         uint32_t numCallArgs = isCall ? GET_ARGC(pc) : 0;
   900         if (resumeAfter && !enterMonitorChain)
   901             pc = GetNextPc(pc);
   903         builder.setResumeFramePtr(prevFramePtr);
   905         if (enterMonitorChain) {
   906             ICEntry &icEntry = baselineScript->icEntryFromPCOffset(pcOff);
   907             ICFallbackStub *fallbackStub = icEntry.firstStub()->getChainFallback();
   908             JS_ASSERT(fallbackStub->isMonitoredFallback());
   909             IonSpew(IonSpew_BaselineBailouts, "      [TYPE-MONITOR CHAIN]");
   910             ICMonitoredFallbackStub *monFallbackStub = fallbackStub->toMonitoredFallbackStub();
   911             ICStub *firstMonStub = monFallbackStub->fallbackMonitorStub()->firstMonitorStub();
   913             // To enter a monitoring chain, we load the top stack value into R0
   914             IonSpew(IonSpew_BaselineBailouts, "      Popping top stack value into R0.");
   915             builder.popValueInto(PCMappingSlotInfo::SlotInR0);
   917             // Need to adjust the frameSize for the frame to match the values popped
   918             // into registers.
   919             frameSize -= sizeof(Value);
   920             blFrame->setFrameSize(frameSize);
   921             IonSpew(IonSpew_BaselineBailouts, "      Adjusted framesize -= %d: %d",
   922                             (int) sizeof(Value), (int) frameSize);
   924             // If resuming into a JSOP_CALL, baseline keeps the arguments on the
   925             // stack and pops them only after returning from the call IC.
   926             // Push undefs onto the stack in anticipation of the popping of the
   927             // callee, thisv, and actual arguments passed from the caller's frame.
   928             if (isCall) {
   929                 builder.writeValue(UndefinedValue(), "CallOp FillerCallee");
   930                 builder.writeValue(UndefinedValue(), "CallOp FillerThis");
   931                 for (uint32_t i = 0; i < numCallArgs; i++)
   932                     builder.writeValue(UndefinedValue(), "CallOp FillerArg");
   934                 frameSize += (numCallArgs + 2) * sizeof(Value);
   935                 blFrame->setFrameSize(frameSize);
   936                 IonSpew(IonSpew_BaselineBailouts, "      Adjusted framesize += %d: %d",
   937                                 (int) ((numCallArgs + 2) * sizeof(Value)), (int) frameSize);
   938             }
   940             // Set the resume address to the return point from the IC, and set
   941             // the monitor stub addr.
   942             builder.setResumeAddr(baselineScript->returnAddressForIC(icEntry));
   943             builder.setMonitorStub(firstMonStub);
   944             IonSpew(IonSpew_BaselineBailouts, "      Set resumeAddr=%p monitorStub=%p",
   945                     baselineScript->returnAddressForIC(icEntry), firstMonStub);
   947         } else {
   948             // If needed, initialize BaselineBailoutInfo's valueR0 and/or valueR1 with the
   949             // top stack values.
   950             PCMappingSlotInfo slotInfo;
   951             uint8_t *nativeCodeForPC = baselineScript->nativeCodeForPC(script, pc, &slotInfo);
   952             unsigned numUnsynced = slotInfo.numUnsynced();
   953             JS_ASSERT(numUnsynced <= 2);
   954             PCMappingSlotInfo::SlotLocation loc1, loc2;
   955             if (numUnsynced > 0) {
   956                 loc1 = slotInfo.topSlotLocation();
   957                 IonSpew(IonSpew_BaselineBailouts, "      Popping top stack value into %d.",
   958                             (int) loc1);
   959                 builder.popValueInto(loc1);
   960             }
   961             if (numUnsynced > 1) {
   962                 loc2 = slotInfo.nextSlotLocation();
   963                 IonSpew(IonSpew_BaselineBailouts, "      Popping next stack value into %d.",
   964                             (int) loc2);
   965                 JS_ASSERT_IF(loc1 != PCMappingSlotInfo::SlotIgnore, loc1 != loc2);
   966                 builder.popValueInto(loc2);
   967             }
   969             // Need to adjust the frameSize for the frame to match the values popped
   970             // into registers.
   971             frameSize -= sizeof(Value) * numUnsynced;
   972             blFrame->setFrameSize(frameSize);
   973             IonSpew(IonSpew_BaselineBailouts, "      Adjusted framesize -= %d: %d",
   974                             int(sizeof(Value) * numUnsynced), int(frameSize));
   976             // If scopeChain is nullptr, then bailout is occurring during argument check.
   977             // In this case, resume into the prologue.
   978             uint8_t *opReturnAddr;
   979             if (scopeChain == nullptr) {
   980                 // Global and eval scripts expect the scope chain in R1, so only
   981                 // resume into the prologue for function scripts.
   982                 JS_ASSERT(fun);
   983                 JS_ASSERT(numUnsynced == 0);
   984                 opReturnAddr = baselineScript->prologueEntryAddr();
   985                 IonSpew(IonSpew_BaselineBailouts, "      Resuming into prologue.");
   987                 // If bailing into prologue, HAS_PUSHED_SPS_FRAME should not be set on frame.
   988                 blFrame->unsetPushedSPSFrame();
   990                 if (cx->runtime()->spsProfiler.enabled()) {
   991                     if (js_JitOptions.profileInlineFrames) {
   992                         // If SPS is enabled, there are two corner cases to handle:
   993                         //  1. If resuming into the prologue, and innermost frame is an inlined
   994                         //     frame, and bailout is because of argument check failure, then:
   995                         //          Top SPS profiler entry would be for caller frame.
   996                         //          Ion would not have set the PC index field on that frame
   997                         //              (since this bailout happens before MFunctionBoundary).
   998                         //          Make sure that's done now.
   999                         //  2. If resuming into the prologue, and the bailout is NOT because of an
  1000                         //     argument check, then:
  1001                         //          Top SPS profiler entry would be for callee frame.
  1002                         //          Ion would already have pushed an SPS entry for this frame.
  1003                         //          The pc for this entry would be set to nullptr.
  1004                         //          Make sure it's set to script->pc.
  1005                         if (caller && bailoutKind == Bailout_ArgumentCheck) {
  1006                             IonSpew(IonSpew_BaselineBailouts, "      Setting PCidx on innermost "
  1007                                     "inlined frame's parent's SPS entry (%s:%d) (pcIdx=%d)!",
  1008                                     caller->filename(), caller->lineno(),
  1009                                     caller->pcToOffset(callerPC));
  1010                             cx->runtime()->spsProfiler.updatePC(caller, callerPC);
  1012                         } else if (bailoutKind != Bailout_ArgumentCheck) {
  1013                             IonSpew(IonSpew_BaselineBailouts,
  1014                                     "      Popping SPS entry for innermost inlined frame");
  1015                             cx->runtime()->spsProfiler.exit(script, fun);
  1018                     } else {
  1019                         // If not profiling inline frames, then this is logically simpler.
  1020                         //
  1021                         // 1. If resuming into inline code, then the top SPS entry will be
  1022                         // for the outermost caller, and will have an uninitialized PC.
  1023                         // This will be fixed up later in BailoutIonToBaseline.
  1024                         //
  1025                         // 2. If resuming into top-level code prologue, with ArgumentCheck,
  1026                         // no SPS entry will have been pushed.  Can be left alone.
  1027                         //
  1028                         // 3. If resuming into top-level code prologue, without ArgumentCheck,
  1029                         // an SPS entry will have been pushed, and needs to be popped.
  1030                         //
  1031                         // 4. If resuming into top-level code main body, an SPS entry will
  1032                         // have been pushed, and can be left alone.
  1033                         //
  1034                         // Only need to handle case 3 here.
  1035                         if (!caller && bailoutKind != Bailout_ArgumentCheck) {
  1036                             IonSpew(IonSpew_BaselineBailouts,
  1037                                     "      Popping SPS entry for outermost frame");
  1038                             cx->runtime()->spsProfiler.exit(script, fun);
  1042             } else {
  1043                 opReturnAddr = nativeCodeForPC;
  1045             builder.setResumeAddr(opReturnAddr);
  1046             IonSpew(IonSpew_BaselineBailouts, "      Set resumeAddr=%p", opReturnAddr);
  1049         if (cx->runtime()->spsProfiler.enabled()) {
  1050             if (blFrame->hasPushedSPSFrame()) {
  1051                 // Set PC index to 0 for the innermost frame to match what the
  1052                 // interpreter and Baseline do: they update the SPS pc for
  1053                 // JSOP_CALL ops but set it to 0 when running other ops. Ion code
  1054                 // can set the pc to NullPCIndex and this will confuse SPS when
  1055                 // Baseline calls into the VM at non-CALL ops and re-enters JS.
  1056                 IonSpew(IonSpew_BaselineBailouts, "      Setting PCidx for last frame to 0");
  1057                 cx->runtime()->spsProfiler.updatePC(script, script->code());
  1060             // Register bailout with profiler.
  1061             const char *filename = script->filename();
  1062             if (filename == nullptr)
  1063                 filename = "<unknown>";
  1064             unsigned len = strlen(filename) + 200;
  1065             char *buf = js_pod_malloc<char>(len);
  1066             if (buf == nullptr)
  1067                 return false;
  1068             JS_snprintf(buf, len, "%s %s %s on line %d of %s:%d",
  1069                                   BailoutKindString(bailoutKind),
  1070                                   resumeAfter ? "after" : "at",
  1071                                   js_CodeName[op],
  1072                                   int(PCToLineNumber(script, pc)),
  1073                                   filename,
  1074                                   int(script->lineno()));
  1075             cx->runtime()->spsProfiler.markEvent(buf);
  1076             js_free(buf);
  1079         return true;
  1082     *callPC = pc;
  1084     // Write out descriptor of BaselineJS frame.
  1085     size_t baselineFrameDescr = MakeFrameDescriptor((uint32_t) builder.framePushed(),
  1086                                                     JitFrame_BaselineJS);
  1087     if (!builder.writeWord(baselineFrameDescr, "Descriptor"))
  1088         return false;
  1090     // Calculate and write out return address.
  1091     // The icEntry in question MUST have an inlinable fallback stub.
  1092     ICEntry &icEntry = baselineScript->icEntryFromPCOffset(pcOff);
  1093     JS_ASSERT(IsInlinableFallback(icEntry.firstStub()->getChainFallback()));
  1094     if (!builder.writePtr(baselineScript->returnAddressForIC(icEntry), "ReturnAddr"))
  1095         return false;
  1097     // Build baseline stub frame:
  1098     // +===============+
  1099     // |    StubPtr    |
  1100     // +---------------+
  1101     // |   FramePtr    |
  1102     // +---------------+
  1103     // |     ArgA      |
  1104     // +---------------+
  1105     // |     ...       |
  1106     // +---------------+
  1107     // |     Arg0      |
  1108     // +---------------+
  1109     // |     ThisV     |
  1110     // +---------------+
  1111     // |  ActualArgC   |
  1112     // +---------------+
  1113     // |  CalleeToken  |
  1114     // +---------------+
  1115     // | Descr(BLStub) |
  1116     // +---------------+
  1117     // |  ReturnAddr   |
  1118     // +===============+
  1120     IonSpew(IonSpew_BaselineBailouts, "      [BASELINE-STUB FRAME]");
  1122     size_t startOfBaselineStubFrame = builder.framePushed();
  1124     // Write stub pointer.
  1125     JS_ASSERT(IsInlinableFallback(icEntry.fallbackStub()));
  1126     if (!builder.writePtr(icEntry.fallbackStub(), "StubPtr"))
  1127         return false;
  1129     // Write previous frame pointer (saved earlier).
  1130     if (!builder.writePtr(prevFramePtr, "PrevFramePtr"))
  1131         return false;
  1132     prevFramePtr = builder.virtualPointerAtStackOffset(0);
  1134     // Write out actual arguments (and thisv), copied from unpacked stack of BaselineJS frame.
  1135     // Arguments are reversed on the BaselineJS frame's stack values.
  1136     JS_ASSERT(IsIonInlinablePC(pc));
  1137     unsigned actualArgc;
  1138     if (needToSaveArgs) {
  1139         // For FUNAPPLY or an accessor, the arguments are not on the stack anymore,
  1140         // but they are copied in a vector and are written here.
  1141         if (op == JSOP_FUNAPPLY)
  1142             actualArgc = blFrame->numActualArgs();
  1143         else
  1144             actualArgc = IsSetPropPC(pc);
  1146         JS_ASSERT(actualArgc + 2 <= exprStackSlots);
  1147         JS_ASSERT(savedCallerArgs.length() == actualArgc + 2);
  1148         for (unsigned i = 0; i < actualArgc + 1; i++) {
  1149             size_t arg = savedCallerArgs.length() - (i + 1);
  1150             if (!builder.writeValue(savedCallerArgs[arg], "ArgVal"))
  1151                 return false;
  1153     } else {
  1154         actualArgc = GET_ARGC(pc);
  1155         if (op == JSOP_FUNCALL) {
  1156             JS_ASSERT(actualArgc > 0);
  1157             actualArgc--;
  1160         JS_ASSERT(actualArgc + 2 <= exprStackSlots);
  1161         for (unsigned i = 0; i < actualArgc + 1; i++) {
  1162             size_t argSlot = (script->nfixed() + exprStackSlots) - (i + 1);
  1163             if (!builder.writeValue(*blFrame->valueSlot(argSlot), "ArgVal"))
  1164                 return false;
  1168     // In case these arguments need to be copied on the stack again for a rectifier frame,
  1169     // save the framePushed values here for later use.
  1170     size_t endOfBaselineStubArgs = builder.framePushed();
  1172     // Calculate frame size for descriptor.
  1173     size_t baselineStubFrameSize = builder.framePushed() - startOfBaselineStubFrame;
  1174     size_t baselineStubFrameDescr = MakeFrameDescriptor((uint32_t) baselineStubFrameSize,
  1175                                                         JitFrame_BaselineStub);
  1177     // Push actual argc
  1178     if (!builder.writeWord(actualArgc, "ActualArgc"))
  1179         return false;
  1181     // Push callee token (must be a JS Function)
  1182     Value callee;
  1183     if (needToSaveArgs) {
  1184         // The arguments of FUNAPPLY or inlined accessors are not writen to the stack.
  1185         // So get the callee from the specially saved vector.
  1186         callee = savedCallerArgs[0];
  1187     } else {
  1188         uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2);
  1189         size_t calleeOffset = (builder.framePushed() - endOfBaselineJSFrameStack)
  1190             + ((exprStackSlots - (calleeStackSlot + 1)) * sizeof(Value));
  1191         callee = *builder.valuePointerAtStackOffset(calleeOffset);
  1192         IonSpew(IonSpew_BaselineBailouts, "      CalleeStackSlot=%d", (int) calleeStackSlot);
  1194     IonSpew(IonSpew_BaselineBailouts, "      Callee = %016llx", *((uint64_t *) &callee));
  1195     JS_ASSERT(callee.isObject() && callee.toObject().is<JSFunction>());
  1196     JSFunction *calleeFun = &callee.toObject().as<JSFunction>();
  1197     if (!builder.writePtr(CalleeToToken(calleeFun), "CalleeToken"))
  1198         return false;
  1199     nextCallee.set(calleeFun);
  1201     // Push BaselineStub frame descriptor
  1202     if (!builder.writeWord(baselineStubFrameDescr, "Descriptor"))
  1203         return false;
  1205     // Push return address into ICCall_Scripted stub, immediately after the call.
  1206     void *baselineCallReturnAddr = GetStubReturnAddress(cx, pc);
  1207     JS_ASSERT(baselineCallReturnAddr);
  1208     if (!builder.writePtr(baselineCallReturnAddr, "ReturnAddr"))
  1209         return false;
  1211     // If actualArgc >= fun->nargs, then we are done.  Otherwise, we need to push on
  1212     // a reconstructed rectifier frame.
  1213     if (actualArgc >= calleeFun->nargs())
  1214         return true;
  1216     // Push a reconstructed rectifier frame.
  1217     // +===============+
  1218     // |  UndefinedU   |
  1219     // +---------------+
  1220     // |     ...       |
  1221     // +---------------+
  1222     // |  Undefined0   |
  1223     // +---------------+
  1224     // |     ArgA      |
  1225     // +---------------+
  1226     // |     ...       |
  1227     // +---------------+
  1228     // |     Arg0      |
  1229     // +---------------+
  1230     // |     ThisV     |
  1231     // +---------------+
  1232     // |  ActualArgC   |
  1233     // +---------------+
  1234     // |  CalleeToken  |
  1235     // +---------------+
  1236     // |  Descr(Rect)  |
  1237     // +---------------+
  1238     // |  ReturnAddr   |
  1239     // +===============+
  1241     IonSpew(IonSpew_BaselineBailouts, "      [RECTIFIER FRAME]");
  1243     size_t startOfRectifierFrame = builder.framePushed();
  1245     // On x86-only, the frame pointer is saved again in the rectifier frame.
  1246 #if defined(JS_CODEGEN_X86)
  1247     if (!builder.writePtr(prevFramePtr, "PrevFramePtr-X86Only"))
  1248         return false;
  1249 #endif
  1251     // Push undefined for missing arguments.
  1252     for (unsigned i = 0; i < (calleeFun->nargs() - actualArgc); i++) {
  1253         if (!builder.writeValue(UndefinedValue(), "FillerVal"))
  1254             return false;
  1257     // Copy arguments + thisv from BaselineStub frame.
  1258     if (!builder.subtract((actualArgc + 1) * sizeof(Value), "CopiedArgs"))
  1259         return false;
  1260     BufferPointer<uint8_t> stubArgsEnd =
  1261         builder.pointerAtStackOffset<uint8_t>(builder.framePushed() - endOfBaselineStubArgs);
  1262     IonSpew(IonSpew_BaselineBailouts, "      MemCpy from %p", stubArgsEnd.get());
  1263     memcpy(builder.pointerAtStackOffset<uint8_t>(0).get(), stubArgsEnd.get(),
  1264            (actualArgc + 1) * sizeof(Value));
  1266     // Calculate frame size for descriptor.
  1267     size_t rectifierFrameSize = builder.framePushed() - startOfRectifierFrame;
  1268     size_t rectifierFrameDescr = MakeFrameDescriptor((uint32_t) rectifierFrameSize,
  1269                                                      JitFrame_Rectifier);
  1271     // Push actualArgc
  1272     if (!builder.writeWord(actualArgc, "ActualArgc"))
  1273         return false;
  1275     // Push calleeToken again.
  1276     if (!builder.writePtr(CalleeToToken(calleeFun), "CalleeToken"))
  1277         return false;
  1279     // Push rectifier frame descriptor
  1280     if (!builder.writeWord(rectifierFrameDescr, "Descriptor"))
  1281         return false;
  1283     // Push return address into the ArgumentsRectifier code, immediately after the ioncode
  1284     // call.
  1285     void *rectReturnAddr = cx->runtime()->jitRuntime()->getArgumentsRectifierReturnAddr();
  1286     JS_ASSERT(rectReturnAddr);
  1287     if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
  1288         return false;
  1290     return true;
  1293 uint32_t
  1294 jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
  1295                           bool invalidate, BaselineBailoutInfo **bailoutInfo,
  1296                           const ExceptionBailoutInfo *excInfo)
  1298     JS_ASSERT(bailoutInfo != nullptr);
  1299     JS_ASSERT(*bailoutInfo == nullptr);
  1301     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
  1302     TraceLogStopEvent(logger, TraceLogger::IonMonkey);
  1303     TraceLogStartEvent(logger, TraceLogger::Baseline);
  1305     // The caller of the top frame must be one of the following:
  1306     //      IonJS - Ion calling into Ion.
  1307     //      BaselineStub - Baseline calling into Ion.
  1308     //      Entry - Interpreter or other calling into Ion.
  1309     //      Rectifier - Arguments rectifier calling into Ion.
  1310     JS_ASSERT(iter.isIonJS());
  1311     FrameType prevFrameType = iter.prevType();
  1312     JS_ASSERT(prevFrameType == JitFrame_IonJS ||
  1313               prevFrameType == JitFrame_BaselineStub ||
  1314               prevFrameType == JitFrame_Entry ||
  1315               prevFrameType == JitFrame_Rectifier);
  1317     // All incoming frames are going to look like this:
  1318     //
  1319     //      +---------------+
  1320     //      |     ...       |
  1321     //      +---------------+
  1322     //      |     Args      |
  1323     //      |     ...       |
  1324     //      +---------------+
  1325     //      |    ThisV      |
  1326     //      +---------------+
  1327     //      |  ActualArgC   |
  1328     //      +---------------+
  1329     //      |  CalleeToken  |
  1330     //      +---------------+
  1331     //      |  Descriptor   |
  1332     //      +---------------+
  1333     //      |  ReturnAddr   |
  1334     //      +---------------+
  1335     //      |    |||||      | <---- Overwrite starting here.
  1336     //      |    |||||      |
  1337     //      |    |||||      |
  1338     //      +---------------+
  1340     IonSpew(IonSpew_BaselineBailouts, "Bailing to baseline %s:%u (IonScript=%p) (FrameType=%d)",
  1341             iter.script()->filename(), iter.script()->lineno(), (void *) iter.ionScript(),
  1342             (int) prevFrameType);
  1344     bool catchingException;
  1345     bool propagatingExceptionForDebugMode;
  1346     if (excInfo) {
  1347         catchingException = excInfo->catchingException();
  1348         propagatingExceptionForDebugMode = excInfo->propagatingIonExceptionForDebugMode();
  1350         if (catchingException)
  1351             IonSpew(IonSpew_BaselineBailouts, "Resuming in catch or finally block");
  1353         if (propagatingExceptionForDebugMode)
  1354             IonSpew(IonSpew_BaselineBailouts, "Resuming in-place for debug mode");
  1355     } else {
  1356         catchingException = false;
  1357         propagatingExceptionForDebugMode = false;
  1360     IonSpew(IonSpew_BaselineBailouts, "  Reading from snapshot offset %u size %u",
  1361             iter.snapshotOffset(), iter.ionScript()->snapshotsListSize());
  1363     if (!excInfo)
  1364         iter.ionScript()->incNumBailouts();
  1365     iter.script()->updateBaselineOrIonRaw();
  1367     // Allocate buffer to hold stack replacement data.
  1368     BaselineStackBuilder builder(iter, 1024);
  1369     if (!builder.init())
  1370         return BAILOUT_RETURN_FATAL_ERROR;
  1371     IonSpew(IonSpew_BaselineBailouts, "  Incoming frame ptr = %p", builder.startFrame());
  1373     SnapshotIterator snapIter(iter);
  1375     RootedFunction callee(cx, iter.maybeCallee());
  1376     RootedScript scr(cx, iter.script());
  1377     if (callee) {
  1378         IonSpew(IonSpew_BaselineBailouts, "  Callee function (%s:%u)",
  1379                 scr->filename(), scr->lineno());
  1380     } else {
  1381         IonSpew(IonSpew_BaselineBailouts, "  No callee!");
  1384     if (iter.isConstructing())
  1385         IonSpew(IonSpew_BaselineBailouts, "  Constructing!");
  1386     else
  1387         IonSpew(IonSpew_BaselineBailouts, "  Not constructing!");
  1389     IonSpew(IonSpew_BaselineBailouts, "  Restoring frames:");
  1390     size_t frameNo = 0;
  1392     // Reconstruct baseline frames using the builder.
  1393     RootedScript caller(cx);
  1394     jsbytecode *callerPC = nullptr;
  1395     RootedFunction fun(cx, callee);
  1396     AutoValueVector startFrameFormals(cx);
  1398     RootedScript topCaller(cx);
  1399     jsbytecode *topCallerPC = nullptr;
  1401     while (true) {
  1402         MOZ_ASSERT(snapIter.instruction()->isResumePoint());
  1404         if (frameNo > 0) {
  1405             TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr));
  1406             TraceLogStartEvent(logger, TraceLogger::Baseline);
  1409         IonSpew(IonSpew_BaselineBailouts, "    FrameNo %d", frameNo);
  1411         // If we are bailing out to a catch or finally block in this frame,
  1412         // pass excInfo to InitFromBailout and don't unpack any other frames.
  1413         bool handleException = (catchingException && excInfo->frameNo() == frameNo);
  1415         // We also need to pass excInfo if we're bailing out in place for
  1416         // debug mode.
  1417         bool passExcInfo = handleException || propagatingExceptionForDebugMode;
  1419         jsbytecode *callPC = nullptr;
  1420         RootedFunction nextCallee(cx, nullptr);
  1421         if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
  1422                              snapIter, invalidate, builder, startFrameFormals,
  1423                              &nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
  1425             return BAILOUT_RETURN_FATAL_ERROR;
  1428         if (!snapIter.moreFrames()) {
  1429             JS_ASSERT(!callPC);
  1430             break;
  1433         if (handleException)
  1434             break;
  1436         JS_ASSERT(nextCallee);
  1437         JS_ASSERT(callPC);
  1438         caller = scr;
  1439         callerPC = callPC;
  1440         fun = nextCallee;
  1441         scr = fun->existingScriptForInlinedFunction();
  1443         // Save top caller info for adjusting SPS frames later.
  1444         if (!topCaller) {
  1445             JS_ASSERT(frameNo == 0);
  1446             topCaller = caller;
  1447             topCallerPC = callerPC;
  1450         frameNo++;
  1452         snapIter.nextInstruction();
  1454     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
  1456     // If there were multiple inline frames unpacked, and inline frame profiling
  1457     // is off, then the current top SPS frame is for the outermost caller, and
  1458     // has an uninitialized PC.  Initialize it now.
  1459     if (frameNo > 0 && !js_JitOptions.profileInlineFrames)
  1460         cx->runtime()->spsProfiler.updatePC(topCaller, topCallerPC);
  1462     BailoutKind bailoutKind = snapIter.bailoutKind();
  1464     if (!startFrameFormals.empty()) {
  1465         // Set the first frame's formals, see the comment in InitFromBailout.
  1466         Value *argv = builder.startFrame()->argv() + 1; // +1 to skip |this|.
  1467         mozilla::PodCopy(argv, startFrameFormals.begin(), startFrameFormals.length());
  1470     // Do stack check.
  1471     bool overRecursed = false;
  1472     BaselineBailoutInfo *info = builder.info();
  1473     uint8_t *newsp = info->incomingStack - (info->copyStackTop - info->copyStackBottom);
  1474 #ifdef JS_ARM_SIMULATOR
  1475     if (Simulator::Current()->overRecursed(uintptr_t(newsp)))
  1476         overRecursed = true;
  1477 #else
  1478     JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, newsp, overRecursed = true);
  1479 #endif
  1480     if (overRecursed) {
  1481         IonSpew(IonSpew_BaselineBailouts, "  Overrecursion check failed!");
  1482         return BAILOUT_RETURN_OVERRECURSED;
  1485     // Take the reconstructed baseline stack so it doesn't get freed when builder destructs.
  1486     info = builder.takeBuffer();
  1487     info->numFrames = frameNo + 1;
  1488     info->bailoutKind = bailoutKind;
  1489     *bailoutInfo = info;
  1490     return BAILOUT_RETURN_OK;
  1493 static bool
  1494 HandleBoundsCheckFailure(JSContext *cx, HandleScript outerScript, HandleScript innerScript)
  1496     IonSpew(IonSpew_Bailouts, "Bounds check failure %s:%d, inlined into %s:%d",
  1497             innerScript->filename(), innerScript->lineno(),
  1498             outerScript->filename(), outerScript->lineno());
  1500     JS_ASSERT(!outerScript->ionScript()->invalidated());
  1502     // TODO: Currently this mimic's Ion's handling of this case.  Investigate setting
  1503     // the flag on innerScript as opposed to outerScript, and maybe invalidating both
  1504     // inner and outer scripts, instead of just the outer one.
  1505     if (!outerScript->failedBoundsCheck())
  1506         outerScript->setFailedBoundsCheck();
  1507     IonSpew(IonSpew_BaselineBailouts, "Invalidating due to bounds check failure");
  1508     return Invalidate(cx, outerScript);
  1511 static bool
  1512 HandleShapeGuardFailure(JSContext *cx, HandleScript outerScript, HandleScript innerScript)
  1514     IonSpew(IonSpew_Bailouts, "Shape guard failure %s:%d, inlined into %s:%d",
  1515             innerScript->filename(), innerScript->lineno(),
  1516             outerScript->filename(), outerScript->lineno());
  1518     JS_ASSERT(!outerScript->ionScript()->invalidated());
  1520     // TODO: Currently this mimic's Ion's handling of this case.  Investigate setting
  1521     // the flag on innerScript as opposed to outerScript, and maybe invalidating both
  1522     // inner and outer scripts, instead of just the outer one.
  1523     outerScript->setFailedShapeGuard();
  1524     IonSpew(IonSpew_BaselineBailouts, "Invalidating due to shape guard failure");
  1525     return Invalidate(cx, outerScript);
  1528 static bool
  1529 HandleBaselineInfoBailout(JSContext *cx, JSScript *outerScript, JSScript *innerScript)
  1531     IonSpew(IonSpew_Bailouts, "Baseline info failure %s:%d, inlined into %s:%d",
  1532             innerScript->filename(), innerScript->lineno(),
  1533             outerScript->filename(), outerScript->lineno());
  1535     JS_ASSERT(!outerScript->ionScript()->invalidated());
  1537     IonSpew(IonSpew_BaselineBailouts, "Invalidating due to invalid baseline info");
  1538     return Invalidate(cx, outerScript);
  1541 static bool
  1542 CopyFromRematerializedFrame(JSContext *cx, JitActivation *act, uint8_t *fp, size_t inlineDepth,
  1543                             BaselineFrame *frame)
  1545     RematerializedFrame *rematFrame = act->lookupRematerializedFrame(fp, inlineDepth);
  1547     // We might not have rematerialized a frame if the user never requested a
  1548     // Debugger.Frame for it.
  1549     if (!rematFrame)
  1550         return true;
  1552     MOZ_ASSERT(rematFrame->script() == frame->script());
  1553     MOZ_ASSERT(rematFrame->numActualArgs() == frame->numActualArgs());
  1555     frame->setScopeChain(rematFrame->scopeChain());
  1556     frame->thisValue() = rematFrame->thisValue();
  1558     for (unsigned i = 0; i < frame->numActualArgs(); i++)
  1559         frame->argv()[i] = rematFrame->argv()[i];
  1561     for (size_t i = 0; i < frame->script()->nfixed(); i++)
  1562         *frame->valueSlot(i) = rematFrame->locals()[i];
  1564     IonSpew(IonSpew_BaselineBailouts,
  1565             "  Copied from rematerialized frame at (%p,%u)",
  1566             fp, inlineDepth);
  1568     if (cx->compartment()->debugMode())
  1569         return Debugger::handleIonBailout(cx, rematFrame, frame);
  1571     return true;
  1574 uint32_t
  1575 jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
  1577     // The caller pushes R0 and R1 on the stack without rooting them.
  1578     // Since GC here is very unlikely just suppress it.
  1579     JSContext *cx = GetJSContextFromJitCode();
  1580     js::gc::AutoSuppressGC suppressGC(cx);
  1582     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
  1584     // Check that we can get the current script's PC.
  1585 #ifdef DEBUG
  1586     jsbytecode *pc;
  1587     cx->currentScript(&pc);
  1588     IonSpew(IonSpew_BaselineBailouts, "  Got pc=%p", pc);
  1589 #endif
  1591     uint32_t numFrames = bailoutInfo->numFrames;
  1592     JS_ASSERT(numFrames > 0);
  1593     BailoutKind bailoutKind = bailoutInfo->bailoutKind;
  1595     // Free the bailout buffer.
  1596     js_free(bailoutInfo);
  1597     bailoutInfo = nullptr;
  1599     // Ensure the frame has a call object if it needs one. If the scope chain
  1600     // is nullptr, we will enter baseline code at the prologue so no need to do
  1601     // anything in that case.
  1602     BaselineFrame *topFrame = GetTopBaselineFrame(cx);
  1603     if (topFrame->scopeChain() && !EnsureHasScopeObjects(cx, topFrame))
  1604         return false;
  1606     // Create arguments objects for bailed out frames, to maintain the invariant
  1607     // that script->needsArgsObj() implies frame->hasArgsObj().
  1608     RootedScript innerScript(cx, nullptr);
  1609     RootedScript outerScript(cx, nullptr);
  1611     JS_ASSERT(cx->currentlyRunningInJit());
  1612     JitFrameIterator iter(cx);
  1613     uint8_t *outerFp = nullptr;
  1615     uint32_t frameno = 0;
  1616     while (frameno < numFrames) {
  1617         JS_ASSERT(!iter.isIonJS());
  1619         if (iter.isBaselineJS()) {
  1620             BaselineFrame *frame = iter.baselineFrame();
  1621             MOZ_ASSERT(frame->script()->hasBaselineScript());
  1623             // If the frame doesn't even have a scope chain set yet, then it's resuming
  1624             // into the the prologue before the scope chain is initialized.  Any
  1625             // necessary args object will also be initialized there.
  1626             if (frame->scopeChain() && frame->script()->needsArgsObj()) {
  1627                 ArgumentsObject *argsObj;
  1628                 if (frame->hasArgsObj()) {
  1629                     argsObj = &frame->argsObj();
  1630                 } else {
  1631                     argsObj = ArgumentsObject::createExpected(cx, frame);
  1632                     if (!argsObj)
  1633                         return false;
  1636                 // The arguments is a local binding and needsArgsObj does not
  1637                 // check if it is clobbered. Ensure that the local binding
  1638                 // restored during bailout before storing the arguments object
  1639                 // to the slot.
  1640                 RootedScript script(cx, frame->script());
  1641                 SetFrameArgumentsObject(cx, frame, script, argsObj);
  1644             if (frameno == 0)
  1645                 innerScript = frame->script();
  1647             if (frameno == numFrames - 1) {
  1648                 outerScript = frame->script();
  1649                 outerFp = iter.fp();
  1652             frameno++;
  1655         ++iter;
  1658     MOZ_ASSERT(innerScript);
  1659     MOZ_ASSERT(outerScript);
  1660     MOZ_ASSERT(outerFp);
  1662     // If we rematerialized Ion frames due to debug mode toggling, copy their
  1663     // values into the baseline frame. We need to do this even when debug mode
  1664     // is off, as we should respect the mutations made while debug mode was
  1665     // on.
  1666     JitActivation *act = cx->mainThread().activation()->asJit();
  1667     if (act->hasRematerializedFrame(outerFp)) {
  1668         JitFrameIterator iter(cx);
  1669         size_t inlineDepth = numFrames;
  1670         while (inlineDepth > 0) {
  1671             if (iter.isBaselineJS() &&
  1672                 !CopyFromRematerializedFrame(cx, act, outerFp, --inlineDepth,
  1673                                              iter.baselineFrame()))
  1675                 return false;
  1677             ++iter;
  1680         // After copying from all the rematerialized frames, remove them from
  1681         // the table to keep the table up to date.
  1682         act->removeRematerializedFrame(outerFp);
  1685     IonSpew(IonSpew_BaselineBailouts,
  1686             "  Restored outerScript=(%s:%u,%u) innerScript=(%s:%u,%u) (bailoutKind=%u)",
  1687             outerScript->filename(), outerScript->lineno(), outerScript->getUseCount(),
  1688             innerScript->filename(), innerScript->lineno(), innerScript->getUseCount(),
  1689             (unsigned) bailoutKind);
  1691     switch (bailoutKind) {
  1692       case Bailout_Normal:
  1693         // Do nothing.
  1694         break;
  1695       case Bailout_ArgumentCheck:
  1696         // Do nothing, bailout will resume before the argument monitor ICs.
  1697         break;
  1698       case Bailout_BoundsCheck:
  1699         if (!HandleBoundsCheckFailure(cx, outerScript, innerScript))
  1700             return false;
  1701         break;
  1702       case Bailout_ShapeGuard:
  1703         if (!HandleShapeGuardFailure(cx, outerScript, innerScript))
  1704             return false;
  1705         break;
  1706       case Bailout_BaselineInfo:
  1707         if (!HandleBaselineInfoBailout(cx, outerScript, innerScript))
  1708             return false;
  1709         break;
  1710       case Bailout_IonExceptionDebugMode:
  1711         // Return false to resume in HandleException with reconstructed
  1712         // baseline frame.
  1713         return false;
  1714       default:
  1715         MOZ_ASSUME_UNREACHABLE("Unknown bailout kind!");
  1718     if (!CheckFrequentBailouts(cx, outerScript))
  1719         return false;
  1721     return true;

mercurial