Backed out changeset 0f963fbdc918 (bug 1141865)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 03 Jun 2015 12:41:48 +0200
changeset 269640 b003dbf1e2536d38220b85961422c95a3860faed
parent 269639 05411d0a95ad05108ec468fbc12bb84ddaee7d4b
child 269641 8b7268073cd82c258a45f5fb98aaec0bc055a20c
push id2540
push userwcosta@mozilla.com
push dateWed, 03 Jun 2015 20:55:41 +0000
bugs1141865
milestone41.0a1
backs out0f963fbdc9182335ece49a6aa16b846529e623ad
Backed out changeset 0f963fbdc918 (bug 1141865)
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/Parser.cpp
js/src/frontend/SharedContext.h
js/src/jit-test/tests/debug/Frame-newTargetEval-02.js
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineFrame.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/RematerializedFrame.h
js/src/jsfun.h
js/src/tests/ecma_6/Class/newTargetArrow.js
js/src/tests/ecma_6/Class/newTargetEval.js
js/src/tests/js1_8_5/reflect-parse/newTarget.js
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/Opcodes.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/Xdr.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5447,29 +5447,16 @@ BytecodeEmitter::emitFor(ParseNode* pn, 
 
     if (pn->pn_left->isKind(PNK_FOROF))
         return emitForOf(STMT_FOR_OF_LOOP, pn, top);
 
     MOZ_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
     return emitNormalFor(pn, top);
 }
 
-bool
-BytecodeEmitter::arrowNeedsNewTarget()
-{
-    for (BytecodeEmitter* bce = this; bce; bce = bce->parent) {
-        SharedContext *sc = bce->sc;
-        if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow())
-            continue;
-
-        return sc->allowSyntax(SharedContext::AllowedSyntax::NewTarget);
-    }
-    MOZ_CRASH("impossible parent chain");
-}
-
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
 {
     FunctionBox* funbox = pn->pn_funbox;
     RootedFunction fun(cx, funbox->function());
     MOZ_ASSERT_IF(fun->isInterpretedLazy(), fun->lazyScript());
 
     /*
@@ -5551,31 +5538,20 @@ BytecodeEmitter::emitFunction(ParseNode*
         MOZ_ASSERT(IsAsmJSModuleNative(fun->native()));
     }
 
     /* Make the function object a literal in the outer script's pool. */
     unsigned index = objectList.add(pn->pn_funbox);
 
     /* Non-hoisted functions simply emit their respective op. */
     if (!pn->functionIsHoisted()) {
-        /* JSOP_LAMBDA_ARROW is always preceded by JSOP_THIS and a new.target */
+        /* JSOP_LAMBDA_ARROW is always preceded by JSOP_THIS. */
         MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
-        if (fun->isArrow()) {
-            if (!emit1(JSOP_THIS))
-                return false;
-
-            if (arrowNeedsNewTarget()) {
-                if (!emit1(JSOP_NEWTARGET))
-                    return false;
-            } else {
-                if (!emit1(JSOP_NULL))
-                    return false;
-            }
-        }
-
+        if (fun->isArrow() && !emit1(JSOP_THIS))
+            return false;
         if (needsProto) {
             MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA);
             pn->setOp(JSOP_FUNWITHPROTO);
         }
         return emitIndex32(pn->getOp(), index);
     }
 
     MOZ_ASSERT(!needsProto);
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -427,17 +427,16 @@ struct BytecodeEmitter
     bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
     bool emitArrayComp(ParseNode* pn);
 
     bool emitInternedObjectOp(uint32_t index, JSOp op);
     bool emitObjectOp(ObjectBox* objbox, JSOp op);
     bool emitObjectPairOp(ObjectBox* objbox1, ObjectBox* objbox2, JSOp op);
     bool emitRegExp(uint32_t index);
 
