Bug 666094 - initCallFrameLatePrologue should ensureSlots (r=dvander,a=clegnitto) BETA_BASE_20110705
authorLuke Wagner <luke@mozilla.com>
Tue, 05 Jul 2011 09:05:50 -0700
changeset 70378 43e6c03cdb340aa7e19f13e6a624bf0a891ad86b
parent 70377 8ccb9b7ab7f2cbb0b82118ff02e7a4aac2dfdc5b
child 70379 5b3305e5eb5a78e7cc58a5dc4a7a15ed15017a8c
push id207
push userlwagner@mozilla.com
push dateTue, 05 Jul 2011 16:06:22 +0000
treeherdermozilla-aurora@43e6c03cdb34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander, clegnitto
bugs666094
milestone6.0a2
Bug 666094 - initCallFrameLatePrologue should ensureSlots (r=dvander,a=clegnitto)
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -304,17 +304,17 @@ stubs::CompileFunction(VMFrame &f, uint3
 
     if (nactual != fp->numFormalArgs()) {
         fp = (StackFrame *)FixupArity(f, nactual);
         if (!fp)
             return NULL;
     }
 
     /* Finish frame initialization. */
-    fp->initCallFrameLatePrologue();
+    fp->initCallFrameLatePrologue(cx, f.entryfp, &f.stackLimit);
 
     /* These would have been initialized by the prologue. */
     f.regs.prepareToRun(fp, script);
 
     if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp))
         THROWV(NULL);
 
     CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT);
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -651,17 +651,17 @@ class CallCompiler : public BaseCompiler
         masm.loadPtr(Address(t0, offset), t0);
         Jump hasCode = masm.branchPtr(Assembler::Above, t0, ImmPtr(JS_UNJITTABLE_SCRIPT));
 
         /* Try and compile. On success we get back the nmap pointer. */
         masm.storePtr(JSFrameReg, FrameAddress(VMFrame::offsetOfFp));
         void *compilePtr = JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction);
         if (ic.frameSize.isStatic()) {
             masm.move(Imm32(ic.frameSize.staticArgc()), Registers::ArgReg1);
-            masm.fallibleVMCall(compilePtr, script->code, ic.frameSize.staticLocalSlots());
+            masm.fallibleVMCall(compilePtr, script->code, 0 /* sp not used */);
         } else {
             masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), Registers::ArgReg1);
             masm.fallibleVMCall(compilePtr, script->code, -1);
         }
         masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
 
         Jump notCompiled = masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
                                               Registers::ReturnReg);
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -374,35 +374,47 @@ StackFrame::initCallFrameCallerHalf(JSCo
                             UNDERFLOW_ARGS)) == 0);
 
     flags_ = FUNCTION | flagsArg;
     prev_ = cx->fp();
     ncode_ = ncode;
 }
 
 /*
- * The "early prologue" refers to the members that are stored for the benefit
- * of slow paths before initializing the rest of the members.
+ * The "early prologue" refers to either the fast path or arity check path up
+ * to the "late prologue".
  */
 inline void
 StackFrame::initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual)
 {
     exec.fun = fun;
     if (flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS))
         args.nactual = nactual;
 }
 
 /*
- * The "late prologue" refers to the members that are stored after having
- * checked for stack overflow and formal/actual arg mismatch.
+ * The "late prologue" (in generatePrologue) extends from the join point of the
+ * fast path and arity check to where the call object is (possibly) created.
  */
-inline void
-StackFrame::initCallFrameLatePrologue()
+inline bool
+StackFrame::initCallFrameLatePrologue(JSContext *cx, StackFrame *fp, Value **limit)
 {
+    uintN nvals = script()->nslots + VALUES_PER_STACK_FRAME;
+    Value *required = (Value *)this + nvals;
+    if (required >= *limit) {
+        ContextStack &stack = cx->stack;
+        if (!stack.space().bumpLimit(NULL, fp, slots(), nvals, limit)) {
+            stack.popFrameAfterOverflow();
+            js_ReportOverRecursed(cx);
+            return false;
+        }
+    }
+
     SetValueRangeToUndefined(slots(), script()->nfixed);
+    return true;
 }
 
 inline void
 StackFrame::initEvalFrame(JSContext *cx, JSScript *script, StackFrame *prev, uint32 flagsArg)
 {
     JS_ASSERT(flagsArg & EVAL);
     JS_ASSERT((flagsArg & ~(EVAL | DEBUGGER)) == 0);
     JS_ASSERT(prev->isScriptFrame());
@@ -923,16 +935,23 @@ ContextStack::popInlineFrame()
 
     Value *newsp = fp->actualArgs() - 1;
     JS_ASSERT(newsp >= fp->prev()->base());
 
     newsp[-1] = fp->returnValue();
     regs_->popFrame(newsp);
 }
 
+inline void
+ContextStack::popFrameAfterOverflow()
+{
+    /* Restore the regs to what they were on entry to JSOP_CALL. */
+    regs_->popFrame(regs_->fp()->actualArgsEnd());
+}
+
 JS_ALWAYS_INLINE bool
 ContextStack::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *argsGuard)
 {
     if (!isCurrentAndActive())
         return pushInvokeArgsSlow(cx, argc, argsGuard);
 
     Value *start = space().activeFirstUnused();
     uintN vplen = 2 + argc;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -300,17 +300,17 @@ class StackFrame
                               uint32 nactual, uint32 flags);
 
     /* Used for SessionInvoke. */
     inline void resetInvokeCallFrame();
 
     /* Called by method-jit stubs and serve as a specification for jit-code. */
     inline void initCallFrameCallerHalf(JSContext *cx, uint32 flags, void *ncode);
     inline void initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual);
-    inline void initCallFrameLatePrologue();
+    bool initCallFrameLatePrologue(JSContext *cx, StackFrame *fp, Value **limit);
 
     /* Used for eval. */
     inline void initEvalFrame(JSContext *cx, JSScript *script, StackFrame *prev,
                               uint32 flags);
     inline void initGlobalFrame(JSScript *script, JSObject &chain, StackFrame *prev,
                                 uint32 flags);
 
     /* Used when activating generators. */
@@ -1321,16 +1321,19 @@ class ContextStack
                    JSFunction *fun, JSScript *script, uint32 *flags) const;
     inline StackFrame *
     getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
                               JSFunction *fun, JSScript *script, uint32 *flags,
                               StackFrame *base, Value **limit) const;
     inline void pushInlineFrame(JSScript *script, StackFrame *fp, FrameRegs &regs);
     inline void popInlineFrame();
 
+    /* Pop a partially-pushed frame after hitting the limit before throwing. */
+    void popFrameAfterOverflow();
+
     /* For jit use: */
     static size_t offsetOfRegs() { return offsetof(ContextStack, regs_); }
 };
 
 /*****************************************************************************/
 
 class InvokeArgsGuard : public CallArgs
 {