[INFER] Use ICs on monitored calls, reenable APPLY optimizations, bug 621942.
authorBrian Hackett <bhackett1024@gmail.com>
Sat, 12 Mar 2011 21:59:46 -0800
changeset 74760 ce1accd11d7adff7b97884b542b21a703feb0de9
parent 74759 bcf148dbce2f3de31d37f393b4b0e5297f06c565
child 74761 dd21e37cff014c6d2c7c04a0b0fb03b042c9b6ce
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs621942
milestone2.0b13pre
[INFER] Use ICs on monitored calls, reenable APPLY optimizations, bug 621942.
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -667,17 +667,17 @@ struct TypeCompartment
     /* Number of recompilations triggered. */
     unsigned recompilations;
 
     void init(JSContext *cx);
     ~TypeCompartment();
 
     uint64 currentTime()
     {
-#ifndef _MSC_VER
+#if 0
         timeval current;
         gettimeofday(&current, NULL);
         return current.tv_sec * (uint64_t) 1000000 + current.tv_usec;
 #else
         /* Timing not available on Windows. */
         return 0;
 #endif
     }
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1128,11 +1128,18 @@ inline TypeObject::TypeObject(jsid name,
 }
 
 inline TypeFunction::TypeFunction(jsid name, JSObject *proto)
     : TypeObject(name, proto), handler(NULL), script(NULL), isGeneric(false)
 {
     isFunction = true;
 }
 
+inline void
+SweepType(jstype *ptype)
+{
+    if (TypeIsObject(*ptype) && !((TypeObject*)*ptype)->marked)
+        *ptype = TYPE_UNKNOWN;
+}
+
 } } /* namespace js::types */
 
 #endif // jsinferinlines_h___
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -455,28 +455,48 @@ mjit::Compiler::generatePrologue()
         {
             /*
              * Entry point #3: The caller has partially constructed a frame,
              * but argc might be != nargs, so an arity check might be called.
              *
              * This loops back to entry point #2.
              */
             arityLabel = stubcc.masm.label();
+
             Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
                                                  Imm32(fun->nargs));
-            stubcc.crossJump(argMatch, fastPath);
 
             if (JSParamReg_Argc != Registers::ArgReg1)
                 stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
 
             /* Slow path - call the arity check function. Returns new fp. */
             stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
             stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
             OOL_STUBCALL(stubs::FixupArity);
             stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
+            argMatch.linkTo(stubcc.masm.label(), &stubcc.masm);
+
+            if (cx->typeInferenceEnabled()) {
+                /* Make sure 'this' and all arguments are marked as undefined. */
+                bool emitCall = false;
+                if (!isConstructing && !script->thisTypes()->unknown())
+                    emitCall = true;
+                for (unsigned i = 0; i < fun->nargs; i++) {
+                    if (!isConstructing && !script->argTypes(i)->unknown())
+                        emitCall = true;
+                }
+                if (emitCall) {
+                    stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
+                    OOL_STUBCALL(stubs::ClearArgumentTypes);
+                } else if (recompiling) {
+                    stubcc.crossJump(stubcc.masm.jump(), fastPath);
+                    OOL_STUBCALL(stubs::ClearArgumentTypes);
+                }
+            }
+
             stubcc.crossJump(stubcc.masm.jump(), fastPath);
         }
 
         /*
          * Guard that there is enough stack space. Note we include the size of
          * a second frame, to ensure we can create a frame from call sites.
          */
         masm.addPtr(Imm32((script->nslots + VALUES_PER_STACK_FRAME * 2) * sizeof(Value)),
@@ -747,16 +767,18 @@ mjit::Compiler::finishThisUp(JITScript *
     ic::CallICInfo *jitCallICs = (ic::CallICInfo *)cursor;
     jit->nCallICs = callICs.length();
     cursor += sizeof(ic::CallICInfo) * jit->nCallICs;
     for (size_t i = 0; i < jit->nCallICs; i++) {
         jitCallICs[i].reset();
         jitCallICs[i].funGuard = fullCode.locationOf(callICs[i].funGuard);
         jitCallICs[i].funJump = fullCode.locationOf(callICs[i].funJump);
         jitCallICs[i].slowPathStart = stubCode.locationOf(callICs[i].slowPathStart);
+        jitCallICs[i].typeMonitored = callICs[i].typeMonitored;
+        jitCallICs[i].argTypes = callICs[i].argTypes;
 
         /* Compute the hot call offset. */
         uint32 offset = fullCode.locationOf(callICs[i].hotJump) -
                         fullCode.locationOf(callICs[i].funGuard);
         jitCallICs[i].hotJumpOffset = offset;
         JS_ASSERT(jitCallICs[i].hotJumpOffset == offset);
 
         /* Compute the join point offset. */
@@ -2805,26 +2827,25 @@ mjit::Compiler::checkCallApplySpeculatio
         stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.fp)), JSFrameReg);
         Address ncodeAddr(JSFrameReg, JSStackFrame::offsetOfncode());
         uncachedCallPatch->hasSlowNcode = true;
         uncachedCallPatch->slowNcodePatch = stubcc.masm.storePtrWithPatch(ImmPtr(NULL), ncodeAddr);
 
         stubcc.masm.jump(r0);
         notCompiled.linkTo(stubcc.masm.label(), &stubcc.masm);
 