-    bool arrowNeedsNewTarget();
     MOZ_NEVER_INLINE bool emitFunction(ParseNode* pn, bool needsProto = false);
     MOZ_NEVER_INLINE bool emitObject(ParseNode* pn);
 
     bool emitPropertyList(ParseNode* pn, MutableHandlePlainObject objp, PropListType type);
 
     // To catch accidental misuse, emitUint16Operand/emit3 assert that they are
     // not used to unconditionally emit JSOP_GETLOCAL. Variable access should
     // instead be emitted using EmitVarOp. In special cases, when the caller
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -7839,18 +7839,23 @@ bool
 Parser<ParseHandler>::checkAllowedNestedSyntax(SharedContext::AllowedSyntax allowed,
                                                SharedContext** allowingContext)
 {
     for (GenericParseContext* gpc = pc; gpc; gpc = gpc->parent) {
         SharedContext* sc = gpc->sc;
 
         // Arrow functions don't help decide whether we should allow nested
         // syntax, as they don't store any of the necessary state for themselves.
-        if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow())
+        if (sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow()) {
+            // For now (!), disallow new.target in arrow functions. This will
+            // change later in this bug!
+            if (allowed == SharedContext::AllowedSyntax::NewTarget)
+                return false;
             continue;
+        }
 
         if (!sc->allowSyntax(allowed))
             return false;
         if (allowingContext)
             *allowingContext = sc;
         return true;
     }
     return false;
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -267,19 +267,23 @@ class GlobalSharedContext : public Share
     {}
 
     ObjectBox* toObjectBox() { return nullptr; }
     HandleObject evalStaticScope() const { return staticEvalScope_; }
 
     bool allowSyntax(AllowedSyntax allowed) const {
         StaticScopeIter<CanGC> it(context, staticEvalScope_);
         for (; !it.done(); it++) {
-            if (it.type() == StaticScopeIter<CanGC>::Function &&
-                !it.fun().isArrow())
-            {
+            if (it.type() == StaticScopeIter<CanGC>::Function) {
+                if (it.fun().isArrow()) {
+                    // For the moment, disallow new.target inside arrow functions
+                    if (allowed == AllowedSyntax::NewTarget)
+                        return false;
+                    continue;
+                }
                 return FunctionAllowsSyntax(&it.fun(), allowed);
             }
         }
         return false;
     }
 };
 
 class FunctionBox : public ObjectBox, public SharedContext
deleted file mode 100644
--- a/js/src/jit-test/tests/debug/Frame-newTargetEval-02.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Test that new.target is acceptably usable in RematerializedFrames.
-
-load(libdir + "jitopts.js");
-
-if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
-  quit();
-
-withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
-  var g = newGlobal();
-  var dbg = new Debugger;
-
-  g.toggle = function toggle(d, expected) {
-    if (d) {
-      dbg.addDebuggee(g);
-
-      var frame = dbg.getNewestFrame();
-      assertEq(frame.implementation, "ion");
-
-      // the arrow function will not be constructing, even though it has a
-      // new.target value.
-      assertEq(frame.constructing, false);
-
-      // CONGRATS IF THIS FAILS! You, proud saviour, have made new.target parse
-      // in debug frame evals (presumably by hooking up static scope walks).
-      // Uncomment the assert below for efaust's undying gratitude.
-      // Note that we use .name here because of CCW nonsense.
-      assertEq(frame.eval('new.target').throw.unsafeDereference().name, "SyntaxError");
-      // assertEq(frame.eval('new.target').return.unsafeDereference(), expected);
-    }
-  };
-
-  g.eval("" + function f(d) { new g(d, g, 15); });
-
-  g.eval("" + function g(d, expected) { (() => toggle(d, expected))(); });
-
-  g.eval("(" + function test() {
-    for (var i = 0; i < 5; i++)
-      f(false);
-    f(true);
-  } + ")();");
-});
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1458,34 +1458,32 @@ BaselineCompiler::emit_JSOP_LAMBDA()
         return false;
 
     // Box and push return value.
     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
     frame.push(R0);
     return true;
 }
 
-typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject,
-                                   HandleValue, HandleValue);
+typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
 static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
 
 bool
 BaselineCompiler::emit_JSOP_LAMBDA_ARROW()
 {
-    // Keep pushed |this| in R0, and newTarget in R1.
-    frame.popRegsAndSync(2);
+    // Keep pushed |this| in R0.
+    frame.popRegsAndSync(1);
 
     RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc)));
 
     prepareVMCall();
-    masm.loadPtr(frame.addressOfScopeChain(), R2.scratchReg());
-
-    pushArg(R1);
+    masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg());
+
     pushArg(R0);
-    pushArg(R2.scratchReg());
+    pushArg(R1.scratchReg());
     pushArg(ImmGCPtr(fun));
 
     if (!callVM(LambdaArrowInfo))
         return false;
 
     // Box and push return value.
     masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
     frame.push(R0);
@@ -2691,26 +2689,16 @@ BaselineCompiler::emit_JSOP_NEWTARGET()
     if (script->isForEval()) {
         frame.pushEvalNewTarget();
         return true;
     }
 
     MOZ_ASSERT(function());
     frame.syncStack(0);
 
