Example #1
0
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JSContext *cx = GetJSContextFromJitCode();
    JS_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
               "Fake jitTop pointer should be within the first page.");
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
    gc::AutoSuppressGC suppress(cx);

    JitActivationIterator jitActivations(cx->runtime());
    IonBailoutIterator iter(jitActivations, sp);
    JitActivation *activation = jitActivations->asJit();

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Bailout);

    JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    JS_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
    JS_ASSERT(retval == BAILOUT_RETURN_OK ||
              retval == BAILOUT_RETURN_FATAL_ERROR ||
              retval == BAILOUT_RETURN_OVERRECURSED);
    JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        //
        // However, if the bailout was during argument check, then a
        // pseudostack frame would not have been pushed in the first
        // place, so don't pop anything in that case.
        bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
                           (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck);
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);

        EnsureExitFrame(iter.jsFrame());
    }

    return retval;
}
Example #2
0
uint32_t
jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
{
    JSContext* cx = GetJSContextFromJitCode();
    MOZ_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
               "Fake jitTop pointer should be within the first page.");
    cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;

    JitActivationIterator jitActivations(cx->runtime());
    BailoutFrameInfo bailoutData(jitActivations, sp);
    JitFrameIterator iter(jitActivations);
    MOZ_ASSERT(!iter.ionScript()->invalidated());
    CommonFrameLayout* currentFramePtr = iter.current();

    TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger_Bailout);

    JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    MOZ_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
                                           /* excInfo = */ nullptr);
    MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
               retval == BAILOUT_RETURN_FATAL_ERROR ||
               retval == BAILOUT_RETURN_OVERRECURSED);
    MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        JSScript* script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(),
                           /* popSPSFrame = */ false);

        EnsureExitFrame(iter.jsFrame());
    }

    // This condition was wrong when we entered this bailout function, but it
    // might be true now. A GC might have reclaimed all the Jit code and
    // invalidated all frames which are currently on the stack. As we are
    // already in a bailout, we could not switch to an invalidation
    // bailout. When the code of an IonScript which is on the stack is
    // invalidated (see InvalidateActivation), we remove references to it and
    // increment the reference counter for each activation that appear on the
    // stack. As the bailed frame is one of them, we have to decrement it now.
    if (iter.ionScript()->invalidated())
        iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());

    // NB: Commentary on how |lastProfilingFrame| is set from bailouts.
    //
    // Once we return to jitcode, any following frames might get clobbered,
    // but the current frame will not (as it will be clobbered "in-place"
    // with a baseline frame that will share the same frame prefix).
    // However, there may be multiple baseline frames unpacked from this
    // single Ion frame, which means we will need to once again reset
    // |lastProfilingFrame| to point to the correct unpacked last frame
    // in |FinishBailoutToBaseline|.
    //
    // In the case of error, the jitcode will jump immediately to an
    // exception handler, which will unwind the frames and properly set
    // the |lastProfilingFrame| to point to the frame being resumed into
    // (see |AutoResetLastProfilerFrameOnReturnFromException|).
    //
    // In both cases, we want to temporarily set the |lastProfilingFrame|
    // to the current frame being bailed out, and then fix it up later.
    if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
        cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);

    return retval;
}
Example #3
0
static void
TestIsInRangeClass()
{
  void* nul = nullptr;
  Base* baseBegin = nullptr;
  Base* baseEnd = baseBegin + 1;
  Base* baseEnd2 = baseBegin + 2;

  MOZ_RELEASE_ASSERT(IsInRange(nul, baseBegin, baseEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(nul, baseEnd, baseEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, baseBegin, baseEnd));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, baseBegin, baseEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, baseBegin, baseEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, baseBegin, baseEnd2));

  uintptr_t ubaseBegin = uintptr_t(baseBegin);
  uintptr_t ubaseEnd = uintptr_t(baseEnd);
  uintptr_t ubaseEnd2 = uintptr_t(baseEnd2);

  MOZ_RELEASE_ASSERT(IsInRange(nul, ubaseBegin, ubaseEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(nul, ubaseEnd, ubaseEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, ubaseBegin, ubaseEnd));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, ubaseBegin, ubaseEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, ubaseBegin, ubaseEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, ubaseBegin, ubaseEnd2));
}
Example #4
0
static void
TestIsInRangeVoid()
{
  int* intBegin = nullptr;
  int* intEnd = intBegin + 1;
  int* intEnd2 = intBegin + 2;

  void* voidBegin = intBegin;
  void* voidEnd = intEnd;
  void* voidEnd2 = intEnd2;

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, intBegin, intEnd));

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, voidBegin, voidEnd));

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, intBegin, intEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, intBegin, intEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, intBegin, intEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, voidBegin, voidEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, voidBegin, voidEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, voidBegin, voidEnd2));

  uintptr_t uintBegin = uintptr_t(intBegin);
  uintptr_t uintEnd = uintptr_t(intEnd);
  uintptr_t uintEnd2 = uintptr_t(intEnd2);

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd, uintBegin, uintEnd));

  MOZ_RELEASE_ASSERT(IsInRange(voidBegin, uintBegin, uintEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(voidEnd, uintBegin, uintEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(voidEnd2, uintBegin, uintEnd2));
}
Example #5
0
static void
TestIsInRangeClassExtraDerivedEmpty()
{
  void* nul = nullptr;
  ExtraDerivedEmpty* derivedBegin = nullptr;
  ExtraDerivedEmpty* derivedEnd = derivedBegin + 1;
  ExtraDerivedEmpty* derivedEnd2 = derivedBegin + 2;

  EmptyBase* baseBegin = static_cast<EmptyBase*>(derivedBegin);
  EmptyBase* baseEnd = static_cast<EmptyBase*>(derivedEnd);
  EmptyBase* baseEnd2 = static_cast<EmptyBase*>(derivedEnd2);

  MOZ_RELEASE_ASSERT(IsInRange(nul, derivedBegin, derivedEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(nul, derivedEnd, derivedEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd, derivedBegin, derivedEnd));

  MOZ_RELEASE_ASSERT(IsInRange(baseBegin, derivedBegin, derivedEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(baseEnd, derivedBegin, derivedEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(baseEnd2, derivedBegin, derivedEnd2));

  uintptr_t uderivedBegin = uintptr_t(derivedBegin);
  uintptr_t uderivedEnd = uintptr_t(derivedEnd);
  uintptr_t uderivedEnd2 = uintptr_t(derivedEnd2);

  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd, uderivedBegin, uderivedEnd));

  MOZ_RELEASE_ASSERT(IsInRange(derivedBegin, uderivedBegin, uderivedEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(derivedEnd, uderivedBegin, uderivedEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(derivedEnd2, uderivedBegin, uderivedEnd2));
}
Example #6
0
static void
TestIsInRangeNonClass()
{
  void* nul = nullptr;
  int* intBegin = nullptr;
  int* intEnd = intBegin + 1;
  int* intEnd2 = intBegin + 2;

  MOZ_RELEASE_ASSERT(IsInRange(nul, intBegin, intEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(nul, intEnd, intEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, intBegin, intEnd));

  MOZ_RELEASE_ASSERT(IsInRange(intBegin, intBegin, intEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(intEnd, intBegin, intEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, intBegin, intEnd2));

  uintptr_t uintBegin = uintptr_t(intBegin);
  uintptr_t uintEnd = uintptr_t(intEnd);
  uintptr_t uintEnd2 = uintptr_t(intEnd2);

  MOZ_RELEASE_ASSERT(IsInRange(nul, uintBegin, uintEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(nul, uintEnd, uintEnd2));

  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd));
  MOZ_RELEASE_ASSERT(!IsInRange(intEnd, uintBegin, uintEnd));

  MOZ_RELEASE_ASSERT(IsInRange(intBegin, uintBegin, uintEnd2));
  MOZ_RELEASE_ASSERT(IsInRange(intEnd, uintBegin, uintEnd2));
  MOZ_RELEASE_ASSERT(!IsInRange(intEnd2, uintBegin, uintEnd2));
}
Example #7
0
uint32_t
jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
{
    JSContext *cx = GetJSContextFromJitCode();
    MOZ_ASSERT(bailoutInfo);

    // We don't have an exit frame.
    MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
               IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
               "Fake jitTop pointer should be within the first page.");
    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;

    JitActivationIterator jitActivations(cx->runtime());
    BailoutFrameInfo bailoutData(jitActivations, sp);
    JitFrameIterator iter(jitActivations);
    MOZ_ASSERT(!iter.ionScript()->invalidated());

    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
    TraceLogTimestamp(logger, TraceLogger::Bailout);

    JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());

    MOZ_ASSERT(IsBaselineEnabled(cx));

    *bailoutInfo = nullptr;
    bool poppedLastSPSFrame = false;
    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
                                           /* excInfo = */ nullptr, &poppedLastSPSFrame);
    MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
               retval == BAILOUT_RETURN_FATAL_ERROR ||
               retval == BAILOUT_RETURN_OVERRECURSED);
    MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);

    if (retval != BAILOUT_RETURN_OK) {
        // If the bailout failed, then bailout trampoline will pop the
        // current frame and jump straight to exception handling code when
        // this function returns.  Any SPS entry pushed for this frame will
        // be silently forgotten.
        //
        // We call ExitScript here to ensure that if the ionScript had SPS
        // instrumentation, then the SPS entry for it is popped.
        //
        // However, if the bailout was during argument check, then a
        // pseudostack frame would not have been pushed in the first
        // place, so don't pop anything in that case.
        bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
                           (SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
                           !poppedLastSPSFrame;
        JSScript *script = iter.script();
        probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);

        EnsureExitFrame(iter.jsFrame());
    }

    // This condition was wrong when we entered this bailout function, but it
    // might be true now. A GC might have reclaimed all the Jit code and
    // invalidated all frames which are currently on the stack. As we are
    // already in a bailout, we could not switch to an invalidation
    // bailout. When the code of an IonScript which is on the stack is
    // invalidated (see InvalidateActivation), we remove references to it and
    // increment the reference counter for each activation that appear on the
    // stack. As the bailed frame is one of them, we have to decrement it now.
    if (iter.ionScript()->invalidated())
        iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());

    return retval;
}