Bug 740446 - make 'arguments' more like a normal local binding (r=bhackett)
authorLuke Wagner <luke@mozilla.com>
Mon, 02 Apr 2012 08:58:30 -0700
changeset 91357 fa24b215d49e781ccee44780c34230a3b524de5b
parent 91356 4c298ca28fa6580ecdeeb72964ff592ba4cecdbb
child 91358 1664d00a1d242878c8e214db86a45c483e29b6fa
push id8173
push userlwagner@mozilla.com
push dateTue, 10 Apr 2012 21:03:02 +0000
treeherdermozilla-inbound@1664d00a1d24 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs740446
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 740446 - make 'arguments' more like a normal local binding (r=bhackett)
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter-inl.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode-inl.h
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/jit-test/tests/basic/builtinLocals.js
js/src/jit-test/tests/basic/testBug741497.js
js/src/jit-test/tests/basic/testBug743408.js
js/src/jit-test/tests/basic/testCallApplySpeculationFailed.js
js/src/jit-test/tests/basic/testDynamicLookup.js
js/src/jit-test/tests/debug/Frame-eval-08.js
js/src/jit-test/tests/debug/Frame-evalWithBindings-03.js
js/src/jit-test/tests/debug/Frame-onPop-21.js
js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsdbgapi.cpp
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/jsscript.cpp
js/src/jsscript.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastBuiltins.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/tests/js1_8/genexps/regress-634472.js
js/src/tests/js1_8_1/strict/generator-eval-arguments.js
js/src/vm/ArgumentsObject.cpp
js/src/vm/ArgumentsObject.h
js/src/vm/Debugger.cpp
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
js/src/vm/Xdr.h
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -356,17 +356,17 @@ frontend::CompileFunctionBody(JSContext 
 
     BytecodeEmitter funbce(&parser, tokenStream.getLineno());
     if (!funbce.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
         return false;
 
     funbce.flags |= TCF_IN_FUNCTION;
     funbce.setFunction(fun);
     funbce.bindings.transfer(cx, bindings);
-    fun->setArgCount(funbce.bindings.countArgs());
+    fun->setArgCount(funbce.bindings.numArgs());
     if (!GenerateBlockId(&funbce, funbce.bodyid))
         return false;
 
     /* FIXME: make Function format the source for a function definition. */
     ParseNode *fn = FunctionNode::create(PNK_NAME, &funbce);
     if (fn) {
         fn->pn_body = NULL;
         fn->pn_cookie.makeFree();
@@ -393,19 +393,17 @@ frontend::CompileFunctionBody(JSContext 
 
     /*
      * After we're done parsing, we must fold constants, analyze any nested
      * functions, and generate code for this function, including a stop opcode
      * at the end.
      */
     ParseNode *pn = fn ? parser.functionBody(Parser::StatementListBody) : NULL;
     if (pn) {
-        if (!CheckStrictParameters(cx, &funbce)) {
-            pn = NULL;
-        } else if (!tokenStream.matchToken(TOK_EOF)) {
+        if (!tokenStream.matchToken(TOK_EOF)) {
             parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             pn = NULL;
         } else if (!FoldConstants(cx, pn, &funbce)) {
             /* FoldConstants reported the error already. */
             pn = NULL;
         } else if (!AnalyzeFunctions(&funbce)) {
             pn = NULL;
         } else {
--- a/js/src/frontend/BytecodeEmitter-inl.h
+++ b/js/src/frontend/BytecodeEmitter-inl.h
@@ -43,17 +43,17 @@
 
 #include "frontend/ParseNode.h"
 #include "frontend/TokenStream.h"
 
 namespace js {
 
 inline
 TreeContext::TreeContext(Parser *prs)
-  : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0), argumentsCount(0),
+  : flags(0), bodyid(0), blockidGen(0), parenDepth(0), yieldCount(0),
     topStmt(NULL), topScopeStmt(NULL), blockChain(NULL), blockNode(NULL),
     decls(prs->context), parser(prs), yieldNode(NULL), argumentsNode(NULL), scopeChain_(NULL),
     lexdeps(prs->context), parent(prs->tc), staticLevel(0), funbox(NULL), functionList(NULL),
     innermostWith(NULL), bindings(prs->context), bindingsRoot(prs->context, &bindings),
     funcStmts(NULL)
 {
     prs->tc = this;
 }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -70,16 +70,17 @@
 #include "vm/RegExpObject.h"
 
 #include "jsatominlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/BytecodeEmitter-inl.h"
 #include "frontend/ParseMaps-inl.h"
+#include "frontend/ParseNode-inl.h"
 
 /* Allocation chunk counts, must be powers of two in general. */
 #define BYTECODE_CHUNK_LENGTH  1024    /* initial bytecode chunk length */
 #define SRCNOTE_CHUNK_LENGTH   1024    /* initial srcnote chunk length */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
@@ -236,18 +237,16 @@ UpdateDecomposeLength(BytecodeEmitter *b
     unsigned end = bce->offset();
     JS_ASSERT(unsigned(end - start) < 256);
     bce->code(start)[-1] = end - start;
 }
 
 ptrdiff_t
 frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op)
 {
-    JS_ASSERT_IF(op == JSOP_ARGUMENTS, !bce->mayOverwriteArguments());
-
     ptrdiff_t offset = EmitCheck(cx, bce, 1);
 
     if (offset >= 0) {
         *bce->current->next++ = (jsbytecode)op;
         UpdateDepth(cx, bce, offset);
     }
     return offset;
 }
@@ -962,54 +961,46 @@ EmitObjectOp(JSContext *cx, ObjectBox *o
 }
 
 static bool
 EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
 {
     return EmitIndex32(cx, JSOP_REGEXP, index, bce);
 }
 
-static bool
-EmitArguments(JSContext *cx, BytecodeEmitter *bce)
-{
-    if (!bce->mayOverwriteArguments())
-        return Emit1(cx, bce, JSOP_ARGUMENTS) >= 0;
-    return EmitAtomOp(cx, cx->runtime->atomState.argumentsAtom, JSOP_NAME, bce);
-}
-
 bool
 BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
 {
     return !bindingsAccessedDynamically() && pn->isDefn() && pn->isClosed();
 }
 
 bool
 BytecodeEmitter::noteClosedVar(ParseNode *pn)
 {
 #ifdef DEBUG
     JS_ASSERT(shouldNoteClosedName(pn));
     Definition *dn = (Definition *)pn;
     JS_ASSERT(dn->kind() == Definition::VAR || dn->kind() == Definition::CONST ||
               dn->kind() == Definition::FUNCTION);
-    JS_ASSERT(pn->pn_cookie.slot() < bindings.countVars());
+    JS_ASSERT(pn->pn_cookie.slot() < bindings.numVars());
     for (size_t i = 0; i < closedVars.length(); ++i)
         JS_ASSERT(closedVars[i] != pn->pn_cookie.slot());
 #endif
     flags |= TCF_FUN_HEAVYWEIGHT;
     return closedVars.append(pn->pn_cookie.slot());
 }
 
 bool
 BytecodeEmitter::noteClosedArg(ParseNode *pn)
 {
 #ifdef DEBUG
     JS_ASSERT(shouldNoteClosedName(pn));
     Definition *dn = (Definition *)pn;
     JS_ASSERT(dn->kind() == Definition::ARG);
-    JS_ASSERT(pn->pn_cookie.slot() < bindings.countArgs());
+    JS_ASSERT(pn->pn_cookie.slot() < bindings.numArgs());
     for (size_t i = 0; i < closedArgs.length(); ++i)
         JS_ASSERT(closedArgs[i] != pn->pn_cookie.slot());
 #endif
     flags |= TCF_FUN_HEAVYWEIGHT;
     return closedArgs.append(pn->pn_cookie.slot());
 }
 
 /*
@@ -1020,17 +1011,17 @@ BytecodeEmitter::noteClosedArg(ParseNode
  *
  * The function returns -1 on failures.
  */
 static int
 AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
 {
     JS_ASSERT((unsigned) slot < bce->maxStackDepth);
     if (bce->inFunction()) {
-        slot += bce->bindings.countVars();
+        slot += bce->bindings.numVars();
         if ((unsigned) slot >= SLOTNO_LIMIT) {
             ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR,
                                      JSMSG_TOO_MANY_LOCALS);
             slot = -1;
         }
     }
     return slot;
 }
@@ -1235,18 +1226,18 @@ BindNameToSlot(JSContext *cx, BytecodeEm
     Definition::Kind dn_kind;
 
     JS_ASSERT(pn->isKind(PNK_NAME));
 
     /* Idempotency tests come first, since we may be called more than once. */
     if (pn->pn_dflags & PND_BOUND)
         return JS_TRUE;
 
-    /* No cookie initialized for these two, they're pre-bound by definition. */
-    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
+    /* No cookie initialized for callee; it is pre-bound by definition. */
+    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
 
     /*
      * The parser linked all uses (including forward references) to their
      * definitions, unless a with statement or direct eval intervened.
      */
     if (pn->isUsed()) {
         JS_ASSERT(pn->pn_cookie.isFree());
         dn = pn->pn_lexdef;
@@ -1557,19 +1548,17 @@ CheckSideEffects(JSContext *cx, Bytecode
         } else {
             /*
              * All invocation operations (construct: PNK_NEW, call: PNK_LP)
              * are presumed to be useful, because they may have side effects
              * even if their main effect (their return value) is discarded.
              *
              * PNK_LB binary trees of 3 or more nodes are flattened into lists
              * to avoid too much recursion.  All such lists must be presumed
-             * to be useful because each index operation could invoke a getter
-             * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
-             * does not apply here: arguments[i][j] might invoke a getter).
+             * to be useful because each index operation could invoke a getter.
              *
              * Likewise, array and object initialisers may call prototype
              * setters (the __defineSetter__ built-in, and writable __proto__
              * on Array.prototype create this hazard). Initialiser list nodes
              * have JSOP_NEWINIT in their pn_op.
              */
             *answer = JS_TRUE;
         }
@@ -1680,40 +1669,30 @@ CheckSideEffects(JSContext *cx, Bytecode
         /*
          * Take care to avoid trying to bind a label name (labels, both for
          * statements and property values in object initialisers, have pn_op
          * defaulted to JSOP_NOP).
          */
         if (pn->isKind(PNK_NAME) && !pn->isOp(JSOP_NOP)) {
             if (!BindNameToSlot(cx, bce, pn))
                 return JS_FALSE;
-            if (!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE) &&
-                pn->pn_cookie.isFree()) {
+            if (!pn->isOp(JSOP_CALLEE) && pn->pn_cookie.isFree()) {
                 /*
-                 * Not an argument or local variable use, and not a use of a
-                 * unshadowed named function expression's given name, so this
-                 * expression could invoke a getter that has side effects.
+                 * Not a use of an unshadowed named function expression's given
+                 * name, so this expression could invoke a getter that has side
+                 * effects.
                  */
                 *answer = JS_TRUE;
             }
         }
-        pn2 = pn->maybeExpr();
         if (pn->isKind(PNK_DOT)) {
-            if (pn2->isKind(PNK_NAME) && !BindNameToSlot(cx, bce, pn2))
-                return JS_FALSE;
-            if (!(pn2->isOp(JSOP_ARGUMENTS) &&
-                  pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
-                /*
-                 * Any dotted property reference could call a getter, except
-                 * for arguments.length where arguments is unambiguous.
-                 */
-                *answer = JS_TRUE;
-            }
+            /* Dotted property references in general can call getters. */
+            *answer = JS_TRUE;
         }
-        ok = CheckSideEffects(cx, bce, pn2, answer);
+        ok = CheckSideEffects(cx, bce, pn->maybeExpr(), answer);
         break;
 
       case PN_NAMESET:
         ok = CheckSideEffects(cx, bce, pn->pn_tree, answer);
         break;
 
       case PN_NULLARY:
         if (pn->isKind(PNK_DEBUGGER))
@@ -1766,25 +1745,22 @@ EmitNameOp(JSContext *cx, BytecodeEmitte
             break;
           case JSOP_GETARG:
             op = JSOP_CALLARG;
             break;
           case JSOP_GETLOCAL:
             op = JSOP_CALLLOCAL;
             break;
           default:
-            JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
+            JS_ASSERT(op == JSOP_CALLEE);
             break;
         }
     }
 
-    if (op == JSOP_ARGUMENTS) {
-        if (!EmitArguments(cx, bce))
-            return JS_FALSE;
-    } else if (op == JSOP_CALLEE) {
+    if (op == JSOP_CALLEE) {
         if (Emit1(cx, bce, op) < 0)
             return JS_FALSE;
     } else {
         if (!pn->pn_cookie.isFree()) {
             JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
             EMIT_UINT16_IMM_OP(op, pn->pn_cookie.slot());
         } else {
             if (!EmitAtomOp(cx, pn, op, bce))
@@ -2738,20 +2714,29 @@ frontend::EmitFunctionScript(JSContext *
 {
     /*
      * The decompiler has assumptions about what may occur immediately after
      * script->main (e.g., in the case of destructuring params). Thus, put the
      * following ops into the range [script->code, script->main). Note:
      * execution starts from script->code, so this has no semantic effect.
      */
 
+    if (bce->argumentsHasLocalBinding()) {
+        JS_ASSERT(bce->next() == bce->base());  /* See JSScript::argumentsBytecode. */
+        bce->switchToProlog();
+        if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
+            return false;
+        EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, bce->argumentsLocalSlot());
+        if (Emit1(cx, bce, JSOP_POP) < 0)
+            return false;
+        bce->switchToMain();
+    }
+
     if (bce->flags & TCF_FUN_IS_GENERATOR) {
-        /* JSOP_GENERATOR must be the first instruction. */
         bce->switchToProlog();
-        JS_ASSERT(bce->next() == bce->base());
         if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
             return false;
         bce->switchToMain();
     }
 
     return EmitTree(cx, bce, body) &&
            Emit1(cx, bce, JSOP_STOP) >= 0 &&
            JSScript::NewScriptFromEmitter(cx, bce);
@@ -2818,17 +2803,17 @@ typedef JSBool
 
 static JSBool
 EmitDestructuringDecl(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
     if (!BindNameToSlot(cx, bce, pn))
         return JS_FALSE;
 
-    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
+    JS_ASSERT(!pn->isOp(JSOP_CALLEE));
     return MaybeEmitVarDecl(cx, bce, prologOp, pn, NULL);
 }
 
 static JSBool
 EmitDestructuringDecls(JSContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn)
 {
     ParseNode *pn2, *pn3;
     DestructuringDeclEmitter emitter;
@@ -2926,32 +2911,21 @@ EmitDestructuringLHS(JSContext *cx, Byte
             break;
 
           case JSOP_SETCONST:
             if (!EmitElemOp(cx, pn, JSOP_ENUMCONSTELEM, bce))
                 return JS_FALSE;
             break;
 
           case JSOP_SETLOCAL:
-          {
-            uint16_t slot = pn->pn_cookie.slot();
-            EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, slot);
+          case JSOP_SETARG:
+            EMIT_UINT16_IMM_OP(pn->getOp(), pn->pn_cookie.slot());
             if (Emit1(cx, bce, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
-          }
-
-          case JSOP_SETARG:
-          {
-            uint16_t slot = pn->pn_cookie.slot();
-            EMIT_UINT16_IMM_OP(pn->getOp(), slot);
-            if (Emit1(cx, bce, JSOP_POP) < 0)
-                return JS_FALSE;
-            break;
-          }
 
           default:
           {
             ptrdiff_t top;
 
             top = bce->offset();
             if (!EmitTree(cx, bce, pn))
                 return JS_FALSE;
@@ -3464,55 +3438,49 @@ EmitVariables(JSContext *cx, BytecodeEmi
          * pn_lexdef.
          */
         pn3 = pn2->maybeExpr();
 
      do_name:
         if (!BindNameToSlot(cx, bce, pn2))
             return JS_FALSE;
 
+
         JSOp op;
-        jsatomid atomIndex;
-
         op = pn2->getOp();
-        if (op == JSOP_ARGUMENTS) {
-            /* JSOP_ARGUMENTS => no initializer */
-            JS_ASSERT(!pn3 && !letNotes);
-            pn3 = NULL;
-            atomIndex = 0;
-        } else {
-            JS_ASSERT(op != JSOP_CALLEE);
-            JS_ASSERT(!pn2->pn_cookie.isFree() || !pn->isOp(JSOP_NOP));
-            if (!MaybeEmitVarDecl(cx, bce, pn->getOp(), pn2, &atomIndex))
+        JS_ASSERT(op != JSOP_CALLEE);
+        JS_ASSERT(!pn2->pn_cookie.isFree() || !pn->isOp(JSOP_NOP));
+
+        jsatomid atomIndex;
+        if (!MaybeEmitVarDecl(cx, bce, pn->getOp(), pn2, &atomIndex))
+            return JS_FALSE;
+
+        if (pn3) {
+            JS_ASSERT(emitOption != DefineVars);
+            JS_ASSERT_IF(emitOption == PushInitialValues, op == JSOP_SETLOCAL);
+            if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
+                JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME;
+                if (!EmitIndex32(cx, bindOp, atomIndex, bce))
+                    return false;
+            }
+            if (pn->isOp(JSOP_DEFCONST) &&
+                !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3))
+            {
                 return JS_FALSE;
-
-            if (pn3) {
-                JS_ASSERT(emitOption != DefineVars);
-                JS_ASSERT_IF(emitOption == PushInitialValues, op == JSOP_SETLOCAL);
-                if (op == JSOP_SETNAME || op == JSOP_SETGNAME) {
-                    JSOp bindOp = (op == JSOP_SETNAME) ? JSOP_BINDNAME : JSOP_BINDGNAME;
-                    if (!EmitIndex32(cx, bindOp, atomIndex, bce))
-                        return false;
-                }
-                if (pn->isOp(JSOP_DEFCONST) &&
-                    !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3))
-                {
-                    return JS_FALSE;
-                }
-
-                unsigned oldflags = bce->flags;
-                bce->flags &= ~TCF_IN_FOR_INIT;
-                if (!EmitTree(cx, bce, pn3))
-                    return JS_FALSE;
-                bce->flags |= oldflags & TCF_IN_FOR_INIT;
-            } else if (letNotes) {
-                /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
-                if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
-                    return JS_FALSE;
             }
+
+            unsigned oldflags = bce->flags;
+            bce->flags &= ~TCF_IN_FOR_INIT;
+            if (!EmitTree(cx, bce, pn3))
+                return JS_FALSE;
+            bce->flags |= oldflags & TCF_IN_FOR_INIT;
+        } else if (letNotes) {
+            /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
+            if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
+                return JS_FALSE;
         }
 
         /* If we are not initializing, nothing to pop. */
         if (emitOption != InitializeVars) {
             if (next)
                 continue;
             break;
         }
@@ -3521,20 +3489,17 @@ EmitVariables(JSContext *cx, BytecodeEmi
         if (first && NewSrcNote2(cx, bce, SRC_DECL,
                                  (pn->isOp(JSOP_DEFCONST))
                                  ? SRC_DECL_CONST
                                  : (pn->isOp(JSOP_DEFVAR))
                                  ? SRC_DECL_VAR
                                  : SRC_DECL_LET) < 0) {
             return JS_FALSE;
         }
-        if (op == JSOP_ARGUMENTS) {
-            if (!EmitArguments(cx, bce))
-                return JS_FALSE;
-        } else if (!pn2->pn_cookie.isFree()) {
+        if (!pn2->pn_cookie.isFree()) {
             EMIT_UINT16_IMM_OP(op, atomIndex);
         } else {
             if (!EmitIndexOp(cx, op, atomIndex, bce))
                 return false;
         }
 
 #if JS_HAS_DESTRUCTURING
     emit_note_pop:
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -175,66 +175,54 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_
     TCF_RETURN_EXPR =                          0x4,
 
     /* function has 'return;' */
     TCF_RETURN_VOID =                          0x8,
 
     /* parsing init expr of for; exclude 'in' */
     TCF_IN_FOR_INIT =                         0x10,
 
-    /* function has parameter named arguments */
-    TCF_FUN_PARAM_ARGUMENTS =                 0x20,
-
-    /* function may contain a local named arguments */
-    TCF_FUN_LOCAL_ARGUMENTS =                 0x40,
-
-    /* function uses arguments except as a parameter name */
-    TCF_FUN_USES_ARGUMENTS =                  0x80,
-
     /* function needs Call object per call */
-    TCF_FUN_HEAVYWEIGHT =                    0x100,
+    TCF_FUN_HEAVYWEIGHT =                     0x20,
 
     /* parsed yield statement in function */
-    TCF_FUN_IS_GENERATOR =                   0x200,
-
-    /* named function expression that uses its own name */
-    TCF_FUN_USES_OWN_NAME =                  0x400,
+    TCF_FUN_IS_GENERATOR =                    0x40,
 
     /* block contains a function statement */
-    TCF_HAS_FUNCTION_STMT =                  0x800,
+    TCF_HAS_FUNCTION_STMT =                   0x80,
 
     /* flag lambda from generator expression */
-    TCF_GENEXP_LAMBDA =                     0x1000,
+    TCF_GENEXP_LAMBDA =                      0x100,
 
     /* script can optimize name references based on scope chain */
-    TCF_COMPILE_N_GO =                      0x2000,
+    TCF_COMPILE_N_GO =                       0x200,
 
     /* API caller does not want result value from global script */
-    TCF_NO_SCRIPT_RVAL =                    0x4000,
+    TCF_NO_SCRIPT_RVAL =                     0x400,
 
     /*
      * Set when parsing a declaration-like destructuring pattern.  This flag
      * causes PrimaryExpr to create PN_NAME parse nodes for variable references
      * which are not hooked into any definition's use chain, added to any tree
      * context's AtomList, etc. etc.  CheckDestructuring will do that work
      * later.
      *
      * The comments atop CheckDestructuring explain the distinction between
      * assignment-like and declaration-like destructuring patterns, and why
      * they need to be treated differently.
      */
-    TCF_DECL_DESTRUCTURING =                0x8000,
+    TCF_DECL_DESTRUCTURING =                 0x800,
 
     /*
      * This function/global/eval code body contained a Use Strict Directive.
      * Treat certain strict warnings as errors, and forbid the use of 'with'.
      * See also TSF_STRICT_MODE_CODE, JSScript::strictModeCode, and
      * JSREPORT_STRICT_ERROR.
      */
-    TCF_STRICT_MODE_CODE =                 0x10000,
+    TCF_STRICT_MODE_CODE =                  0x1000,
 
     /*
      * The (static) bindings of this script need to support dynamic name
      * read/write access. Here, 'dynamic' means dynamic dictionary lookup on
      * the scope chain for a dynamic set of keys. The primary examples are:
      *  - direct eval
      *  - function::
      *  - with
@@ -248,81 +236,109 @@ JS_ENUM_HEADER(TreeContextFlags, uint32_
      *
      * Note: access through the arguments object is not considered dynamic
      * binding access since it does not go through the normal name lookup
      * mechanism. This is debatable and could be changed (although care must be
      * taken not to turn off the whole 'arguments' optimization). To answer the
      * more general "is this argument aliased" question, script->needsArgsObj
      * should be tested (see JSScript::argIsAlised).
      */
-    TCF_BINDINGS_ACCESSED_DYNAMICALLY =    0x20000,
-
-    /* The function mutates a positional (non-destructuring) parameter. */
-    TCF_FUN_MUTATES_PARAMETER =            0x40000,
+    TCF_BINDINGS_ACCESSED_DYNAMICALLY =     0x2000,
 
     /* Compiling an eval() script. */
-    TCF_COMPILE_FOR_EVAL =                0x100000,
+    TCF_COMPILE_FOR_EVAL =                  0x4000,
 
     /*
      * The function or a function that encloses it may define new local names
      * at runtime through means other than calling eval.
      */
-    TCF_FUN_MIGHT_ALIAS_LOCALS =          0x200000,
+    TCF_FUN_MIGHT_ALIAS_LOCALS =            0x8000,
 
     /* The script contains singleton initialiser JSOP_OBJECT. */
-    TCF_HAS_SINGLETONS =                  0x400000,
+    TCF_HAS_SINGLETONS =                   0x10000,
 
     /* Some enclosing scope is a with-statement or E4X filter-expression. */
-    TCF_IN_WITH =                         0x800000,
+    TCF_IN_WITH =                          0x20000,
 
     /*
      * This function does something that can extend the set of bindings in its
      * call objects --- it does a direct eval in non-strict code, or includes a
      * function statement (as opposed to a function definition).
      *
      * This flag is *not* inherited by enclosed or enclosing functions; it
      * applies only to the function in whose flags it appears.
      */
-    TCF_FUN_EXTENSIBLE_SCOPE =           0x1000000,
+    TCF_FUN_EXTENSIBLE_SCOPE =             0x40000,
 
     /* The caller is JS_Compile*Script*. */
-    TCF_NEED_SCRIPT_GLOBAL =             0x2000000
+    TCF_NEED_SCRIPT_GLOBAL =               0x80000,
+
+    /*
+     * Technically, every function has a binding named 'arguments'. Internally,
+     * this binding is only added when 'arguments' is mentioned by the function
+     * body. This flag indicates whether 'arguments' has been bound either
+     * through implicit use:
+     *   function f() { return arguments }
+     * or explicit redeclaration:
+     *   function f() { var arguments; return arguments }
+     *
+     * Note 1: overwritten arguments (function() { arguments = 3 }) will cause
+     * this flag to be set but otherwise require no special handling:
+     * 'arguments' is just a local variable and uses of 'arguments' will just
+     * read the local's current slot which may have been assigned. The only
+     * special semantics is that the initial value of 'arguments' is the
+     * arguments object (not undefined, like normal locals).
+     *
+     * Note 2: if 'arguments' is bound as a formal parameter, there will be an
+     * 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
+     * flag will not be set. This is because, as a formal, 'arguments' will
+     * have no special semantics: the initial value is unconditionally the
+     * actual argument (or undefined if nactual < nformal).
+     */
+    TCF_ARGUMENTS_HAS_LOCAL_BINDING =     0x100000,
+
+    /*
+     * In many cases where 'arguments' has a local binding (as described above)
+     * we do not need to actually create an arguments object in the function
+     * prologue: instead we can analyze how 'arguments' is used (using the
+     * simple dataflow analysis in analyzeSSA) to determine that uses of
+     * 'arguments' can just read from the stack frame directly. However, the
+     * dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
+     * be unsound in several cases. The frontend filters out such cases by
+     * setting this flag which eagerly sets script->needsArgsObj to true.
+     */
+    TCF_DEFINITELY_NEEDS_ARGS_OBJ =       0x200000
 
 } JS_ENUM_FOOTER(TreeContextFlags);
 
 /* Flags to check for return; vs. return expr; in a function. */
 static const uint32_t TCF_RETURN_FLAGS = TCF_RETURN_EXPR | TCF_RETURN_VOID;
 
 /*
  * Sticky deoptimization flags to propagate from FunctionBody.
  */
-static const uint32_t TCF_FUN_FLAGS = TCF_FUN_USES_ARGUMENTS |
-                                      TCF_FUN_PARAM_ARGUMENTS |
-                                      TCF_FUN_LOCAL_ARGUMENTS |
-                                      TCF_FUN_HEAVYWEIGHT |
+static const uint32_t TCF_FUN_FLAGS = TCF_FUN_HEAVYWEIGHT |
                                       TCF_FUN_IS_GENERATOR |
-                                      TCF_FUN_USES_OWN_NAME |
                                       TCF_BINDINGS_ACCESSED_DYNAMICALLY |
                                       TCF_FUN_MIGHT_ALIAS_LOCALS |
-                                      TCF_FUN_MUTATES_PARAMETER |
                                       TCF_STRICT_MODE_CODE |
-                                      TCF_FUN_EXTENSIBLE_SCOPE;
+                                      TCF_FUN_EXTENSIBLE_SCOPE |
+                                      TCF_ARGUMENTS_HAS_LOCAL_BINDING |
+                                      TCF_DEFINITELY_NEEDS_ARGS_OBJ;
 
 struct BytecodeEmitter;
 
 struct TreeContext {                /* tree context for semantic checks */
     uint32_t        flags;          /* statement state flags, see above */
     uint32_t        bodyid;         /* block number of program/function body */
     uint32_t        blockidGen;     /* preincremented block number generator */
     uint32_t        parenDepth;     /* nesting depth of parens that might turn out
                                        to be generator expressions */
     uint32_t        yieldCount;     /* number of |yield| tokens encountered at
                                        non-zero depth in current paren tree */
-    uint32_t        argumentsCount; /* number of |arguments| references encountered
-                                       at non-zero depth in current paren tree */
     StmtInfo        *topStmt;       /* top of statement info stack */
     StmtInfo        *topScopeStmt;  /* top lexical scope statement */
     StaticBlockObject *blockChain;  /* compile block scope chain (NB: one
                                        deeper than the topScopeStmt/downScope
                                        chain when in head of let block/expr) */
     ParseNode       *blockNode;     /* parse node for a block with let declarations
                                        (block with its own lexical scope)  */
     AtomDecls       decls;          /* function, const, and var declarations */
@@ -427,82 +443,55 @@ struct TreeContext {                /* t
     bool skipSpansGenerator(unsigned skip);
 
     bool compileAndGo() const { return flags & TCF_COMPILE_N_GO; }
     bool inFunction() const { return flags & TCF_IN_FUNCTION; }
 
     bool compiling() const { return flags & TCF_COMPILING; }
     inline BytecodeEmitter *asBytecodeEmitter();
 
-    bool usesArguments() const {
-        return flags & TCF_FUN_USES_ARGUMENTS;
-    }
-
     void noteBindingsAccessedDynamically() {
         flags |= TCF_BINDINGS_ACCESSED_DYNAMICALLY;
     }
 
     bool bindingsAccessedDynamically() const {
         return flags & TCF_BINDINGS_ACCESSED_DYNAMICALLY;
     }
 
     void noteMightAliasLocals() {
         flags |= TCF_FUN_MIGHT_ALIAS_LOCALS;
     }
 
     bool mightAliasLocals() const {
         return flags & TCF_FUN_MIGHT_ALIAS_LOCALS;
     }
 
-    void noteParameterMutation() {
-        JS_ASSERT(inFunction());
-        flags |= TCF_FUN_MUTATES_PARAMETER;
-    }
-
-    bool mutatesParameter() const {
-        JS_ASSERT(inFunction());
-        return flags & TCF_FUN_MUTATES_PARAMETER;
+    void noteArgumentsHasLocalBinding() {
+        flags |= TCF_ARGUMENTS_HAS_LOCAL_BINDING;
     }
 
-    bool mayOverwriteArguments() const {
-        JS_ASSERT(inFunction());
-        JS_ASSERT_IF(inStrictMode(),
-                     !(flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS)));
-        return !inStrictMode() &&
-               (bindingsAccessedDynamically() ||
-                flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS));
-    }
-
-    void noteLocalOverwritesArguments() {
-        flags |= TCF_FUN_LOCAL_ARGUMENTS;
+    bool argumentsHasLocalBinding() const {
+        return flags & TCF_ARGUMENTS_HAS_LOCAL_BINDING;
     }
 
-    void noteArgumentsNameUse(ParseNode *node) {
-        JS_ASSERT(inFunction());
-        JS_ASSERT(node->isKind(PNK_NAME));
-        JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
-        countArgumentsUse(node);
-        flags |= TCF_FUN_USES_ARGUMENTS;
+    unsigned argumentsLocalSlot() const {
+        PropertyName *arguments = parser->context->runtime->atomState.argumentsAtom;
+        unsigned slot;
+        DebugOnly<BindingKind> kind = bindings.lookup(parser->context, arguments, &slot);
+        JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
+        return slot;
     }
 
-    /*
-     * Uses of |arguments| must be noted so that such uses can be forbidden if
-     * they occur inside generator expressions (which desugar to functions and
-     * yields, in which |arguments| would have an entirely different meaning).
-     */
-    void countArgumentsUse(ParseNode *node) {
-        JS_ASSERT(node->isKind(PNK_NAME));
-        JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
-        argumentsCount++;
-        argumentsNode = node;
+    void noteDefinitelyNeedsArgsObj() {
+        JS_ASSERT(argumentsHasLocalBinding());
+        flags |= TCF_DEFINITELY_NEEDS_ARGS_OBJ;
     }
 
-    bool needsEagerArguments() const {
-        return inStrictMode() &&
-               (bindingsAccessedDynamically() || (usesArguments() && mutatesParameter()));
+    bool definitelyNeedsArgsObj() const {
+        return flags & TCF_DEFINITELY_NEEDS_ARGS_OBJ;
     }
 
     void noteHasExtensibleScope() {
         flags |= TCF_FUN_EXTENSIBLE_SCOPE;
     }
 
     bool hasExtensibleScope() const {
         return flags & TCF_FUN_EXTENSIBLE_SCOPE;
--- a/js/src/frontend/ParseNode-inl.h
+++ b/js/src/frontend/ParseNode-inl.h
@@ -41,16 +41,24 @@
 #define ParseNode_inl_h__
 
 #include "frontend/ParseNode.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
 
 namespace js {
 
+inline PropertyName *
+ParseNode::atom() const
+{
+    JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME));
+    JSAtom *atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom : pn_atom;
+    return atom->asPropertyName();
+}
+
 inline bool
 ParseNode::isConstant()
 {
     switch (pn_type) {
       case PNK_NUMBER:
       case PNK_STRING:
       case PNK_NULL:
       case PNK_FALSE:
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -729,16 +729,18 @@ struct ParseNode {
      * Either append right to left, if left meets the conditions necessary to
      * append (see append), or form a binary node whose children are right and
      * left.
      */
     static ParseNode *
     newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
                       TreeContext *tc);
 
+    inline PropertyName *atom() const;
+
     /*
      * The pn_expr and lexdef members are arms of an unsafe union. Unless you
      * know exactly what you're doing, use only the following methods to access
      * them. For less overhead and assertions for protection, use pn->expr()
      * and pn->lexdef(). Otherwise, use pn->maybeExpr() and pn->maybeLexDef().
      */
     ParseNode *expr() const {
         JS_ASSERT(!pn_used);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -517,30 +517,30 @@ ReportBadParameter(JSContext *cx, TreeCo
 }
 
 /*
  * In strict mode code, all parameter names must be distinct, must not be
  * strict mode reserved keywords, and must not be 'eval' or 'arguments'.  We
  * must perform these checks here, and not eagerly during parsing, because a
  * function's body may turn on strict mode for the function head.
  */
-bool
-js::CheckStrictParameters(JSContext *cx, TreeContext *tc)
+static bool
+CheckStrictParameters(JSContext *cx, TreeContext *tc)
 {
     JS_ASSERT(tc->inFunction());
 
-    if (!tc->needStrictChecks() || tc->bindings.countArgs() == 0)
+    if (!tc->needStrictChecks() || tc->bindings.numArgs() == 0)
         return true;
 
     JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
 
     /* name => whether we've warned about the name already */
     HashMap<JSAtom *, bool> parameters(cx);
-    if (!parameters.init(tc->bindings.countArgs()))
+    if (!parameters.init(tc->bindings.numArgs()))
         return false;
 
     /* Start with lastVariable(), not lastArgument(), for destructuring. */
     for (Shape::Range r = tc->bindings.lastVariable(); !r.empty(); r.popFront()) {
         jsid id = r.front().propid();
         if (!JSID_IS_ATOM(id))
             continue;
 
@@ -572,16 +572,30 @@ js::CheckStrictParameters(JSContext *cx,
             if (!parameters.add(p, name, false))
                 return false;
         }
     }
 
     return true;
 }
 
+static bool
+BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
+{
+    JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
+
+    unsigned index = tc->bindings.numVars();
+    if (!tc->bindings.add(cx, pn->pn_atom, kind))
+        return false;
+
+    pn->pn_cookie.set(tc->staticLevel, index);
+    pn->pn_dflags |= PND_BOUND;
+    return true;
+}
+
 ParseNode *
 Parser::functionBody(FunctionBodyType type)
 {
     JS_ASSERT(tc->inFunction());
 
     StmtInfo stmtInfo;
     PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
     stmtInfo.flags = SIF_BODY_BLOCK;
@@ -621,40 +635,104 @@ Parser::functionBody(FunctionBodyType ty
         /* Check for falling off the end of a function that returns a value. */
         if (context->hasStrictOption() && (tc->flags & TCF_RETURN_EXPR) &&
             !CheckFinalReturn(context, tc, pn)) {
             pn = NULL;
         }
     }
 
     /*
-     * Check whether any parameters have been assigned within this function.
-     * In strict mode parameters do not alias arguments[i], and to make the
-     * arguments object reflect initial parameter values prior to any mutation
-     * we create it eagerly whenever parameters are (or might, in the case of
-     * calls to eval) be assigned.
+     * Check CheckStrictParameters before arguments logic below adds
+     * 'arguments' to bindings.
      */
-    if (tc->inStrictMode() && tc->fun()->nargs > 0) {
-        AtomDeclsIter iter(&tc->decls);
-        while (Definition *dn = iter.next()) {
-            if (dn->kind() == Definition::ARG && dn->isAssigned()) {
-                tc->flags |= TCF_FUN_MUTATES_PARAMETER;
-                break;
-            }
+    if (!CheckStrictParameters(context, tc))
+        return NULL;
+
+    PropertyName * const arguments = context->runtime->atomState.argumentsAtom;
+
+    /*
+     * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
+     * operation which means it aliases any bindings with the same name.
+     * Due to the implicit declaration mechanism (below), 'arguments' will not
+     * have decls and, even if it did, they will not be noted as closed in the
+     * emitter. Thus, in the corner case of function-statement-overridding-
+     * arguments, flag the whole scope as dynamic.
+     */
+    if (FuncStmtSet *set = tc->funcStmts) {
+        for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
+            PropertyName *name = r.front()->asPropertyName();
+            if (name == arguments)
+                tc->noteBindingsAccessedDynamically();
+            else if (Definition *dn = tc->decls.lookupFirst(name))
+                dn->pn_dflags |= PND_CLOSED;
         }
     }
 
     /*
-     * Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
-     * operation which means it aliases any bindings with the same name.
+     * As explained by the TCF_ARGUMENTS_HAS_LOCAL_BINDING comment, turn uses
+     * of 'arguments' into bindings. Use of 'arguments' should never escape a
+     * nested function as an upvar.
+     */
+    for (AtomDefnRange r = tc->lexdeps->all(); !r.empty(); r.popFront()) {
+        JSAtom *atom = r.front().key();
+        Definition *dn = r.front().value();
+        JS_ASSERT(dn->isPlaceholder());
+        if (atom == arguments) {
+            /*
+             * Turn 'dn' into a proper definition so uses will be bound as
+             * GETLOCAL in the emitter.
+             */
+            if (!BindLocalVariable(context, tc, dn, VARIABLE))
+                return NULL;
+            dn->setOp(JSOP_GETLOCAL);
+            dn->pn_dflags &= ~PND_PLACEHOLDER;
+
+            /* NB: this leaves r invalid so we must break immediately. */
+            tc->lexdeps->remove(arguments);
+            break;
+        }
+    }
+
+    /*
+     * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup
+     * forces an 'arguments' binding.
      */
-    if (FuncStmtSet *set = tc->funcStmts) {
-        for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
-            if (Definition *dn = tc->decls.lookupFirst(r.front()))
-                dn->pn_dflags |= PND_CLOSED;
+    if (tc->bindingsAccessedDynamically() && !tc->bindings.hasBinding(context, arguments)) {
+        if (!tc->bindings.addVariable(context, arguments))
+            return NULL;
+    }
+
+    /*
+     * Now that all possible 'arguments' bindings have been added, note whether
+     * 'arguments' has a local binding and whether it unconditionally needs an
+     * arguments object.
+     */
+    BindingKind bindKind = tc->bindings.lookup(context, arguments, NULL);
+    if (bindKind == VARIABLE || bindKind == CONSTANT) {
+        tc->noteArgumentsHasLocalBinding();
+
+        /* Dynamic scope access destroys all hope of optimization. */
+        if (tc->bindingsAccessedDynamically())
+            tc->noteDefinitelyNeedsArgsObj();
+
+        /*
+         * Check whether any parameters have been assigned within this
+         * function. In strict mode parameters do not alias arguments[i], and
+         * to make the arguments object reflect initial parameter values prior
+         * to any mutation we create it eagerly whenever parameters are (or
+         * might, in the case of calls to eval) be assigned.
+         */
+        if (tc->inStrictMode()) {
+            AtomDeclsIter iter(&tc->decls);
+            while (Definition *dn = iter.next()) {
+                if (dn->kind() == Definition::ARG && dn->isAssigned()) {
+                    tc->noteDefinitelyNeedsArgsObj();
+                    break;
+                }
+             }
         }
     }
 
     tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
     return pn;
 }
 
 /* Create a placeholder Definition node for |atom|. */
@@ -815,20 +893,16 @@ MakeDefIntoUse(Definition *dn, ParseNode
     dn->pn_cookie.makeFree();
     dn->pn_dflags &= ~PND_BOUND;
     return dn;
 }
 
 bool
 js::DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, TreeContext *tc)
 {
-    /* Flag tc so we don't have to lookup arguments on every use. */
-    if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
-        tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
-
     /*
      * Make an argument definition node, distinguished by being in tc->decls
      * but having PNK_NAME kind and JSOP_NOP op. Insert it in a PNK_ARGSBODY
      * list node returned via pn->pn_body.
      */
     ParseNode *argpn = NameNode::create(PNK_NAME, atom, tc);
     if (!argpn)
         return false;
@@ -898,41 +972,20 @@ struct BindData {
     }
 
     void initVarOrConst(JSOp op) {
         this->op = op;
         this->binder = BindVarOrConst;
     }
 };
 
-static bool
-BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
-{
-    JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
-
-    /* 'arguments' can be bound as a local only via a destructuring formal parameter. */
-    JS_ASSERT_IF(pn->pn_atom == cx->runtime->atomState.argumentsAtom, kind == VARIABLE);
-
-    unsigned index = tc->bindings.countVars();
-    if (!tc->bindings.add(cx, pn->pn_atom, kind))
-        return false;
-
-    pn->pn_cookie.set(tc->staticLevel, index);
-    pn->pn_dflags |= PND_BOUND;
-    return true;
-}
-
 #if JS_HAS_DESTRUCTURING
 static JSBool
 BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, TreeContext *tc)
 {
-    /* Flag tc so we don't have to lookup arguments on every use. */
-    if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
-        tc->flags |= TCF_FUN_PARAM_ARGUMENTS;
-
     JS_ASSERT(tc->inFunction());
 
     /*
      * NB: Check tc->decls rather than tc->bindings, because destructuring
      *     bindings aren't added to tc->bindings until after all arguments have
      *     been parsed.
      */
     if (tc->decls.lookupFirst(atom)) {
@@ -1452,17 +1505,17 @@ Parser::functionDef(PropertyName *funNam
              * variable, not an argument, for the function statement. Thus
              * we add a variable even if a parameter with the given name
              * already exists.
              */
             unsigned index;
             switch (tc->bindings.lookup(context, funName, &index)) {
               case NONE:
               case ARGUMENT:
-                index = tc->bindings.countVars();
+                index = tc->bindings.numVars();
                 if (!tc->bindings.addVariable(context, funName))
                     return NULL;
                 /* FALL THROUGH */
 
               case VARIABLE:
                 pn->pn_cookie.set(tc->staticLevel, index);
                 pn->pn_dflags |= PND_BOUND;
                 break;
@@ -1485,17 +1538,17 @@ Parser::functionDef(PropertyName *funNam
 
     JSFunction *fun = funbox->function();
 
     /* Now parse formal argument list and compute fun->nargs. */
     ParseNode *prelude = NULL;
     if (!functionArguments(funtc, funbox, &prelude))
         return NULL;
 
-    fun->setArgCount(funtc.bindings.countArgs());
+    fun->setArgCount(funtc.bindings.numArgs());
 
 #if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, bind the destructured-to
      * local variables now that we've parsed all the regular and destructuring
      * formal parameters. Because js::Bindings::add must be called first for
      * all ARGUMENTs, then all VARIABLEs and CONSTANTs, and finally all UPVARs,
      * we can't bind vars induced by formal parameter destructuring until after
@@ -1538,19 +1591,16 @@ Parser::functionDef(PropertyName *funNam
 
     ParseNode *body = functionBody(bodyType);
     if (!body)
         return NULL;
 
     if (funName && !CheckStrictBinding(context, &funtc, funName, pn))
         return NULL;
 
-    if (!CheckStrictParameters(context, &funtc))
-        return NULL;
-
 #if JS_HAS_EXPR_CLOSURES
     if (bodyType == StatementListBody)
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
     else if (kind == Statement && !MatchOrInsertSemicolon(context, &tokenStream))
         return NULL;
 #else
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);
 #endif
@@ -1622,18 +1672,16 @@ Parser::functionDef(PropertyName *funNam
              * compound statement such as the "then" part of an "if" statement,
              * binds a closure only if control reaches that sub-statement.
              */
             JS_ASSERT(!outertc->inStrictMode());
             op = JSOP_DEFFUN;
             outertc->noteMightAliasLocals();
             outertc->noteHasExtensibleScope();
             outertc->flags |= TCF_FUN_HEAVYWEIGHT;
-            if (fun->atom == context->runtime->atomState.argumentsAtom)
-                outertc->noteLocalOverwritesArguments();
 
             /*
              * Instead of noteBindingsAccessedDynamically, which would be
              * overly conservative, remember the names of all function
              * statements and mark any bindings with the same as aliased at the
              * end of functionBody.
              */
             if (!outertc->funcStmts) {
@@ -2165,28 +2213,16 @@ BindTopLevelVar(JSContext *cx, BindData 
 static bool
 BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContext *tc)
 {
     JS_ASSERT(tc->inFunction());
 
     ParseNode *pn = data->pn;
     JSAtom *name = pn->pn_atom;
 
-    /*
-     * Don't create a local variable with the name 'arguments', per ECMA-262.
-     * Instead, 'var arguments' always restates that predefined binding of the
-     * lexical environment for function activations. Assignments to arguments
-     * must be handled specially -- see NoteLValue.
-     */
-    if (name == cx->runtime->atomState.argumentsAtom) {
-        pn->setOp(JSOP_ARGUMENTS);
-        pn->pn_dflags |= PND_BOUND;
-        return true;
-    }
-
     BindingKind kind = tc->bindings.lookup(cx, name, NULL);
     if (kind == NONE) {
         /*
          * Property not found in current variable scope: we have not seen this
          * variable before, so bind a new local variable for it. Any locals
          * declared in a with statement body are handled at runtime, by script
          * prolog JSOP_DEFVAR opcodes generated for global and heavyweight-
          * function-local vars.
@@ -2396,64 +2432,45 @@ NoteLValue(JSContext *cx, ParseNode *pn,
         }
 
         dn->pn_dflags |= dflag;
     }
 
     pn->pn_dflags |= dflag;
 
     /*
-     * Both arguments and the enclosing function's name are immutable bindings
-     * in ES5, so assignments to them must do nothing or throw a TypeError
-     * depending on code strictness.  Assignment to arguments is a syntax error
-     * in strict mode and thus cannot happen.  Outside strict mode, we optimize
-     * away assignment to the function name.  For assignment to function name
-     * to fail in strict mode, we must have a binding for it in the scope
-     * chain; we ensure this happens by making such functions heavyweight.
+     * An enclosing function's name is an immutable binding in ES5, so
+     * assignments to them must do nothing or throw a TypeError depending on
+     * code strictness. Outside strict mode, we optimize away assignment to
+     * the function name. For assignment to function name to fail in strict
+     * mode, we must have a binding for it in the scope chain; we ensure this
+     * happens by making such functions heavyweight.
      */
-    JSAtom *lname = pn->pn_atom;
-    if (lname == cx->runtime->atomState.argumentsAtom) {
+    if (tc->inFunction() && pn->pn_atom == tc->fun()->atom)
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
-        tc->noteLocalOverwritesArguments();
-        tc->countArgumentsUse(pn);
-    } else if (tc->inFunction() && lname == tc->fun()->atom) {
-        tc->flags |= TCF_FUN_HEAVYWEIGHT;
-    }
 }
 
 #if JS_HAS_DESTRUCTURING
 
 static JSBool
 BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, TreeContext *tc)
 {
-    JSAtom *atom;
-
-    /*
-     * Destructuring is a form of assignment, so just as for an initialized
-     * simple variable, we must check for assignment to 'arguments' and flag
-     * the enclosing function (if any) as heavyweight.
-     */
     JS_ASSERT(pn->isKind(PNK_NAME));
-    atom = pn->pn_atom;
-    if (atom == cx->runtime->atomState.argumentsAtom) {
-        tc->flags |= TCF_FUN_HEAVYWEIGHT;
-        tc->noteLocalOverwritesArguments();
-    }
 
     data->pn = pn;
-    if (!data->binder(cx, data, atom, tc))
+    if (!data->binder(cx, data, pn->pn_atom, tc))
         return JS_FALSE;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND) {
         JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
-        pn->setOp(pn->isOp(JSOP_ARGUMENTS) ? JSOP_SETNAME : JSOP_SETLOCAL);
+        pn->setOp(JSOP_SETLOCAL);
     } else {
         pn->setOp((data->op == JSOP_DEFCONST) ? JSOP_SETCONST : JSOP_SETNAME);
     }
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
     NoteLValue(cx, pn, tc, PND_INITIALIZED);
@@ -2990,24 +3007,17 @@ NewBindingNode(JSAtom *atom, TreeContext
                 tc->lexdeps->remove(removal);
                 return pn;
             }
         }
     }
 
     /* Make a new node for this declarator name (or destructuring pattern). */
     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_NAME);
-    ParseNode *pn = NameNode::create(PNK_NAME, atom, tc);
-    if (!pn)
-        return NULL;
-
-    if (atom == tc->parser->context->runtime->atomState.argumentsAtom)
-        tc->countArgumentsUse(pn);
-
-    return pn;
+    return NameNode::create(PNK_NAME, atom, tc);
 }
 
 ParseNode *
 Parser::switchStatement()
 {
     JS_ASSERT(tc->parser->tokenStream.currentToken().type == TOK_SWITCH);
     ParseNode *pn = BinaryNode::create(PNK_SWITCH, tc);
     if (!pn)
@@ -4375,36 +4385,26 @@ Parser::variables(ParseNodeKind kind, St
                 if (!pn2)
                     return NULL;
             } else {
                 pn2->pn_expr = init;
             }
 
             JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
 
-            pn2->setOp(pn2->isOp(JSOP_ARGUMENTS)
-                       ? JSOP_SETNAME
-                       : (pn2->pn_dflags & PND_BOUND)
+            pn2->setOp((pn2->pn_dflags & PND_BOUND)
                        ? JSOP_SETLOCAL
                        : (data.op == JSOP_DEFCONST)
                        ? JSOP_SETCONST
                        : JSOP_SETNAME);
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
-
-            if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
-                tc->noteArgumentsNameUse(pn2);
-                if (!blockObj) {
-                    tc->flags |= TCF_FUN_HEAVYWEIGHT;
-                    tc->noteLocalOverwritesArguments();
-                }
-            }
         }
     } while (tokenStream.matchToken(TOK_COMMA));
 
     pn->pn_pos.end = pn->last()->pn_pos.end;
     return pn;
 }
 
 ParseNode *
@@ -4921,20 +4921,16 @@ Parser::unaryExpr()
             }
             break;
           case PNK_NAME:
             if (!ReportStrictModeError(context, &tokenStream, tc, pn,
                                        JSMSG_DEPRECATED_DELETE_OPERAND)) {
                 return NULL;
             }
             pn2->setOp(JSOP_DELNAME);
-            if (pn2->pn_atom == context->runtime->atomState.argumentsAtom) {
-                tc->flags |= TCF_FUN_HEAVYWEIGHT;
-                tc->countArgumentsUse(pn2);
-            }
             break;
           default:;
         }
         pn->pn_kid = pn2;
         break;
       }
       case TOK_ERROR:
         return NULL;
@@ -5018,28 +5014,26 @@ class CompExprTransplanter {
  * call endBody() to reset the context's state, and then immediately call:
  *
  * - checkValidBody() if this *did* turn out to be a generator expression
  * - maybeNoteGenerator() if this *did not* turn out to be a generator expression
  */
 class GenexpGuard {
     TreeContext     *tc;
     uint32_t        startYieldCount;
-    uint32_t        startArgumentsCount;
 
   public:
     explicit GenexpGuard(TreeContext *tc)
       : tc(tc)
     {
         if (tc->parenDepth == 0) {
-            tc->yieldCount = tc->argumentsCount = 0;
+            tc->yieldCount = 0;
             tc->yieldNode = tc->argumentsNode = NULL;
         }
         startYieldCount = tc->yieldCount;
-        startArgumentsCount = tc->argumentsCount;
         tc->parenDepth++;
     }
 
     void endBody();
     bool checkValidBody(ParseNode *pn);
     bool maybeNoteGenerator(ParseNode *pn);
 };
 
@@ -5062,24 +5056,16 @@ GenexpGuard::checkValidBody(ParseNode *p
     if (tc->yieldCount > startYieldCount) {
         ParseNode *errorNode = tc->yieldNode;
         if (!errorNode)
             errorNode = pn;
         tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_yield_str);
         return false;
     }
 
-    if (tc->argumentsCount > startArgumentsCount) {
-        ParseNode *errorNode = tc->argumentsNode;
-        if (!errorNode)
-            errorNode = pn;
-        tc->parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
-        return false;
-    }
-
     return true;
 }
 
 /*
  * Check whether a |yield| token has been encountered in the body expression,
  * and if so, note that the current function is a generator function.
  *
  * Call this after endBody() when determining that the body *was not* in a
@@ -5585,35 +5571,43 @@ Parser::generatorExpr(ParseNode *kid)
             return NULL;
 
         FunctionBox *funbox = EnterFunction(genfn, &gentc);
         if (!funbox)
             return NULL;
 
         /*
          * We assume conservatively that any deoptimization flag in tc->flags
-         * besides TCF_FUN_PARAM_ARGUMENTS can come from the kid. So we
-         * propagate these flags into genfn. For code simplicity we also do
-         * not detect if the flags were only set in the kid and could be
-         * removed from tc->flags.
+         * come from the kid. So we propagate these flags into genfn. For code
+         * simplicity we also do not detect if the flags were only set in the
+         * kid and could be removed from tc->flags.
          */
         gentc.flags |= TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA |
-                       (outertc->flags & (TCF_FUN_FLAGS & ~TCF_FUN_PARAM_ARGUMENTS));
+                       (outertc->flags & TCF_FUN_FLAGS);
         funbox->tcflags |= gentc.flags;
         genfn->pn_funbox = funbox;
         genfn->pn_blockid = gentc.bodyid;
 
         ParseNode *body = comprehensionTail(pn, outertc->blockid(), true);
         if (!body)
             return NULL;
         JS_ASSERT(!genfn->pn_body);
         genfn->pn_body = body;
         genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin;
         genfn->pn_pos.end = body->pn_pos.end = tokenStream.currentToken().pos.end;
 
+        JSAtom *arguments = gentc.parser->context->runtime->atomState.argumentsAtom;
+        if (AtomDefnPtr p = gentc.lexdeps->lookup(arguments)) {
+            Definition *dn = p.value();
+            ParseNode *errorNode = dn->dn_uses ? dn->dn_uses : body;
+            gentc.parser->reportErrorNumber(errorNode, JSREPORT_ERROR, JSMSG_BAD_GENEXP_BODY,
+                                             js_arguments_str);
+            return false;
+        }
+
         if (!LeaveFunction(genfn, &gentc))
             return NULL;
     }
 
     /*
      * Our result is a call expression that invokes the anonymous generator
      * function object.
      */
@@ -6626,45 +6620,22 @@ Parser::identifierName(bool afterDoubleD
 
     PropertyName *name = tokenStream.currentToken().name();
     ParseNode *node = NameNode::create(PNK_NAME, name, tc);
     if (!node)
         return NULL;
     JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
     node->setOp(JSOP_NAME);
 
-    if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
-        name == context->runtime->atomState.argumentsAtom)
-    {
-        /*
-         * Bind early to JSOP_ARGUMENTS to relieve later code from having
-         * to do this work (new rule for the emitter to count on).
-         */
-        if (!afterDoubleDot) {
-            /*
-             * Note use of |arguments| to ensure we can properly create the
-             * |arguments| object for this function.
-             */
-            tc->noteArgumentsNameUse(node);
-
-            if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
-                node->setOp(JSOP_ARGUMENTS);
-                node->pn_dflags |= PND_BOUND;
-            }
-        }
-    } else if ((!afterDoubleDot
+    if ((!afterDoubleDot
 #if JS_HAS_XML_SUPPORT
                 || (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
 #endif
                ) && !(tc->flags & TCF_DECL_DESTRUCTURING))
     {
-        /* In case this is a generator expression outside of any function. */
-        if (!tc->inFunction() && name == context->runtime->atomState.argumentsAtom)
-            tc->countArgumentsUse(node);
-
         StmtInfo *stmt = LexicalLookup(tc, name, NULL);
 
         MultiDeclRange mdl = tc->decls.lookupMulti(name);
 
         Definition *dn;
         if (!mdl.empty()) {
             dn = mdl.front();
         } else {
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -289,19 +289,16 @@ Parser::reportErrorNumber(ParseNode *pn,
     va_list args;
     va_start(args, errorNumber);
     bool result = tokenStream.reportCompileErrorNumberVA(pn, flags, errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-CheckStrictParameters(JSContext *cx, TreeContext *tc);
-
-bool
 DefineArg(ParseNode *pn, JSAtom *atom, unsigned i, TreeContext *tc);
 
 } /* namespace js */
 
 /*
  * Convenience macro to access Parser.tokenStream as a pointer.
  */
 #define TS(p) (&(p)->tokenStream)
--- a/js/src/jit-test/tests/basic/builtinLocals.js
+++ b/js/src/jit-test/tests/basic/builtinLocals.js
@@ -2,17 +2,17 @@
 /* Resolve 'arguments' and the name of the function itself in the presence of such local variables. */
 
 function f() {
     return typeof arguments;
     function arguments() {
         return 7;
     }
 }
-assertEq(f(), "object");
+assertEq(f(), "function");
 
 function g() {
     var arguments = 0;
     return typeof arguments;
 }
 assertEq(g(), "number");
 
 function h() {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug741497.js
@@ -0,0 +1,2 @@
+"use strict";
+function inner() (([arguments, b] = this, c)());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug743408.js
@@ -0,0 +1,6 @@
+// |jit-test| error:ReferenceError
+test();
+function test() {
+  (arguments);
+  F.prototype = new F();
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testCallApplySpeculationFailed.js
@@ -0,0 +1,5 @@
+function foo(n) { return n; }
+foo.apply = function(a, b) { return b[0]; }
+function bar(value) { return foo.apply(null, arguments); }
+for (var i = 1 ; i < 4; i++)
+  assertEq(bar(i), i);
--- a/js/src/jit-test/tests/basic/testDynamicLookup.js
+++ b/js/src/jit-test/tests/basic/testDynamicLookup.js
@@ -56,13 +56,18 @@
 (function([x]) { (function() { assertEq(x, 2) })() })([2]);
 (function([x]) { (function() { eval('assertEq(x, 2)') })() })([2]);
 
 (function f() { assertEq(f.length, 0) })();
 (function f() { eval('assertEq(f.length, 0)') })();
 (function f() { (function f(x) { eval('assertEq(f.length, 1)') })() })();
 (function f() { eval("(function f(x) { eval('assertEq(f.length, 1)') })()") })();
 
+(function f() { arguments = 3; function arguments() {}; assertEq(arguments, 3) })();
+(function f() { function arguments() {}; arguments = 3; assertEq(arguments, 3) })();
+(function f() { var arguments = 3; function arguments() {}; assertEq(arguments, 3) })();
+(function f() { function arguments() {}; var arguments = 3; assertEq(arguments, 3) })();
+
 function f1() { assertEq(typeof f1, "function") }; f1();
 with({}) { (function() { assertEq(typeof f1, "function") })() }
 if (Math)
     function f2(x) {}
 assertEq(f2.length, 1);
--- a/js/src/jit-test/tests/debug/Frame-eval-08.js
+++ b/js/src/jit-test/tests/debug/Frame-eval-08.js
@@ -1,23 +1,15 @@
-// The arguments can escape from a function via a debugging hook.
+// Test that 'arguments' access in a function that doesn't expect 'arguments'
+// doesn't crash.
+
+// TODO bug 659577: the debugger should be improved to throw an error in such
+// cases rather than silently returning whatever it finds on the scope chain.
 
 var g = newGlobal('new-compartment');
 var dbg = new Debugger(g);
 
 // capture arguments object and test function
-var args, testfn;
 dbg.onDebuggerStatement = function (frame) {
-    args = frame.eval("arguments").return;
-    testfn = frame.eval("test").return;
+    args = frame.eval("arguments");
 };
 g.eval("function f() { debugger; }");
-g.eval("var test = " + function test(args) {
-        assertEq(args.length, 3);
-        assertEq(args[0], this);
-        assertEq(args[1], f);
-        assertEq(args[2].toString(), "[object Object]");
-        return 42;
-    } + ";");
 g.eval("f(this, f, {});");
-
-var cv = testfn.apply(null, [args]);
-assertEq(cv.return, 42);
--- a/js/src/jit-test/tests/debug/Frame-evalWithBindings-03.js
+++ b/js/src/jit-test/tests/debug/Frame-evalWithBindings-03.js
@@ -1,16 +1,17 @@
 // arguments works in evalWithBindings (it does not interpose a function scope)
+// when the function expects 'arguments'
 var g = newGlobal('new-compartment');
 var dbg = new Debugger;
 var global = dbg.addDebuggee(g);
 var hits = 0;
 dbg.onDebuggerStatement = function (frame) {
     var argc = frame.arguments.length;
     assertEq(argc, 7);
     assertEq(frame.evalWithBindings("arguments[prop]", {prop: "length"}).return, argc);
     for (var i = 0; i < argc; i++)
         assertEq(frame.evalWithBindings("arguments[i]", {i: i}).return, frame.arguments[i]);
     hits++;
 };
-g.eval("function f() { debugger; }");
+g.eval("function f() { eval('arguments'); debugger; }");
 g.eval("f(undefined, -0, NaN, '\uffff', Array.prototype, Math, f);");
 assertEq(hits, 1);
--- a/js/src/jit-test/tests/debug/Frame-onPop-21.js
+++ b/js/src/jit-test/tests/debug/Frame-onPop-21.js
@@ -11,17 +11,16 @@ dbg.onDebuggerStatement = function handl
 };
 
 function handlePop(c) {
     log += ')';
 
     // Arguments must be live.
     assertEq(this.eval('a').return, 'frieze');
     assertEq(this.eval('b = "architrave"').return, 'architrave');
-    assertEq(this.eval('arguments[1]').return, 'architrave');
     assertEq(this.eval('b').return, 'architrave');
 
     // function-scope variables must be live.
     assertEq(this.eval('x').return, 'entablature');
     assertEq(this.eval('y = "cornice"').return, 'cornice');
     assertEq(this.eval('y').return, 'cornice');
 }
 
--- a/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/eif-trap-newvar.js
@@ -1,10 +1,10 @@
 // |jit-test| mjitalways;debug
 setDebug(true);
 
 function nop(){}
 function caller(code, obj) {
   eval(code); // Make the compiler give up on binding analysis.
   return x;
 }
-trap(caller, 15, "var x = 'success'; nop()");
+trap(caller, 20, "var x = 'success'; nop()");
 assertEq(caller("var y = 'ignominy'", this), "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in main. */
-  a = { valueOf: function () { trap(main, 84, "success()"); } };
+  a = { valueOf: function () { trap(main, 89, "success()"); } };
   b = "";
   eval();
   a + b;
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -173,24 +173,24 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
     PodZero(codeArray, length);
 
     /*
      * Populate arg and local slots which can escape and be accessed in ways
      * other than through ARG* and LOCAL* opcodes (though arguments can still
      * be indirectly read but not written through 'arguments' properties).
      * All escaping locals are treated as having possible use-before-defs.
-     * Conservatively use 'mayNeedArgsObj' instead of 'needsArgsObj'
+     * Conservatively use 'hasArgsBinding' instead of 'needsArgsObj'
      * (needsArgsObj requires SSA which requires escapedSlots).
      */
 
     PodZero(escapedSlots, numSlots);
 
-    if (script->bindingsAccessedDynamically || script->mayNeedArgsObj() ||
-        script->compartment()->debugMode())
+    if (script->bindingsAccessedDynamically || script->compartment()->debugMode() ||
+        script->argumentsHasLocalBinding())
     {
         for (unsigned i = 0; i < nargs; i++)
             escapedSlots[ArgSlot(i)] = true;
     } else {
         for (uint32_t i = 0; i < script->numClosedArgs(); i++) {
             unsigned arg = script->getClosedArg(i);
             JS_ASSERT(arg < nargs);
             escapedSlots[ArgSlot(arg)] = true;
@@ -216,17 +216,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
         usesReturnValue_ = true;
 
     bool heavyweight = script->function() && script->function()->isHeavyweight();
 
     isCompileable = true;
 
     isInlineable = true;
     if (script->numClosedArgs() || script->numClosedVars() || heavyweight ||
-        script->bindingsAccessedDynamically || script->mayNeedArgsObj() ||
+        script->bindingsAccessedDynamically || script->argumentsHasLocalBinding() ||
         cx->compartment->debugMode())
     {
         isInlineable = false;
     }
 
     modifiesArguments_ = false;
     if (script->numClosedArgs() || heavyweight)
         modifiesArguments_ = true;
@@ -703,23 +703,18 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
     ranBytecode_ = true;
 
     /*
      * Always ensure that a script's arguments usage has been analyzed before
      * entering the script. This allows the functionPrologue to ensure that
      * arguments are always created eagerly which simplifies interp logic.
      */
-    if (!script->analyzedArgsUsage()) {
-        if (!script->mayNeedArgsObj())
-            script->setNeedsArgsObj(false);
-        else
-            analyzeSSA(cx);
-        JS_ASSERT_IF(!failed(), script->analyzedArgsUsage());
-    }
+    if (!script->analyzedArgsUsage())
+        analyzeSSA(cx);
 }
 
 /////////////////////////////////////////////////////////////////////
 // Lifetime Analysis
 /////////////////////////////////////////////////////////////////////
 
 void
 ScriptAnalysis::analyzeLifetimes(JSContext *cx)
@@ -1633,84 +1628,20 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
 
         offset = successorOffset;
     }
 
     ranSSA_ = true;
 
     /*
      * Now that we have full SSA information for the script, analyze whether
-     * the arguments object is actually needed. The first pass performed by the
-     * frontend just looked for the 'arguments' keyword. Here, we can see how
-     * 'arguments' is used and optimize several cases where we can read values
-     * from the stack frame directly.
-     */
-    if (script->analyzedArgsUsage())
-        return;
-
-    /* Ensured by analyzeBytecode. */
-    JS_ASSERT(script->function());
-    JS_ASSERT(script->mayNeedArgsObj());
-    JS_ASSERT(!script->bindingsAccessedDynamically);
-
-    /*
-     * Since let variables are not tracked, we cannot soundly perform this
-     * analysis in their presence.
-     */
-    if (localsAliasStack()) {
-        script->setNeedsArgsObj(true);
-        return;
-    }
-
-    /*
-     * In the case of 'f.apply(x, arguments)', we want to avoid creating
-     * 'arguments' eagerly: 'f.apply' can read directly out of the frame.
-     * However, if 'f.apply' turns out to not be Function.prototype.apply, we
-     * need to set flip script->needsArgsObj and fix up all stack frames. To
-     * avoid a full stack scan (to find outstanding JS_OPTIMIZED_APPLY magic
-     * values), we only apply this optimization when there are no other uses of
-     * 'arguments' in the function. See Script::applySpeculationFailed.
-     * Also, to simplify logic involving closed-over variables and call
-     * objects, we skip the optimization for heavyweight functions.
+     * we can avoid creating the arguments object.
      */
-    bool canOptimizeApply = !script->function()->isHeavyweight();
-    bool haveOptimizedApply = false;
-
-    jsbytecode *pc;
-    for (offset = 0; offset < script->length; offset += GetBytecodeLength(pc)) {
-        pc = script->code + offset;
-
-        /* Ensured by NewScriptFromEmitter. */
-        JS_ASSERT_IF(script->strictModeCode, *pc != JSOP_SETARG);
-
-        /* The front-end took care of dynamic ways to name 'arguments'. */
-        if (JSOp(*pc) != JSOP_ARGUMENTS)
-            continue;
-
-        /* A null Bytecode* means unreachable. */
-        if (!maybeCode(offset))
-            continue;
-
-        if (SpeculateApplyOptimization(pc) && canOptimizeApply) {
-            haveOptimizedApply = true;
-            continue;
-        }
-
-        Vector<SSAValue> seen(cx);
-        if (haveOptimizedApply ||
-            !followEscapingArguments(cx, SSAValue::PushedValue(offset, 0), &seen))
-        {
-            script->setNeedsArgsObj(true);
-            return;
-        }
-
-        canOptimizeApply = false;
-    }
-
-    script->setNeedsArgsObj(false);
+    if (!script->analyzedArgsUsage())
+        script->setNeedsArgsObj(needsArgsObj(cx));
 }
 
 /* Get a phi node's capacity for a given length. */
 static inline unsigned
 PhiNodeCapacity(unsigned length)
 {
     if (length <= 4)
         return 4;
@@ -1984,82 +1915,120 @@ ScriptAnalysis::freezeNewValues(JSContex
     for (unsigned i = 0; i < count; i++)
         code.newValues[i] = (*pending)[i];
     code.newValues[count].slot = 0;
     code.newValues[count].value.clear();
 
     cx->delete_(pending);
 }
 
+struct NeedsArgsObjState
+{
+    JSContext *cx;
+    Vector<SSAValue, 16> seen;
+    bool canOptimizeApply;
+    bool haveOptimizedApply;
+    NeedsArgsObjState(JSContext *cx)
+      : cx(cx), seen(cx), canOptimizeApply(true), haveOptimizedApply(false) {}
+};
+
 bool
-ScriptAnalysis::followEscapingArguments(JSContext *cx, const SSAValue &v, Vector<SSAValue> *seen)
+ScriptAnalysis::needsArgsObj(NeedsArgsObjState &state, const SSAValue &v)
 {
     /*
      * trackUseChain is false for initial values of variables, which
      * cannot hold the script's arguments object.
      */
     if (!trackUseChain(v))
-        return true;
+        return false;
 
-    for (unsigned i = 0; i < seen->length(); i++) {
-        if (v == (*seen)[i])
-            return true;
+    for (unsigned i = 0; i < state.seen.length(); i++) {
+        if (v == state.seen[i])
+            return false;
     }
-    if (!seen->append(v)) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return false;
+    if (!state.seen.append(v)) {
+        state.cx->compartment->types.setPendingNukeTypes(state.cx);
+        return true;
     }
 
     SSAUseChain *use = useChain(v);
     while (use) {
-        if (!followEscapingArguments(cx, use, seen))
-            return false;
+        if (needsArgsObj(state, use))
+            return true;
         use = use->next;
     }
 
+    return false;
+}
+
+bool
+ScriptAnalysis::needsArgsObj(NeedsArgsObjState &state, SSAUseChain *use)
+{
+    if (!use->popped)
+        return needsArgsObj(state, SSAValue::PhiValue(use->offset, use->u.phi));
+
+    jsbytecode *pc = script->code + use->offset;
+    JSOp op = JSOp(*pc);
+
+    if (op == JSOP_POP || op == JSOP_POPN)
+        return false;
+
+    /* SplatApplyArgs can read fp->canonicalActualArg(i) directly. */
+    if (state.canOptimizeApply && op == JSOP_FUNAPPLY && GET_ARGC(pc) == 2 && use->u.which == 0) {
+        JS_ASSERT(mjit::IsLowerableFunCallOrApply(pc));
+        state.haveOptimizedApply = true;
+        state.canOptimizeApply = false;
+        return false;
+    }
+
+    /* arguments[i] can read fp->canonicalActualArg(i) directly. */
+    if (!state.haveOptimizedApply && op == JSOP_GETELEM && use->u.which == 1) {
+        state.canOptimizeApply = false;
+        return false;
+    }
+
+    /* arguments.length length can read fp->numActualArgs() directly. */
+    if (!state.haveOptimizedApply && op == JSOP_LENGTH) {
+        state.canOptimizeApply = false;
+        return false;
+    }
+
+    /* Allow assignments to non-closed locals (but not arguments). */
+
+    if (op == JSOP_SETLOCAL) {
+        uint32_t slot = GetBytecodeSlot(script, pc);
+        if (!trackSlot(slot))
+            return true;
+        return needsArgsObj(state, SSAValue::PushedValue(use->offset, 0)) ||
+               needsArgsObj(state, SSAValue::WrittenVar(slot, use->offset));
+    }
+
+    if (op == JSOP_GETLOCAL)
+        return needsArgsObj(state, SSAValue::PushedValue(use->offset, 0));
+
     return true;
 }
 
 bool
-ScriptAnalysis::followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<SSAValue> *seen)
+ScriptAnalysis::needsArgsObj(JSContext *cx)
 {
-    if (!use->popped)
-        return followEscapingArguments(cx, SSAValue::PhiValue(use->offset, use->u.phi), seen);
-
-    jsbytecode *pc = script->code + use->offset;
-    uint32_t which = use->u.which;
+    JS_ASSERT(script->argumentsHasLocalBinding());
 
-    JSOp op = JSOp(*pc);
-
-    if (op == JSOP_POP || op == JSOP_POPN)
-        return true;
-
-    /* arguments[i] can read fp->canonicalActualArg(i) directly. */
-    if (op == JSOP_GETELEM && which == 1)
+    /*
+     * Since let variables and dynamic name access are not tracked, we cannot
+     * soundly perform this analysis in their presence. Also, debuggers may
+     * want to see 'arguments', so assume every arguments object escapes.
+     */
+    if (script->bindingsAccessedDynamically || localsAliasStack() || cx->compartment->debugMode())
         return true;
 
-    /* arguments.length length can read fp->numActualArgs() directly. */
-    if (op == JSOP_LENGTH)
-        return true;
-
-    /* Allow assignments to non-closed locals (but not arguments). */
+    unsigned pcOff = script->argumentsBytecode() - script->code;
 
-    if (op == JSOP_SETLOCAL) {
-        uint32_t slot = GetBytecodeSlot(script, pc);
-        if (!trackSlot(slot) || script->strictModeCode)
-            return false;
-        if (!followEscapingArguments(cx, SSAValue::PushedValue(use->offset, 0), seen))
-            return false;
-        return followEscapingArguments(cx, SSAValue::WrittenVar(slot, use->offset), seen);
-    }
-
-    if (op == JSOP_GETLOCAL)
-        return followEscapingArguments(cx, SSAValue::PushedValue(use->offset, 0), seen);
-
-    return false;
+    NeedsArgsObjState state(cx);
+    return needsArgsObj(state, SSAValue::PushedValue(pcOff, 0));
 }
 
 CrossSSAValue
 CrossScriptSSA::foldValue(const CrossSSAValue &cv)
 {
     const Frame &frame = getFrame(cv.frame);
     const SSAValue &v = cv.v;
 
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -823,16 +823,18 @@ class SSAUseChain
 class SlotValue
 {
   public:
     uint32_t slot;
     SSAValue value;
     SlotValue(uint32_t slot, const SSAValue &value) : slot(slot), value(value) {}
 };
 
+struct NeedsArgsObjState;
+
 /* Analysis information about a script. */
 class ScriptAnalysis
 {
     friend class Bytecode;
 
     JSScript *script;
 
     Bytecode **codeArray;
@@ -1062,17 +1064,17 @@ class ScriptAnalysis
     }
 
     /* Whether an arithmetic operation is operating on integers, with an integer result. */
     bool integerOperation(JSContext *cx, jsbytecode *pc);
 
     bool trackUseChain(const SSAValue &v) {
         JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
         return v.kind() != SSAValue::EMPTY &&
-            (v.kind() != SSAValue::VAR || !v.varInitial());
+               (v.kind() != SSAValue::VAR || !v.varInitial());
     }
 
     /*
      * Get the use chain for an SSA value. May be invalid for some opcodes in
      * scripts where localsAliasStack(). You have been warned!
      */
     SSAUseChain *& useChain(const SSAValue &v) {
         JS_ASSERT(trackUseChain(v));
@@ -1220,18 +1222,19 @@ class ScriptAnalysis
         types::TypeSet *forTypes;
         TypeInferenceState(JSContext *cx)
             : phiNodes(cx), hasGetSet(false), hasHole(false), forTypes(NULL)
         {}
     };
 
     /* Type inference helpers */
     bool analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state);
-    bool followEscapingArguments(JSContext *cx, const SSAValue &v, Vector<SSAValue> *seen);
-    bool followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<SSAValue> *seen);
+    bool needsArgsObj(NeedsArgsObjState &state, const SSAValue &v);
+    bool needsArgsObj(NeedsArgsObjState &state, SSAUseChain *use);
+    bool needsArgsObj(JSContext *cx);
 
   public:
 #ifdef DEBUG
     void assertMatchingDebugMode();
 #else
     void assertMatchingDebugMode() { }
 #endif
 };
@@ -1348,24 +1351,16 @@ class CrossScriptSSA
     Frame outerFrame;
     Vector<Frame> inlineFrames;
 };
 
 #ifdef DEBUG
 void PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc);
 #endif
 
-static inline bool
-SpeculateApplyOptimization(jsbytecode *pc)
-{
-    JS_ASSERT(*pc == JSOP_ARGUMENTS);
-    jsbytecode *nextpc = pc + JSOP_ARGUMENTS_LENGTH;
-    return *nextpc == JSOP_FUNAPPLY && GET_ARGC(nextpc) == 2;
-}
-
 } /* namespace analyze */
 } /* namespace js */
 
 namespace js {
 namespace tl {
 
 template <> struct IsPodType<js::analyze::LifetimeVariable> { static const bool result = true; };
 template <> struct IsPodType<js::analyze::LoopAnalysis>     { static const bool result = true; };
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -422,17 +422,17 @@ JS_PUBLIC_API(unsigned)
 JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
 {
     return fun->nargs;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun)
 {
-    return fun->script()->bindings.hasLocalNames();
+    return fun->script()->bindings.count() > 0;
 }
 
 extern JS_PUBLIC_API(uintptr_t *)
 JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp)
 {
     Vector<JSAtom *> localNames(cx);
     if (!fun->script()->bindings.getLocalNameArray(cx, &localNames))
         return NULL;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -424,17 +424,17 @@ js::XDRInterpretedFunction(XDRState<mode
     if (mode == XDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16_t(flagsword);
         fun->atom.init(atom);
         fun->initScript(script);
         if (!script->typeSetFunction(cx, fun))
             return false;
-        JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
+        JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
         *objp = fun;
     }
 
     return true;
 }
 
 template bool
@@ -856,17 +856,17 @@ fun_isGenerator(JSContext *cx, unsigned 
         JS_SET_RVAL(cx, vp, BooleanValue(false));
         return true;
     }
 
     bool result = false;
     if (fun->isInterpreted()) {
         JSScript *script = fun->script();
         JS_ASSERT(script->length != 0);
-        result = script->code[0] == JSOP_GENERATOR;
+        result = script->isGenerator;
     }
 
     JS_SET_RVAL(cx, vp, BooleanValue(result));
     return true;
 }
 #endif
 
 /* ES5 15.3.4.5. */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3250,20 +3250,18 @@ ScriptAnalysis::resolveNameAccess(JSCont
         /*
          * Don't resolve names in scripts which use 'let' or 'with'. New names
          * bound here can mask variables of the script itself.
          *
          * Also, don't resolve names in scripts which are generators. Frame
          * balancing works differently for generators and we do not maintain
          * active frame counts for such scripts.
          */
-        if (script->analysis()->addsScopeObjects() ||
-            JSOp(*script->code) == JSOP_GENERATOR) {
+        if (script->analysis()->addsScopeObjects() || script->isGenerator)
             return access;
-        }
 
         /* Check if the script definitely binds the identifier. */
         unsigned index;
         BindingKind kind = script->bindings.lookup(cx, atom, &index);
         if (kind == ARGUMENT || kind == VARIABLE) {
             TypeObject *obj = script->function()->getType(cx);
 
             if (addDependency) {
@@ -3663,17 +3661,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         break;
       }
 
       case JSOP_ARGUMENTS:
         /* Compute a precise type only when we know the arguments won't escape. */
         if (script->needsArgsObj())
             pushed[0].addType(cx, Type::UnknownType());
         else
-            pushed[0].addType(cx, Type::LazyArgsType());
+            pushed[0].addType(cx, Type::MagicArgType());
         break;
 
       case JSOP_SETPROP: {
         jsid id = GetAtomId(cx, script, pc, 0);
         poppedTypes(pc, 1)->addSetProperty(cx, script, pc, poppedTypes(pc, 0), id);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
@@ -4126,21 +4124,18 @@ ScriptAnalysis::analyzeTypes(JSContext *
         }
 
 
         if (!detached) {
             /*
              * Don't track for parents which add call objects or are generators,
              * don't resolve NAME accesses into the parent.
              */
-            if (nesting->parent->analysis()->addsScopeObjects() || 
-                JSOp(*nesting->parent->code) == JSOP_GENERATOR)
-            {
+            if (nesting->parent->analysis()->addsScopeObjects() || nesting->parent->isGenerator)
                 DetachNestingParent(script);
-            }
         }
     }
 
     TypeInferenceState state(cx);
 
     unsigned offset = 0;
     while (offset < script->length) {
         Bytecode *code = maybeCode(offset);
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -138,17 +138,17 @@ class Type
     bool operator != (Type o) const { return data != o.data; }
 
     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
     static inline Type DoubleType()    { return Type(JSVAL_TYPE_DOUBLE); }
     static inline Type StringType()    { return Type(JSVAL_TYPE_STRING); }
-    static inline Type LazyArgsType()  { return Type(JSVAL_TYPE_MAGIC); }
+    static inline Type MagicArgType()  { return Type(JSVAL_TYPE_MAGIC); }
     static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
     static inline Type UnknownType()   { return Type(JSVAL_TYPE_UNKNOWN); }
 
     static inline Type PrimitiveType(JSValueType type) {
         JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
         return Type(type);
     }
 
@@ -463,17 +463,17 @@ class TypeSet
      */
 
     /* Completely freeze the contents of this type set. */
     void addFreeze(JSContext *cx);
 
     /* Get any type tag which all values in this set must have. */
     JSValueType getKnownTypeTag(JSContext *cx);
 
-    bool isLazyArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
+    bool isMagicArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
 
     /* Whether the type set or a particular object has any of a set of flags. */
     bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
     static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
 
     /*
      * Watch for a generic object state change on a type object. This currently
      * includes reallocations of slot pointers for global objects, and changes
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2650,25 +2650,18 @@ BEGIN_CASE(JSOP_EVAL)
     }
     CHECK_INTERRUPT_HANDLER();
     regs.sp = args.spAfterCall();
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 BEGIN_CASE(JSOP_FUNAPPLY)
-    if (regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
-        CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
-        if (!IsNativeFunction(args.calleev(), js_fun_apply)) {
-            JS_ASSERT(args.length() == 2);
-            if (!script->applySpeculationFailed(cx))
-                goto error;
-            args[1] = ObjectValue(regs.fp()->argsObj());
-        }
-    }
+    if (!GuardFunApplySpeculation(cx, regs))
+        goto error;
     /* FALL THROUGH */
 
 BEGIN_CASE(JSOP_NEW)
 BEGIN_CASE(JSOP_CALL)
 BEGIN_CASE(JSOP_FUNCALL)
 {
     CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
     JS_ASSERT(args.base() >= regs.fp()->base());
@@ -2978,20 +2971,24 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
 
   end_lookup_switch:
     len = GET_JUMP_OFFSET(pc2);
 }
 END_VARLEN_CASE
 }
 
 BEGIN_CASE(JSOP_ARGUMENTS)
-    if (script->needsArgsObj())
-        PUSH_COPY(ObjectValue(regs.fp()->argsObj()));
-    else
+    if (script->needsArgsObj()) {
+        ArgumentsObject *obj = ArgumentsObject::create(cx, regs.fp());
+        if (!obj)
+            goto error;
+        PUSH_COPY(ObjectValue(*obj));
+    } else {
         PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
+    }
 END_CASE(JSOP_ARGUMENTS)
 
 BEGIN_CASE(JSOP_GETARG)
 BEGIN_CASE(JSOP_CALLARG)
     PUSH_COPY(regs.fp()->formalArg(GET_ARGNO(regs.pc)));
 END_CASE(JSOP_GETARG)
 
 BEGIN_CASE(JSOP_SETARG)
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -866,11 +866,25 @@ GreaterThanOperation(JSContext *cx, cons
 
 static JS_ALWAYS_INLINE bool
 GreaterThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
     RELATIONAL_OP(>=);
 }
 
 #undef RELATIONAL_OP
 
+static inline bool
+GuardFunApplySpeculation(JSContext *cx, FrameRegs &regs)
+{
+    if (regs.sp[-1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
+        CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
+        if (!IsNativeFunction(args.calleev(), js_fun_apply)) {
+            if (!regs.fp()->script()->applySpeculationFailed(cx))
+                return false;
+            args[1] = ObjectValue(regs.fp()->argsObj());
+        }
+    }
+    return true;
+}
+
 }  /* namespace js */
 
 #endif /* jsinterpinlines_h__ */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1101,17 +1101,17 @@ js_NewPrinter(JSContext *cx, const char 
     jp->grouped = !!grouped;
     jp->strict = !!strict;
     jp->script = NULL;
     jp->dvgfence = NULL;
     jp->pcstack = NULL;
     jp->fun = fun;
     jp->localNames = NULL;
     jp->decompiledOpcodes = NULL;
-    if (fun && fun->isInterpreted() && fun->script()->bindings.hasLocalNames()) {
+    if (fun && fun->isInterpreted() && fun->script()->bindings.count() > 0) {
         jp->localNames = cx->new_<Vector<JSAtom *> >(cx);
         if (!jp->localNames || !fun->script()->bindings.getLocalNameArray(cx, jp->localNames)) {
             js_DestroyPrinter(jp);
             return NULL;
         }
     }
     return jp;
 }
@@ -1750,17 +1750,17 @@ DecompileSwitch(SprintStack *ss, TableEn
 
 #define LOCAL_ASSERT_RV(expr, rv)                                             \
     LOCAL_ASSERT_CUSTOM(expr, return (rv))
 
 static JSAtom *
 GetArgOrVarAtom(JSPrinter *jp, unsigned slot)
 {
     LOCAL_ASSERT_RV(jp->fun, NULL);
-    LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.countLocalNames(), NULL);
+    LOCAL_ASSERT_RV(slot < jp->fun->script()->bindings.count(), NULL);
     JSAtom *name = (*jp->localNames)[slot];
 #if !JS_HAS_DESTRUCTURING
     LOCAL_ASSERT_RV(name, NULL);
 #endif
     return name;
 }
 
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, "")
@@ -4658,17 +4658,17 @@ Decompile(SprintStack *ss, jsbytecode *p
 
                     /*
                      * All allocation when decompiling is LIFO, using malloc or,
                      * more commonly, arena-allocating from cx->tempLifoAlloc
                      * Therefore after InitSprintStack succeeds, we must release
                      * to mark before returning.
                      */
                     LifoAllocScope las(&cx->tempLifoAlloc());
-                    if (fun->script()->bindings.hasLocalNames()) {
+                    if (fun->script()->bindings.count() > 0) {
                         innerLocalNames = cx->new_<Vector<JSAtom *> >(cx);
                         if (!innerLocalNames ||
                             !fun->script()->bindings.getLocalNameArray(cx, innerLocalNames))
                         {
                             return NULL;
                         }
                     } else {
                         innerLocalNames = NULL;
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -118,17 +118,17 @@ OPDEF(JSOP_POPV,      2,  "popv",       
 OPDEF(JSOP_ENTERWITH, 3,  "enterwith",  NULL,         1,  1,  1,  0,  JOF_BYTE|JOF_PARENHEAD)
 OPDEF(JSOP_LEAVEWITH, 4,  "leavewith",  NULL,         1,  1,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_RETURN,    5,  "return",     NULL,         1,  1,  0,  2,  JOF_BYTE)
 OPDEF(JSOP_GOTO,      6,  "goto",       NULL,         5,  0,  0,  0,  JOF_JUMP)
 OPDEF(JSOP_IFEQ,      7,  "ifeq",       NULL,         5,  1,  0,  4,  JOF_JUMP|JOF_DETECTING)
 OPDEF(JSOP_IFNE,      8,  "ifne",       NULL,         5,  1,  0,  0,  JOF_JUMP|JOF_PARENHEAD)
 
 /* Get the arguments object for the current, lightweight function activation. */
-OPDEF(JSOP_ARGUMENTS, 9, js_arguments_str, js_arguments_str, 1, 0, 1, 18, JOF_BYTE)
+OPDEF(JSOP_ARGUMENTS, 9,  "arguments",  NULL,         1,  0,  1,  0,  JOF_BYTE)
 
 OPDEF(JSOP_SWAP,      10, "swap",       NULL,         1,  2,  2,  0,  JOF_BYTE)
 OPDEF(JSOP_POPN,      11, "popn",       NULL,         3, -1,  0,  0,  JOF_UINT16)
 
 /* More long-standing bytecodes. */
 OPDEF(JSOP_DUP,       12, "dup",        NULL,         1,  1,  2,  0,  JOF_BYTE)
 OPDEF(JSOP_DUP2,      13, "dup2",       NULL,         1,  2,  4,  0,  JOF_BYTE)
 OPDEF(JSOP_SETCONST,  14, "setconst",   NULL,         5,  1,  1,  3,  JOF_ATOM|JOF_NAME|JOF_SET)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -212,22 +212,22 @@ Bindings::callObjectShape(JSContext *cx)
 
     return shape;
 }
 
 bool
 Bindings::getLocalNameArray(JSContext *cx, Vector<JSAtom *> *namesp)
 {
     JS_ASSERT(lastBinding);
-    JS_ASSERT(hasLocalNames());
+    JS_ASSERT(count() > 0);
 
     Vector<JSAtom *> &names = *namesp;
     JS_ASSERT(names.empty());
 
-    unsigned n = countLocalNames();
+    unsigned n = count();
     if (!names.growByUninitialized(n))
         return false;
 
 #ifdef DEBUG
     JSAtom * const POISON = reinterpret_cast<JSAtom *>(0xdeadbeef);
     for (unsigned i = 0; i < n; i++)
         names[i] = POISON;
 #endif
@@ -393,20 +393,21 @@ template<XDRMode mode>
 bool
 js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
 {
     enum ScriptBits {
         NoScriptRval,
         SavedCallerFun,
         StrictModeCode,
         ContainsDynamicNameAccess,
-        MayNeedArgsObj,
+        ArgumentsHasLocalBinding,
         NeedsArgsObj,
         OwnFilename,
-        ParentFilename
+        ParentFilename,
+        IsGenerator
     };
 
     uint32_t length, lineno, nslots;
     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, nClosedArgs, nClosedVars, i;
     uint32_t prologLength, version;
     uint32_t nTypeSets = 0;
     uint32_t scriptBits = 0;
 
@@ -424,18 +425,18 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
     uint32_t argsVars;
     if (mode == XDR_ENCODE) {
         script = *scriptp;
         JS_ASSERT_IF(parentScript, parentScript->compartment() == script->compartment());
     
         /* Should not XDR scripts optimized for a single global object. */
         JS_ASSERT(!JSScript::isValidOffset(script->globalsOffset));
 
-        nargs = script->bindings.countArgs();
-        nvars = script->bindings.countVars();
+        nargs = script->bindings.numArgs();
+        nvars = script->bindings.numVars();
         argsVars = (nargs << 16) | nvars;
     }
     if (!xdr->codeUint32(&argsVars))
         return false;
     if (mode == XDR_DECODE) {
         nargs = argsVars >> 16;
         nvars = argsVars & 0xFFFF;
     }
@@ -549,31 +550,27 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
         if (script->noScriptRval)
             scriptBits |= (1 << NoScriptRval);
         if (script->savedCallerFun)
             scriptBits |= (1 << SavedCallerFun);
         if (script->strictModeCode)
             scriptBits |= (1 << StrictModeCode);
         if (script->bindingsAccessedDynamically)
             scriptBits |= (1 << ContainsDynamicNameAccess);
-        if (script->mayNeedArgsObj()) {
-            scriptBits |= (1 << MayNeedArgsObj);
-            /*
-             * In some cases, the front-end calls setNeedsArgsObj when the
-             * script definitely needsArgsObj; preserve this information which
-             * would otherwise be lost.
-             */
-            if (script->analyzedArgsUsage() && script->needsArgsObj())
-                scriptBits |= (1 << NeedsArgsObj);
-        }
+        if (script->argumentsHasLocalBinding())
+            scriptBits |= (1 << ArgumentsHasLocalBinding);
+        if (script->analyzedArgsUsage() && script->needsArgsObj())
+            scriptBits |= (1 << NeedsArgsObj);
         if (script->filename) {
             scriptBits |= (parentScript && parentScript->filename == script->filename)
                           ? (1 << ParentFilename)
                           : (1 << OwnFilename);
         }
+        if (script->isGenerator)
+            scriptBits |= (1 << IsGenerator);
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
     }
 
     if (!xdr->codeUint32(&prologLength))
         return JS_FALSE;
     if (!xdr->codeUint32(&version))
@@ -626,23 +623,27 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
         if (scriptBits & (1 << NoScriptRval))
             script->noScriptRval = true;
         if (scriptBits & (1 << SavedCallerFun))
             script->savedCallerFun = true;
         if (scriptBits & (1 << StrictModeCode))
             script->strictModeCode = true;
         if (scriptBits & (1 << ContainsDynamicNameAccess))
             script->bindingsAccessedDynamically = true;
-        if (scriptBits & (1 << MayNeedArgsObj)) {
-            script->setMayNeedArgsObj();
-            if (scriptBits & (1 << NeedsArgsObj))
-                script->setNeedsArgsObj(true);
-        } else {
-            JS_ASSERT(!(scriptBits & (1 << NeedsArgsObj)));
+        if (scriptBits & (1 << ArgumentsHasLocalBinding)) {
+            PropertyName *arguments = cx->runtime->atomState.argumentsAtom;
+            unsigned slot;
+            DebugOnly<BindingKind> kind = script->bindings.lookup(cx, arguments, &slot);
+            JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
+            script->setArgumentsHasLocalBinding(slot);
         }
+        if (scriptBits & (1 << NeedsArgsObj))
+            script->setNeedsArgsObj(true);
+        if (scriptBits & (1 << IsGenerator))
+            script->isGenerator = true;
     }
 
     JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
     JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
     if (!xdr->codeBytes(script->code, length) ||
         !xdr->codeBytes(notes, nsrcnotes) ||
         !xdr->codeUint32(&lineno) ||
         !xdr->codeUint32(&nslots)) {
@@ -1205,17 +1206,17 @@ JSScript::NewScriptFromEmitter(JSContext
         return NULL;
 
     bce->bindings.makeImmutable();
 
     JS_ASSERT(script->mainOffset == 0);
     script->mainOffset = prologLength;
     PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength);
     PodCopy<jsbytecode>(script->main(), bce->base(), mainLength);
-    nfixed = bce->inFunction() ? bce->bindings.countVars() : 0;
+    nfixed = bce->inFunction() ? bce->bindings.numVars() : 0;
     JS_ASSERT(nfixed < SLOTNO_LIMIT);
     script->nfixed = uint16_t(nfixed);
     InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms);
 
     filename = bce->parser->tokenStream.getFilename();
     if (filename) {
         script->filename = SaveScriptFilename(cx, filename);
         if (!script->filename)
@@ -1262,29 +1263,23 @@ JSScript::NewScriptFromEmitter(JSContext
         const StackFrame *fp = bce->parser->callerFrame;
         if (fp && fp->isFunctionFrame())
             script->savedCallerFun = true;
     }
     if (bce->bindingsAccessedDynamically())
         script->bindingsAccessedDynamically = true;
     if (bce->flags & TCF_HAS_SINGLETONS)
         script->hasSingletons = true;
+    if (bce->flags & TCF_FUN_IS_GENERATOR)
+        script->isGenerator = true;
 
-    /*
-     * The arguments-usage analysis in analyzeSSA only looks at
-     * JSOP_ARGUMENTS use. Therefore, anything else that definitely requires an
-     * arguments object needs to be accounted for here.
-     */
-    if (bce->inFunction()) {
-        bool needsArgsObj = bce->mayOverwriteArguments() || bce->needsEagerArguments();
-        if (needsArgsObj || bce->usesArguments()) {
-            script->setMayNeedArgsObj();
-            if (needsArgsObj)
-                script->setNeedsArgsObj(true);
-        }
+    if (bce->argumentsHasLocalBinding()) {
+        script->setArgumentsHasLocalBinding(bce->argumentsLocalSlot());
+        if (bce->definitelyNeedsArgsObj())
+            script->setNeedsArgsObj(true);
     }
 
     if (bce->globalUses.length()) {
         PodCopy<GlobalSlotArray::Entry>(script->globals()->vector, &bce->globalUses[0],
                                         bce->globalUses.length());
     }
 
     if (nClosedArgs)
@@ -1873,73 +1868,83 @@ JSScript::markChildren(JSTracer *trc)
             BreakpointSite *site = debug->breakpoints[i];
             if (site && site->trapHandler)
                 MarkValue(trc, &site->trapClosure, "trap closure");
         }
     }
 }
 
 void
+JSScript::setArgumentsHasLocalBinding(uint16_t slot)
+{
+    argsHasLocalBinding_ = true;
+    argsSlot_ = slot;
+    needsArgsAnalysis_ = true;
+}
+
+void
 JSScript::setNeedsArgsObj(bool needsArgsObj)
 {
-    JS_ASSERT(!analyzedArgsUsage_);
-    analyzedArgsUsage_ = true;
+    JS_ASSERT(!analyzedArgsUsage());
+    JS_ASSERT_IF(needsArgsObj, argumentsHasLocalBinding());
+    needsArgsAnalysis_ = false;
     needsArgsObj_ = needsArgsObj;
 }
 
 bool
 JSScript::applySpeculationFailed(JSContext *cx)
 {
     JS_ASSERT(analyzedArgsUsage());
+    JS_ASSERT(argumentsHasLocalBinding());
     JS_ASSERT(!needsArgsObj());
     needsArgsObj_ = true;
 
+    const unsigned slot = argumentsLocalSlot();
+
     /*
      * By design, the apply-arguments optimization is only made when there
      * are no outstanding cases of MagicValue(JS_OPTIMIZED_ARGUMENTS) other
      * than this particular invocation of 'f.apply(x, arguments)'. Thus, there
      * are no outstanding values of MagicValue(JS_OPTIMIZED_ARGUMENTS) on the
      * stack. However, there are three things that need fixup:
      *  - there may be any number of activations of this script that don't have
      *    an argsObj that now need one.
      *  - jit code compiled (and possible active on the stack) with the static
      *    assumption of !script->needsArgsObj();
      *  - type inference data for the script assuming script->needsArgsObj; and
      */
     for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) {
         StackFrame *fp = i.fp();
         if (fp->isFunctionFrame() && fp->script() == this) {
-            if (!fp->hasArgsObj() && !ArgumentsObject::create(cx, fp)) {
-                /*
-                 * We can't leave stack frames where fp->script->needsArgsObj
-                 * and !fp->hasArgsObj. It is, however, safe to leave frames
-                 * where fp->hasArgsObj and !fp->script->needsArgsObj.
-                 */
-                needsArgsObj_ = false;
-                return false;
+            if (!fp->hasArgsObj()) {
+                ArgumentsObject *obj = ArgumentsObject::create(cx, fp);
+                if (!obj) {
+                    /*
+                     * We can't leave stack frames where script->needsArgsObj
+                     * and !fp->hasArgsObj. It is, however, safe to leave frames
+                     * where fp->hasArgsObj and !fp->script->needsArgsObj.
+                     */
+                    needsArgsObj_ = false;
+                    return false;
+                }
+                fp->localSlot(slot) = ObjectValue(*obj);
             }
         }
     }
 
 #ifdef JS_METHODJIT
     if (hasJITCode()) {
         mjit::Recompiler::clearStackReferences(cx->runtime->defaultFreeOp(), this);
         mjit::ReleaseScriptCode(cx->runtime->defaultFreeOp(), this);
     }
 #endif
 
     if (hasAnalysis() && analysis()->ranInference()) {
         types::AutoEnterTypeInference enter(cx);
-        for (unsigned off = 0; off < length; off += GetBytecodeLength(code + off)) {
-            if (code[off] == JSOP_ARGUMENTS) {
-                types::TypeSet *set = analysis()->pushedTypes(off, 0);
-                JS_ASSERT(set->isLazyArguments(cx));
-                set->addType(cx, types::Type::UnknownType());
-            }
-        }
+        types::TypeScript::MonitorUnknown(cx, this, argumentsBytecode());
     }
 
     return true;
 }
 
 #ifdef DEBUG
 bool
 JSScript::varIsAliased(unsigned varSlot)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -136,22 +136,19 @@ class Bindings
 
     /*
      * Clones bindings data from bindings, which must be immutable, into this
      * fresh Bindings instance. A Bindings instance may be cloned multiple
      * times.
      */
     inline void clone(JSContext *cx, Bindings *bindings);
 
-    uint16_t countArgs() const { return nargs; }
-    uint16_t countVars() const { return nvars; }
-
-    unsigned countLocalNames() const { return nargs + nvars; }
-
-    bool hasLocalNames() const { return countLocalNames() > 0; }
+    uint16_t numArgs() const { return nargs; }
+    uint16_t numVars() const { return nvars; }
+    unsigned count() const { return nargs + nvars; }
 
     /* Ensure these bindings have a shape lineage. */
     inline bool ensureShape(JSContext *cx);
 
     /* Return the shape lineage generated for these bindings. */
     inline Shape *lastShape() const;
 
     /*
@@ -445,20 +442,16 @@ struct JSScript : public js::gc::Cell
 
   private:
     js::DebugScript     *debug;
     js::HeapPtrFunction function_;
 
     size_t          useCount;   /* Number of times the script has been called
                                  * or has had backedges taken. Reset if the
                                  * script's JIT code is forcibly discarded. */
-#if JS_BITS_PER_WORD == 32
-    void *padding_;
-#endif
-
     // 32-bit fields.
 
   public:
     uint32_t        length;     /* length of code vector */
 
     uint32_t        lineno;     /* base line number of script */
 
     uint32_t        mainOffset; /* offset of main entry point from code, after
@@ -485,16 +478,19 @@ struct JSScript : public js::gc::Cell
                                    slot array */
 
     uint16_t        nTypeSets;  /* number of type sets used in this script for
                                    dynamic type monitoring */
 
     uint16_t        nslots;     /* vars plus maximum stack depth */
     uint16_t        staticLevel;/* static level for display maintenance */
 
+  private:
+    uint16_t        argsSlot_;  /* slot holding 'arguments' (if argumentsHasLocalBindings) */
+
     // 8-bit fields.
 
   public:
     // Offsets to various array structures from the end of this script, or
     // JSScript::INVALID_OFFSET if the array has length 0.
     uint8_t         constsOffset;   /* offset to the array of constants */
     uint8_t         objectsOffset;  /* offset to the array of nested function,
                                        block, scope, xml and one-time regexps
@@ -530,32 +526,22 @@ struct JSScript : public js::gc::Cell
     bool            uninlineable:1;   /* script is considered uninlineable by analysis */
     bool            reentrantOuterFunction:1; /* outer function marked reentrant */
     bool            typesPurged:1;    /* TypeScript has been purged at some point */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
     bool            callDestroyHook:1;/* need to call destroy hook */
+    bool            isGenerator:1;    /* is a generator */
 
-    /*
-     * An arguments object is created for a function script (when the function
-     * is first called) iff script->needsArgsObj(). There are several cases
-     * where the 'arguments' keyword is technically used but which don't really
-     * need an object (e.g., 'arguments[i]', 'f.apply(null, arguments')'). This
-     * determination is made during script analysis which occurs lazily (right
-     * before a script is run). Thus, the output of the front-end is a
-     * conservative 'mayNeedArgsObj' which leads to further analysis in
-     * analyzeBytecode and analyzeSSA. To avoid the complexity of spurious
-     * argument objects creation, we maintain the invariant that needsArgsObj()
-     * is only queried after this analysis has occurred (analyzedArgsUsage()).
-     */
   private:
-    bool            mayNeedArgsObj_:1;
-    bool            analyzedArgsUsage_:1;
+    /* See comments below. */
+    bool            argsHasLocalBinding_:1;
+    bool            needsArgsAnalysis_:1;
     bool            needsArgsObj_:1;
 
     //
     // End of fields.  Start methods.
     //
 
     /*
      * Two successively less primitive ways to make a new JSScript.  The first
@@ -571,26 +557,37 @@ struct JSScript : public js::gc::Cell
   public:
     static JSScript *NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
                                uint32_t nobjects, uint32_t nregexps,
                                uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
                                uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets,
                                JSVersion version);
     static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
 
-    bool mayNeedArgsObj() const { return mayNeedArgsObj_; }
-    bool analyzedArgsUsage() const { return analyzedArgsUsage_; }
+    /* See TCF_ARGUMENTS_HAS_LOCAL_BINDING comment. */
+    bool argumentsHasLocalBinding() const { return argsHasLocalBinding_; }
+    jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; }
+    unsigned argumentsLocalSlot() const { JS_ASSERT(argsHasLocalBinding_); return argsSlot_; }
+    void setArgumentsHasLocalBinding(uint16_t slot);
+
+    /*
+     * As an optimization, even when argsHasLocalBinding, the function prologue
+     * may not need to create an arguments object. This is determined by
+     * needsArgsObj which is set by ScriptAnalysis::analyzeSSA before running
+     * the script the first time. When !needsArgsObj, the prologue may simply
+     * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
+     * uses of 'arguments' will be guaranteed to handle this magic value.
+     * So avoid spurious arguments object creation, we maintain the invariant
+     * that needsArgsObj is only called after the script has been analyzed.
+     */
+    bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
     bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; }
     void setNeedsArgsObj(bool needsArgsObj);
     bool applySpeculationFailed(JSContext *cx);
 
-    void setMayNeedArgsObj() {
-        mayNeedArgsObj_ = true;
-    }
-
     /* Hash table chaining for JSCompartment::evalCache. */
     JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); }
 
     /*
      * Original compiled function for the script, if it has a function.
      * NULL for global and eval scripts.
      */
     JSFunction *function() const { return function_; }
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -122,17 +122,16 @@ mjit::Compiler::Compiler(JSContext *cx, 
     chunkEdges(CompilerAllocPolicy(cx, *thisFromCtor())),
     stubcc(cx, *thisFromCtor(), frame),
     debugMode_(cx->compartment->debugMode()),
     inlining_(false),
     hasGlobalReallocation(false),
     oomInVector(false),
     overflowICSpace(false),
     gcNumber(cx->runtime->gcNumber),
-    applyTricks(NoApplyTricks),
     pcLengths(NULL)
 {
     /* Once a script starts getting really hot we will inline calls in it. */
     if (!debugMode() && cx->typeInferenceEnabled() && globalObj &&
         (outerScript->getUseCount() >= USES_BEFORE_INLINING ||
          cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS))) {
         inlining_ = true;
     }
@@ -1150,22 +1149,23 @@ mjit::Compiler::generatePrologue()
                 masm.add32(Imm32(1), AbsoluteAddress(&nesting->activeFrames));
 
                 stubcc.linkExitDirect(mismatch, stubcc.masm.label());
                 OOL_STUBCALL(stubs::FunctionFramePrologue, REJOIN_FUNCTION_PROLOGUE);
                 stubcc.crossJump(stubcc.masm.jump(), masm.label());
             }
         }
 
-        if (script->mayNeedArgsObj()) {
-            /*
-             * Make sure that fp->u.nactual is always coherent. This may be
-             * inspected directly by JIT code, and is not guaranteed to be
-             * correct if the UNDERFLOW and OVERFLOW flags are not set.
-             */
+        /*
+         * When 'arguments' is used in the script, it may be optimized away
+         * which involves reading from the stack frame directly, including
+         * fp->u.nactual. fp->u.nactual is only set when numActual != numFormal,
+         * so store 'fp->u.nactual = numFormal' when there is no over/underflow.
+         */
+        if (script->argumentsHasLocalBinding()) {
             Jump hasArgs = masm.branchTest32(Assembler::NonZero, FrameFlagsAddress(),
                                              Imm32(StackFrame::UNDERFLOW_ARGS |
                                                    StackFrame::OVERFLOW_ARGS));
             masm.storePtr(ImmPtr((void *)(size_t) script->function()->nargs),
                           Address(JSFrameReg, StackFrame::offsetOfNumActual()));
             hasArgs.linkTo(masm.label(), &masm);
         }
 
@@ -2225,58 +2225,23 @@ mjit::Compiler::generateMethod()
             if (!jsop_ifneq(op, target))
                 return Compile_Error;
             PC += js_CodeSpec[op].length;
             break;
           }
           END_CASE(JSOP_IFNE)
 
           BEGIN_CASE(JSOP_ARGUMENTS)
-          {
-            /*
-             * For calls of the form 'f.apply(x, arguments)' we can avoid
-             * creating an args object by having ic::SplatApplyArgs pull
-             * directly from the stack. To do this, we speculate here that
-             * 'apply' actually refers to js_fun_apply. If this is not true,
-             * the slow path in JSOP_FUNAPPLY will create the args object.
-             */
-            if (!script->needsArgsObj()) {
-                if (canUseApplyTricks()) {
-                    /*
-                     * Check for interrupts at the JSOP_ARGUMENTS when using
-                     * apply tricks, see inlineCallHelper().
-                     */
-                    interruptCheckHelper();
-
-                    applyTricks = LazyArgsObj;
-                    pushSyncedEntry(0);
-                } else {
-                    /*
-                     * When analyzing whether a script needsArgsObject, the analysis in
-                     * analyzeSSA uses the simple predicate SpeculateApplyOptimization.
-                     * The actual mjit predicate for using the optimization is
-                     * canUseApplyTricks which depends on temporal compiler state.
-                     * Thus, script->needsArgsObj can be over-optimistic and needs to
-                     * be checked here and corrected.
-                     */
-                    if (SpeculateApplyOptimization(PC)) {
-                        if (!script->applySpeculationFailed(cx))
-                            return Compile_Error;
-
-                        /* All our assumptions are wrong, try again. */
-                        return Compile_Retry;
-                    }
-
-                    frame.push(MagicValue(JS_OPTIMIZED_ARGUMENTS));
-                }
+            if (script->needsArgsObj()) {
+                prepareStubCall(Uses(0));
+                INLINE_STUBCALL(stubs::Arguments, REJOIN_FALLTHROUGH);
+                pushSyncedEntry(0);
             } else {
-                jsop_arguments(REJOIN_FALLTHROUGH);
-                pushSyncedEntry(0);
+                frame.push(MagicValue(JS_OPTIMIZED_ARGUMENTS));
             }
-          }
           END_CASE(JSOP_ARGUMENTS)
 
           BEGIN_CASE(JSOP_ITERNEXT)
             iterNext(GET_INT8(PC));
           END_CASE(JSOP_ITERNEXT)
 
           BEGIN_CASE(JSOP_DUP)
             frame.dup();
@@ -3932,30 +3897,18 @@ mjit::Compiler::emitUncachedCall(uint32_
 
     stubcc.linkExitDirect(notCompiled, stubcc.masm.label());
     stubcc.rejoin(Changes(1));
     callPatches.append(callPatch);
 
     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
 }
 
-static bool
-IsLowerableFunCallOrApply(jsbytecode *pc)
-{
-#ifdef JS_MONOIC
-    return (*pc == JSOP_FUNCALL && GET_ARGC(pc) >= 1) ||
-           (*pc == JSOP_FUNAPPLY && GET_ARGC(pc) == 2);
-#else
-    return false;
-#endif
-}
-
 void
-mjit::Compiler::checkCallApplySpeculation(uint32_t callImmArgc, uint32_t speculatedArgc,
-                                          FrameEntry *origCallee, FrameEntry *origThis,
+mjit::Compiler::checkCallApplySpeculation(uint32_t argc, FrameEntry *origCallee, FrameEntry *origThis,
                                           MaybeRegisterID origCalleeType, RegisterID origCalleeData,
                                           MaybeRegisterID origThisType, RegisterID origThisData,
                                           Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch)
 {
     JS_ASSERT(IsLowerableFunCallOrApply(PC));
 
     RegisterID temp;
     Registers tempRegs(Registers::AvailRegs);
@@ -3986,92 +3939,51 @@ mjit::Compiler::checkCallApplySpeculatio
      * assumption that speculation succeeds. Instead, just do an uncached call.
      */
     {
         if (isObj.isSet())
             stubcc.linkExitDirect(isObj.getJump(), stubcc.masm.label());
         stubcc.linkExitDirect(isFun, stubcc.masm.label());
         stubcc.linkExitDirect(isNative, stubcc.masm.label());
 
-        int32_t frameDepthAdjust;
-        if (applyTricks == LazyArgsObj) {
-            OOL_STUBCALL(stubs::Arguments, REJOIN_RESUME);
-            frameDepthAdjust = +1;
-        } else {
-            frameDepthAdjust = 0;
-        }
-
-        stubcc.masm.move(Imm32(callImmArgc), Registers::ArgReg1);
+        stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
         JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
         OOL_STUBCALL_LOCAL_SLOTS(JS_FUNC_TO_DATA_PTR(void *, stubs::SlowCall),
-                                 REJOIN_FALLTHROUGH, frame.totalDepth() + frameDepthAdjust);
+                                 REJOIN_FALLTHROUGH, frame.totalDepth());
         JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
 
         /*
          * 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
-     * communicated dynamically through the VMFrame.
-     */
-    if (*PC == JSOP_FUNAPPLY) {
-        masm.store32(Imm32(applyTricks == LazyArgsObj),
-                     FrameAddress(VMFrame::offsetOfLazyArgsObj()));
-    }
-}
-
-/* This predicate must be called before the current op mutates the FrameState. */
-bool
-mjit::Compiler::canUseApplyTricks()
-{
-    JS_ASSERT(*PC == JSOP_ARGUMENTS);
-    JS_ASSERT(!script->needsArgsObj());
-    jsbytecode *nextpc = PC + JSOP_ARGUMENTS_LENGTH;
-    return *nextpc == JSOP_FUNAPPLY &&
-           IsLowerableFunCallOrApply(nextpc) &&
-           !analysis->jumpTarget(nextpc) &&
-           !debugMode() &&
-           !a->parent &&
-           bytecodeInChunk(nextpc);
 }
 
 /* See MonoIC.cpp, CallCompiler for more information on call ICs. */
 bool
-mjit::Compiler::inlineCallHelper(uint32_t callImmArgc, bool callingNew, FrameSize &callFrameSize)
+mjit::Compiler::inlineCallHelper(uint32_t argc, bool callingNew, FrameSize &callFrameSize)
 {
-    int32_t speculatedArgc;
-    if (applyTricks == LazyArgsObj) {
-        frame.pop();
-        speculatedArgc = 1;
-    } else {
-        /*
-         * Check for interrupts on function call. We don't do this for lazy
-         * arguments objects as the interrupt may kick this frame into the
-         * interpreter, which doesn't know about the apply tricks. Instead, we
-         * do the interrupt check at the start of the JSOP_ARGUMENTS.
-         */
-        interruptCheckHelper();
-
-        speculatedArgc = callImmArgc;
-    }
-
-    FrameEntry *origCallee = frame.peek(-(speculatedArgc + 2));
-    FrameEntry *origThis = frame.peek(-(speculatedArgc + 1));
+    /*
+     * Check for interrupts on function call. We don't do this for lazy
+     * arguments objects as the interrupt may kick this frame into the
+     * interpreter, which doesn't know about the apply tricks. Instead, we
+     * do the interrupt check at the start of the JSOP_ARGUMENTS.
+     */
+    interruptCheckHelper();
+
+    FrameEntry *origCallee = frame.peek(-(int(argc) + 2));
+    FrameEntry *origThis = frame.peek(-(int(argc) + 1));
 
     /*
      * 'this' does not need to be synced for constructing. :FIXME: is it
      * possible that one of the arguments is directly copying the 'this'
      * entry (something like 'new x.f(x)')?
      */
     if (callingNew) {
         frame.discardFe(origThis);
@@ -4083,22 +3995,16 @@ mjit::Compiler::inlineCallHelper(uint32_
          * (i.e. the GC happens on constructing the 'new' object or the call
          * object for a heavyweight callee), it needs to be able to read the
          * 'this' value to tell whether newScript constraints will need to be
          * regenerated afterwards.
          */
         masm.storeValue(NullValue(), frame.addressOf(origThis));
     }
 
-    if (!cx->typeInferenceEnabled()) {
-        CompileStatus status = callArrayBuiltin(callImmArgc, callingNew);
-        if (status != Compile_InlineAbort)
-            return (status == Compile_Okay);
-    }
-
     /*
      * 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.
      *
      * Note: do *NOT* use type information or inline state in any way when
@@ -4108,23 +4014,17 @@ mjit::Compiler::inlineCallHelper(uint32_
      */
     bool lowerFunCallOrApply = IsLowerableFunCallOrApply(PC);
 
     bool newType = callingNew && cx->typeInferenceEnabled() && types::UseNewType(cx, script, PC);
 
 #ifdef JS_MONOIC
     if (debugMode() || newType) {
 #endif
-        if (applyTricks == LazyArgsObj) {
-            /* frame.pop() above reset us to pre-JSOP_ARGUMENTS state */
-            jsop_arguments(REJOIN_RESUME);
-            frame.pushSynced(JSVAL_TYPE_UNKNOWN);
-        }
-        emitUncachedCall(callImmArgc, callingNew);
-        applyTricks = NoApplyTricks;
+        emitUncachedCall(argc, callingNew);
         return true;
 #ifdef JS_MONOIC
     }
 
     frame.forgetMismatchedObject(origCallee);
     if (lowerFunCallOrApply)
         frame.forgetMismatchedObject(origThis);
 
@@ -4168,47 +4068,46 @@ mjit::Compiler::inlineCallHelper(uint32_
             RegisterID origThisData;
             {
                 /* Get thisv in registers. */
                 frame.ensureFullRegs(origThis, &origThisType, &maybeOrigThisData);
                 origThisData = maybeOrigThisData.reg();
                 PinRegAcrossSyncAndKill p3(frame, origThisData), p4(frame, origThisType);
 
                 /* Leaves pinned regs untouched. */
-                frame.syncAndKill(Uses(speculatedArgc + 2));
+                frame.syncAndKill(Uses(argc + 2));
             }
 
-            checkCallApplySpeculation(callImmArgc, speculatedArgc,
-                                      origCallee, origThis,
+            checkCallApplySpeculation(argc, origCallee, origThis,
                                       origCalleeType, origCalleeData,
                                       origThisType, origThisData,
                                       &uncachedCallSlowRejoin, &uncachedCallPatch);
 
             icCalleeType = origThisType;
             icCalleeData = origThisData;
             icRvalAddr = frame.addressOf(origThis);
 
             /*
              * For f.call(), since we compile the ic under the (checked)
              * assumption that call == js_fun_call, we still have a static
              * frame size. For f.apply(), the frame size depends on the dynamic
              * length of the array passed to apply.
              */
             if (*PC == JSOP_FUNCALL)
-                callIC.frameSize.initStatic(frame.totalDepth(), speculatedArgc - 1);
+                callIC.frameSize.initStatic(frame.totalDepth(), argc - 1);
             else
                 callIC.frameSize.initDynamic();
         } else {
             /* Leaves pinned regs untouched. */
-            frame.syncAndKill(Uses(speculatedArgc + 2));
+            frame.syncAndKill(Uses(argc + 2));
 
             icCalleeType = origCalleeType;
             icCalleeData = origCalleeData;
             icRvalAddr = frame.addressOf(origCallee);
-            callIC.frameSize.initStatic(frame.totalDepth(), speculatedArgc);
+            callIC.frameSize.initStatic(frame.totalDepth(), argc);
         }
     }
 
     callFrameSize = callIC.frameSize;
 
     callIC.typeMonitored = monitored(PC) || hasTypeBarriers(PC);
 
     /* Test the type if necessary. Failing this always takes a really slow path. */
@@ -4358,17 +4257,17 @@ mjit::Compiler::inlineCallHelper(uint32_
     /*
      * We've placed hotJump, joinPoint and hotPathLabel, and no other labels are located by offset
      * in the in-line path so we can check the IC space now.
      */
     CHECK_IC_SPACE();
 
     JSValueType type = knownPushedType(0);
 
-    frame.popn(speculatedArgc + 2);
+    frame.popn(argc + 2);
     frame.takeReg(JSReturnReg_Type);
     frame.takeReg(JSReturnReg_Data);
     frame.pushRegs(JSReturnReg_Type, JSReturnReg_Data, type);
 
     BarrierState barrier = testBarrier(JSReturnReg_Type, JSReturnReg_Data,
                                        /* testUndefined = */ false,
                                        /* testReturn = */ true);
 
@@ -4392,110 +4291,20 @@ mjit::Compiler::inlineCallHelper(uint32_
         stubcc.crossJump(uncachedCallSlowRejoin, masm.label());
 
     callICs.append(callIC);
     callPatches.append(callPatch);
     if (lowerFunCallOrApply)
         callPatches.append(uncachedCallPatch);
 
     finishBarrier(barrier, REJOIN_FALLTHROUGH, 0);
-
-    applyTricks = NoApplyTricks;
     return true;
 #endif
 }
 
-CompileStatus
-mjit::Compiler::callArrayBuiltin(uint32_t argc, bool callingNew)
-{
-    if (!globalObj)
-        return Compile_InlineAbort;
-
-    if (applyTricks == LazyArgsObj)
-        return Compile_InlineAbort;
-
-    FrameEntry *origCallee = frame.peek(-((int)argc + 2));
-    if (origCallee->isNotType(JSVAL_TYPE_OBJECT))
-        return Compile_InlineAbort;
-
-    if (frame.extra(origCallee).name != cx->runtime->atomState.classAtoms[JSProto_Array])
-        return Compile_InlineAbort;
-
-    JSObject *arrayObj;
-    if (!js_GetClassObject(cx, globalObj, JSProto_Array, &arrayObj))
-        return Compile_Error;
-
-    JSObject *arrayProto = globalObj->global().getOrCreateArrayPrototype(cx);
-    if (!arrayProto)
-        return Compile_Error;
-
-    if (argc > 1)
-        return Compile_InlineAbort;
-    FrameEntry *origArg = (argc == 1) ? frame.peek(-1) : NULL;
-    if (origArg) {
-        if (origArg->isNotType(JSVAL_TYPE_INT32))
-            return Compile_InlineAbort;
-        if (origArg->isConstant() && origArg->getValue().toInt32() < 0)
-            return Compile_InlineAbort;
-    }
-
-    if (!origCallee->isTypeKnown()) {
-        Jump notObject = frame.testObject(Assembler::NotEqual, origCallee);
-        stubcc.linkExit(notObject, Uses(argc + 2));
-    }
-
-    RegisterID reg = frame.tempRegForData(origCallee);
-    Jump notArray = masm.branchPtr(Assembler::NotEqual, reg, ImmPtr(arrayObj));
-    stubcc.linkExit(notArray, Uses(argc + 2));
-
-    int32_t knownSize = 0;
-    MaybeRegisterID sizeReg;
-    if (origArg) {
-        if (origArg->isConstant()) {
-            knownSize = origArg->getValue().toInt32();
-        } else {
-            if (!origArg->isTypeKnown()) {
-                Jump notInt = frame.testInt32(Assembler::NotEqual, origArg);
-                stubcc.linkExit(notInt, Uses(argc + 2));
-            }
-            sizeReg = frame.tempRegForData(origArg);
-            Jump belowZero = masm.branch32(Assembler::LessThan, sizeReg.reg(), Imm32(0));
-            stubcc.linkExit(belowZero, Uses(argc + 2));
-        }
-    } else {
-        knownSize = 0;
-    }
-
-    stubcc.leave();
-    stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
-    OOL_STUBCALL(callingNew ? stubs::SlowNew : stubs::SlowCall, REJOIN_FALLTHROUGH);
-
-    {
-        PinRegAcrossSyncAndKill p1(frame, sizeReg);
-        frame.popn(argc + 2);
-        frame.syncAndKill(Uses(0));
-    }
-
-    prepareStubCall(Uses(0));
-    masm.storePtr(ImmPtr(arrayProto), FrameAddress(offsetof(VMFrame, scratch)));
-    if (sizeReg.isSet())
-        masm.move(sizeReg.reg(), Registers::ArgReg1);
-    else
-        masm.move(Imm32(knownSize), Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::NewDenseUnallocatedArray, REJOIN_PUSH_OBJECT);
-
-    frame.takeReg(Registers::ReturnReg);
-    frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
-    frame.forgetType(frame.peek(-1));
-
-    stubcc.rejoin(Changes(1));
-
-    return Compile_Okay;
-}
-
 /* Maximum number of calls we will inline at the same site. */
 static const uint32_t INLINE_SITE_LIMIT = 5;
 
 CompileStatus
 mjit::Compiler::inlineScriptedFunction(uint32_t argc, bool callingNew)
 {
     JS_ASSERT(inlining());
 
@@ -4953,17 +4762,17 @@ mjit::Compiler::jsop_getprop(PropertyNam
                 stubcc.rejoin(Changes(1));
             return true;
         }
 
         /*
          * Check if we are accessing the 'length' of the lazy arguments for the
          * current frame.
          */
-        if (types->isLazyArguments(cx)) {
+        if (types->isMagicArguments(cx)) {
             frame.pop();
             frame.pushWord(Address(JSFrameReg, StackFrame::offsetOfNumActual()), JSVAL_TYPE_INT32);
             if (script->scriptCounts)
                 bumpPropCount(PC, PCCounts::PROP_DEFINITE);
             return true;
         }
     }
 
@@ -6679,23 +6488,16 @@ mjit::Compiler::emitEval(uint32_t argc)
     frame.syncAndKill(Uses(argc + 2));
     prepareStubCall(Uses(argc + 2));
     masm.move(Imm32(argc), Registers::ArgReg1);
     INLINE_STUBCALL(stubs::Eval, REJOIN_FALLTHROUGH);
     frame.popn(argc + 2);
     pushSyncedEntry(0);
 }
 
-void
-mjit::Compiler::jsop_arguments(RejoinState rejoin)
-{
-    prepareStubCall(Uses(0));
-    INLINE_STUBCALL(stubs::Arguments, rejoin);
-}
-
 bool
 mjit::Compiler::jsop_newinit()
 {
     bool isArray;
     unsigned count = 0;
     JSObject *baseobj = NULL;
     switch (*PC) {
       case JSOP_NEWINIT:
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -484,17 +484,16 @@ private:
     Jump argsCheckJump;
 #endif
     bool debugMode_;
     bool inlining_;
     bool hasGlobalReallocation;
     bool oomInVector;       // True if we have OOM'd appending to a vector. 
     bool overflowICSpace;   // True if we added a constant pool in a reserved space.
     uint64_t gcNumber;
-    enum { NoApplyTricks, LazyArgsObj } applyTricks;
     PCLengthEntry *pcLengths;
 
     Compiler *thisFromCtor() { return this; }
 
     friend class CompilerAllocPolicy;
   public:
     Compiler(JSContext *cx, JSScript *outerScript, unsigned chunkIndex, bool isConstructing);
     ~Compiler();
@@ -608,17 +607,16 @@ private:
     void finishBarrier(const BarrierState &barrier, RejoinState rejoin, uint32_t which);
 
     void testPushedType(RejoinState rejoin, int which, bool ool = true);
 
     /* Non-emitting helpers. */
     void pushSyncedEntry(uint32_t pushed);
     bool jumpInScript(Jump j, jsbytecode *pc);
     bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
-    bool canUseApplyTricks();
 
     /* Emitting helpers. */
     bool constantFoldBranch(jsbytecode *target, bool taken);
     bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
     bool iter(unsigned flags);
     void iterNext(ptrdiff_t offset);
     bool iterMore(jsbytecode *target);
     void iterEnd();
@@ -664,18 +662,17 @@ private:
     void emitFinalReturn(Assembler &masm);
     void loadReturnValue(Assembler *masm, FrameEntry *fe);
     void emitReturnValue(Assembler *masm, FrameEntry *fe);
     void emitInlineReturnValue(FrameEntry *fe);
     void dispatchCall(VoidPtrStubUInt32 stub, uint32_t argc);
     void interruptCheckHelper();
     void recompileCheckHelper();
     void emitUncachedCall(uint32_t argc, bool callingNew);
-    void checkCallApplySpeculation(uint32_t callImmArgc, uint32_t speculatedArgc,
-                                   FrameEntry *origCallee, FrameEntry *origThis,
+    void checkCallApplySpeculation(uint32_t argc, FrameEntry *origCallee, FrameEntry *origThis,
                                    MaybeRegisterID origCalleeType, RegisterID origCalleeData,
                                    MaybeRegisterID origThisType, RegisterID origThisData,
                                    Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch);
     bool inlineCallHelper(uint32_t argc, bool callingNew, FrameSize &callFrameSize);
     void fixPrimitiveReturn(Assembler *masm, FrameEntry *fe);
     void jsop_getgname(uint32_t index);
     void jsop_getgname_slow(uint32_t index);
     void jsop_setgname(PropertyName *name, bool popGuaranteed);
@@ -689,17 +686,16 @@ private:
     bool jsop_setprop(PropertyName *name, bool popGuaranteed);
     void jsop_setprop_slow(PropertyName *name);
     bool jsop_instanceof();
     void jsop_name(PropertyName *name, JSValueType type);
     bool jsop_xname(PropertyName *name);
     void enterBlock(StaticBlockObject *block);
     void leaveBlock();
     void emitEval(uint32_t argc);
-    void jsop_arguments(RejoinState rejoin);
     bool jsop_tableswitch(jsbytecode *pc);
 
     /* Fast arithmetic. */
     bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
     bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
     void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                           JSValueType type, bool cannotOverflow, bool ignoreOverflow);
     void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
@@ -791,17 +787,16 @@ private:
     static inline Assembler::Condition
     GetStubCompareCondition(JSOp fused)
     {
         return fused == JSOP_IFEQ ? Assembler::Zero : Assembler::NonZero;
     }
 
     /* Fast builtins. */
     JSObject *pushedSingleton(unsigned pushed);
-    CompileStatus callArrayBuiltin(uint32_t argc, bool callingNew);
     CompileStatus inlineNativeFunction(uint32_t argc, bool callingNew);
     CompileStatus inlineScriptedFunction(uint32_t argc, bool callingNew);
     CompileStatus compileMathAbsInt(FrameEntry *arg);
     CompileStatus compileMathAbsDouble(FrameEntry *arg);
     CompileStatus compileMathSqrt(FrameEntry *arg);
     CompileStatus compileMathMinMaxDouble(FrameEntry *arg1, FrameEntry *arg2, 
                                           Assembler::DoubleCondition cond); 
     CompileStatus compileMathMinMaxInt(FrameEntry *arg1, FrameEntry *arg2, 
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -900,19 +900,16 @@ mjit::Compiler::compileParseInt(JSValueT
 }
 
 CompileStatus
 mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
 {
     if (!cx->typeInferenceEnabled())
         return Compile_InlineAbort;
 
-    if (applyTricks == LazyArgsObj)
-        return Compile_InlineAbort;
-
     FrameEntry *origCallee = frame.peek(-((int)argc + 2));
     FrameEntry *thisValue = frame.peek(-((int)argc + 1));
     types::TypeSet *thisTypes = analysis->poppedTypes(PC, argc);
 
     if (!origCallee->isConstant() || !origCallee->isType(JSVAL_TYPE_OBJECT))
         return Compile_InlineAbort;
 
     JSObject *callee = &origCallee->getValue().toObject();
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -2122,17 +2122,17 @@ mjit::Compiler::jsop_getelem()
         jsop_getelem_slow();
         return true;
     }
 
     // If the object is definitely an arguments object, a dense array or a typed array
     // we can generate code directly without using an inline cache.
     if (cx->typeInferenceEnabled() && !id->isType(JSVAL_TYPE_STRING)) {
         types::TypeSet *types = analysis->poppedTypes(PC, 1);
-        if (types->isLazyArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
+        if (types->isMagicArguments(cx) && !outerScript->analysis()->modifiesArguments()) {
             // Inline arguments path.
             jsop_getelem_args();
             return true;
         }
 
         if (obj->mightBeType(JSVAL_TYPE_OBJECT) &&
             !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
             !types::ArrayPrototypeHasIndexedProperty(cx, outerScript)) {
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -167,16 +167,19 @@ InlineReturn(VMFrame &f)
               op == JSOP_FUNCALL ||
               op == JSOP_FUNAPPLY);
     f.regs.pc += JSOP_CALL_LENGTH;
 }
 
 void JS_FASTCALL
 stubs::SlowCall(VMFrame &f, uint32_t argc)
 {
+    if (*f.regs.pc == JSOP_FUNAPPLY && !GuardFunApplySpeculation(f.cx, f.regs))
+        THROW();
+
     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
     if (!InvokeKernel(f.cx, args))
         THROW();
 
     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 }
 
 void JS_FASTCALL
--- a/js/src/methodjit/LoopState.cpp
+++ b/js/src/methodjit/LoopState.cpp
@@ -807,17 +807,17 @@ LoopState::invariantLength(const CrossSS
 
     uint32_t objSlot;
     int32_t objConstant;
     if (!getEntryValue(obj, &objSlot, &objConstant) || objSlot == UNASSIGNED || objConstant != 0)
         return NULL;
     TypeSet *objTypes = ssa->getValueTypes(obj);
 
     /* Check for 'length' on the lazy arguments for the current frame. */
-    if (objTypes->isLazyArguments(cx)) {
+    if (objTypes->isMagicArguments(cx)) {
         JS_ASSERT(obj.frame == CrossScriptSSA::OUTER_FRAME);
 
         for (unsigned i = 0; i < invariantEntries.length(); i++) {
             InvariantEntry &entry = invariantEntries[i];
             if (entry.kind == InvariantEntry::INVARIANT_ARGS_LENGTH)
                 return frame.getTemporary(entry.u.array.temporary);
         }
 
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -111,25 +111,20 @@ struct VMFrame
 #endif
 
     union Arguments {
         struct {
             void *ptr;
             void *ptr2;
         } x;
         struct {
-            uint32_t lazyArgsObj;
             uint32_t dynamicArgc;
         } call;
     } u;
 
-    static size_t offsetOfLazyArgsObj() {
-        return offsetof(VMFrame, u.call.lazyArgsObj);
-    }
-
     static size_t offsetOfDynamicArgc() {
         return offsetof(VMFrame, u.call.dynamicArgc);
     }
 
     VMFrame      *previous;
     void         *scratch;
     FrameRegs    regs;
 
@@ -975,16 +970,27 @@ inline void * bsearch_nmap(NativeMapEntr
         if (bcOff > bcOff_mid) {
             lo = mid+1;
             continue;
         }
         return nmap[mid-1].ncode;
     }
 }
 
+static inline bool
+IsLowerableFunCallOrApply(jsbytecode *pc)
+{
+#ifdef JS_MONOIC
+    return (*pc == JSOP_FUNCALL && GET_ARGC(pc) >= 1) ||
+           (*pc == JSOP_FUNAPPLY && GET_ARGC(pc) == 2);
+#else
+    return false;
+#endif
+}
+
 } /* namespace mjit */
 
 inline mjit::JITChunk *
 VMFrame::chunk()
 {
     return jit()->chunk(regs.pc);
 }
 
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -1071,69 +1071,59 @@ BumpStack(VMFrame &f, unsigned inc)
  * All successful paths through SplatApplyArgs must set f.u.call.dynamicArgc
  * and f.regs.sp.
  */
 JSBool JS_FASTCALL
 ic::SplatApplyArgs(VMFrame &f)
 {
     JSContext *cx = f.cx;
     JS_ASSERT(!f.regs.inlined());
-    JS_ASSERT(GET_ARGC(f.regs.pc) == 2);
 
-    /*
-     * The lazyArgsObj flag indicates an optimized call |f.apply(x, arguments)|
-     * where the args obj has not been created or pushed on the stack. Thus,
-     * if lazyArgsObj is set, the stack for |f.apply(x, arguments)| is:
-     *
-     *  | Function.prototype.apply | f | x |
-     *
-     * Otherwise, if !lazyArgsObj, the stack is a normal 2-argument apply:
-     *
-     *  | Function.prototype.apply | f | x | arguments |
-     */
-    if (f.u.call.lazyArgsObj) {
+    CallArgs args = CallArgsFromSp(GET_ARGC(f.regs.pc), f.regs.sp);
+    JS_ASSERT(args.length() == 2);
+    JS_ASSERT(IsNativeFunction(args.calleev(), js_fun_apply));
+
+    if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         /* Mirror isMagic(JS_OPTIMIZED_ARGUMENTS) case in js_fun_apply. */
         /* Steps 4-6. */
         unsigned length = f.regs.fp()->numActualArgs();
         JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
 
+        f.regs.sp--;
         if (!BumpStack(f, length))
             THROWV(false);
 
         /* Steps 7-8. */
         f.regs.fp()->forEachCanonicalActualArg(CopyTo(f.regs.sp));
 
         f.regs.sp += length;
         f.u.call.dynamicArgc = length;
         return true;
     }
 
-    Value *vp = f.regs.sp - 4;
-    JS_ASSERT(JS_CALLEE(cx, vp).toObject().toFunction()->native() == js_fun_apply);
-
     /*
      * This stub should mimic the steps taken by js_fun_apply. Step 1 and part
      * of Step 2 have already been taken care of by calling jit code.
      */
 
     /* Step 2 (part 2). */
-    if (vp[3].isNullOrUndefined()) {
+    if (args[1].isNullOrUndefined()) {
         f.regs.sp--;
         f.u.call.dynamicArgc = 0;
         return true;
     }
 
     /* Step 3. */
-    if (!vp[3].isObject()) {
+    if (!args[1].isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
         THROWV(false);
     }
 
     /* Steps 4-5. */
-    JSObject *aobj = &vp[3].toObject();
+    JSObject *aobj = &args[1].toObject();
     uint32_t length;
     if (!js_GetLengthProperty(cx, aobj, &length))
         THROWV(false);
 
     /* Step 6. */
     if (length > StackSpace::ARGS_LENGTH_MAX) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TOO_MANY_FUN_APPLY_ARGS);
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1167,26 +1167,20 @@ stubs::Throw(VMFrame &f)
     JS_ASSERT(!cx->isExceptionPending());
     cx->setPendingException(f.regs.sp[-1]);
     THROW();
 }
 
 void JS_FASTCALL
 stubs::Arguments(VMFrame &f)
 {
-    if (!f.fp()->hasArgsObj()) {
-        /*
-         * This case occurs when checkCallApplySpeculation detects that
-         * 'f.apply' is not actually js_fun_apply. In this case, we need to
-         * report the mis-speculation which will bail
-         */
-        if (!f.fp()->script()->applySpeculationFailed(f.cx))
-            THROW();
-    }
-    f.regs.sp[0] = ObjectValue(f.fp()->argsObj());
+    ArgumentsObject *obj = ArgumentsObject::create(f.cx, f.fp());
+    if (!obj)
+        THROW();
+    f.regs.sp[0] = ObjectValue(*obj);
 }
 
 JSBool JS_FASTCALL
 stubs::InstanceOf(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
--- a/js/src/tests/js1_8/genexps/regress-634472.js
+++ b/js/src/tests/js1_8/genexps/regress-634472.js
@@ -50,22 +50,25 @@ function error(str) {
     base = (function(){try{eval('throw new Error()')}catch(e){return e.lineNumber}})(); eval(str);
     return null;
   } catch (e) {
     e.lineNumber = e.lineNumber - base + 1;
     return e;
   }
 }
 
-const JSMSG_GENEXP_YIELD     = error("(function(){((yield) for (x in []))})").message;
-const JSMSG_GENEXP_ARGUMENTS = error("(function(){(arguments for (x in []))})").message;
-const JSMSG_TOP_YIELD        = error("yield").message;
-const JSMSG_YIELD_PAREN      = error("(function(){yield, 1})").message;
-const JSMSG_GENERIC          = error("(for)").message;
-const JSMSG_GENEXP_PAREN     = error("print(1, x for (x in []))").message;
+const JSMSG_GENEXP_YIELD         = error("(function(){((yield) for (x in []))})").message;
+const JSMSG_GENEXP_ARGUMENTS     = error("(function(){(arguments for (x in []))})").message;
+const JSMSG_TOP_YIELD            = error("yield").message;
+const JSMSG_YIELD_PAREN          = error("(function(){yield, 1})").message;
+const JSMSG_GENERIC              = error("(for)").message;
+const JSMSG_GENEXP_PAREN         = error("print(1, x for (x in []))").message;
+const JSMSG_BAD_GENERATOR_SYNTAX = error("(1, arguments for (x in []))").message;
+
+const JSMSG_GENEXP_MIX = { simple: JSMSG_BAD_GENERATOR_SYNTAX, call: JSMSG_GENEXP_ARGUMENTS };
 
 const cases = [
   // yield expressions
   { expr: "yield",        top: JSMSG_TOP_YIELD, fun: null,              gen: JSMSG_GENEXP_YIELD, desc: "simple yield" },
   { expr: "yield 1",      top: JSMSG_TOP_YIELD, fun: null,              gen: JSMSG_GENEXP_YIELD, desc: "yield w/ arg" },
   { expr: "1, yield",     top: JSMSG_TOP_YIELD, fun: null,              gen: JSMSG_GENEXP_YIELD, desc: "simple yield at end of list" },
   { expr: "1, yield 2",   top: JSMSG_TOP_YIELD, fun: null,              gen: JSMSG_GENEXP_YIELD, desc: "yield w/ arg at end of list" },
   { expr: "yield, 1",     top: JSMSG_TOP_YIELD, fun: JSMSG_YIELD_PAREN, gen: JSMSG_YIELD_PAREN,  desc: "simple yield in list" },
@@ -110,21 +113,21 @@ const cases = [
   { expr: "(1, (yield 2, 3) for (x in []))", top: JSMSG_TOP_YIELD, fun: JSMSG_YIELD_PAREN,  gen: JSMSG_YIELD_PAREN,  desc: "yield w/ arg in list, parenthesized in list in genexp" },
 
   // deeply nested yield in generator expressions
   { expr: "((((1, yield 2))) for (x in []))",               top: JSMSG_TOP_YIELD, fun: JSMSG_GENEXP_YIELD, gen: JSMSG_GENEXP_YIELD, desc: "deeply nested yield in genexp" },
   { expr: "((((1, yield 2)) for (x in [])) for (y in []))", top: JSMSG_TOP_YIELD, fun: JSMSG_GENEXP_YIELD, gen: JSMSG_GENEXP_YIELD, desc: "deeply nested yield in multiple genexps" },
 
   // arguments in generator expressions
   { expr: "(arguments for (x in []))",         top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "simple arguments in genexp" },
-  { expr: "(1, arguments for (x in []))",      top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "arguments in list in genexp" },
+  { expr: "(1, arguments for (x in []))",      top: JSMSG_GENEXP_MIX,       fun: JSMSG_GENEXP_MIX,       gen: JSMSG_GENEXP_MIX,       desc: "arguments in list in genexp" },
   { expr: "((arguments) for (x in []))",       top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "arguments, parenthesized in genexp" },
-  { expr: "(1, (arguments) for (x in []))",    top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "arguments, parenthesized in list in genexp" },
+  { expr: "(1, (arguments) for (x in []))",    top: JSMSG_GENEXP_MIX,       fun: JSMSG_GENEXP_MIX,       gen: JSMSG_GENEXP_MIX,       desc: "arguments, parenthesized in list in genexp" },
   { expr: "((1, arguments) for (x in []))",    top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "arguments in list, parenthesized in genexp" },
-  { expr: "(1, (2, arguments) for (x in []))", top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "arguments in list, parenthesized in list in genexp" },
+  { expr: "(1, (2, arguments) for (x in []))", top: JSMSG_GENEXP_MIX,       fun: JSMSG_GENEXP_MIX,       gen: JSMSG_GENEXP_MIX,       desc: "arguments in list, parenthesized in list in genexp" },
 
   // deeply nested arguments in generator expressions
   { expr: "((((1, arguments))) for (x in []))",               top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "deeply nested arguments in genexp" },
   { expr: "((((1, arguments)) for (x in [])) for (y in []))", top: JSMSG_GENEXP_ARGUMENTS, fun: JSMSG_GENEXP_ARGUMENTS, gen: JSMSG_GENEXP_ARGUMENTS, desc: "deeply nested arguments in multiple genexps" },
 
   // legal yield/arguments in nested function
   { expr: "((function() { yield }) for (x in []))",           top: null, fun: null, gen: null, desc: "legal yield in nested function" },
   { expr: "((function() { arguments }) for (x in []))",       top: null, fun: null, gen: null, desc: "legal arguments in nested function" },
@@ -141,17 +144,18 @@ function splitKeyword(str) {
          replace(/yield ([0-9])/, '\nyield $1\n').
          replace(/yield([^ ]|$)/, '\nyield\n$1').
          replace(/arguments/, '\narguments\n');
 }
 
 function expectError1(err, ctx, msg) {
   reportCompare('object', typeof err,     'exn for: ' + msg);
   reportCompare(ctx,      err.message,    'exn message for: ' + msg);
-  reportCompare(2,        err.lineNumber, 'exn token for: ' + msg);
+  if (ctx !== JSMSG_BAD_GENERATOR_SYNTAX)
+      reportCompare(2,    err.lineNumber, 'exn token for: ' + msg);
 }
 
 function expectError(expr, call, wrapCtx, expect, msg) {
   let exps = (typeof expect === "string")
            ? { simple: expect, call: expect }
            : expect;
   expectError1(error(wrapCtx(expr)), exps.simple, msg);
   if (call)
--- a/js/src/tests/js1_8_1/strict/generator-eval-arguments.js
+++ b/js/src/tests/js1_8_1/strict/generator-eval-arguments.js
@@ -17,21 +17,21 @@ assertEq(testLenientAndStrict('(1 for ([
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(1 for ({x:eval} in []))',
                               parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(1 for (arguments in []))',
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(1 for ([arguments] in []))',
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 assertEq(testLenientAndStrict('(1 for ({x:arguments} in []))',
-                              parseRaisesException(SyntaxError),
+                              parsesSuccessfully,
                               parseRaisesException(SyntaxError)),
          true);
 
 reportCompare(true, true);
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -139,21 +139,20 @@ ArgumentsObject::create(JSContext *cx, u
     argsobj.setStackFrame(NULL);
 
     JS_ASSERT(argsobj.numFixedSlots() >= NormalArgumentsObject::RESERVED_SLOTS);
     JS_ASSERT(argsobj.numFixedSlots() >= StrictArgumentsObject::RESERVED_SLOTS);
 
     return &argsobj;
 }
 
-bool
+ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp->script()->needsArgsObj());
-    JS_ASSERT(!fp->hasCallObj());
 
     ArgumentsObject *argsobj = ArgumentsObject::create(cx, fp->numActualArgs(), fp->callee());
     if (!argsobj)
         return NULL;
 
     /*
      * Strict mode functions have arguments objects that copy the initial
      * actual parameter values. Non-strict mode arguments use the frame pointer
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -140,17 +140,17 @@ class ArgumentsObject : public JSObject
     void initData(ArgumentsData *data);
     static ArgumentsObject *create(JSContext *cx, uint32_t argc, JSObject &callee);
 
   public:
     static const uint32_t RESERVED_SLOTS = 3;
     static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
 
     /* Create an arguments object for a frame that is expecting them. */
-    static bool create(JSContext *cx, StackFrame *fp);
+    static ArgumentsObject *create(JSContext *cx, StackFrame *fp);
 
     /*
      * Purposefully disconnect the returned arguments object from the frame
      * by always creating a new copy that does not alias formal parameters.
      * This allows function-local analysis to determine that formals are
      * not aliased and generally simplifies arguments objects.
      */
     static ArgumentsObject *createUnexpected(JSContext *cx, StackFrame *fp);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3650,17 +3650,17 @@ DebuggerObject_getParameterNames(JSConte
 
     const JSFunction *fun = obj->toFunction();
     JSObject *result = NewDenseAllocatedArray(cx, fun->nargs, NULL);
     if (!result)
         return false;
     result->ensureDenseArrayInitializedLength(cx, 0, fun->nargs);
 
     if (fun->isInterpreted()) {
-        JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
+        JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
 
         if (fun->nargs > 0) {
             Vector<JSAtom *> names(cx);
             if (!fun->script()->bindings.getLocalNameArray(cx, &names))
                 return false;
 
             for (size_t i = 0; i < fun->nargs; i++) {
                 JSAtom *name = names[i];
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -103,30 +103,16 @@ CallObject::getCallee() const
 
 inline JSFunction *
 CallObject::getCalleeFunction() const
 {
     return getReservedSlot(CALLEE_SLOT).toObject().toFunction();
 }
 
 inline const Value &
-CallObject::arguments() const
-{
-    JS_ASSERT(!isForEval());
-    return getReservedSlot(ARGUMENTS_SLOT);
-}
-
-inline void
-CallObject::setArguments(const Value &v)
-{
-    JS_ASSERT(!isForEval());
-    setFixedSlot(ARGUMENTS_SLOT, v);
-}
-
-inline const Value &
 CallObject::arg(unsigned i) const
 {
     JS_ASSERT(i < getCalleeFunction()->nargs);
     return getSlot(RESERVED_SLOTS + i);
 }
 
 inline void
 CallObject::setArg(unsigned i, const Value &v)
@@ -141,36 +127,36 @@ CallObject::initArgUnchecked(unsigned i,
     JS_ASSERT(i < getCalleeFunction()->nargs);
     initSlotUnchecked(RESERVED_SLOTS + i, v);
 }
 
 inline const Value &
 CallObject::var(unsigned i) const
 {
     JSFunction *fun = getCalleeFunction();
-    JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
-    JS_ASSERT(i < fun->script()->bindings.countVars());
+    JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
+    JS_ASSERT(i < fun->script()->bindings.numVars());
     return getSlot(RESERVED_SLOTS + fun->nargs + i);
 }
 
 inline void
 CallObject::setVar(unsigned i, const Value &v)
 {
     JSFunction *fun = getCalleeFunction();
-    JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
-    JS_ASSERT(i < fun->script()->bindings.countVars());
+    JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
+    JS_ASSERT(i < fun->script()->bindings.numVars());
     setSlot(RESERVED_SLOTS + fun->nargs + i, v);
 }
 
 inline void
 CallObject::initVarUnchecked(unsigned i, const Value &v)
 {
     JSFunction *fun = getCalleeFunction();
-    JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
-    JS_ASSERT(i < fun->script()->bindings.countVars());
+    JS_ASSERT(fun->nargs == fun->script()->bindings.numArgs());
+    JS_ASSERT(i < fun->script()->bindings.numVars());
     initSlotUnchecked(RESERVED_SLOTS + fun->nargs + i, v);
 }
 
 inline void
 CallObject::copyValues(unsigned nargs, Value *argv, unsigned nvars, Value *slots)
 {
     JS_ASSERT(slotInRange(RESERVED_SLOTS + nargs + nvars, SENTINEL_ALLOWED));
     copySlotRange(RESERVED_SLOTS, argv, nargs);
@@ -185,17 +171,17 @@ CallObject::argArray()
     return HeapSlotArray(getSlotAddress(RESERVED_SLOTS));
 }
 
 inline HeapSlotArray
 CallObject::varArray()
 {
     JSFunction *fun = getCalleeFunction();
     JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS + fun->nargs,
-                                 fun->script()->bindings.countVars()));
+                                 fun->script()->bindings.numVars()));
     return HeapSlotArray(getSlotAddress(RESERVED_SLOTS + fun->nargs));
 }
 
 inline uint32_t
 NestedScopeObject::stackDepth() const
 {
     return getReservedSlot(DEPTH_SLOT).toPrivateUint32();
 }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -63,29 +63,29 @@ js_PutCallObject(StackFrame *fp)
     JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
     JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
 
     JSScript *script = fp->script();
     Bindings &bindings = script->bindings;
 
     if (callobj.isForEval()) {
         JS_ASSERT(script->strictModeCode);
-        JS_ASSERT(bindings.countArgs() == 0);
+        JS_ASSERT(bindings.numArgs() == 0);
 
         /* This could be optimized as below, but keep it simple for now. */
-        callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
+        callobj.copyValues(0, NULL, bindings.numVars(), fp->slots());
     } else {
         JSFunction *fun = fp->fun();
         JS_ASSERT(script == callobj.getCalleeFunction()->script());
         JS_ASSERT(script == fun->script());
 
-        unsigned n = bindings.countLocalNames();
+        unsigned n = bindings.count();
         if (n > 0) {
-            uint32_t nvars = bindings.countVars();
-            uint32_t nargs = bindings.countArgs();
+            uint32_t nvars = bindings.numVars();
+            uint32_t nargs = bindings.numArgs();
             JS_ASSERT(fun->nargs == nargs);
             JS_ASSERT(nvars + nargs == n);
 
             JSScript *script = fun->script();
             if (script->bindingsAccessedDynamically
 #ifdef JS_METHODJIT
                 || script->debugMode
 #endif
@@ -195,17 +195,16 @@ CallObject::create(JSContext *cx, JSScri
     }
 #endif
 
     if (!obj->asScope().setEnclosingScope(cx, enclosing))
         return NULL;
 
     JS_ASSERT_IF(callee, callee->isFunction());
     obj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee));
-    obj->initFixedSlot(ARGUMENTS_SLOT, MagicValue(JS_UNASSIGNED_ARGUMENTS));
 
     /*
      * If |bindings| is for a function that has extensible parents, that means
      * its Call should have its own shape; see BaseShape::extensibleParents.
      */
     if (obj->lastProperty()->extensibleParents() && !obj->generateOwnShape(cx))
         return NULL;
 
@@ -239,67 +238,32 @@ CallObject::createForFunction(JSContext 
     }
 
     CallObject *callobj = create(cx, fp->script(), *scopeChain, &fp->callee());
     if (!callobj)
         return NULL;
 
     callobj->setStackFrame(fp);
     fp->setScopeChainWithOwnCallObj(*callobj);
-    if (fp->hasArgsObj())
-        callobj->setArguments(ObjectValue(fp->argsObj()));
     return callobj;
 }
 
 CallObject *
 CallObject::createForStrictEval(JSContext *cx, StackFrame *fp)
 {
     CallObject *callobj = create(cx, fp->script(), fp->scopeChain(), NULL);
     if (!callobj)
         return NULL;
 
     callobj->setStackFrame(fp);
     fp->setScopeChainWithOwnCallObj(*callobj);
     return callobj;
 }
 
 JSBool
-CallObject::getArgumentsOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    *vp = callobj.arguments();
-
-    /*
-     * This can only happen through eval-in-frame. Eventually, this logic can
-     * be hoisted into debugger scope wrappers. That will allow 'arguments' to
-     * be a pure data property and allow call_resolve to be removed.
-     */
-    if (vp->isMagic(JS_UNASSIGNED_ARGUMENTS)) {
-        JS_ASSERT(callobj.compartment()->debugMode());
-        StackFrame *fp = callobj.maybeStackFrame();
-        ArgumentsObject *argsObj = ArgumentsObject::createUnexpected(cx, fp);
-        if (!argsObj)
-            return false;
-
-        *vp = ObjectValue(*argsObj);
-        callobj.setArguments(*vp);
-    }
-
-    return true;
-}
-
-JSBool
-CallObject::setArgumentsOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    JS_ASSERT(obj->asCall().maybeStackFrame());
-    obj->asCall().setArguments(*vp);
-    return true;
-}
-
-JSBool
 CallObject::getArgOp(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     CallObject &callobj = obj->asCall();
 
     JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
     unsigned i = (uint16_t) JSID_TO_INT(id);
 
     DebugOnly<JSScript *> script = callobj.getCalleeFunction()->script();
@@ -346,16 +310,21 @@ CallObject::getVarOp(JSContext *cx, JSOb
 
     DebugOnly<JSScript *> script = callobj.getCalleeFunction()->script();
     JS_ASSERT_IF(!callobj.compartment()->debugMode(), script->varIsAliased(i));
 
     if (StackFrame *fp = callobj.maybeStackFrame())
         *vp = fp->varSlot(i);
     else
         *vp = callobj.var(i);
+
+    /* This can only happen via the debugger. Bug 659577 will remove it. */
+    if (vp->isMagic(JS_OPTIMIZED_ARGUMENTS))
+        *vp = UndefinedValue();
+
     return true;
 }
 
 JSBool
 CallObject::setVarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     CallObject &callobj = obj->asCall();
 
@@ -388,79 +357,39 @@ CallObject::containsVarOrArg(PropertyNam
     PropertyOp op = shape->getterOp();
     if (op != getVarOp && op != getArgOp)
         return false;
 
     JS_ALWAYS_TRUE(op(cx, this, INT_TO_JSID(shape->shortid()), vp));
     return true;
 }
 
-static JSBool
-call_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags, JSObject **objp)
-{
-    JS_ASSERT(!obj->getProto());
-
-    if (!JSID_IS_ATOM(id))
-        return true;
-
-    JSObject *callee = obj->asCall().getCallee();
-#ifdef DEBUG
-    if (callee) {
-        JSScript *script = callee->toFunction()->script();
-        JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
-    }
-#endif
-
-    /*
-     * Resolve arguments so that we never store a particular Call object's
-     * arguments object reference in a Call prototype's |arguments| slot.
-     *
-     * Include JSPROP_ENUMERATE for consistency with all other Call object
-     * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
-     * rebinding-Call-property logic.
-     */
-    if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
-        if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
-                                  CallObject::getArgumentsOp, CallObject::setArgumentsOp,
-                                  JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
-                                  0, 0, DNP_DONT_PURGE)) {
-            return false;
-        }
-        *objp = obj;
-        return true;
-    }
-
-    /* Control flow reaches here only if id was not resolved. */
-    return true;
-}
-
 static void
 call_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isCall());
 
     /* Mark any generator frame, as for arguments objects. */
 #if JS_HAS_GENERATORS
     StackFrame *fp = (StackFrame *) obj->getPrivate();
     if (fp && fp->isFloatingGenerator())
         MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
 #endif
 }
 
 JS_PUBLIC_DATA(Class) js::CallClass = {
     "Call",
-    JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
+    JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_IS_ANONYMOUS |
+    JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS),
     JS_PropertyStub,         /* addProperty */
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
-    (JSResolveOp)call_resolve,
+    JS_ResolveStub,
     NULL,                    /* convert: Leave it NULL so we notice if calls ever escape */
     NULL,                    /* finalize */
     NULL,                    /* checkAccess */
     NULL,                    /* call        */
     NULL,                    /* construct   */
     NULL,                    /* hasInstance */
     call_trace
 };
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -108,17 +108,16 @@ class ScopeObject : public JSObject
 
     /* For jit access. */
     static inline size_t offsetOfEnclosingScope();
 };
 
 class CallObject : public ScopeObject
 {
     static const uint32_t CALLEE_SLOT = 1;
-    static const uint32_t ARGUMENTS_SLOT = 2;
 
     static CallObject *
     create(JSContext *cx, JSScript *script, JSObject &enclosing, JSObject *callee);
 
   public:
     static const uint32_t RESERVED_SLOTS = 3;
 
     static CallObject *createForFunction(JSContext *cx, StackFrame *fp);
@@ -130,25 +129,16 @@ class CallObject : public ScopeObject
     /*
      * The callee function if this CallObject was created for a function
      * invocation, or null if it was created for a strict mode eval frame.
      */
     inline JSObject *getCallee() const;
     inline JSFunction *getCalleeFunction() const;
     inline void setCallee(JSObject *callee);
 
-    /*
-     * When a call object is created, CallObject::arguments has the value
-     * MagicValue(JS_UNASSIGNED_ARGUMENTS). This value is overwritten if:
-     *  1. js_PutCallObject is called in a frame which hasArgsObj
-     *  2. the script assigns to 'arguments'
-     */
-    inline const Value &arguments() const;
-    inline void setArguments(const Value &v);
-
     /* Returns the formal argument at the given index. */
     inline const Value &arg(unsigned i) const;
     inline void setArg(unsigned i, const Value &v);
     inline void initArgUnchecked(unsigned i, const Value &v);
 
     /* Returns the variable at the given index. */
     inline const Value &var(unsigned i) const;
     inline void setVar(unsigned i, const Value &v);
@@ -159,18 +149,16 @@ class CallObject : public ScopeObject
      * inference is enabled, where we ensure that call object variables are in
      * contiguous slots (see NewCallObject).
      */
     inline HeapSlotArray argArray();
     inline HeapSlotArray varArray();
 
     inline void copyValues(unsigned nargs, Value *argv, unsigned nvars, Value *slots);
 
-    static JSBool getArgumentsOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
-    static JSBool setArgumentsOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
     static JSBool getArgOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool getVarOp(JSContext *cx, JSObject *obj, jsid id, Value *vp);
     static JSBool setArgOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
     static JSBool setVarOp(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp);
 
     /* Return whether this environment contains 'name' and, if so, its value. */
     bool containsVarOrArg(PropertyName *name, Value *vp, JSContext *cx);
 };
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -350,19 +350,16 @@ inline bool
 StackFrame::functionPrologue(JSContext *cx)
 {
     JS_ASSERT(isNonEvalFunctionFrame());
     JS_ASSERT(!isGeneratorFrame());
 
     JSFunction *fun = this->fun();
     JSScript *script = fun->script();
 
-    if (script->needsArgsObj() && !ArgumentsObject::create(cx, this))
-        return false;
-
     if (fun->isHeavyweight()) {
         if (!CallObject::createForFunction(cx, this))
             return false;
     } else {
         /* Force instantiation of the scope chain, for JIT frames. */
         scopeChain();
     }
 
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -539,17 +539,17 @@ class StackFrame
     }
 
     Value *base() const {
         return slots() + script()->nfixed;
     }
 
     Value &varSlot(unsigned i) {
         JS_ASSERT(i < script()->nfixed);
-        JS_ASSERT_IF(maybeFun(), i < script()->bindings.countVars());
+        JS_ASSERT_IF(maybeFun(), i < script()->bindings.numVars());
         return slots()[i];
     }
 
     Value &localSlot(unsigned i) {
         /* Let variables can be above script->nfixed. */
         JS_ASSERT(i < script()->nslots);
         return slots()[i];
     }
@@ -721,16 +721,18 @@ class StackFrame
     inline Value *actualArgs() const;
     inline Value *actualArgsEnd() const;
 
     inline Value &canonicalActualArg(unsigned i) const;
     template <class Op>
     inline bool forEachCanonicalActualArg(Op op, unsigned start = 0, unsigned count = unsigned(-1));
     template <class Op> inline bool forEachFormalArg(Op op);
 
+    /* XXX: all these argsObj functions will be removed with bug 659577. */
+
     bool hasArgsObj() const {
         /*
          * HAS_ARGS_OBJ is still technically not equivalent to
          * script()->needsArgsObj() during functionPrologue (where GC can
          * observe a frame that needsArgsObj but has not yet been given the
          * args). This can be fixed by creating and rooting the args/call
          * object before pushing the frame, which should be done eventually.
          */
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -50,17 +50,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 113);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 114);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;