-    if (function()->isArrow()) {
-        // Arrow functions store their |new.target| value in an
-        // extended slot.
-        Register scratch = R0.scratchReg();
-        masm.loadFunctionFromCalleeToken(frame.addressOfCalleeToken(), scratch);
-        masm.loadValue(Address(scratch, FunctionExtended::offsetOfArrowNewTargetSlot()), R0);
-        frame.push(R0);
-        return true;
-    }
-
     // if (!isConstructing()) push(undefined)
     Label constructing, done;
     masm.branchTestPtr(Assembler::NonZero, frame.addressOfCalleeToken(),
                        Imm32(CalleeToken_FunctionConstructing), &constructing);
     masm.moveValue(UndefinedValue(), R0);
     masm.jump(&done);
 
     masm.bind(&constructing);
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -222,21 +222,18 @@ class BaselineFrame
         MOZ_ASSERT(isEvalFrame());
         return (Value*)(reinterpret_cast<const uint8_t*>(this) +
                         BaselineFrame::Size() +
                         offsetOfEvalNewTarget());
     }
 
   public:
     Value newTarget() const {
-        MOZ_ASSERT(isFunctionFrame());
         if (isEvalFrame())
             return *evalNewTargetAddress();
-        if (fun()->isArrow())
-            return fun()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
         if (isConstructing())
             return *(Value*)(reinterpret_cast<const uint8_t*>(this) +
                              BaselineFrame::Size() +
                              offsetOfArg(Max(numFormalArgs(), numActualArgs())));
         return UndefinedValue();
     }
 
     bool copyRawFrameSlots(AutoValueVector* vec) const;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1715,110 +1715,52 @@ CodeGenerator::visitLambda(LLambda* lir)
         static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
         masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
     }
 
     masm.bind(ool->rejoin());
 }
 
-class OutOfLineLambdaArrow : public OutOfLineCodeBase<CodeGenerator>
-{
-  public:
-    LLambdaArrow* lir;
-    Label entryNoPop_;
-
-    explicit OutOfLineLambdaArrow(LLambdaArrow* lir)
-      : lir(lir)
-    { }
-
-    void accept(CodeGenerator* codegen) {
-        codegen->visitOutOfLineLambdaArrow(this);
-    }
-
-    Label* entryNoPop() {
-        return &entryNoPop_;
-    }
-};
-
-typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue, HandleValue);
+typedef JSObject* (*LambdaArrowFn)(JSContext*, HandleFunction, HandleObject, HandleValue);
 static const VMFunction LambdaArrowInfo = FunctionInfo<LambdaArrowFn>(js::LambdaArrow);
 
 void
-CodeGenerator::visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool)
-{
-    Register scopeChain = ToRegister(ool->lir->scopeChain());
-    ValueOperand thisv = ToValue(ool->lir, LLambdaArrow::ThisValue);
-    ValueOperand newTarget = ToValue(ool->lir, LLambdaArrow::NewTargetValue);
-    Register output = ToRegister(ool->lir->output());
-    const LambdaFunctionInfo& info = ool->lir->mir()->info();
-
-    // When we get here, we may need to restore part of the newTarget,
-    // which has been conscripted into service as a temp register.
-    masm.pop(newTarget.scratchReg());
-
-    masm.bind(ool->entryNoPop());
-
-    saveLive(ool->lir);
-
-    pushArg(newTarget);
-    pushArg(thisv);
-    pushArg(scopeChain);
-    pushArg(ImmGCPtr(info.fun));
-
-    callVM(LambdaArrowInfo, ool->lir);
-    StoreRegisterTo(output).generate(this);
-
-    restoreLiveIgnore(ool->lir, StoreRegisterTo(output).clobbered());
-
-    masm.jump(ool->rejoin());
-}
-
-void
 CodeGenerator::visitLambdaArrow(LLambdaArrow* lir)
 {
     Register scopeChain = ToRegister(lir->scopeChain());
     ValueOperand thisv = ToValue(lir, LLambdaArrow::ThisValue);
-    ValueOperand newTarget = ToValue(lir, LLambdaArrow::NewTargetValue);
     Register output = ToRegister(lir->output());
+    Register tempReg = ToRegister(lir->temp());
     const LambdaFunctionInfo& info = lir->mir()->info();
 
-    OutOfLineLambdaArrow* ool = new (alloc()) OutOfLineLambdaArrow(lir);
-    addOutOfLineCode(ool, lir->mir());
+    OutOfLineCode* ool = oolCallVM(LambdaArrowInfo, lir,
+                                   (ArgList(), ImmGCPtr(info.fun), scopeChain, thisv),
+                                   StoreRegisterTo(output));
 
     MOZ_ASSERT(!info.useSingletonForClone);
 
     if (info.singletonType) {
         // If the function has a singleton type, this instruction will only be
         // executed once so we don't bother inlining it.
-        masm.jump(ool->entryNoPop());
+        masm.jump(ool->entry());
         masm.bind(ool->rejoin());
         return;
     }
 
-    // There's not enough registers on x86 with the profiler enabled to request
-    // a temp. Instead, spill part of one of the values, being prepared to
-    // restore it if necessary on the out of line path.
-    Register tempReg = newTarget.scratchReg();
-    masm.push(newTarget.scratchReg());
-
     masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
 
-    masm.pop(newTarget.scratchReg());
-
     emitLambdaInit(output, scopeChain, info);
 
     // Initialize extended slots. Lexical |this| is stored in the first one.
     MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
     static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
     static_assert(FunctionExtended::ARROW_THIS_SLOT == 0, "|this| must be stored in first slot");
-    static_assert(FunctionExtended::ARROW_NEWTARGET_SLOT == 1,
-                  "|new.target| must be stored in second slot");
     masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
-    masm.storeValue(newTarget, Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
+    masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1)));
 
     masm.bind(ool->rejoin());
 }
 
 void
 CodeGenerator::emitLambdaInit(Register output, Register scopeChain,
                               const LambdaFunctionInfo& info)
 {
@@ -5019,24 +4961,16 @@ void
 CodeGenerator::visitLoadArrowThis(LLoadArrowThis* lir)
 {
     Register callee = ToRegister(lir->callee());
     ValueOperand output = ToOutValue(lir);
     masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowThisSlot()), output);
 }
 
 void
