Bug 602129 - JM: make f.call(...) fast, part 1 (r=dvander)
authorLuke Wagner <lw@mozilla.com>
Wed, 13 Oct 2010 15:57:42 -0700
changeset 57712 2f3a0ac5e25129ccea55b42344eb1f4e29e52801
parent 57711 19f70f8c2b88c6aca3e217cd861f6c58b243e7b3
child 57713 d1bf74046ba7970addc532c8c9e9cc9a24a4a619
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdvander
bugs602129
milestone2.0b8pre
Bug 602129 - JM: make f.call(...) fast, part 1 (r=dvander)
js/src/imacros.jsasm
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsparse.cpp
js/src/jstracer.cpp
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/InlineFrameAssembler.h
js/src/methodjit/InvokeHelpers.cpp
--- a/js/src/imacros.jsasm
+++ b/js/src/imacros.jsasm
@@ -399,17 +399,17 @@ 2:      callprop valueOf                
 3:      swap                                # String this rval obj
         pop                                 # String this rval
         new 1                               # strobj
         stop                                # strobj
     .end
 
 .end new
 
-.igroup apply JSOP_APPLY
+.igroup funapply JSOP_FUNAPPLY
 
     .imacro apply0                          # apply fun this arr
         pick 3                              # fun this arr apply
         pop                                 # fun this arr
         pop                                 # fun this
         call 0                              #
         stop                                #
     .end                                    #
@@ -617,16 +617,20 @@ 3:      swap                            
         int8 7                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arr 7
         getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arg7
         swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arr
         pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7
         call 8                              #
         stop                                #
     .end                                    #
 
+.end funapply
+
+.igroup funcall JSOP_FUNCALL
+
     .imacro call0                           # call fun
         swap                                # fun call
         pop                                 # fun
         null                                # fun this
         call 0                              #
         stop                                #
     .end                                    #
 
@@ -681,17 +685,17 @@ 3:      swap                            
 
     .imacro call8                           # call fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6
         pick 9                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 call
         pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6
         call 7                              #
         stop                                #
     .end                                    #
 
-.end apply
+.end funcall
 
 .igroup getprop JSOP_GETPROP
     .imacro scriptgetter        # obj
         .fixup +1               # getter obj
         call 0                  # val
         stop
     .end
 .end getprop
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4674,17 +4674,18 @@ BEGIN_CASE(JSOP_EVAL)
         goto not_direct_eval;
 
     if (!DirectEval(cx, newfun, argc, vp))
         goto error;
 }
 END_CASE(JSOP_EVAL)
 
 BEGIN_CASE(JSOP_CALL)
