Trace apply/call using an imacro (465214, r=brendan).
☠☠ backed out by 29d88d786017 ☠ ☠
authorAndreas Gal <gal@mozilla.com>
Wed, 17 Dec 2008 22:53:35 -0800
changeset 23086 95b210c2fc920a0987653dbd5229f30b8cb2af4c
parent 23084 47152e6cdb4b5c74fa374d499cc3226df3ea4983
child 23087 37aea64bfdb43c13d1a3ae89d532b7f89daa2919
child 23089 29d88d7860177b3e0a31257c24006eae2b969a6c
push id4346
push userrsayre@mozilla.com
push dateFri, 26 Dec 2008 01:26:36 +0000
treeherdermozilla-central@8eb5a5b83a93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs465214
milestone1.9.2a1pre
Trace apply/call using an imacro (465214, r=brendan).
js/src/imacro_asm.js.in
js/src/imacros.c.out
js/src/imacros.jsasm
js/src/jsinterp.cpp
js/src/jsopcode.tbl
js/src/jstracer.cpp
js/src/jstracer.h
js/src/trace-test.js
--- a/js/src/imacro_asm.js.in
+++ b/js/src/imacro_asm.js.in
@@ -100,16 +100,18 @@ function immediate(op) {
     let info = op.info;
     if (info.flags.indexOf("JOF_ATOM") >= 0) {
         if (/^(?:void|object|function|string|number|boolean)$/.test(op.imm1))
             return "0, COMMON_TYPE_ATOM_INDEX(JSTYPE_" + op.imm1.toUpperCase() + ")";
         return "0, COMMON_ATOM_INDEX(" + op.imm1 + ")";
     }
     if (info.flags.indexOf("JOF_JUMP") >= 0)
         return ((op.target >> 8) & 0xff) + ", " + (op.target & 0xff);
+    if (info.flags.indexOf("JOF_UINT8") >= 0)
+        return (op.imm1 & 0xff);
     if (info.flags.indexOf("JOF_UINT16") >= 0)
         return ((op.imm1 & 0xff00) >> 8) + ", " + (op.imm1 & 0xff);
     throw new Error(info.jsop + " format not yet implemented");
 }
 
 /*
  * Syntax (spaces are significant only to delimit tokens):
  *
--- a/js/src/imacros.c.out
+++ b/js/src/imacros.c.out
@@ -166,16 +166,299 @@ static struct {
 /*62*/  JSOP_CALL, 0, 0,
 /*65*/  JSOP_GOTO, 0, 5,
 /*68*/  JSOP_SWAP,
 /*69*/  JSOP_POP,
 /*70*/  JSOP_ADD,
 /*71*/  JSOP_STOP,
     },
 };