-        /* :FIXME: not handling call/apply speculation that results in a double. */
-        JS_ASSERT(knownPushedType(0) != JSVAL_TYPE_DOUBLE);
-
         /*
          * inlineCallHelper will link uncachedCallSlowRejoin to the join point
          * at the end of the ic. At that join point, the return value of the
          * call is assumed to be in registers, so load them before jumping.
          */
         JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n");
         Address rval = frame.addressOf(origCallee);  /* vp[0] == rval */
+        if (knownPushedType(0) == JSVAL_TYPE_DOUBLE)
+            stubcc.masm.ensureInMemoryDouble(rval);
         stubcc.masm.loadValueAsComponents(rval, JSReturnReg_Type, JSReturnReg_Data);
         *uncachedCallSlowRejoin = stubcc.masm.jump();
         JaegerSpew(JSpew_Insns, " ---- END SLOW RESTORE CODE ---- \n");
     }
 
     /*
      * For simplicity, we don't statically specialize calls to
      * ic::SplatApplyArgs based on applyTricks. Rather, this state is
@@ -2835,36 +2856,26 @@ mjit::Compiler::checkCallApplySpeculatio
                      FrameAddress(offsetof(VMFrame, u.call.lazyArgsObj)));
     }
 }
 
 /* This predicate must be called before the current op mutates the FrameState. */
 bool
 mjit::Compiler::canUseApplyTricks()
 {
-    if (cx->typeInferenceEnabled()) {
-        /*
-         * :FIXME: bug 619428 inference currently assumes that arguments passed
-         * via call and apply are monitored, and that short circuiting these
-         * doesn't happen.
-         */
-        return false;
-    }
-
     JS_ASSERT(*PC == JSOP_ARGUMENTS);
     jsbytecode *nextpc = PC + JSOP_ARGUMENTS_LENGTH;
     return *nextpc == JSOP_FUNAPPLY &&
-           !cx->typeInferenceEnabled() /* :FIXME: bug 619428 */ && 
            IsLowerableFunCallOrApply(nextpc) &&
            !analysis->jumpTarget(nextpc) &&
            !debugMode();
 }
 
 /* See MonoIC.cpp, CallCompiler for more information on call ICs. */