-CodeGenerator::visitArrowNewTarget(LArrowNewTarget* lir)
-{
-    Register callee = ToRegister(lir->callee());
-    ValueOperand output = ToOutValue(lir);
-    masm.loadValue(Address(callee, FunctionExtended::offsetOfArrowNewTargetSlot()), output);
-}
-
-void
 CodeGenerator::visitArrayLength(LArrayLength* lir)
 {
     Address length(ToRegister(lir->elements()), ObjectElements::offsetOfLength());
     masm.load32(length, ToRegister(lir->output()));
 }
 
 void
 CodeGenerator::visitSetArrayLength(LSetArrayLength* lir)
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -37,17 +37,16 @@ class OutOfLineInterruptCheckImplicit;
 class OutOfLineUnboxFloatingPoint;
 class OutOfLineStoreElementHole;
 class OutOfLineTypeOfV;
 class OutOfLineUpdateCache;
 class OutOfLineCallPostWriteBarrier;
 class OutOfLineIsCallable;
 class OutOfLineRegExpExec;
 class OutOfLineRegExpTest;
-class OutOfLineLambdaArrow;
 
 class CodeGenerator : public CodeGeneratorSpecific
 {
     void generateArgumentsChecks(bool bailout = true);
     bool generateBody();
 
   public:
     CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm = nullptr);
@@ -100,17 +99,16 @@ class CodeGenerator : public CodeGenerat
     void visitRegExp(LRegExp* lir);
     void visitRegExpExec(LRegExpExec* lir);
     void visitOutOfLineRegExpExec(OutOfLineRegExpExec* ool);
     void visitRegExpTest(LRegExpTest* lir);
     void visitOutOfLineRegExpTest(OutOfLineRegExpTest* ool);
     void visitRegExpReplace(LRegExpReplace* lir);
     void visitStringReplace(LStringReplace* lir);
     void visitLambda(LLambda* lir);
-    void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
     void visitLambdaArrow(LLambdaArrow* lir);
     void visitLambdaForSingleton(LLambdaForSingleton* lir);
     void visitPointer(LPointer* lir);
     void visitNurseryObject(LNurseryObject* lir);
     void visitKeepAliveObject(LKeepAliveObject* lir);
     void visitSlots(LSlots* lir);
     void visitLoadSlotT(LLoadSlotT* lir);
     void visitLoadSlotV(LLoadSlotV* lir);
@@ -321,17 +319,16 @@ class CodeGenerator : public CodeGenerat
     void visitHasClass(LHasClass* lir);
     void visitAsmJSParameter(LAsmJSParameter* lir);
     void visitAsmJSReturn(LAsmJSReturn* ret);
     void visitAsmJSVoidReturn(LAsmJSVoidReturn* ret);
     void visitLexicalCheck(LLexicalCheck* ins);
     void visitThrowUninitializedLexical(LThrowUninitializedLexical* ins);
     void visitDebugger(LDebugger* ins);
     void visitNewTarget(LNewTarget* ins);