+static struct {
+    jsbytecode apply0[8];
+    jsbytecode apply1[12];
+    jsbytecode apply2[16];
+    jsbytecode apply3[21];
+    jsbytecode apply4[26];
+    jsbytecode apply5[31];
+    jsbytecode apply6[36];
+    jsbytecode apply7[41];
+    jsbytecode apply8[46];
+    jsbytecode call0[7];
+    jsbytecode call1[7];
+    jsbytecode call2[7];
+    jsbytecode call3[7];
+    jsbytecode call4[7];
+    jsbytecode call5[7];
+    jsbytecode call6[7];
+    jsbytecode call7[7];
+    jsbytecode call8[7];
+} apply_imacros = {
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_POP,
+/* 4*/  JSOP_CALL, 0, 0,
+/* 7*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_POP,
+/* 8*/  JSOP_CALL, 0, 1,
+/*11*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_POP,
+/*12*/  JSOP_CALL, 0, 2,
+/*15*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_POP,
+/*17*/  JSOP_CALL, 0, 3,
+/*20*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_DUP,
+/*17*/  JSOP_INT8, 3,
+/*19*/  JSOP_GETELEM,
+/*20*/  JSOP_SWAP,
+/*21*/  JSOP_POP,
+/*22*/  JSOP_CALL, 0, 4,
+/*25*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_DUP,
+/*17*/  JSOP_INT8, 3,
+/*19*/  JSOP_GETELEM,
+/*20*/  JSOP_SWAP,
+/*21*/  JSOP_DUP,
+/*22*/  JSOP_INT8, 4,
+/*24*/  JSOP_GETELEM,
+/*25*/  JSOP_SWAP,
+/*26*/  JSOP_POP,
+/*27*/  JSOP_CALL, 0, 5,
+/*30*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_DUP,
+/*17*/  JSOP_INT8, 3,
+/*19*/  JSOP_GETELEM,
+/*20*/  JSOP_SWAP,
+/*21*/  JSOP_DUP,
+/*22*/  JSOP_INT8, 4,
+/*24*/  JSOP_GETELEM,
+/*25*/  JSOP_SWAP,
+/*26*/  JSOP_DUP,
+/*27*/  JSOP_INT8, 5,
+/*29*/  JSOP_GETELEM,
+/*30*/  JSOP_SWAP,
+/*31*/  JSOP_POP,
+/*32*/  JSOP_CALL, 0, 6,
+/*35*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_DUP,
+/*17*/  JSOP_INT8, 3,
+/*19*/  JSOP_GETELEM,
+/*20*/  JSOP_SWAP,
+/*21*/  JSOP_DUP,
+/*22*/  JSOP_INT8, 4,
+/*24*/  JSOP_GETELEM,
+/*25*/  JSOP_SWAP,
+/*26*/  JSOP_DUP,
+/*27*/  JSOP_INT8, 5,
+/*29*/  JSOP_GETELEM,
+/*30*/  JSOP_SWAP,
+/*31*/  JSOP_DUP,
+/*32*/  JSOP_INT8, 6,
+/*34*/  JSOP_GETELEM,
+/*35*/  JSOP_SWAP,
+/*36*/  JSOP_POP,
+/*37*/  JSOP_CALL, 0, 7,
+/*40*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_DUP,
+/* 4*/  JSOP_ZERO,
+/* 5*/  JSOP_GETELEM,
+/* 6*/  JSOP_SWAP,
+/* 7*/  JSOP_DUP,
+/* 8*/  JSOP_ONE,
+/* 9*/  JSOP_GETELEM,
+/*10*/  JSOP_SWAP,
+/*11*/  JSOP_DUP,
+/*12*/  JSOP_INT8, 2,
+/*14*/  JSOP_GETELEM,
+/*15*/  JSOP_SWAP,
+/*16*/  JSOP_DUP,
+/*17*/  JSOP_INT8, 3,
+/*19*/  JSOP_GETELEM,
+/*20*/  JSOP_SWAP,
+/*21*/  JSOP_DUP,
+/*22*/  JSOP_INT8, 4,
+/*24*/  JSOP_GETELEM,
+/*25*/  JSOP_SWAP,
+/*26*/  JSOP_DUP,
+/*27*/  JSOP_INT8, 5,
+/*29*/  JSOP_GETELEM,
+/*30*/  JSOP_SWAP,
+/*31*/  JSOP_DUP,
+/*32*/  JSOP_INT8, 6,
+/*34*/  JSOP_GETELEM,
+/*35*/  JSOP_SWAP,
+/*36*/  JSOP_DUP,
+/*37*/  JSOP_INT8, 7,
+/*39*/  JSOP_GETELEM,
+/*40*/  JSOP_SWAP,
+/*41*/  JSOP_POP,
+/*42*/  JSOP_CALL, 0, 8,
+/*45*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_SWAP,
+/* 1*/  JSOP_POP,
+/* 2*/  JSOP_NULLTHIS,
+/* 3*/  JSOP_CALL, 0, 0,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 2,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 0,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 3,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 1,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 4,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 2,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 5,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 3,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 6,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 4,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 7,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 5,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 8,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 6,
+/* 6*/  JSOP_STOP,
+    },
+    {
+/* 0*/  JSOP_PICK, 9,
+/* 2*/  JSOP_POP,
+/* 3*/  JSOP_CALL, 0, 7,
+/* 6*/  JSOP_STOP,
+    },
+};
 uint8 js_opcode2extra[JSOP_LIMIT] = {
     0,  /* JSOP_INTERRUPT */
     0,  /* JSOP_PUSH */
     0,  /* JSOP_POPV */
     0,  /* JSOP_ENTERWITH */
     0,  /* JSOP_LEAVEWITH */
     0,  /* JSOP_RETURN */
     0,  /* JSOP_GOTO */
@@ -245,17 +528,17 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
     0,  /* JSOP_TABLESWITCH */
     0,  /* JSOP_LOOKUPSWITCH */
     0,  /* JSOP_STRICTEQ */
     0,  /* JSOP_STRICTNE */
     0,  /* JSOP_NULLTHIS */
     0,  /* JSOP_ITER */
     0,  /* JSOP_NEXTITER */
     0,  /* JSOP_ENDITER */
-    0,  /* JSOP_APPLY */
+    7,  /* JSOP_APPLY */
     0,  /* JSOP_SWAP */
     0,  /* JSOP_OBJECT */
     0,  /* JSOP_POP */
     0,  /* JSOP_POS */
     0,  /* JSOP_TRAP */
     0,  /* JSOP_GETARG */
     0,  /* JSOP_SETARG */
     0,  /* JSOP_GETLOCAL */
@@ -368,17 +651,17 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
     0,  /* JSOP_STARTXMLEXPR */
     0,  /* JSOP_CALLELEM */
     0,  /* JSOP_STOP */
     0,  /* JSOP_GETXPROP */
     0,  /* JSOP_CALLXMLNAME */
     0,  /* JSOP_TYPEOFEXPR */
     0,  /* JSOP_ENTERBLOCK */
     0,  /* JSOP_LEAVEBLOCK */
-    0,  /* JSOP_UNUSED201 */
+    0,  /* JSOP_PICK */
     0,  /* JSOP_UNUSED202 */
     0,  /* JSOP_UNUSED203 */
     0,  /* JSOP_UNUSED204 */
     0,  /* JSOP_UNUSED205 */
     0,  /* JSOP_UNUSED206 */
     0,  /* JSOP_UNUSED207 */
     0,  /* JSOP_UNUSED208 */
     0,  /* JSOP_UNUSED209 */
--- a/js/src/imacros.jsasm
+++ b/js/src/imacros.jsasm
@@ -203,8 +203,291 @@ 6:      pop                             
         goto 8                          # lval rval
 7:      swap                            # lval rval obj
         pop                             # lval rval
 8:      add                             # aval
         stop
     .end
 
 .end
+
+.igroup apply JSOP_APPLY
+    .imacro apply0                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        pop                                 # fun this
+        call 0                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply1                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        pop                                 # fun this arg0
+        call 1                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply2                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        pop                                 # fun this arg0 arg1
+        call 2                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply3                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        pop                                 # fun this arg0 arg1 arg2
+        call 3                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply4                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        dup                                 # fun this arg0 arg1 arg2 arr arr
+        int8 3                              # fun this arg0 arg1 arg2 arr arr 3
+        getelem                             # fun this arg0 arg1 arg2 arr arg3
+        swap                                # fun this arg0 arg1 arg2 arg3 arr
+        pop                                 # fun this arg0 arg1 arg2 arg3
+        call 4                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply5                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        dup                                 # fun this arg0 arg1 arg2 arr arr
+        int8 3                              # fun this arg0 arg1 arg2 arr arr 3
+        getelem                             # fun this arg0 arg1 arg2 arr arg3
+        swap                                # fun this arg0 arg1 arg2 arg3 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arr arr
+        int8 4                              # fun this arg0 arg1 arg2 arg3 arr arr 4
+        getelem                             # fun this arg0 arg1 arg2 arg3 arr arg4
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arr
+        pop                                 # fun this arg0 arg1 arg2 arg3 arg4
+        call 5                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply6                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        dup                                 # fun this arg0 arg1 arg2 arr arr
+        int8 3                              # fun this arg0 arg1 arg2 arr arr 3
+        getelem                             # fun this arg0 arg1 arg2 arr arg3
+        swap                                # fun this arg0 arg1 arg2 arg3 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arr arr
+        int8 4                              # fun this arg0 arg1 arg2 arg3 arr arr 4
+        getelem                             # fun this arg0 arg1 arg2 arg3 arr arg4
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arr arr
+        int8 5                              # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5
+        getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arr arg5
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr
+        pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5
+        call 6                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply7                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        dup                                 # fun this arg0 arg1 arg2 arr arr
+        int8 3                              # fun this arg0 arg1 arg2 arr arr 3
+        getelem                             # fun this arg0 arg1 arg2 arr arg3
+        swap                                # fun this arg0 arg1 arg2 arg3 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arr arr
+        int8 4                              # fun this arg0 arg1 arg2 arg3 arr arr 4
+        getelem                             # fun this arg0 arg1 arg2 arg3 arr arg4
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arr arr
+        int8 5                              # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5
+        getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arr arg5
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr
+        int8 6                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr 6
+        getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arg6
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr
+        pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6
+        call 7                              #
+        stop                                #
+    .end                                    #
+
+    .imacro apply8                          # apply fun this arr
+        pick 3                              # fun this arr apply
+        pop                                 # fun this arr
+        dup                                 # fun this arr arr
+        zero                                # fun this arr arr 0
+        getelem                             # fun this arr arg0
+        swap                                # fun this arg0 arr
+        dup                                 # fun this arg0 arr arr
+        one                                 # fun this arg0 arr arr 1
+        getelem                             # fun this arg0 arr arg1
+        swap                                # fun this arg0 arg1 arr
+        dup                                 # fun this arg0 arg1 arr arr
+        int8 2                              # fun this arg0 arg1 arr arr 2
+        getelem                             # fun this arg0 arg1 arr arg2
+        swap                                # fun this arg0 arg1 arg2 arr
+        dup                                 # fun this arg0 arg1 arg2 arr arr
+        int8 3                              # fun this arg0 arg1 arg2 arr arr 3
+        getelem                             # fun this arg0 arg1 arg2 arr arg3
+        swap                                # fun this arg0 arg1 arg2 arg3 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arr arr
+        int8 4                              # fun this arg0 arg1 arg2 arg3 arr arr 4
+        getelem                             # fun this arg0 arg1 arg2 arg3 arr arg4
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arr arr
+        int8 5                              # fun this arg0 arg1 arg2 arg3 arg4 arr arr 5
+        getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arr arg5
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr
+        int8 6                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arr 6
+        getelem                             # fun this arg0 arg1 arg2 arg3 arg4 arg5 arr arg6
+        swap                                # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr
+        dup                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5 arg6 arr arr
+        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                                    #
+
+    .imacro call0                           # call fun
+        swap                                # fun call
+        pop                                 # fun
+        nullthis                            # fun this
+        call 0                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call1                           # call fun this
+        pick 2                              # fun this call
+        pop                                 # fun this
+        call 0                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call2                           # call fun this arg0
+        pick 3                              # fun this arg0 call
+        pop                                 # fun this arg0
+        call 1                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call3                           # call fun this arg0 arg1
+        pick 4                              # fun this arg0 arg1 call
+        pop                                 # fun this arg0 arg1
+        call 2                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call4                           # call fun this arg0 arg1 arg2
+        pick 5                              # fun this arg0 arg1 arg2 call
+        pop                                 # fun this arg0 arg1 arg2
+        call 3                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call5                           # call fun this arg0 arg1 arg2 arg3
+        pick 6                              # fun this arg0 arg1 arg2 arg3 call
+        pop                                 # fun this arg0 arg1 arg2 arg3
+        call 4                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call6                           # call fun this arg0 arg1 arg2 arg3 arg4
+        pick 7                              # fun this arg0 arg1 arg2 arg3 arg4 call
+        pop                                 # fun this arg0 arg1 arg2 arg3 arg4
+        call 5                              #
+        stop                                #
+    .end                                    #
+
+    .imacro call7                           # call fun this arg0 arg1 arg2 arg3 arg4 arg5
+        pick 8                              # fun this arg0 arg1 arg2 arg3 arg4 arg5 call
+        pop                                 # fun this arg0 arg1 arg2 arg3 arg4 arg5
+        call 6                              #
+        stop                                #
+    .end                                    #
+
+    .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
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3333,16 +3333,24 @@ js_Interpret(JSContext *cx)
 
           BEGIN_CASE(JSOP_SWAP)
             JS_ASSERT(regs.sp - 2 >= StackBase(fp));
             lval = FETCH_OPND(-2);
             rval = FETCH_OPND(-1);
             STORE_OPND(-1, lval);
             STORE_OPND(-2, rval);
           END_CASE(JSOP_SWAP)
+          
+          BEGIN_CASE(JSOP_PICK)
+            i = regs.pc[1];
+            JS_ASSERT(regs.sp - (i+1) >= StackBase(fp));
+            lval = regs.sp[-(i+1)];
+            memmove(regs.sp - (i+1), regs.sp - i, sizeof(jsval)*i);
+            regs.sp[-1] = lval;
+          END_CASE(JSOP_PICK)
 
 #define PROPERTY_OP(n, call)                                                  \
     JS_BEGIN_MACRO                                                            \
         /* Fetch the left part and resolve it to a non-null object. */        \
         FETCH_OBJECT(cx, n, lval, obj);                                       \
                                                                               \
         /* Get or set the property. */                                        \
         if (!call)                                                            \
@@ -4795,138 +4803,24 @@ js_Interpret(JSContext *cx)
                 }
             }
 
             if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp))
                 goto error;
             regs.sp = vp + 1;
             LOAD_INTERRUPT_HANDLER(cx);
           END_CASE(JSOP_NEW)
