Backed out changeset 0f963fbdc918 (bug 1141865)
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 03 Jun 2015 12:41:48 +0200
changeset 246982 b003dbf1e2536d38220b85961422c95a3860faed
parent 246981 05411d0a95ad05108ec468fbc12bb84ddaee7d4b
child 246983 8b7268073cd82c258a45f5fb98aaec0bc055a20c
push id28848
push userryanvm@gmail.com
push dateWed, 03 Jun 2015 20:00:13 +0000
treeherdermozilla-central@0920f2325a6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1141865
milestone41.0a1
backs out0f963fbdc9182335ece49a6aa16b846529e623ad
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
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.");