-    void visitArrowNewTarget(LArrowNewTarget* ins);
 
     void visitCheckOverRecursed(LCheckOverRecursed* lir);
     void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
 
     void visitInterruptCheckImplicit(LInterruptCheckImplicit* ins);
     void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
 
     void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -9438,24 +9438,16 @@ IonBuilder::jsop_newtarget()
 {
     if (!info().funMaybeLazy()) {
         MOZ_ASSERT(!info().script()->isForEval());
         pushConstant(NullValue());
         return true;
     }
 
     MOZ_ASSERT(info().funMaybeLazy());
-
-    if (info().funMaybeLazy()->isArrow()) {
-        MArrowNewTarget* arrowNewTarget = MArrowNewTarget::New(alloc(), getCallee());
-        current->add(arrowNewTarget);
-        current->push(arrowNewTarget);
-        return true;
-    }
-
     if (inliningDepth_ == 0) {
         MNewTarget* newTarget = MNewTarget::New(alloc());
         current->add(newTarget);
         current->push(newTarget);
         return true;
     }
 
     if (!info().constructing()) {
@@ -11882,21 +11874,20 @@ IonBuilder::jsop_lambda(JSFunction* fun)
 
 bool
 IonBuilder::jsop_lambda_arrow(JSFunction* fun)
 {
     MOZ_ASSERT(analysis().usesScopeChain());
     MOZ_ASSERT(fun->isArrow());
     MOZ_ASSERT(!fun->isNative());
 
-    MDefinition* newTargetDef = current->pop();
     MDefinition* thisDef = current->pop();
 
     MLambdaArrow* ins = MLambdaArrow::New(alloc(), constraints(), current->scopeChain(),
-                                          thisDef, newTargetDef, fun);
+                                          thisDef, fun);
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_setarg(uint32_t arg)
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3985,30 +3985,33 @@ class LLambda : public LInstructionHelpe
     const LDefinition* temp() {
         return getTemp(0);
     }
     const MLambda* mir() const {
         return mir_->toLambda();
     }
 };
 
-class LLambdaArrow : public LInstructionHelper<1, 1 + (2 * BOX_PIECES), 0>
+class LLambdaArrow : public LInstructionHelper<1, 1 + BOX_PIECES, 1>
 {
   public:
     LIR_HEADER(LambdaArrow)
 
     static const size_t ThisValue = 1;
-    static const size_t NewTargetValue = ThisValue + BOX_PIECES;
-
-    explicit LLambdaArrow(const LAllocation& scopeChain) {
+
+    LLambdaArrow(const LAllocation& scopeChain, const LDefinition& temp) {
         setOperand(0, scopeChain);
+        setTemp(0, temp);
     }
     const LAllocation* scopeChain() {
         return getOperand(0);
     }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
     const MLambdaArrow* mir() const {
         return mir_->toLambdaArrow();
     }
 };
 
 class LKeepAliveObject : public LInstructionHelper<0, 1, 0>
 {
   public:
@@ -7013,26 +7016,12 @@ class LDebugger : public LCallInstructio
 };
 
 class LNewTarget : public LInstructionHelper<BOX_PIECES, 0, 0>
 {
   public:
     LIR_HEADER(NewTarget)
 };
 
-class LArrowNewTarget : public LInstructionHelper<BOX_PIECES, 1, 0>
-{
-  public:
-    explicit LArrowNewTarget(const LAllocation& callee) {
-        setOperand(0, callee);
-    }
-
-    LIR_HEADER(ArrowNewTarget)
-
-    const LAllocation* callee() {
-        return getOperand(0);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_LIR_Common_h */
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -345,18 +345,17 @@
     _(AssertRangeF)                 \
     _(AssertRangeV)                 \
     _(AssertResultV)                \
     _(AssertResultT)                \
     _(LexicalCheck)                 \
     _(ThrowUninitializedLexical)    \
     _(NurseryObject)                \
     _(Debugger)                     \
-    _(NewTarget)                    \
-    _(ArrowNewTarget)
+    _(NewTarget)
 
 #if defined(JS_CODEGEN_X86)
 # include "jit/x86/LOpcodes-x86.h"
 #elif defined(JS_CODEGEN_X64)
 # include "jit/x64/LOpcodes-x64.h"
 #elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/LOpcodes-arm.h"
 #elif defined(JS_CODEGEN_MIPS)
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -381,26 +381,16 @@ LIRGenerator::visitLoadArrowThis(MLoadAr
     MOZ_ASSERT(ins->type() == MIRType_Value);
     MOZ_ASSERT(ins->callee()->type() == MIRType_Object);
 
     LLoadArrowThis* lir = new(alloc()) LLoadArrowThis(useRegister(ins->callee()));
     defineBox(lir, ins);
 }
 
 void
-LIRGenerator::visitArrowNewTarget(MArrowNewTarget* ins)
-{
-    MOZ_ASSERT(ins->type() == MIRType_Value);
-    MOZ_ASSERT(ins->callee()->type() == MIRType_Object);
-
-    LArrowNewTarget* lir = new(alloc()) LArrowNewTarget(useRegister(ins->callee()));
-    defineBox(lir, ins);
-}
-
-void
 LIRGenerator::lowerCallArguments(MCall* call)
 {
     uint32_t argc = call->numStackArgs();
 
     // Align the arguments of a call such that the callee would keep the same
     // alignment as the caller.
     uint32_t baseSlot = 0;
     if (JitStackValueAlignment > 1)
@@ -2153,21 +2143,19 @@ LIRGenerator::visitLambda(MLambda* ins)
     }
 }
 
 void
 LIRGenerator::visitLambdaArrow(MLambdaArrow* ins)
 {
     MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
     MOZ_ASSERT(ins->thisDef()->type() == MIRType_Value);
-    MOZ_ASSERT(ins->newTargetDef()->type() == MIRType_Value);
-
-    LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()));
+
+    LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
     useBox(lir, LLambdaArrow::ThisValue, ins->thisDef());
-    useBox(lir, LLambdaArrow::NewTargetValue, ins->newTargetDef());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins)
 {
     MDefinition* obj = ins->object();
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -292,15 +292,14 @@ class LIRGenerator : public LIRGenerator
     void visitObjectState(MObjectState* ins);
     void visitArrayState(MArrayState* ins);
     void visitUnknownValue(MUnknownValue* ins);
     void visitLexicalCheck(MLexicalCheck* ins);
     void visitThrowUninitializedLexical(MThrowUninitializedLexical* ins);
     void visitDebugger(MDebugger* ins);
     void visitNurseryObject(MNurseryObject* ins);
     void visitNewTarget(MNewTarget* ins);
-    void visitArrowNewTarget(MArrowNewTarget* ins);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_Lowering_h */
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6702,46 +6702,16 @@ class MLoadArrowThis
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const override {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
 
-// Load an arrow function's |new.target| value.
-class MArrowNewTarget
-  : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
-{
-    explicit MArrowNewTarget(MDefinition* callee)
-      : MUnaryInstruction(callee)
-    {
-        setResultType(MIRType_Value);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(ArrowNewTarget)
-
-    static MArrowNewTarget* New(TempAllocator& alloc, MDefinition* callee) {
-        return new(alloc) MArrowNewTarget(callee);
-    }
-    MDefinition* callee() const {
-        return getOperand(0);
-    }
-    bool congruentTo(const MDefinition* ins) const override {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const override {
-        // An arrow function's lexical |this| value is immutable.
-        return AliasSet::None();
-    }
-};
-
 class MPhi final
   : public MDefinition,
     public InlineListNode<MPhi>,
     public NoTypePolicy::Data
 {
     js::Vector<MUse, 2, JitAllocPolicy> inputs_;
 
     TruncateKind truncateKind_;
@@ -7564,49 +7534,45 @@ class MLambda
     }
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
     }
 };
 
 class MLambdaArrow
-  : public MTernaryInstruction,
-    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >::Data
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >::Data
 {
     const LambdaFunctionInfo info_;
 
     MLambdaArrow(CompilerConstraintList* constraints, MDefinition* scopeChain,
-                 MDefinition* this_, MDefinition* newTarget_, JSFunction* fun)
-      : MTernaryInstruction(scopeChain, this_, newTarget_), info_(fun)
+                 MDefinition* this_, JSFunction* fun)
+      : MBinaryInstruction(scopeChain, this_), info_(fun)
     {
         setResultType(MIRType_Object);
         MOZ_ASSERT(!ObjectGroup::useSingletonForClone(fun));
         if (!fun->isSingleton())
             setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
     }
 
   public:
     INSTRUCTION_HEADER(LambdaArrow)
 
     static MLambdaArrow* New(TempAllocator& alloc, CompilerConstraintList* constraints,
-                             MDefinition* scopeChain, MDefinition* this_, MDefinition* newTarget_,
-                             JSFunction* fun)
-    {
-        return new(alloc) MLambdaArrow(constraints, scopeChain, this_, newTarget_, fun);
+                             MDefinition* scopeChain, MDefinition* this_, JSFunction* fun)
+    {
+        return new(alloc) MLambdaArrow(constraints, scopeChain, this_, fun);
     }
     MDefinition* scopeChain() const {
         return getOperand(0);
     }
     MDefinition* thisDef() const {
         return getOperand(1);
     }
-    MDefinition* newTargetDef() const {
-        return getOperand(2);
-    }
     const LambdaFunctionInfo& info() const {
         return info_;
     }
 };
 
 // Returns obj->slots.
 class MSlots
   : public MUnaryInstruction,
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -264,18 +264,17 @@ namespace jit {
     _(RecompileCheck)                                                       \
     _(MemoryBarrier)                                                        \
     _(AsmJSCompareExchangeHeap)                                             \
     _(AsmJSAtomicBinopHeap)                                                 \
     _(UnknownValue)                                                         \
     _(LexicalCheck)                                                         \
     _(ThrowUninitializedLexical)                                            \
     _(Debugger)                                                             \
-    _(NewTarget)                                                            \
-    _(ArrowNewTarget)
+    _(NewTarget)
 
 // Forward declarations of MIR types.
 #define FORWARD_DECLARE(op) class M##op;
  MIR_OPCODE_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class MDefinitionVisitor // interface i.e. pure abstract class
 {
--- a/js/src/jit/RematerializedFrame.h
+++ b/js/src/jit/RematerializedFrame.h
@@ -197,18 +197,16 @@ class RematerializedFrame
         MOZ_ASSERT(i < numActualArgs());
         MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
         MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
         return argv()[i];
     }
 
     Value newTarget() {
         MOZ_ASSERT(isFunctionFrame());
-        if (callee()->isArrow())
-            return callee()->getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
         if (isConstructing())
             return argv()[numActualArgs()];
         return UndefinedValue();
     }
 
     Value returnValue() const {
         return returnValue_;
     }
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -604,30 +604,26 @@ fun_bind(JSContext* cx, unsigned argc, V
  */
 class FunctionExtended : public JSFunction
 {
   public:
     static const unsigned NUM_EXTENDED_SLOTS = 2;
 
     /* Arrow functions store their lexical |this| in the first extended slot. */
     static const unsigned ARROW_THIS_SLOT = 0;
-    static const unsigned ARROW_NEWTARGET_SLOT = 1;
 
     static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
 
     static inline size_t offsetOfExtendedSlot(unsigned which) {
         MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
         return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue);
     }
     static inline size_t offsetOfArrowThisSlot() {
         return offsetOfExtendedSlot(ARROW_THIS_SLOT);
     }
-    static inline size_t offsetOfArrowNewTargetSlot() {
-        return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
-    }
 
   private:
     friend class JSFunction;
 
     /* Reserved slots available for storage by particular native functions. */
     HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
 };
 
deleted file mode 100644
--- a/js/src/tests/ecma_6/Class/newTargetArrow.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// new.target is valid in any arrow function not in a global context.
-new Function('(() => new.target)()');
-
-// It's also good inside eval, but not global eval
-assertThrowsInstanceOf(() => eval('() => new.target'), SyntaxError);
-
-function assertNewTarget(expected) {
-    assertEq((()=>new.target)(), expected);
-    assertEq(eval('()=>new.target')(), expected);
-
-    // Make sure that arrow functions can escape their original context and
-    // still get the right answer.
-    return (() => new.target);
-}
-
-const ITERATIONS = 550;
-for (let i = 0; i < ITERATIONS; i++)
-    assertEq(assertNewTarget(undefined)(), undefined);
-
-for (let i = 0; i < ITERATIONS; i++)
-    assertEq(new assertNewTarget(assertNewTarget)(), assertNewTarget);
-
-if (typeof reportCompare === 'function')
-    reportCompare(0,0,"OK");
--- a/js/src/tests/ecma_6/Class/newTargetEval.js
+++ b/js/src/tests/ecma_6/Class/newTargetEval.js
@@ -1,27 +1,27 @@
 // Eval of new.target is invalid outside functions.
 try {
     eval('new.target');
     assertEq(false, true);
 } catch (e if e instanceof SyntaxError) { }
 
-// new.target is invalid inside eval inside top-level arrow functions
+// new.target is (for now!) invalid inside arrow functions, or eval inside arrow
+// functions.
 assertThrowsInstanceOf(() => eval('new.target'), SyntaxError);
 
 // new.target is invalid inside indirect eval.
 let ieval = eval;
 try {
     (function () ieval('new.target'))();
     assertEq(false, true);
 } catch (e if e instanceof SyntaxError) { }
 
 function assertNewTarget(expected) {
     assertEq(eval('new.target'), expected);
-    assertEq((()=>eval('new.target'))(), expected);
 
     // Also test nestings "by induction"
     assertEq(eval('eval("new.target")'), expected);
     assertEq(eval("eval('eval(`new.target`)')"), expected);
 }
 
 const ITERATIONS = 550;
 for (let i = 0; i < ITERATIONS; i++)
--- a/js/src/tests/js1_8_5/reflect-parse/newTarget.js
+++ b/js/src/tests/js1_8_5/reflect-parse/newTarget.js
@@ -6,18 +6,18 @@ function testNewTarget() {
 
     // even with gratuitous whitespace.
     assertInFunctionExpr(`new.
                             target`, newTarget());
 
     // invalid in top-level scripts
     assertError("new.target", SyntaxError);
 
-    // valid in arrow functions inside functions
-    assertInFunctionExpr("()=>new.target", arrowExpr([], newTarget()));
+    // invalid (for now!) in any arrow function
+    assertError("function foo() { (() => new.target) }", SyntaxError);
     assertError("(() => new.target))", SyntaxError);
 
     // invalid (for now!) in generators
     assertError("function *foo() { new.target; }", SyntaxError);
 
     // new.target is a member expression. You should be able to call, invoke, or
     // access properties of it.
     assertInFunctionExpr("new.target.foo", dotExpr(newTarget(), ident("foo")));
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3415,24 +3415,22 @@ CASE(JSOP_LAMBDA)
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_LAMBDA)
 
 CASE(JSOP_LAMBDA_ARROW)
 {
     /* Load the specified function object literal. */
     ReservedRooted<JSFunction*> fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc)));
-    ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-2]);
-    ReservedRooted<Value> newTarget(&rootValue1, REGS.sp[-1]);
-    JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv, newTarget);
+    ReservedRooted<Value> thisv(&rootValue0, REGS.sp[-1]);
+    JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), thisv);
     if (!obj)
         goto error;
     MOZ_ASSERT(obj->getProto());