-
-          BEGIN_CASE(JSOP_APPLY)
-          {
-            argc = GET_ARGC(regs.pc);
-            vp = regs.sp - (argc + 2);
-            lval = *vp;
-            if (!VALUE_IS_FUNCTION(cx, lval))
-                goto do_call;
-            obj = JSVAL_TO_OBJECT(lval);
-            fun = GET_FUNCTION_PRIVATE(cx, obj);
-            if (FUN_INTERPRETED(fun))
-                goto do_call;
-
-            bool apply = (JSFastNative)fun->u.n.native == js_fun_apply;
-            if (!apply && (JSFastNative)fun->u.n.native != js_fun_call)
-                goto do_call;
-
-            /* 
-             * If the second arg to apply is null or void, treat it as an empty
-             * array.
-             */
-            jsuint applylen = 0;
-            if (apply && argc >= 2 &&
-                !JSVAL_IS_VOID(vp[3]) && !JSVAL_IS_NULL(vp[3])) {
-                /* 
-                 * Fall back on js_Invoke when the array argument has a wrong
-                 * type or when it has too many elements to fit into the
-                 * current stack chunk.
-                 */
-                if (!JSVAL_IS_OBJECT(vp[3]))
-                    goto do_call;
-
-                JSBool arraylike;
-                JSObject* aobj = JSVAL_TO_OBJECT(vp[3]);
-                if (!js_IsArrayLike(cx, aobj, &arraylike, &applylen))
-                    goto error;
-                if (!arraylike || applylen > ARGC_LIMIT)
-                    goto do_call;
-
-                JSArena *a = cx->stackPool.current;
-                JS_ASSERT(jsuword(vp + 2) <= a->limit);
-
-                /*
-                 * We need space for applylen elements plus an extra slot to
-                 * temporary root the array object when we unpack its elements
-                 * using OBJ_GET_PROPERTY below.
-                 */
-                if (a->limit - jsuword(vp + 2) < (applylen + 1) * sizeof(jsval))
-                    goto do_call;
-            }
-
-            if (!VALUE_IS_FUNCTION(cx, vp[1]))
-                goto do_call;
-            vp[0] = vp[1];
-
-            if (argc == 0) {
-                /* 
-                 * Call fun with its global object as the 'this' param if 
-                 * no args. 
-                 */
-                obj = NULL;
-            } else {
-                /* Convert the first arg to 'this'. */
-                if (!JSVAL_IS_PRIMITIVE(vp[2]))
-                    obj = JSVAL_TO_OBJECT(vp[2]);
-                else if (!js_ValueToObject(cx, vp[2], &obj))
-                    goto error;
-            }
-            vp[1] = OBJECT_TO_JSVAL(obj);
-
-            if (!apply) {
-                if (argc != 0) {
-                    --argc;
-                    memmove(vp + 2, vp + 3, argc * sizeof *vp);
-                }
-            } else if (applylen == 0) {
-                argc = 0;
-            } else {
-                /* 
-                 * Make room for missing arguments to the right including the
-                 * temporary root nulling any extra stack slots for GC safety.
-                 */
-                jsval* newsp = vp + 2 + applylen + 1;
-                if (newsp > regs.sp) {
-                    JSArena *a = cx->stackPool.current;
-                    JS_ASSERT(jsuword(newsp) <= a->limit); /* see above */
-                    if ((jsuword) newsp > a->avail)
-                        a->avail = (jsuword) newsp;
-                    memset(vp + 2 + argc, 0, (applylen - argc) * sizeof(jsval));
-                }
-
-                JSObject *aobj = JSVAL_TO_OBJECT(vp[3]);
-                newsp[-1] = vp[3];
-                regs.sp = newsp;
-
-                /* Expand array content onto the stack. */
-                for (i = 0; i < jsint(applylen); i++) {
-                    id = INT_TO_JSID(i);
-                    if (!OBJ_GET_PROPERTY(cx, aobj, id, &vp[2 + i])) {
-                        /* 
-                         * There is no good way to restore the original stack
-                         * state here, but it is in a reasonable  state with
-                         * either original elements or nulls for all arguments
-                         * we didn't unpack yet, so we leave it at that.
-                         */
-                        goto error;
-                    }
-                }
-                argc = applylen;
-            }
-            regs.sp = vp + 2 + argc;
-            TRACE_1(ApplyComplete, argc);
-            goto do_call_with_specified_vp_and_argc;
-          }
           
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_EVAL)
+          BEGIN_CASE(JSOP_APPLY)
           do_call:
             argc = GET_ARGC(regs.pc);
             vp = regs.sp - (argc + 2);
             