-BEGIN_CASE(JSOP_APPLY)
+BEGIN_CASE(JSOP_FUNAPPLY)
+BEGIN_CASE(JSOP_FUNCALL)
 {
     argc = GET_ARGC(regs.pc);
     vp = regs.sp - (argc + 2);
 
     if (IsFunctionObject(*vp, &callee)) {
         newfun = callee->getFunctionPrivate();
 
       not_direct_eval:
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -222,17 +222,17 @@ js_GetVariableStackUses(JSOp op, jsbytec
       case JSOP_LEAVEBLOCKEXPR:
         return GET_UINT16(pc) + 1;
       case JSOP_NEWARRAY:
         return GET_UINT16(pc);
       default:
         /* stack: fun, this, [argc arguments] */
         JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL ||
                   op == JSOP_EVAL || op == JSOP_SETCALL ||
-                  op == JSOP_APPLY);
+                  op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
         return 2 + GET_ARGC(pc);
     }
 }
 
 uintN
 js_GetEnterBlockStackDefs(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     JSObject *obj;
@@ -1943,17 +1943,18 @@ Decompile(SprintStack *ss, jsbytecode *p
  * expression contains any unparenthesized function calls. So when building a
  * MemberExpression or CallExpression, we set ss->opcodes[n] to JSOP_CALL if
  * this is true. x(y).z gets JSOP_CALL, not JSOP_GETPROP.
  */
 #define PROPAGATE_CALLNESS()                                                  \
     JS_BEGIN_MACRO                                                            \
         if (ss->opcodes[ss->top - 1] == JSOP_CALL ||                          \
             ss->opcodes[ss->top - 1] == JSOP_EVAL ||                          \
-            ss->opcodes[ss->top - 1] == JSOP_APPLY) {                         \
+            ss->opcodes[ss->top - 1] == JSOP_FUNCALL ||                       \
+            ss->opcodes[ss->top - 1] == JSOP_FUNAPPLY) {                      \
             saveop = JSOP_CALL;                                               \
         }                                                                     \
     JS_END_MACRO
 
     cx = ss->sprinter.context;
     JS_CHECK_RECURSION(cx, return NULL);
 
     jp = ss->printer;
@@ -3581,17 +3582,18 @@ Decompile(SprintStack *ss, jsbytecode *p
                     js_printf(jp, "\t%s;\n", rval);
                     todo = -2;
                 }
                 break;
 
               case JSOP_NEW:
               case JSOP_CALL:
               case JSOP_EVAL:
-              case JSOP_APPLY:
+              case JSOP_FUNCALL:
+              case JSOP_FUNAPPLY:
               case JSOP_SETCALL:
                 argc = GET_ARGC(pc);
                 argv = (char **)
                     cx->malloc((size_t)(argc + 1) * sizeof *argv);
                 if (!argv)
                     return NULL;
 
                 op = JSOP_SETNAME;
@@ -3608,17 +3610,18 @@ Decompile(SprintStack *ss, jsbytecode *p
                  * Same for new (x(y).z) -- contrast with new x(y).z.
                  * See PROPAGATE_CALLNESS.
                  */
                 op = (JSOp) ss->opcodes[ss->top - 1];
                 lval = PopStr(ss,
                               (saveop == JSOP_NEW &&
                                (op == JSOP_CALL ||
                                 op == JSOP_EVAL ||
-                                op == JSOP_APPLY ||
+                                op == JSOP_FUNCALL ||
+                                op == JSOP_FUNAPPLY ||
                                 (js_CodeSpec[op].format & JOF_CALLOP)))
                               ? JSOP_NAME
                               : saveop);
                 op = saveop;
 
                 argv[0] = JS_strdup(cx, lval);
                 if (!argv[0])
                     ok = JS_FALSE;
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -216,17 +216,17 @@ OPDEF(JSOP_SETCALL,   74, "setcall",    
  *
  * JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator
  * for temporary GC rooting.
  */
 OPDEF(JSOP_ITER,      75, "iter",       NULL,         2,  1,  1,  0,  JOF_UINT8)
 OPDEF(JSOP_MOREITER,  76, "moreiter",   NULL,         1,  1,  2,  0,  JOF_BYTE)
 OPDEF(JSOP_ENDITER,   77, "enditer",    NULL,         1,  1,  0,  0,  JOF_BYTE)
 
-OPDEF(JSOP_APPLY,     78, "apply",      NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE)
+OPDEF(JSOP_FUNAPPLY,  78, "funapply",   NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE)
 OPDEF(JSOP_SWAP,      79, "swap",       NULL,         1,  2,  2,  0,  JOF_BYTE)
 
 /* Push object literal. */
 OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_OBJECT)
 
 /* Pop value and discard it. */
 OPDEF(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  2,  JOF_BYTE)
 
@@ -620,8 +620,9 @@ OPDEF(JSOP_FORGLOBAL,     246,"forglobal
  * the blockChain. The special NULLBLOCKCHAIN is needed because the JOF_OBJECT
  * does not permit NULL object references, since it stores an index into a table of
  * objects.
  */
 OPDEF(JSOP_BLOCKCHAIN,    247,"blockchain",    NULL,  3,  0,  0,  0, JOF_OBJECT)
 OPDEF(JSOP_NULLBLOCKCHAIN,248,"nullblockchain",NULL,  1,  0,  0,  0, JOF_BYTE)
 
 /* When changing bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */
+OPDEF(JSOP_FUNCALL,       249,"funcall",       NULL,  3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE)
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -3771,17 +3771,18 @@ BindVarOrConst(JSContext *cx, BindData *
 }
 
 static JSBool
 MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg)
 {
     JSParseNode *pn2;
 
     JS_ASSERT(pn->pn_arity == PN_LIST);
-    JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY);
+    JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL ||
+              pn->pn_op == JSOP_FUNCALL || pn->pn_op == JSOP_FUNAPPLY);
     pn2 = pn->pn_head;
     if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg);
         return JS_FALSE;
     }
     pn->pn_op = JSOP_SETCALL;
     return JS_TRUE;
 }