-    REGS.sp[-2].setObject(*obj);
-    REGS.sp--;
+    REGS.sp[-1].setObject(*obj);
 }
 END_CASE(JSOP_LAMBDA_ARROW)
 
 CASE(JSOP_CALLEE)
     MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
     PUSH_COPY(REGS.fp()->calleev());
 END_CASE(JSOP_CALLEE)
 
@@ -3962,17 +3960,16 @@ CASE(JSOP_SUPERBASE)
     }
     if (si.done())
         MOZ_CRASH("Unexpected scope chain in superbase");
 }
 END_CASE(JSOP_SUPERBASE)
 
 CASE(JSOP_NEWTARGET)
     PUSH_COPY(REGS.fp()->newTarget());
-    MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
 END_CASE(JSOP_NEWTARGET)
 
 DEFAULT()
 {
     char numBuf[12];
     JS_snprintf(numBuf, sizeof numBuf, "%d", *REGS.pc);
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                          JSMSG_BAD_BYTECODE, numBuf);
@@ -4164,29 +4161,27 @@ js::Lambda(JSContext* cx, HandleFunction
     if (!clone)
         return nullptr;
 
     MOZ_ASSERT(fun->global() == clone->global());
     return clone;
 }
 
 JSObject*
-js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv,
-                HandleValue newTargetv)
+js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv)
 {
     MOZ_ASSERT(fun->isArrow());
 
     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, nullptr,
                                                              TenuredObject));
     if (!clone)
         return nullptr;
 
     MOZ_ASSERT(clone->as<JSFunction>().isArrow());
     clone->as<JSFunction>().setExtendedSlot(0, thisv);