-          do_call_with_specified_vp_and_argc:
             lval = *vp;
             if (VALUE_IS_FUNCTION(cx, lval)) {
                 obj = JSVAL_TO_OBJECT(lval);
                 fun = GET_FUNCTION_PRIVATE(cx, obj);
 
                 /* Clear frame flags since this is not a constructor call. */
                 flags = 0;
                 if (FUN_INTERPRETED(fun))
@@ -6948,17 +6842,16 @@ js_Interpret(JSContext *cx)
           L_JSOP_TOATTRNAME:
           L_JSOP_QNAME:
           L_JSOP_QNAMECONST:
           L_JSOP_QNAMEPART:
           L_JSOP_ANYNAME:
           L_JSOP_DEFXMLNS:
 # endif
 
-          L_JSOP_UNUSED201:
           L_JSOP_UNUSED202:
           L_JSOP_UNUSED203:
           L_JSOP_UNUSED204:
           L_JSOP_UNUSED205:
           L_JSOP_UNUSED206:
           L_JSOP_UNUSED207:
           L_JSOP_UNUSED208:
           L_JSOP_UNUSED209:
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -189,17 +189,17 @@ OPDEF(JSOP_AND,       69, "and",        
 OPDEF(JSOP_TABLESWITCH,  70, "tableswitch",  NULL,   -1,  1,  0,  0,  JOF_TABLESWITCH|JOF_DETECTING|JOF_PARENHEAD)
 OPDEF(JSOP_LOOKUPSWITCH, 71, "lookupswitch", NULL,   -1,  1,  0,  0,  JOF_LOOKUPSWITCH|JOF_DETECTING|JOF_PARENHEAD)
 
 /* New, infallible/transitive identity ops. */
 OPDEF(JSOP_STRICTEQ,  72, "stricteq",   "===",        1,  2,  1, 10,  JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
 OPDEF(JSOP_STRICTNE,  73, "strictne",   "!==",        1,  2,  1, 10,  JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC)
 
 /* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
-OPDEF(JSOP_NULLTHIS,  74, js_null_str,  js_null_str,  1,  0,  1, 19,  JOF_BYTE)
+OPDEF(JSOP_NULLTHIS,  74, "nullthis",   "nullthis",   1,  0,  1, 19,  JOF_BYTE)
 
 /*
  * JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
  * in this op's uint8 immediate operand. It replaces the top of stack object
  * with an iterator for that object, and pushes a slot used by JSOP_NEXTITER.
  *
  * JSOP_NEXTITER stores the next iterated value in the top of stack slot which
  * was allocated by JSOP_ITER and pushes true, or stores JSVAL_HOLE and pushes
@@ -479,17 +479,22 @@ OPDEF(JSOP_CALLXMLNAME,   197, "callxmln
  */
 OPDEF(JSOP_TYPEOFEXPR,    198,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
 
 /*
  * Block-local scope support.
  */
 OPDEF(JSOP_ENTERBLOCK,    199,"enterblock",  NULL,    3,  0, -1,  0,  JOF_OBJECT)
 OPDEF(JSOP_LEAVEBLOCK,    200,"leaveblock",  NULL,    3, -1,  0,  0,  JOF_UINT16)
-OPDEF(JSOP_UNUSED201,     201,"unused201",   NULL,    1,  0,  0,  0,  JOF_BYTE)
+
+/*
+ * Pick an element from the stack.
+ */
+OPDEF(JSOP_PICK,          201,"pick",        NULL,    2,  1,  0,  0,  JOF_UINT8)
+
 OPDEF(JSOP_UNUSED202,     202,"unused202",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED203,     203,"unused203",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED204,     204,"unused204",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED205,     205,"unused205",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED206,     206,"unused206",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED207,     207,"unused207",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED208,     208,"unused208",   NULL,    1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED209,     209,"unused209",   NULL,    1,  0,  0,  0,  JOF_BYTE)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1830,19 +1830,19 @@ TraceRecorder::determineSlotType(jsval* 
         : JSVAL_TAG(*vp);
     JS_ASSERT((m != JSVAL_INT) || isInt32(*vp));
     return m;
 }
 
 /*
  * Combine fp->imacpc and fp->regs->pc into one word, with 8 bits for the pc
  * adjustment from one byte before the imacro's start (so a 0 high byte means
- * we're not in an imacro), and 24 for the pc adjustment from script->code.
+ * we're not in an imacro), and 22 for the pc adjustment from script->code.
  */
-#define IMACRO_PC_ADJ_BITS   8
+#define IMACRO_PC_ADJ_BITS   10
 #define SCRIPT_PC_ADJ_BITS   (32 - IMACRO_PC_ADJ_BITS)
 
 // The stored imacro_pc_adj byte offset is biased by 1.
 #define IMACRO_PC_ADJ_LIMIT  (JS_BIT(IMACRO_PC_ADJ_BITS) - 1)
 #define SCRIPT_PC_ADJ_LIMIT  JS_BIT(SCRIPT_PC_ADJ_BITS)
 
 #define IMACRO_PC_ADJ(ip)    ((uintptr_t)(ip) >> SCRIPT_PC_ADJ_BITS)
 #define SCRIPT_PC_ADJ(ip)    ((ip) & JS_BITMASK(SCRIPT_PC_ADJ_BITS))
@@ -1869,16 +1869,17 @@ TraceRecorder::determineSlotType(jsval* 
                                 (fp)->regs->pc = imacro_code[*(fp)->imacpc] + \
                                                  IMACRO_PC_ADJ(ip)            \
                               : (fp)->regs->pc = (fp)->script->code + (ip))
 
 static jsbytecode* imacro_code[JSOP_LIMIT];
 
 JS_STATIC_ASSERT(sizeof(binary_imacros) < IMACRO_PC_ADJ_LIMIT);
 JS_STATIC_ASSERT(sizeof(add_imacros) < IMACRO_PC_ADJ_LIMIT);
+JS_STATIC_ASSERT(sizeof(apply_imacros) < IMACRO_PC_ADJ_LIMIT);
 
 JS_REQUIRES_STACK LIns*
 TraceRecorder::snapshot(ExitType exitType)
 {
     JSStackFrame* fp = cx->fp;
     JSFrameRegs* regs = fp->regs;
     jsbytecode* pc = regs->pc;
     if (exitType == BRANCH_EXIT && js_IsLoopExit(pc, (jsbytecode*)fragment->root->ip))
@@ -5577,16 +5578,29 @@ TraceRecorder::record_JSOP_SWAP()
     LIns* l_ins = get(&l);
     LIns* r_ins = get(&r);
     set(&r, l_ins);
     set(&l, r_ins);
     return true;
 }
 
 JS_REQUIRES_STACK bool
+TraceRecorder::record_JSOP_PICK()
+{
+    jsval* sp = cx->fp->regs->sp;
+    jsuint n = cx->fp->regs->pc[1];
+    JS_ASSERT(sp - (n+1) >= StackBase(cx->fp));
+    LIns* top = tracker.get(sp - (n+1));
+    for (jsint i = 0; i < n; ++i)
+        tracker.set(sp - (n+1) + i, tracker.get(sp - n + i));
+    tracker.set(&sp[-1], top);
+    return true;
+}
+
+JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_SETCONST()
 {
     return false;
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_BITOR()
 {
@@ -6574,173 +6588,118 @@ TraceRecorder::interpretedFunctionCall(j
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_CALL()
 {
     return functionCall(false, GET_ARGC(cx->fp->regs->pc));
 }
 
+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
+};
+
+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
+};
+
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_APPLY()
 {
     JSStackFrame* fp = cx->fp;
     jsbytecode *pc = fp->regs->pc;
     uintN argc = GET_ARGC(pc);
     jsval* vp = fp->regs->sp - (argc + 2);
     JS_ASSERT(vp >= StackBase(fp));
     jsuint length = 0;
     JSObject* aobj = NULL;
     LIns* aobj_ins = NULL;
-    LIns* dslots_ins = NULL;
+    
+    JS_ASSERT(!fp->imacpc);
     
     if (!VALUE_IS_FUNCTION(cx, vp[0]))
         return record_JSOP_CALL();
 
     JSObject* obj = JSVAL_TO_OBJECT(vp[0]);
     JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj);
     if (FUN_INTERPRETED(fun))
         return record_JSOP_CALL();
 
     bool apply = (JSFastNative)fun->u.n.native == js_fun_apply;
     if (!apply && (JSFastNative)fun->u.n.native != js_fun_call)
         return record_JSOP_CALL();
 
-    /* 
-     * If this is apply, and the argument is too long and would need
-     * a separate stack chunk, do a heavy-weight apply. 
+    /*
+     * We don't trace apply and call with a primitive 'this', which is the
+     * first positional parameter.
      */
+    if (argc > 0 && JSVAL_IS_PRIMITIVE(vp[2]))
+        return record_JSOP_CALL();
+    
+    /*
+     * Guard on the identity of this, which is the function we are applying.
+     */
+    if (!guardCallee(vp[1]))
+        return false;
+
     if (apply && argc >= 2) {
+        if (argc != 2)
+            ABORT_TRACE("apply with excess arguments");
         if (JSVAL_IS_PRIMITIVE(vp[3]))
             ABORT_TRACE("arguments parameter of apply is primitive");
         aobj = JSVAL_TO_OBJECT(vp[3]);
         aobj_ins = get(&vp[3]);
-        
+
         /* 
          * We expect a dense array for the arguments (the other
          * frequent case is the arguments object, but that we
          * don't trace at the moment). 
          */
-        guard(false, lir->ins_eq0(aobj_ins), MISMATCH_EXIT);
         if (!guardDenseArray(aobj, aobj_ins))
             ABORT_TRACE("arguments parameter of apply is not a dense array");
         
         /*
+         * We trace only apply calls with a certain number of arguments.
+         */
+        length = jsuint(aobj->fslots[JSSLOT_ARRAY_LENGTH]);
+        if (length >= JS_ARRAY_LENGTH(apply_imacro_table))
+            ABORT_TRACE("too many arguments to apply");
+        
+        /*
          * Make sure the array has the same length at runtime.
          */
-        length = jsuint(aobj->fslots[JSSLOT_ARRAY_LENGTH]);
-        guard(true, lir->ins2i(LIR_eq,
-                               stobj_get_fslot(aobj_ins, JSSLOT_ARRAY_LENGTH),
-                               length), 
-                               BRANCH_EXIT);
- 
-        /* 
-         * Make sure dslots is not NULL and guard the array's capacity.
-         */
-        dslots_ins = lir->insLoad(LIR_ldp, aobj_ins, offsetof(JSObject, dslots));
-        guard(false,
-              lir->ins_eq0(dslots_ins),
-              MISMATCH_EXIT);
-        guard(true,
-              lir->ins2(LIR_ult,
-                        lir->insImm(length),
-                        lir->insLoad(LIR_ldp, dslots_ins, 0 - (int)sizeof(jsval))),
-              MISMATCH_EXIT);
+        guard(true, 
+              lir->ins2i(LIR_eq,
+                         stobj_get_fslot(aobj_ins, JSSLOT_ARRAY_LENGTH),
+                         length), 
+              BRANCH_EXIT);
         
-        /*
-         * The interpreter deoptimizes if we are about to cross a stack chunk by
-         * re-entering itself indirectly from js_Invoke, and we can't trace that 
-         * case.
-         */
-        length = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
-        jsval* newsp = vp + 2 + length;
-        JS_ASSERT(newsp >= vp + 2);
-        JSArena *a = cx->stackPool.current;
-        if (jsuword(newsp) > a->limit)
-            ABORT_TRACE("apply or call across stack-chunks");
-    }
-
-    /* Protect against a non-function callee. */
-    if (!VALUE_IS_FUNCTION(cx, vp[1]))
-        ABORT_TRACE("apply on a non-function");
-
-    /*
-     * Guard on the identity of this, which is the function we
-     * are applying.
-     */
-    if (!guardCallee(vp[1]))
-        return false;
-
-    LIns* callee_ins = get(&vp[1]);
-    LIns* this_ins = NULL;
-    if (argc > 0) {
-        this_ins = get(&vp[2]);
-        if (JSVAL_IS_PRIMITIVE(vp[2]))
-            ABORT_TRACE("apply with primitive this");
-    } else {
-        this_ins = lir->insImm(0);
+        return call_imacro(apply_imacro_table[length]);
     }
     
-    LIns** argv;
-    if (argc >= 2) {
-        if (!apply) {
-            --argc;
-            JS_ASSERT(argc >= 0);
-            argv = (LIns**) alloca(sizeof(LIns*) * argc);
-            for (jsuint n = 0; n < argc; ++n)
-                argv[n] = get(&vp[3 + n]); /* skip over the this parameter */
-        } else {
-            /*
-             * We already established that argments is a dense array
-             * and we know its length and we know dslots is not NULL
-             * and the length is not beyond the dense array's capacity. 
-             */
-            argc = length;
-            JS_ASSERT(argc >= 0);
-            argv = (LIns**) alloca(sizeof(LIns*) * argc);
-            for (unsigned n = 0; n < argc; ++n) {
-                /* Load the value and guard on its type to unbox it. */
-                LIns* v_ins = lir->insLoadi(dslots_ins, n * sizeof(jsval));
-                /* 
-                 * We can't "see through" a hole to a possible Array.prototype property, so
-                 * we abort here and guard below (after unboxing).
-                 */
-                jsval* dp = &aobj->dslots[n];
-                if (*dp == JSVAL_HOLE)
-                    ABORT_TRACE("can't see through hole in dense array");
-                if (!unbox_jsval(*dp, v_ins))
-                    return false;
-                if (JSVAL_TAG(*dp) == JSVAL_BOOLEAN) {
-                    // Optimize to guard for a hole only after untagging, so we know that
-                    // we have a boolean, to avoid an extra guard for non-boolean values.
-                    guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_HOLE))),
-                          MISMATCH_EXIT);
-                }
-                argv[n] = v_ins;
-            }
-        }
-    } else {
-        argc = 0;
-    }
-    /*
-     * We have all arguments unpacked and we are now ready to modify the
-     * tracker.
-     */
-    tracker.set(&vp[0], callee_ins);
-    tracker.set(&vp[1], this_ins);
-    for (unsigned n = 0; n < argc; ++n)
-        tracker.set(&vp[2 + n], argv[n]);
-
-    return true;
-}
-
-JS_REQUIRES_STACK bool
-TraceRecorder::record_ApplyComplete(uintN argc)
-{
-    return functionCall(false, argc);
+    if (argc >= JS_ARRAY_LENGTH(call_imacro_table))
+        ABORT_TRACE("too many arguments to call");
+    
+    return call_imacro(call_imacro_table[argc]);
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_FastNativeCallComplete()
 {
     JS_ASSERT(pendingTraceableNative);
     
     /* At this point the generated code has already called the native function
@@ -8553,21 +8512,21 @@ InitIMacroCode()
     for (uintN op = JSOP_BITOR; op <= JSOP_MOD; op++)
         imacro_code[op] = (jsbytecode*)&binary_imacros - 1;
 
     // NB: above loop mis-set JSOP_ADD's entry, so order here is crucial.
     imacro_code[JSOP_ADD] = (jsbytecode*)&add_imacros - 1;
 
     imacro_code[JSOP_ITER] = (jsbytecode*)&iter_imacros - 1;
     imacro_code[JSOP_NEXTITER] = nextiter_imacro - 1;
+    imacro_code[JSOP_APPLY] = (jsbytecode*)&apply_imacros - 1;
 }
 
 #define UNUSED(n) JS_REQUIRES_STACK bool TraceRecorder::record_JSOP_UNUSED##n() { return false; }
 
-UNUSED(201)
 UNUSED(202)
 UNUSED(203)
 UNUSED(204)
 UNUSED(205)
 UNUSED(206)
 UNUSED(207)
 UNUSED(208)
 UNUSED(209)
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -455,17 +455,16 @@ public:
 
     JS_REQUIRES_STACK bool record_EnterFrame();
     JS_REQUIRES_STACK bool record_LeaveFrame();
     JS_REQUIRES_STACK bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
     JS_REQUIRES_STACK bool record_SetPropMiss(JSPropCacheEntry* entry);
     JS_REQUIRES_STACK bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
     JS_REQUIRES_STACK bool record_FastNativeCallComplete();
     JS_REQUIRES_STACK bool record_IteratorNextComplete();
-    JS_REQUIRES_STACK bool record_ApplyComplete(uintN argc);
 
     nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
     void deepAbort() { deepAborted = true; }
     bool wasDeepAborted() { return deepAborted; }
     bool walkedOutOfLoop() { return terminate; }
     void setPromotedPeer(nanojit::Fragment* peer) { promotedPeer = peer; }
     TreeInfo* getTreeInfo() { return treeInfo; }
 
@@ -494,17 +493,17 @@ public:
 #define RECORD_ARGS(x,args)                                                   \
     JS_BEGIN_MACRO                                                            \
         if (!js_MonitorRecording(TRACE_RECORDER(cx))) {                       \
             ENABLE_TRACER(0);                                                 \
         } else {                                                              \
             TRACE_ARGS_(x, args,                                              \
                 if ((fp->flags & JSFRAME_IMACRO_START) &&                     \
                     (x == JSOP_ITER || x == JSOP_NEXTITER ||                  \
-                    JSOP_IS_BINARY(x))) {                                     \
+                     x == JSOP_APPLY || JSOP_IS_BINARY(x))) {                 \
                     fp->flags &= ~JSFRAME_IMACRO_START;                       \
                     atoms = COMMON_ATOMS_START(&rt->atomState);               \
                     op = JSOp(*regs.pc);                                      \
                     DO_OP();                                                  \
                 }                                                             \
             );                                                                \
          }                                                                    \
     JS_END_MACRO
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -3723,16 +3723,73 @@ load("mandelbrot-results.js");
 
   escape = escapeNorm2;
   doImageData = false;  // avoidSparseArray doesn't matter here
   test(createMandelSet);
 //}
 //testMandelbrotAll();
 // END MANDELBROT STUFF
 
+function testApplyCallHelper(f) {
+    var r = [];
+    for (var i = 0; i < 10; ++i) f.call(); 
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0]);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0,1);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0,1]);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0,1,2);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2]);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3]);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3,4);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3,4]);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.call(this,0,1,2,3,4,5);
+    r.push(x);
+    for (var i = 0; i < 10; ++i) f.apply(this,[0,1,2,3,4,5])
+    r.push(x);
+    return(r.join(","));
+}
+function testApplyCall() {
+    var r = testApplyCallHelper(function (a0,a1,a2,a3,a4,a5,a6,a7) { x = [a0,a1,a2,a3,a4,a5,a6,a7]; });
+    r += testApplyCallHelper(function (a0,a1,a2,a3,a4,a5,a6,a7) { x = [a0,a1,a2,a3,a4,a5,a6,a7]; });
+    return r;
+}
+testApplyCall.expected = 
+",,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,0,,,,,,,,0,1,,,,,,,0,1,,,,,,,0,1,2,,,,,,0,1,2,,,,,,0,1,2,3,,,,,0,1,2,3,,,,,0,1,2,3,4,,,,0,1,2,3,4,,,,0,1,2,3,4,5,,,0,1,2,3,4,5,," +
+",,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,,0,,,,,,,,0,1,,,,,,,0,1,,,,,,,0,1,2,,,,,,0,1,2,,,,,,0,1,2,3,,,,,0,1,2,3,,,,,0,1,2,3,4,,,,0,1,2,3,4,,,,0,1,2,3,4,5,,,0,1,2,3,4,5,,";
+test(testApplyCall);
+
+function testApplyUnboxHelper(f,a) {
+    var q;
+    for (var i = 0; i < 10; ++i)
+        q = f.apply(f,a);
+    return q;
+}
+function testApplyUnbox() {
+    var f = function(x) { return x; }
+    return [testApplyUnboxHelper(f,[1]), testApplyUnboxHelper(f,[true])].join(",");
+}
+testApplyUnbox.expected = "1,true";
+test(testApplyUnbox);
+
 /* NOTE: Keep this test last, since it screws up all for...in loops after it. */
 function testGlobalProtoAccess() {
     return "ok";
 }
 this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
 testGlobalProtoAccess.expected = "ok";
 test(testGlobalProtoAccess);