js/src/jit/Bailouts.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "jit/Bailouts.h"
     9 #include "jscntxt.h"
    11 #include "jit/BaselineJIT.h"
    12 #include "jit/Ion.h"
    13 #include "jit/IonSpewer.h"
    14 #include "jit/JitCompartment.h"
    15 #include "jit/Snapshots.h"
    16 #include "vm/TraceLogging.h"
    18 #include "jit/JitFrameIterator-inl.h"
    19 #include "vm/Stack-inl.h"
    21 using namespace js;
    22 using namespace js::jit;
    24 // These constructor are exactly the same except for the type of the iterator
    25 // which is given to the SnapshotIterator constructor. Doing so avoid the
    26 // creation of virtual functions for the IonIterator but may introduce some
    27 // weirdness as IonInlineIterator is using a JitFrameIterator reference.
    28 //
    29 // If a function relies on ionScript() or to use OsiIndex(), due to the
    30 // lack of virtual, these functions will use the JitFrameIterator reference
    31 // contained in the InlineFrameIterator and thus are not able to recover
    32 // correctly the data stored in IonBailoutIterator.
    33 //
    34 // Currently, such cases should not happen because our only use case of the
    35 // JitFrameIterator within InlineFrameIterator is to read the frame content, or
    36 // to clone it to find the parent scripted frame.  Both use cases are fine and
    37 // should not cause any issue since the only potential issue is to read the
    38 // bailed out frame.
    40 SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
    41   : snapshot_(iter.ionScript()->snapshots(),
    42               iter.snapshotOffset(),
    43               iter.ionScript()->snapshotsRVATableSize(),
    44               iter.ionScript()->snapshotsListSize()),
    45     recover_(snapshot_,
    46              iter.ionScript()->recovers(),
    47              iter.ionScript()->recoversSize()),
    48     fp_(iter.jsFrame()),
    49     machine_(iter.machineState()),
    50     ionScript_(iter.ionScript())
    51 {
    52 }
    54 void
    55 IonBailoutIterator::dump() const
    56 {
    57     if (type_ == JitFrame_IonJS) {
    58         InlineFrameIterator frames(GetJSContextFromJitCode(), this);
    59         for (;;) {
    60             frames.dump();
    61             if (!frames.more())
    62                 break;
    63             ++frames;
    64         }
    65     } else {
    66         JitFrameIterator::dump();
    67     }
    68 }
    70 uint32_t
    71 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
    72 {
    73     JSContext *cx = GetJSContextFromJitCode();
    74     JS_ASSERT(bailoutInfo);
    76     // We don't have an exit frame.
    77     cx->mainThread().ionTop = nullptr;
    78     JitActivationIterator jitActivations(cx->runtime());
    79     IonBailoutIterator iter(jitActivations, sp);
    80     JitActivation *activation = jitActivations->asJit();
    82     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    83     TraceLogTimestamp(logger, TraceLogger::Bailout);
    85     IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
    87     JS_ASSERT(IsBaselineEnabled(cx));
    89     *bailoutInfo = nullptr;
    90     uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
    91     JS_ASSERT(retval == BAILOUT_RETURN_OK ||
    92               retval == BAILOUT_RETURN_FATAL_ERROR ||
    93               retval == BAILOUT_RETURN_OVERRECURSED);
    94     JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
    96     if (retval != BAILOUT_RETURN_OK)
    97         EnsureExitFrame(iter.jsFrame());
    99     return retval;
   100 }
   102 uint32_t
   103 jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
   104                          BaselineBailoutInfo **bailoutInfo)
   105 {
   106     sp->checkInvariants();
   108     JSContext *cx = GetJSContextFromJitCode();
   110     // We don't have an exit frame.
   111     cx->mainThread().ionTop = nullptr;
   112     JitActivationIterator jitActivations(cx->runtime());
   113     IonBailoutIterator iter(jitActivations, sp);
   114     JitActivation *activation = jitActivations->asJit();
   116     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
   117     TraceLogTimestamp(logger, TraceLogger::Invalidation);
   119     IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
   121     // Note: the frame size must be computed before we return from this function.
   122     *frameSizeOut = iter.topFrameSize();
   124     JS_ASSERT(IsBaselineEnabled(cx));
   126     *bailoutInfo = nullptr;
   127     uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
   128     JS_ASSERT(retval == BAILOUT_RETURN_OK ||
   129               retval == BAILOUT_RETURN_FATAL_ERROR ||
   130               retval == BAILOUT_RETURN_OVERRECURSED);
   131     JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
   133     if (retval != BAILOUT_RETURN_OK) {
   134         IonJSFrameLayout *frame = iter.jsFrame();
   135         IonSpew(IonSpew_Invalidate, "converting to exit frame");
   136         IonSpew(IonSpew_Invalidate, "   orig calleeToken %p", (void *) frame->calleeToken());
   137         IonSpew(IonSpew_Invalidate, "   orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
   138         IonSpew(IonSpew_Invalidate, "   orig ra %p", (void *) frame->returnAddress());
   140         frame->replaceCalleeToken(nullptr);
   141         EnsureExitFrame(frame);
   143         IonSpew(IonSpew_Invalidate, "   new  calleeToken %p", (void *) frame->calleeToken());
   144         IonSpew(IonSpew_Invalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
   145         IonSpew(IonSpew_Invalidate, "   new  ra %p", (void *) frame->returnAddress());
   146     }
   148     iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
   150     return retval;
   151 }
   153 IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
   154                                        const JitFrameIterator &frame)
   155   : JitFrameIterator(activations),
   156     machine_(frame.machineState())
   157 {
   158     returnAddressToFp_ = frame.returnAddressToFp();
   159     topIonScript_ = frame.ionScript();
   160     const OsiIndex *osiIndex = frame.osiIndex();
   162     current_ = (uint8_t *) frame.fp();
   163     type_ = JitFrame_IonJS;
   164     topFrameSize_ = frame.frameSize();
   165     snapshotOffset_ = osiIndex->snapshotOffset();
   166 }
   168 uint32_t
   169 jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
   170                              ResumeFromException *rfe,
   171                              const ExceptionBailoutInfo &excInfo,
   172                              bool *overrecursed)
   173 {
   174     // We can be propagating debug mode exceptions without there being an
   175     // actual exception pending. For instance, when we return false from an
   176     // operation callback like a timeout handler.
   177     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
   179     cx->mainThread().ionTop = nullptr;
   180     JitActivationIterator jitActivations(cx->runtime());
   181     IonBailoutIterator iter(jitActivations, frame.frame());
   182     JitActivation *activation = jitActivations->asJit();
   184     BaselineBailoutInfo *bailoutInfo = nullptr;
   185     uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
   187     if (retval == BAILOUT_RETURN_OK) {
   188         MOZ_ASSERT(bailoutInfo);
   190         // Overwrite the kind so HandleException after the bailout returns
   191         // false, jumping directly to the exception tail.
   192         if (excInfo.propagatingIonExceptionForDebugMode())
   193             bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
   195         rfe->kind = ResumeFromException::RESUME_BAILOUT;
   196         rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw();
   197         rfe->bailoutInfo = bailoutInfo;
   198     } else {
   199         // Bailout failed. If there was a fatal error, clear the
   200         // exception to turn this into an uncatchable error. If the
   201         // overrecursion check failed, continue popping all inline
   202         // frames and have the caller report an overrecursion error.
   203         MOZ_ASSERT(!bailoutInfo);
   205         if (!excInfo.propagatingIonExceptionForDebugMode())
   206             cx->clearPendingException();
   208         if (retval == BAILOUT_RETURN_OVERRECURSED)
   209             *overrecursed = true;
   210         else
   211             MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR);
   212     }
   214     return retval;
   215 }
   217 // Initialize the decl env Object, call object, and any arguments obj of the current frame.
   218 bool
   219 jit::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
   220 {
   221     if (fp.isFunctionFrame() &&
   222         fp.fun()->isHeavyweight() &&
   223         !fp.hasCallObj())
   224     {
   225         return fp.initFunctionScopeObjects(cx);
   226     }
   227     return true;
   228 }
   230 bool
   231 jit::CheckFrequentBailouts(JSContext *cx, JSScript *script)
   232 {
   233     if (script->hasIonScript()) {
   234         // Invalidate if this script keeps bailing out without invalidation. Next time
   235         // we compile this script LICM will be disabled.
   236         IonScript *ionScript = script->ionScript();
   238         if (ionScript->numBailouts() >= js_JitOptions.frequentBailoutThreshold &&
   239             !script->hadFrequentBailouts())
   240         {
   241             script->setHadFrequentBailouts();
   243             IonSpew(IonSpew_Invalidate, "Invalidating due to too many bailouts");
   245             if (!Invalidate(cx, script))
   246                 return false;
   247         }
   248     }
   250     return true;
   251 }

mercurial