-    clone->as<JSFunction>().setExtendedSlot(1, newTargetv);
 
     MOZ_ASSERT(fun->global() == clone->global());
     return clone;
 }
 
 bool
 js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject scopeChain,
                     HandleFunction funArg)
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -351,18 +351,17 @@ GetScopeName(JSContext* cx, HandleObject
 bool
 GetScopeNameForTypeOf(JSContext* cx, HandleObject obj, HandlePropertyName name,
                       MutableHandleValue vp);
 
 JSObject*
 Lambda(JSContext* cx, HandleFunction fun, HandleObject parent);
 
 JSObject*
-LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv,
-            HandleValue newTargetv);
+LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleValue thisv);
 
 bool
 GetElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
 
 bool
 CallElement(JSContext* cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
 
 bool
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -1335,17 +1335,17 @@ 1234567890123456789012345678901234567890
     /*
      * Pops the top of stack value as 'this', pushes an arrow function with
      * 'this' onto the stack.
      *   Category: Statements
      *   Type: Function
      *   Operands: uint32_t funcIndex
      *   Stack: this => obj
      */ \
-    macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL,   5,  2,  1, JOF_OBJECT) \
+    macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL,   5,  1,  1, JOF_OBJECT) \
     \
     /*
      * Pushes current callee onto the stack.
      *
      * Used for named function expression self-naming, if lightweight.
      *   Category: Variables and Scopes
      *   Type: Arguments
      *   Operands:
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -39,19 +39,16 @@ InterpreterFrame::initExecuteFrame(JSCon
     /*
      * See encoding of ExecuteType. When GLOBAL isn't set, we are executing a
      * script in the context of another frame and the frame type is determined
      * by the context.
      */
     flags_ = type | HAS_SCOPECHAIN;
 
     JSObject* callee = nullptr;