-void
+bool
 mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
 {
     /* Check for interrupts on function call */
     interruptCheckHelper();
 
     int32 speculatedArgc;
     if (applyTricks == LazyArgsObj) {
         frame.pop();
@@ -2882,35 +2893,36 @@ mjit::Compiler::inlineCallHelper(uint32 
 
     /*
      * From the presence of JSOP_FUN{CALL,APPLY}, we speculate that we are
      * going to call js_fun_{call,apply}. Normally, this call would go through
      * js::Invoke to ultimately call 'this'. We can do much better by having
      * the callIC cache and call 'this' directly. However, if it turns out that
      * we are not actually calling js_fun_call, the callIC must act as normal.
      */
-    bool lowerFunCallOrApply = !cx->typeInferenceEnabled() /* :FIXME: bug 619428 */ && IsLowerableFunCallOrApply(PC);
+    bool lowerFunCallOrApply = IsLowerableFunCallOrApply(PC);
 
     /*
      * Currently, constant values are not functions, so don't even try to
      * optimize. This lets us assume that callee/this have regs below.
      */
 #ifdef JS_MONOIC
-    if (debugMode() || monitored(PC) ||
+    if (debugMode() ||
         origCallee->isConstant() || origCallee->isNotType(JSVAL_TYPE_OBJECT) ||
         (lowerFunCallOrApply &&
          (origThis->isConstant() || origThis->isNotType(JSVAL_TYPE_OBJECT)))) {
 #endif
         if (applyTricks == LazyArgsObj) {
             /* frame.pop() above reset us to pre-JSOP_ARGUMENTS state */
             jsop_arguments();
             frame.pushSynced(JSVAL_TYPE_UNKNOWN, NULL);
         }
         emitUncachedCall(callImmArgc, callingNew);
-        return;
+        applyTricks = NoApplyTricks;
+        return true;
 #ifdef JS_MONOIC
     }
 
     /* Initialized by both branches below. */
     CallGenInfo     callIC(PC);
     CallPatchInfo   callPatch;
     MaybeRegisterID icCalleeType; /* type to test for function-ness */
     RegisterID      icCalleeData; /* data to call */
@@ -2983,16 +2995,30 @@ mjit::Compiler::inlineCallHelper(uint32 
 
             icCalleeType = origCalleeType;
             icCalleeData = origCalleeData;
             icRvalAddr = frame.addressOf(origCallee);
             callIC.frameSize.initStatic(frame.localSlots(), speculatedArgc);
         }
     }
 
+    callIC.argTypes = NULL;
+    callIC.typeMonitored = monitored(PC);
+    if (callIC.typeMonitored && callIC.frameSize.isStatic()) {
+        callIC.argTypes = (types::jstype *) js_calloc((1 + callImmArgc) * sizeof(types::jstype));
+        if (!callIC.argTypes)
+            return false;
+        types::TypeSet *types = origThis->getTypeSet();
+        callIC.argTypes[0] = types ? types->getSingleType(cx, script) : types::TYPE_UNKNOWN;
+        for (unsigned i = 0; i < callImmArgc; i++) {
+            types::TypeSet *types = frame.peek(-(callImmArgc - i))->getTypeSet();
+            callIC.argTypes[i + 1] = types ? types->getSingleType(cx, script) : types::TYPE_UNKNOWN;
+        }
+    }
+
     /* Test the type if necessary. Failing this always takes a really slow path. */
     MaybeJump notObjectJump;
     if (icCalleeType.isSet())
         notObjectJump = masm.testObject(Assembler::NotEqual, icCalleeType.reg());
 
     /*
      * For an optimized apply, keep icCalleeData and funPtrReg in a
      * callee-saved registers for the subsequent ic::SplatApplyArgs call.
@@ -3167,16 +3193,18 @@ mjit::Compiler::inlineCallHelper(uint32 
         stubcc.crossJump(uncachedCallSlowRejoin, masm.label());
 
     callICs.append(callIC);
     callPatches.append(callPatch);
     if (lowerFunCallOrApply)
         callPatches.append(uncachedCallPatch);
 
     applyTricks = NoApplyTricks;
+
+    return true;
 #endif
 }
 
 /*
  * This function must be called immediately after any instruction which could
  * cause a new JSStackFrame to be pushed and could lead to a new debug trap
  * being set. This includes any API callbacks and any scripted or native call.
  */
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -149,16 +149,18 @@ class Compiler : public BaseCompiler
         Label        hotPathLabel;
         DataLabelPtr addrLabel1;
         DataLabelPtr addrLabel2;
         Jump         oolJump;
         Label        icCall;
         RegisterID   funObjReg;
         RegisterID   funPtrReg;
         FrameSize    frameSize;
+        bool         typeMonitored;
+        types::jstype *argTypes;
     };
 
   private:
 #endif
 
     /*
      * Writes of call return addresses which needs to be delayed until the final
      * absolute address of the join point is known.
@@ -483,17 +485,17 @@ class Compiler : public BaseCompiler
     void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
     void interruptCheckHelper();
     void emitUncachedCall(uint32 argc, bool callingNew);
     void checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc,
                                    FrameEntry *origCallee, FrameEntry *origThis,
                                    MaybeRegisterID origCalleeType, RegisterID origCalleeData,
                                    MaybeRegisterID origThisType, RegisterID origThisData,
                                    Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch);
-    void inlineCallHelper(uint32 argc, bool callingNew);
+    bool inlineCallHelper(uint32 argc, bool callingNew);
     void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
     void jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index);
     bool jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index);
     bool jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index);
     void jsop_eleminc(JSOp op, VoidStub);
     void jsop_getgname(uint32 index, JSValueType type, types::TypeSet *typeSet);
     void jsop_getgname_slow(uint32 index);
     void jsop_callgname_epilogue();
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -338,27 +338,36 @@ stubs::CompileFunction(VMFrame &f, uint3
 
     if (!ok)
         THROWV(NULL);
 
     return NULL;
 }
 
 static inline bool
-UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc)
+UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc, types::jstype *argTypes)
 {
     JSContext *cx = f.cx;
     Value *vp = f.regs.sp - (argc + 2);
     JSObject &callee = vp->toObject();
     JSFunction *newfun = callee.getFunctionPrivate();
     JSScript *newscript = newfun->script();
 
-    CallArgs args(vp + 2, argc);
-    if (!cx->typeMonitorCall(args, flags & JSFRAME_CONSTRUCTING))
-        return false;
+    if (argTypes) {
+        if (!(flags & JSFRAME_CONSTRUCTING) && !newscript->typeSetThis(cx, argTypes[0]))
+            return false;
+        for (unsigned i = 0; i < newfun->nargs; i++) {
+            if (!newscript->typeSetArgument(cx, i, argTypes[1 + i]))
+                return false;
+        }
+    } else {
+        CallArgs args(vp + 2, argc);
+        if (!cx->typeMonitorCall(args, flags & JSFRAME_CONSTRUCTING))
+            return false;
+    }
 
     /* Get pointer to new frame/slots, prepare arguments. */
     StackSpace &stack = cx->stack();
     JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
                                                           newfun, newscript, &flags,
                                                           f.entryfp, &f.stackLimit);
     if (JS_UNLIKELY(!newfp))
         return false;
@@ -400,44 +409,44 @@ UncachedInlineCall(VMFrame &f, uint32 fl
     *pret = NULL;
     return ok;
 }
 
 void * JS_FASTCALL
 stubs::UncachedNew(VMFrame &f, uint32 argc)
 {
     UncachedCallResult ucr;
-    UncachedNewHelper(f, argc, &ucr);
+    UncachedNewHelper(f, argc, NULL, &ucr);
     return ucr.codeAddr;
 }
 
 void
-stubs::UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
+stubs::UncachedNewHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr)
 {
     ucr->init();
 
     JSContext *cx = f.cx;
     Value *vp = f.regs.sp - (argc + 2);
 
     /* Try to do a fast inline call before the general Invoke path. */
     if (IsFunctionObject(*vp, &ucr->fun) && ucr->fun->isInterpreted()) {
         ucr->callee = &vp->toObject();
-        if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc))
+        if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ucr->codeAddr, &ucr->unjittable, argc, argTypes))
             THROW();
     } else {
         if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
             THROW();
     }
 }
 
 void * JS_FASTCALL
 stubs::UncachedCall(VMFrame &f, uint32 argc)
 {
     UncachedCallResult ucr;
-    UncachedCallHelper(f, argc, &ucr);
+    UncachedCallHelper(f, argc, NULL, &ucr);
     return ucr.codeAddr;
 }
 
 void JS_FASTCALL
 stubs::Eval(VMFrame &f, uint32 argc)
 {
     Value *vp = f.regs.sp - (argc + 2);
 
@@ -448,29 +457,29 @@ stubs::Eval(VMFrame &f, uint32 argc)
     }
 
     JS_ASSERT(f.regs.fp == f.cx->fp());
     if (!DirectEval(f.cx, argc, vp))
         THROW();
 }
 
 void