@@ -6414,17 +6415,18 @@ Parser::mulExpr()
 
 static JSParseNode *
 SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc,
            JSParseNode *pn, JSParseNode *kid, const char *name)
 {
     if (kid->pn_type != TOK_NAME &&
         kid->pn_type != TOK_DOT &&
         (kid->pn_type != TOK_LP ||
-         (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL && kid->pn_op != JSOP_APPLY)) &&
+         (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL &&
+          kid->pn_op != JSOP_FUNCALL && kid->pn_op != JSOP_FUNAPPLY)) &&
 #if JS_HAS_XML_SUPPORT
         (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&
 #endif
         kid->pn_type != TOK_LB) {
         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
         return NULL;
     }
     if (!CheckStrictAssignment(cx, tc, kid))
@@ -7325,21 +7327,21 @@ Parser::memberExpr(JSBool allowCallSynta
             if (pn->pn_op == JSOP_NAME) {
                 if (pn->pn_atom == context->runtime->atomState.evalAtom) {
                     /* Select JSOP_EVAL and flag tc as heavyweight. */
                     pn2->pn_op = JSOP_EVAL;
                     tc->noteCallsEval();
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
                 }
             } else if (pn->pn_op == JSOP_GETPROP) {
-                if (pn->pn_atom == context->runtime->atomState.applyAtom ||
-                    pn->pn_atom == context->runtime->atomState.callAtom) {
-                    /* Select JSOP_APPLY given foo.apply(...). */
-                    pn2->pn_op = JSOP_APPLY;
-                }
+                /* Select JSOP_FUNAPPLY given foo.apply(...). */
+                if (pn->pn_atom == context->runtime->atomState.applyAtom)
+                    pn2->pn_op = JSOP_FUNAPPLY;
+                else if (pn->pn_atom == context->runtime->atomState.callAtom)
+                    pn2->pn_op = JSOP_FUNCALL;
             }
 
             pn2->initList(pn);
             pn2->pn_pos.begin = pn->pn_pos.begin;
 
             if (!argumentList(pn2))
                 return NULL;
             if (pn2->pn_count > ARGC_LIMIT) {
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -4041,18 +4041,18 @@ TraceRecorder::snapshot(ExitType exitTyp
     /*
      * When calling a _FAIL native, make the snapshot's pc point to the next
      * instruction after the CALL or APPLY. Even on failure, a _FAIL native
      * must not be called again from the interpreter.
      */
     bool resumeAfter = (pendingSpecializedNative &&
                         JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS);
     if (resumeAfter) {
-        JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW ||
-                  *pc == JSOP_SETPROP || *pc == JSOP_SETNAME);
+        JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_FUNAPPLY || *pc == JSOP_FUNCALL ||
+                  *pc == JSOP_NEW || *pc == JSOP_SETPROP || *pc == JSOP_SETNAME);
         pc += cs.length;
         regs->pc = pc;
         MUST_FLOW_THROUGH("restore_pc");
     }
 
     /*
      * Generate the entry map for the (possibly advanced) pc and stash it in
      * the trace.
@@ -6642,17 +6642,17 @@ LeaveTree(TraceMonitor *tm, TracerState&
              * immediately flunked the guard on state->builtinStatus.
              *
              * Now LeaveTree has been called again from the tail of
              * ExecuteTree. We are about to return to the interpreter. Adjust
              * the top stack frame to resume on the next op.
              */
             JSFrameRegs* regs = cx->regs;
             JSOp op = (JSOp) *regs->pc;
-            JS_ASSERT(op == JSOP_CALL || op == JSOP_APPLY || op == JSOP_NEW ||
+            JS_ASSERT(op == JSOP_CALL || op == JSOP_FUNAPPLY || op == JSOP_FUNCALL || op == JSOP_NEW ||
                       op == JSOP_GETPROP || op == JSOP_GETTHISPROP || op == JSOP_GETARGPROP ||
                       op == JSOP_GETLOCALPROP || op == JSOP_LENGTH ||
                       op == JSOP_GETELEM || op == JSOP_CALLELEM || op == JSOP_CALLPROP ||
                       op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETMETHOD ||
                       op == JSOP_SETELEM || op == JSOP_INITELEM || op == JSOP_ENUMELEM ||
                       op == JSOP_INSTANCEOF ||
                       op == JSOP_ITER || op == JSOP_MOREITER || op == JSOP_ENDITER ||
                       op == JSOP_FORARG || op == JSOP_FORLOCAL ||
@@ -11046,17 +11046,18 @@ TraceRecorder::callFloatReturningInt(uin
     return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::callNative(uintN argc, JSOp mode)
 {
     LIns* args[5];
 
-    JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_APPLY);
+    JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_FUNAPPLY ||
+              mode == JSOP_FUNCALL);
 
     Value* vp = &stackval(0 - (2 + argc));
     JSObject* funobj = &vp[0].toObject();
     JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj);
     Native native = fun->u.n.native;
 
     switch (argc) {
       case 1:
@@ -13168,53 +13169,70 @@ TraceRecorder::interpretedFunctionCall(V
         debug_only_printf(LC_TMTracer, "%c", TypeToChar(fi->get_typemap()[i]));
     debug_only_print0(LC_TMTracer, "\n");
 #endif
 
     updateAtoms(fun->u.i.script);
     return RECORD_CONTINUE;
 }
 
+/*
+ * We implement JSOP_FUNAPPLY/JSOP_FUNCALL using imacros
+ */
+static inline JSOp
+GetCallMode(JSStackFrame *fp)
+{
+    if (fp->hasImacropc()) {
+        JSOp op = (JSOp) *fp->imacropc();
+        if (op == JSOP_FUNAPPLY || op == JSOP_FUNCALL)
+            return op;
+    }
+    return JSOP_CALL;
+}
+
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_CALL()
 {
     uintN argc = GET_ARGC(cx->regs->pc);
     cx->assertValidStackDepth(argc + 2);
-    return InjectStatus(functionCall(argc,
-                                     (cx->fp()->hasImacropc() && *cx->fp()->imacropc() == JSOP_APPLY)
-                                        ? JSOP_APPLY
-                                        : JSOP_CALL));
-}
-
-static jsbytecode* apply_imacro_table[] = {
-    apply_imacros.apply0,
-    apply_imacros.apply1,
-    apply_imacros.apply2,
-    apply_imacros.apply3,
-    apply_imacros.apply4,
-    apply_imacros.apply5,
-    apply_imacros.apply6,
-    apply_imacros.apply7,
-    apply_imacros.apply8
+    return InjectStatus(functionCall(argc, GetCallMode(cx->fp())));
+}
+
+static jsbytecode* funapply_imacro_table[] = {
+    funapply_imacros.apply0,
+    funapply_imacros.apply1,
+    funapply_imacros.apply2,
+    funapply_imacros.apply3,
+    funapply_imacros.apply4,
+    funapply_imacros.apply5,
+    funapply_imacros.apply6,
+    funapply_imacros.apply7,
+    funapply_imacros.apply8
 };
 
-static jsbytecode* call_imacro_table[] = {
-    apply_imacros.call0,
-    apply_imacros.call1,
-    apply_imacros.call2,
-    apply_imacros.call3,
-    apply_imacros.call4,
-    apply_imacros.call5,
-    apply_imacros.call6,
-    apply_imacros.call7,
-    apply_imacros.call8
+static jsbytecode* funcall_imacro_table[] = {
+    funcall_imacros.call0,
+    funcall_imacros.call1,
+    funcall_imacros.call2,
+    funcall_imacros.call3,
+    funcall_imacros.call4,
+    funcall_imacros.call5,
+    funcall_imacros.call6,
+    funcall_imacros.call7,
+    funcall_imacros.call8
 };
 
 JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_APPLY()
+TraceRecorder::record_JSOP_FUNCALL()
+{
+    return record_JSOP_FUNAPPLY();
+}
+
+JS_REQUIRES_STACK AbortableRecordingStatus
+TraceRecorder::record_JSOP_FUNAPPLY()
 {
     jsbytecode *pc = cx->regs->pc;
     uintN argc = GET_ARGC(pc);
     cx->assertValidStackDepth(argc + 2);
 
     Value* vp = cx->regs->sp - (argc + 2);
     jsuint length = 0;
     JSObject* aobj = NULL;
@@ -13275,38 +13293,39 @@ TraceRecorder::record_JSOP_APPLY()
             if (aobj->isArgsLengthOverridden())
                 RETURN_STOP_A("can't trace arguments with overridden length");
             guardArgsLengthNotAssigned(aobj_ins);
             length = afp->numActualArgs();
         } else {
             RETURN_STOP_A("arguments parameter of apply is not a dense array or argments object");
         }
 
-        if (length >= JS_ARRAY_LENGTH(apply_imacro_table))
+        if (length >= JS_ARRAY_LENGTH(funapply_imacro_table))
             RETURN_STOP_A("too many arguments to apply");
 
-        return InjectStatus(callImacro(apply_imacro_table[length]));
-    }
-
-    if (argc >= JS_ARRAY_LENGTH(call_imacro_table))
+        return InjectStatus(callImacro(funapply_imacro_table[length]));
+    }
+
+    if (argc >= JS_ARRAY_LENGTH(funcall_imacro_table))
         RETURN_STOP_A("too many arguments to call");
 
-    return InjectStatus(callImacro(call_imacro_table[argc]));
+    return InjectStatus(callImacro(funcall_imacro_table[argc]));
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_NativeCallComplete()
 {
     if (pendingSpecializedNative == IGNORE_NATIVE_CALL_COMPLETE_CALLBACK)
         return ARECORD_CONTINUE;
 
 #ifdef DEBUG
     JS_ASSERT(pendingSpecializedNative);
     jsbytecode* pc = cx->regs->pc;
-    JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW || *pc == JSOP_SETPROP);
+    JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_FUNCALL || *pc == JSOP_FUNAPPLY ||
+              *pc == JSOP_NEW || *pc == JSOP_SETPROP);
 #endif
 
     Value& v = stackval(-1);
     LIns* v_ins = get(&v);
 
     /*
      * At this point the generated code has already called the native function
      * and we can no longer fail back to the original pc location (JSOP_CALL)
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -200,17 +200,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 75)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 76)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -1265,17 +1265,18 @@ mjit::Compiler::generateMethod()
           {
             JaegerSpew(JSpew_Insns, " --- EVAL --- \n");
             emitEval(GET_ARGC(PC));
             JaegerSpew(JSpew_Insns, " --- END EVAL --- \n");
           }
           END_CASE(JSOP_EVAL)
 
           BEGIN_CASE(JSOP_CALL)
-          BEGIN_CASE(JSOP_APPLY)
+          BEGIN_CASE(JSOP_FUNAPPLY)
+          BEGIN_CASE(JSOP_FUNCALL)
           {
             JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n");
             inlineCallHelper(GET_ARGC(PC), false);
             JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n");
           }
           END_CASE(JSOP_CALL)
 
           BEGIN_CASE(JSOP_NAME)
--- a/js/src/methodjit/InlineFrameAssembler.h
+++ b/js/src/methodjit/InlineFrameAssembler.h
@@ -70,43 +70,40 @@ class InlineFrameAssembler {
     typedef JSC::MacroAssembler::RegisterID RegisterID;
     typedef JSC::MacroAssembler::Address Address;
     typedef JSC::MacroAssembler::Imm32 Imm32;
     typedef JSC::MacroAssembler::ImmPtr ImmPtr;
     typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
 
     Assembler &masm;
     uint32     frameDepth;      // script->nfixed + stack depth at caller call site
-    uint32     argc;            // number of args being passed to the function
     RegisterID funObjReg;       // register containing the function object (callee)
     jsbytecode *pc;             // bytecode location at the caller call site
     uint32     flags;           // frame flags
 
   public:
     /*
      * Register state, so consumers of this class can restrict which registers
      * can and can't be clobbered.
      */
     Registers  tempRegs;
 
     InlineFrameAssembler(Assembler &masm, ic::CallICInfo &ic, uint32 flags)
       : masm(masm), pc(ic.pc), flags(flags)
     {
         frameDepth = ic.frameDepth;
-        argc = ic.argc;
         funObjReg = ic.funObjReg;
         tempRegs.takeReg(ic.funPtrReg);
         tempRegs.takeReg(funObjReg);
     }
 
     InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, uint32 flags)
       : masm(masm), pc(gen.pc), flags(flags)
     {
         frameDepth = gen.frameDepth;
-        argc = gen.argc;
         funObjReg = gen.funObjReg;
         tempRegs.takeReg(funObjReg);
     }
 
     DataLabelPtr assemble(void *ncode)
     {
         JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
 
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -752,17 +752,18 @@ FrameIsFinished(JSContext *cx)
 
 /* Simulate an inline_return by advancing the pc. */
 static inline void
 AdvanceReturnPC(JSContext *cx)
 {
     JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
               *cx->regs->pc == JSOP_NEW ||
               *cx->regs->pc == JSOP_EVAL ||
-              *cx->regs->pc == JSOP_APPLY);
+              *cx->regs->pc == JSOP_FUNCALL ||
+              *cx->regs->pc == JSOP_FUNAPPLY);
     cx->regs->pc += JSOP_CALL_LENGTH;
 }
 
 
 /*
  * Given a frame that is about to return, make sure its return value and
  * activation objects are fixed up. Then, pop the frame and advance the
  * current PC. Note that while we could enter the JIT at this point, the