Bug 811111 - Ensure that no GC happen during bailouts. r=terrence
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Wed, 05 Dec 2012 16:26:33 -0800
changeset 115139 1f3975a90f400b19a6460d270468707066f9e855
parent 115138 4cc00705166e693c02fffca115ede5d981ac936f
child 115140 3c88682ae393ccb6ad2d7d66a04eab5ff1be167e
push id23973
push useremorley@mozilla.com
push dateThu, 06 Dec 2012 10:04:18 +0000
treeherdermozilla-central@ddda5400c826 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs811111
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 811111 - Ensure that no GC happen during bailouts. r=terrence
js/src/ion/Bailouts.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -180,17 +180,17 @@ StackFrame::initFromBailout(JSContext *c
     IonSpew(IonSpew_Bailouts, " new PC is offset %u within script %p (line %d)",
             pcOff, (void *)script().get(nogc), PCToLineNumber(script().get(nogc), regs.pc));
     JS_ASSERT(exprStackSlots == js_ReconstructStackDepth(cx, script().get(nogc), regs.pc));
 }
 
 static StackFrame *
 PushInlinedFrame(JSContext *cx, StackFrame *callerFrame)
 {
-    AssertCanGC();
+    AutoAssertNoGC nogc;
 
     // Grab the callee object out of the caller's frame, which has already been restored.
     // N.B. we currently assume that the caller frame is at a JSOP_CALL pc for the caller frames,
     // which will not be the case when we inline getters (in which case it would be a
     // JSOP_GETPROP). That will have to be handled differently.
     FrameRegs &regs = cx->regs();
     JS_ASSERT(JSOp(*regs.pc) == JSOP_CALL || JSOp(*regs.pc) == JSOP_NEW);
     int callerArgc = GET_ARGC(regs.pc);
@@ -218,17 +218,17 @@ PushInlinedFrame(JSContext *cx, StackFra
     fp->formals()[-2].setObject(*fun);
 
     return fp;
 }
 
 static uint32_t
 ConvertFrames(JSContext *cx, IonActivation *activation, IonBailoutIterator &it)
 {
-    AssertCanGC();
+    AutoAssertNoGC nogc;
     IonSpew(IonSpew_Bailouts, "Bailing out %s:%u, IonScript %p",
             it.script()->filename, it.script()->lineno, (void *) it.ionScript());
     IonSpew(IonSpew_Bailouts, " reading from snapshot offset %u size %u",
             it.snapshotOffset(), it.ionScript()->snapshotsSize());
 #ifdef DEBUG
     // Use count is reset after invalidation. Log use count on bailouts to
     // determine if we have a critical sequence of bailout.
     if (it.script()->ion == it.ionScript()) {
@@ -352,17 +352,17 @@ EnsureExitFrame(IonCommonFrameLayout *fr
 
     JS_ASSERT(frame->prevType() == IonFrame_OptimizedJS);
     frame->changePrevType(IonFrame_Bailed_JS);
 }
 
 uint32_t
 ion::Bailout(BailoutStack *sp)
 {
-    AssertCanGC();
+    AutoAssertNoGC nogc;
     JSContext *cx = GetIonContext()->cx;
     // We don't have an exit frame.
     cx->runtime->ionTop = NULL;
     IonActivationIterator ionActivations(cx);
     IonBailoutIterator iter(ionActivations, sp);
     IonActivation *activation = ionActivations.activation();
 
     // IonCompartment *ioncompartment = cx->compartment->ionCompartment();
@@ -375,17 +375,17 @@ ion::Bailout(BailoutStack *sp)
 
     EnsureExitFrame(iter.jsFrame());
     return retval;
 }
 
 uint32_t
 ion::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut)
 {
-    AssertCanGC();
+    AutoAssertNoGC nogc;
     sp->checkInvariants();
 
     JSContext *cx = GetIonContext()->cx;
 
     // We don't have an exit frame.
     cx->runtime->ionTop = NULL;
     IonActivationIterator ionActivations(cx);
     IonBailoutIterator iter(ionActivations, sp);
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -379,17 +379,22 @@ StackFrame::callObj() const
 }
 
 /*****************************************************************************/
 
 STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
 JS_ALWAYS_INLINE bool
 StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals) const
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     assertInvariants();
     JS_ASSERT(from >= firstUnused());
 #ifdef XP_WIN
     JS_ASSERT(from <= commitEnd_);
 #endif
     if (JS_UNLIKELY(conservativeEnd_ - from < nvals))
         return ensureSpaceSlow(cx, report, from, nvals);
     return true;
@@ -407,17 +412,22 @@ StackSpace::getStackLimit(JSContext *cx,
 }
 
 /*****************************************************************************/
 
 JS_ALWAYS_INLINE StackFrame *
 ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
                            JSFunction *fun, JSScript *script, StackFrame::Flags *flags) const
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     JS_ASSERT(fun->nonLazyScript() == script);
     unsigned nformal = fun->nargs;
 
     Value *firstUnused = args.end();
     JS_ASSERT(firstUnused == space().firstUnused());
 
     /* Include extra space to satisfy the method-jit stackLimit invariant. */
     unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA;