-stubs::UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr)
+stubs::UncachedCallHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr)
 {
     ucr->init();
 
     JSContext *cx = f.cx;
     Value *vp = f.regs.sp - (argc + 2);
 
     if (IsFunctionObject(*vp, &ucr->callee)) {
         ucr->callee = &vp->toObject();
         ucr->fun = GET_FUNCTION_PRIVATE(cx, ucr->callee);
 
         if (ucr->fun->isInterpreted()) {
-            if (!UncachedInlineCall(f, 0, &ucr->codeAddr, &ucr->unjittable, argc))
+            if (!UncachedInlineCall(f, 0, &ucr->codeAddr, &ucr->unjittable, argc, argTypes))
                 THROW();
             return;
         }
 
         if (ucr->fun->isNative()) {
             if (!CallJSNative(cx, ucr->fun->u.n.native, argc, vp))
                 THROW();
             return;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -963,19 +963,19 @@ class CallCompiler : public BaseCompiler
     void *update()
     {
         JSStackFrame *fp = f.fp();
         JITScript *jit = fp->jit();
         uint32 recompilations = jit->recompilations;
 
         stubs::UncachedCallResult ucr;
         if (callingNew)
-            stubs::UncachedNewHelper(f, ic.frameSize.staticArgc(), &ucr);
+            stubs::UncachedNewHelper(f, ic.frameSize.staticArgc(), ic.argTypes, &ucr);
         else
-            stubs::UncachedCallHelper(f, ic.frameSize.getArgc(f), &ucr);
+            stubs::UncachedCallHelper(f, ic.frameSize.getArgc(f), ic.argTypes, &ucr);
 
         // Watch out in case the IC was invalidated by a recompilation on the calling
         // script. This can happen either if the callee is executed or if it compiles
         // and the compilation has a static overflow.
         if (fp->jit()->recompilations != recompilations)
             return ucr.codeAddr;
 
         // If the function cannot be jitted (generally unjittable or empty script),
@@ -1274,16 +1274,21 @@ JITScript::sweepCallICs(JSContext *cx, b
      * (which is always called during GC). We want to remove references which can keep
      * alive pools that we are trying to destroy (see JSCompartment::sweep).
      */
 
     ic::CallICInfo *callICs_ = callICs();
     for (uint32 i = 0; i < nCallICs; i++) {
         ic::CallICInfo &ic = callICs_[i];
 
+        if (ic.argTypes) {
+            for (unsigned i = 0; i < ic.frameSize.staticArgc(); i++)
+                types::SweepType(&ic.argTypes[i]);
+        }
+
         /*
          * If the object is unreachable, we're guaranteed not to be currently
          * executing a stub generated by a guard on that object. This lets us
          * precisely GC call ICs while keeping the identity guard safe.
          */
         bool fastFunDead = ic.fastGuardedObject &&
             (purgeAll || IsAboutToBeFinalized(cx, ic.fastGuardedObject));
         bool nativeDead = ic.fastGuardedNative &&
--- a/js/src/methodjit/MonoIC.h
+++ b/js/src/methodjit/MonoIC.h
@@ -245,29 +245,37 @@ struct CallICInfo {
 
     /* Join point for all slow call paths. */
     uint32 slowJoinOffset  : 16;
 
     RegisterID funObjReg : 5;
     RegisterID funPtrReg : 5;
     bool hit : 1;
     bool hasJsFunCheck : 1;
+    bool typeMonitored : 1;
+
+    /* For monitored calls with static argc, the types of 'this' and arguments. */
+    types::jstype *argTypes;
 
     inline void reset() {
         fastGuardedObject = NULL;
         fastGuardedNative = NULL;
         hit = false;
         hasJsFunCheck = false;
         pools[0] = pools[1] = pools[2] = NULL;
     }
 
     inline void releasePools() {
         releasePool(Pool_ScriptStub);
         releasePool(Pool_ClosureStub);
         releasePool(Pool_NativeStub);
+        if (argTypes) {
+            js_free(argTypes);
+            argTypes = NULL;
+        }
     }
 
     inline void releasePool(PoolIndex index) {
         if (pools[index]) {
             pools[index]->release();
             pools[index] = NULL;
         }
     }
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -195,18 +195,17 @@ class SetPropCompiler : public PICStubCo
     SetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
                     VoidStubPIC stub)
       : PICStubCompiler("setprop", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
         obj(obj), atom(atom), lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     static void reset(Repatcher &repatcher, ic::PICInfo &pic)
     {
-        if (types::TypeIsObject(pic.knownType) && !((types::TypeObject*)pic.knownType)->marked)
-            pic.knownType = types::TYPE_UNKNOWN;
+        types::SweepType(&pic.knownType);
 
         SetPropLabels &labels = pic.setPropLabels();
         repatcher.repatchLEAToLoadPtr(labels.getDslotsLoad(pic.fastPathRejoin, pic.u.vr));
         repatcher.repatch(labels.getInlineShapeData(pic.fastPathStart, pic.shapeGuard),
                           int32(JSObjectMap::INVALID_SHAPE));
         repatcher.relink(labels.getInlineShapeJump(pic.fastPathStart.labelAtOffset(pic.shapeGuard)),
                          pic.slowPathStart);
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -2790,16 +2790,39 @@ void JS_FASTCALL
 stubs::NegZeroHelper(VMFrame &f)
 {
     if (!f.script()->typeMonitorOverflow(f.cx, f.regs.pc))
         THROW();
     f.regs.sp[-1].setDouble(-0.0);
 }
 
 void JS_FASTCALL
+stubs::ClearArgumentTypes(VMFrame &f)
+{
+    JSFunction *fun = f.fp()->fun();
+    JSScript *script = fun->script();
+
+    /* Postpone recompilations until all args have been updated. */
+    types::AutoEnterTypeInference enter(f.cx);
+
+    if (!f.fp()->isConstructing()) {
+        if (!script->typeSetThis(f.cx, types::TYPE_UNKNOWN))
+            THROW();
+    }
+
+    for (unsigned i = 0; i < fun->nargs; i++) {
+        if (!script->typeSetArgument(f.cx, i, types::TYPE_UNKNOWN))
+            THROW();
+    }
+
+    if (!f.cx->compartment->types.checkPendingRecompiles(f.cx))
+        THROW();
+}
+
+void JS_FASTCALL
 stubs::Exception(VMFrame &f)
 {
     f.regs.sp[0] = f.cx->getPendingException();
     f.cx->clearPendingException();
 }
 
 template <bool Clamped>
 int32 JS_FASTCALL
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -99,18 +99,18 @@ struct UncachedCallResult {
     }        
 };
 
 /*
  * Helper functions for stubs and IC functions for calling functions.
  * These functions either execute the function, return a native code
  * pointer that can be used to call the function, or throw.
  */
-void UncachedCallHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
-void UncachedNewHelper(VMFrame &f, uint32 argc, UncachedCallResult *ucr);
+void UncachedCallHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr);
+void UncachedNewHelper(VMFrame &f, uint32 argc, types::jstype *argTypes, UncachedCallResult *ucr);
 
 void JS_FASTCALL CreateThis(VMFrame &f, JSObject *proto);
 void JS_FASTCALL Throw(VMFrame &f);
 void JS_FASTCALL PutStrictEvalCallObject(VMFrame &f);
 void JS_FASTCALL PutActivationObjects(VMFrame &f);
 void JS_FASTCALL GetCallObject(VMFrame &f);
 #if JS_MONOIC
 void * JS_FASTCALL InvokeTracer(VMFrame &f, ic::TraceICInfo *tic);
@@ -215,16 +215,18 @@ JSBool JS_FASTCALL InstanceOf(VMFrame &f
 void JS_FASTCALL FastInstanceOf(VMFrame &f);
 void JS_FASTCALL ArgCnt(VMFrame &f);
 void JS_FASTCALL Unbrand(VMFrame &f);
 
 /* Helper for triggering recompilation should a name read produce an undefined value or -0. */
 void JS_FASTCALL UndefinedHelper(VMFrame &f);
 void JS_FASTCALL NegZeroHelper(VMFrame &f);
 
+void JS_FASTCALL ClearArgumentTypes(VMFrame &f);
+
 template <bool strict> int32 JS_FASTCALL ConvertToTypedInt(JSContext *cx, Value *vp);
 void JS_FASTCALL ConvertToTypedFloat(JSContext *cx, Value *vp);
 
 void JS_FASTCALL Exception(VMFrame &f);
 
 } /* namespace stubs */
 
 /*