-
-    // newTarget = NullValue is an initial sentinel for "please fill me in from the stack".
-    // It should never be passed from Ion code.
     RootedValue newTarget(cx, newTargetValue);
     if (!(flags_ & (GLOBAL))) {
         if (evalInFramePrev) {
             MOZ_ASSERT(evalInFramePrev.isFunctionFrame() || evalInFramePrev.isGlobalFrame());
             if (evalInFramePrev.isFunctionFrame()) {
                 callee = evalInFramePrev.callee();
                 if (newTarget.isNull())
                     newTarget = evalInFramePrev.newTarget();
@@ -68,16 +65,19 @@ InterpreterFrame::initExecuteFrame(JSCon
                     newTarget = iter.newTarget();
                 callee = iter.callee(cx);
                 flags_ |= FUNCTION;
             } else {
                 flags_ |= GLOBAL;
             }
         }
     }
+    
+    // Null is just a sentinel value. We should have figured it out by now.
+    MOZ_ASSERT_IF(isFunctionFrame(), newTarget.isObject() || newTarget.isUndefined());
 
     Value* dstvp = (Value*)this - 3;
     dstvp[2] = thisv;
 
     if (isFunctionFrame()) {
         dstvp[1] = ObjectValue(*callee);
         exec.fun = &callee->as<JSFunction>();
         u.evalScript = script;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -750,19 +750,16 @@ class InterpreterFrame
      * function will have a copy of the newTarget of the enclosing function
      * frame.
      */
     Value newTarget() const {
         MOZ_ASSERT(isFunctionFrame());
         if (isEvalFrame())
             return ((Value*)this)[-3];
 
-        if (callee().isArrow())
-            return callee().getExtendedSlot(FunctionExtended::ARROW_NEWTARGET_SLOT);
-
         if (isConstructing()) {
             unsigned pushedArgs = Max(numFormalArgs(), numActualArgs());
             return argv()[pushedArgs];
         }
         return UndefinedValue();
     }
 
     /*
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,17 +24,17 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 291;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 290;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
 static_assert(JSErr_Limit == 401,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");