@@ -449,17 +459,22 @@ ContextStack::getCallFrame(JSContext *cx
     return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
 }
 
 JS_ALWAYS_INLINE bool
 ContextStack::pushInlineFrame(JSContext *cx, FrameRegs &regs, const CallArgs &args,
                               JSFunction &callee, JSScript *script,
                               InitialFrameFlags initial, MaybeReportError report)
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     JS_ASSERT(onTop());
     JS_ASSERT(regs.sp == args.end());
     /* Cannot assert callee == args.callee() since this is called from LeaveTree. */
     JS_ASSERT(callee.nonLazyScript() == script);
 
     StackFrame::Flags flags = ToFrameFlags(initial);
     StackFrame *fp = getCallFrame(cx, report, args, &callee, script, &flags);
     if (!fp)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -683,17 +683,22 @@ StackSpace::markActiveCompartments()
         for (StackFrame *fp = seg->maybefp(); (Value *)fp > (Value *)seg; fp = fp->prev())
             MarkCompartmentActive(fp);
     }
 }
 
 JS_FRIEND_API(bool)
 StackSpace::ensureSpaceSlow(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals) const
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     assertInvariants();
 
     JSCompartment *dest = cx->compartment;
     bool trusted = dest->principals == cx->runtime->trustedPrincipals();
     Value *end = trusted ? trustedEnd_ : defaultEnd_;
 
     /*
      * conservativeEnd_ must stay below defaultEnd_: if conservativeEnd_ were
@@ -863,17 +868,21 @@ ContextStack::onTop() const
  *
  * Additionally, to minimize calls to ensureSpace, ensureOnTop ensures that
  * there is space for nvars slots on top of the stack.
  */
 Value *
 ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars,
                           MaybeExtend extend, bool *pushedSeg)
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
 
     Value *firstUnused = space().firstUnused();
     FrameRegs *regs = cx->maybeRegs();
 
 #ifdef JS_METHODJIT
     /*
      * The only calls made by inlined methodjit frames can be to other JIT
      * frames associated with the same VMFrame. If we try to Invoke(),
@@ -943,17 +952,22 @@ ContextStack::popSegment()
     if (!seg_)
         cx_->maybeMigrateVersionOverride();
 }
 
 bool
 ContextStack::pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *iag,
                              MaybeReportError report)
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
     unsigned nvars = 2 + argc;
     Value *firstUnused = ensureOnTop(cx, report, nvars, CAN_EXTEND, &iag->pushedSeg_);
     if (!firstUnused)
         return false;
 
     MakeRangeGCSafe(firstUnused, nvars);
@@ -982,17 +996,22 @@ ContextStack::popInvokeArgs(const Invoke
     Debug_SetValueRangeToCrashOnTouch(space().firstUnused(), oldend);
 }
 
 StackFrame *
 ContextStack::pushInvokeFrame(JSContext *cx, MaybeReportError report,
                               const CallArgs &args, JSFunction *fun,
                               InitialFrameFlags initial, FrameGuard *fg)
 {
-    AssertCanGC();
+    mozilla::Maybe<AutoAssertNoGC> maybeNoGC;
+    if (report)
+        AssertCanGC();
+    else
+        maybeNoGC.construct();
+
     JS_ASSERT(onTop());
     JS_ASSERT(space().firstUnused() == args.end());
 
     RootedScript script(cx, fun->nonLazyScript());
 
     StackFrame::Flags flags = ToFrameFlags(initial);
     StackFrame *fp = getCallFrame(cx, report, args, fun, script, &flags);
     if (!fp)