Bug 1141865 - Part 2: Plumb new.target on the stack and make it accessible to JSNatives. (r=jorendorff, r=jandem, r=shu)
☠☠ backed out by 23fcf07dcd9e ☠ ☠
authorEric Faust <efaustbmo@mozilla.com>
Wed, 03 Jun 2015 02:01:14 -0700
changeset 246972 d038c5da19b0d926d7c6ca3a7d78389548312ee3
parent 246971 2901436c9047202f7cc30fd89474e1bd2075294d
child 246973 8f94d0d72a2197cb3b1c5c063d13b836e0a2b179
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)
reviewersjorendorff, jandem, shu
bugs1141865
milestone41.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 1141865 - Part 2: Plumb new.target on the stack and make it accessible to JSNatives. (r=jorendorff, r=jandem, r=shu)
js/public/CallArgs.h
js/src/frontend/BytecodeEmitter.cpp
js/src/jit-test/tests/basic/newTargetRectifier.js
js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js
js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js
js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineFrame.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/Ion.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/JitFrameIterator.h
js/src/jit/JitFrames.cpp
js/src/jit/LIR-Common.h
js/src/jit/MCallOptimize.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jit/arm/Trampoline-arm.cpp
js/src/jit/x64/Trampoline-x64.cpp
js/src/jit/x86-shared/MacroAssembler-x86-shared.h
js/src/jit/x86/Trampoline-x86.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsfun.cpp
js/src/jsiter.cpp
js/src/jsopcode.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/DirectProxyHandler.cpp
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/tests/ecma_6/Class/newTargetCCW.js
js/src/tests/js1_7/extensions/regress-354945-01.js
js/src/tests/js1_7/extensions/regress-354945-02.js
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/Opcodes.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/src/vm/Xdr.h
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -280,16 +280,17 @@ namespace detail {
 template<UsedRval WantUsedRval>
 class MOZ_STACK_CLASS CallArgsBase :
         public mozilla::Conditional<WantUsedRval == detail::IncludeUsedRval,
                                     CallReceiver,
                                     CallReceiverBase<NoUsedRval> >::Type
 {
   protected:
     unsigned argc_;
+    bool constructing_;
 
   public:
     /* Returns the number of arguments. */
     unsigned length() const { return argc_; }
 
     /* Returns the i-th zero-indexed argument. */
     MutableHandleValue operator[](unsigned i) const {
         MOZ_ASSERT(i < argc_);
@@ -309,63 +310,69 @@ class MOZ_STACK_CLASS CallArgsBase :
     /*
      * Returns true if the i-th zero-indexed argument is present and is not
      * |undefined|.
      */
     bool hasDefined(unsigned i) const {
         return i < argc_ && !this->argv_[i].isUndefined();
     }
 
+    MutableHandleValue newTarget() const {
+        MOZ_ASSERT(constructing_);
+        return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
+    }
+
   public:
     // These methods are publicly exposed, but we're less sure of the interface
     // here than we'd like (because they're hackish and drop assertions).  Try
     // to avoid using these if you can.
 
     Value* array() const { return this->argv_; }
-    Value* end() const { return this->argv_ + argc_; }
+    Value* end() const { return this->argv_ + argc_ + constructing_; }
 };
 
 } // namespace detail
 
 class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval>
 {
   private:
     friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
-    friend CallArgs CallArgsFromSp(unsigned argc, Value* sp);
+    friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing);
 
-    static CallArgs create(unsigned argc, Value* argv) {
+    static CallArgs create(unsigned argc, Value* argv, bool constructing) {
         CallArgs args;
         args.clearUsedRval();
         args.argv_ = argv;
         args.argc_ = argc;
+        args.constructing_ = constructing;
         return args;
     }
 
   public:
     /*
      * Returns true if there are at least |required| arguments passed in. If
      * false, it reports an error message on the context.
      */
     bool requireAtLeast(JSContext* cx, const char* fnname, unsigned required);
 
 };
 
 MOZ_ALWAYS_INLINE CallArgs
 CallArgsFromVp(unsigned argc, Value* vp)
 {
-    return CallArgs::create(argc, vp + 2);
+    return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING));
 }
 
 // This method is only intended for internal use in SpiderMonkey.  We may
 // eventually move it to an internal header.  Embedders should use
 // JS::CallArgsFromVp!
 MOZ_ALWAYS_INLINE CallArgs
-CallArgsFromSp(unsigned argc, Value* sp)
+CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false)
 {
-    return CallArgs::create(argc, sp - argc);
+    return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing);
 }
 
 } // namespace JS
 
 /*
  * Macros to hide interpreter stack layout details from a JSNative using its
  * JS::Value* vp parameter.  DO NOT USE THESE!  Instead use JS::CallArgs and
  * friends, above.  These macros will be removed when we change JSNative to
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6442,31 +6442,44 @@ BytecodeEmitter::emitCallOrNew(ParseNode
         break;
     }
     if (!callop) {
         JSOp thisop = pn->isKind(PNK_GENEXP) ? JSOP_THIS : JSOP_UNDEFINED;
         if (!emit1(thisop))
             return false;
     }
 
+    bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW;
+
     /*
      * Emit code for each argument in order, then emit the JSOP_*CALL or
      * JSOP_NEW bytecode with a two-byte immediate telling how many args
      * were pushed on the operand stack.
      */
     bool oldEmittingForInit = emittingForInit;
     emittingForInit = false;
     if (!spread) {
         for (ParseNode* pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
             if (!emitTree(pn3))
                 return false;
         }
+
+        if (isNewOp) {
+            // Repush the callee as new.target
+            if (!emitDupAt(this->stackDepth - 1 - (argc + 1)))
+                return false;
+        }
     } else {
         if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
             return false;
+
+        if (isNewOp) {
+            if (!emitDupAt(this->stackDepth - 1 - 2))
+                return false;
+        }
     }
     emittingForInit = oldEmittingForInit;
 
     if (!spread) {
         if (!emitCall(pn->getOp(), argc, pn))
             return false;
     } else {
         if (!emit1(pn->getOp()))
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/newTargetRectifier.js
@@ -0,0 +1,12 @@
+function testBailoutNewTarget() {
+    function Inner(ex, forceRectifier) {
+        bailout();
+        assertEq(new.target, ex);
+    }
+
+    for (let i = 0; i < 1100; i++)
+        new Inner(Inner);
+}
+
+for (let i = 0; i < 15; i++)
+    testBailoutNewTarget();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js
@@ -0,0 +1,37 @@
+// Test that Ion frames are invalidated by turning on Debugger. Invalidation
+// is unobservable, but we know that Ion scripts cannot handle Debugger
+// handlers, so we test for the handlers being called.
+
+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) {
+    if (d) {
+      dbg.addDebuggee(g);
+
+      var frame = dbg.getNewestFrame();
+      assertEq(frame.implementation, "ion");
+      assertEq(frame.constructing, true);
+
+      // overflow args are read from the parent's frame
+      // ensure we have the right offset to read from those.
+      assertEq(frame.arguments[1], 15);
+    }
+  };
+
+  g.eval("" + function f(d) { new g(d, 15); });
+
+  g.eval("" + function g(d) { toggle(d); });
+
+  g.eval("(" + function test() {
+    for (var i = 0; i < 5; i++)
+      f(false);
+    f(true);
+  } + ")();");
+});
--- a/js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct1.js
@@ -1,10 +1,12 @@
 // Forward to the target if the trap is undefined
+var p;
 var target = function (x, y) {
+    assertEq(new.target, p);
     this.foo = x + y;
 }
 
-for (let p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
+for (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) {
     var obj = new p(2, 3);
     assertEq(obj.foo, 5);
     assertEq(Object.getPrototypeOf(obj), target.prototype);
 }
--- a/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct2.js
@@ -1,19 +1,21 @@
 load(libdir + "asserts.js");
 /*
  * Call the trap with the handler as the this value, the target as the first
  * argument, and the original arguments as the third argument.
  *
  * Hooks that don't return an object must throw.
  */
+var p;
 var target = function () {};
 var handler = {
-    construct: function (target1, args) {
+    construct: function (target1, args, newTarget) {
         assertEq(this, handler);
         assertEq(target1, target);
         assertEq(args.length, 2);
         assertEq(args[0], 2);
         assertEq(args[1], 3);
+        assertEq(newTarget, p);
     }
 }
-for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
+for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy])
     assertThrowsInstanceOf(function () {new p(2, 3)}, TypeError);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -971,16 +971,18 @@ InitFromBailout(JSContext* cx, HandleScr
 
     JitSpew(JitSpew_BaselineBailouts, "      Resuming %s pc offset %d (op %s) (line %d) of %s:%" PRIuSIZE,
                 resumeAfter ? "after" : "at", (int) pcOff, js_CodeName[op],
                 PCToLineNumber(script, pc), script->filename(), script->lineno());
     JitSpew(JitSpew_BaselineBailouts, "      Bailout kind: %s",
             BailoutKindString(bailoutKind));
 #endif
 
+    bool pushedNewTarget = op == JSOP_NEW;
+    
     // If this was the last inline frame, or we are bailing out to a catch or
     // finally block in this frame, then unpacking is almost done.
     if (!iter.moreFrames() || catchingException) {
         // Last frame, so PC for call to next frame is set to nullptr.
         *callPC = nullptr;
 
         // If the bailout was a resumeAfter, and the opcode is monitored,
         // then the bailed out state should be in a position to enter
@@ -1027,21 +1029,24 @@ InitFromBailout(JSContext* cx, HandleScr
             // stack and pops them only after returning from the call IC.
             // Push undefs onto the stack in anticipation of the popping of the
             // callee, thisv, and actual arguments passed from the caller's frame.
             if (isCall) {
                 builder.writeValue(UndefinedValue(), "CallOp FillerCallee");
                 builder.writeValue(UndefinedValue(), "CallOp FillerThis");
                 for (uint32_t i = 0; i < numCallArgs; i++)
                     builder.writeValue(UndefinedValue(), "CallOp FillerArg");
+                if (pushedNewTarget)
+                    builder.writeValue(UndefinedValue(), "CallOp FillerNewTarget");
 
-                frameSize += (numCallArgs + 2) * sizeof(Value);
+                frameSize += (numCallArgs + 2 + pushedNewTarget) * sizeof(Value);
                 blFrame->setFrameSize(frameSize);
                 JitSpew(JitSpew_BaselineBailouts, "      Adjusted framesize += %d: %d",
-                                (int) ((numCallArgs + 2) * sizeof(Value)), (int) frameSize);
+                                (int) ((numCallArgs + 2 + pushedNewTarget) * sizeof(Value)),
+                                (int) frameSize);
             }
 
             // Set the resume address to the return point from the IC, and set
             // the monitor stub addr.
             builder.setResumeAddr(baselineScript->returnAddressForIC(icEntry));
             builder.setMonitorStub(firstMonStub);
             JitSpew(JitSpew_BaselineBailouts, "      Set resumeAddr=%p monitorStub=%p",
                     baselineScript->returnAddressForIC(icEntry), firstMonStub);
@@ -1223,22 +1228,23 @@ InitFromBailout(JSContext* cx, HandleScr
     } else {
         actualArgc = GET_ARGC(pc);
         if (op == JSOP_FUNCALL) {
             MOZ_ASSERT(actualArgc > 0);
             actualArgc--;
         }
 
         // Align the stack based on the number of arguments.
-        size_t afterFrameSize = (actualArgc + 1) * sizeof(Value) + JitFrameLayout::Size();
+        size_t afterFrameSize = (actualArgc + 1 + pushedNewTarget) * sizeof(Value) +
+                                JitFrameLayout::Size();
         if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding"))
             return false;
 
-        MOZ_ASSERT(actualArgc + 2 <= exprStackSlots);
-        for (unsigned i = 0; i < actualArgc + 1; i++) {
+        MOZ_ASSERT(actualArgc + 2 + pushedNewTarget <= exprStackSlots);
+        for (unsigned i = 0; i < actualArgc + 1 + pushedNewTarget; i++) {
             size_t argSlot = (script->nfixed() + exprStackSlots) - (i + 1);
             if (!builder.writeValue(*blFrame->valueSlot(argSlot), "ArgVal"))
                 return false;
         }
     }
 
     // In case these arguments need to be copied on the stack again for a rectifier frame,
     // save the framePushed values here for later use.
@@ -1255,17 +1261,17 @@ InitFromBailout(JSContext* cx, HandleScr
 
     // Push callee token (must be a JS Function)
     Value callee;
     if (needToSaveArgs) {
         // The arguments of FUNAPPLY or inlined accessors are not writen to the stack.
         // So get the callee from the specially saved vector.
         callee = savedCallerArgs[0];
     } else {
-        uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2);
+        uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2 + pushedNewTarget);
         size_t calleeOffset = (builder.framePushed() - endOfBaselineJSFrameStack)
             + ((exprStackSlots - (calleeStackSlot + 1)) * sizeof(Value));
         callee = *builder.valuePointerAtStackOffset(calleeOffset);
         JitSpew(JitSpew_BaselineBailouts, "      CalleeStackSlot=%d", (int) calleeStackSlot);
     }
     JitSpew(JitSpew_BaselineBailouts, "      Callee = %016llx", *((uint64_t*) &callee));
     MOZ_ASSERT(callee.isObject() && callee.toObject().is<JSFunction>());
     JSFunction* calleeFun = &callee.toObject().as<JSFunction>();
@@ -1326,20 +1332,28 @@ InitFromBailout(JSContext* cx, HandleScr
         return false;
     // Follow the same logic as in JitRuntime::generateArgumentsRectifier.
     prevFramePtr = builder.virtualPointerAtStackOffset(0);
     if (!builder.writePtr(prevFramePtr, "Padding-X86Only"))
         return false;
 #endif
 
     // Align the stack based on the number of arguments.
-    size_t afterFrameSize = (calleeFun->nargs() + 1) * sizeof(Value) + RectifierFrameLayout::Size();
+    size_t afterFrameSize = (calleeFun->nargs() + 1 + pushedNewTarget) * sizeof(Value) +
+                            RectifierFrameLayout::Size();
     if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding"))
         return false;
 
+    // Copy new.target, if necessary.
+    if (pushedNewTarget) {
+        size_t newTargetOffset = (builder.framePushed() - endOfBaselineStubArgs) +
+                                 (actualArgc + 1) * sizeof(Value);
+        builder.writeValue(*builder.valuePointerAtStackOffset(newTargetOffset), "CopiedNewTarget");
+    }
+
     // Push undefined for missing arguments.
     for (unsigned i = 0; i < (calleeFun->nargs() - actualArgc); i++) {
         if (!builder.writeValue(UndefinedValue(), "FillerVal"))
             return false;
     }
 
     // Copy arguments + thisv from BaselineStub frame.
     if (!builder.subtract((actualArgc + 1) * sizeof(Value), "CopiedArgs"))
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2732,29 +2732,30 @@ BaselineCompiler::emit_JSOP_UNINITIALIZE
     return true;
 }
 
 bool
 BaselineCompiler::emitCall()
 {
     MOZ_ASSERT(IsCallPC(pc));
 
+    bool construct = JSOp(*pc) == JSOP_NEW;
     uint32_t argc = GET_ARGC(pc);
 
     frame.syncStack(0);
     masm.move32(Imm32(argc), R0.scratchReg());
 
     // Call IC
-    ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_NEW,
+    ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
                                            /* isSpread = */ false);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     // Update FrameInfo.
-    frame.popn(argc + 2);
+    frame.popn(2 + argc + construct);
     frame.push(R0);
     return true;
 }
 
 bool
 BaselineCompiler::emitSpreadCall()
 {
     MOZ_ASSERT(IsCallPC(pc));
@@ -2764,17 +2765,18 @@ BaselineCompiler::emitSpreadCall()
 
     // Call IC
     ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_SPREADNEW,
                                            /* isSpread = */ true);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     // Update FrameInfo.
-    frame.popn(3);
+    bool construct = JSOp(*pc) == JSOP_SPREADNEW;
+    frame.popn(3 + construct);
     frame.push(R0);
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_CALL()
 {
     return emitCall();
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -32,17 +32,17 @@ BaselineFrame::trace(JSTracer* trc, JitF
 {
     replaceCalleeToken(MarkCalleeToken(trc, calleeToken()));
 
     TraceRoot(trc, &thisValue(), "baseline-this");
 
     // Mark actual and formal args.
     if (isNonEvalFunctionFrame()) {
         unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
-        TraceRootRange(trc, numArgs, argv(), "baseline-args");
+        TraceRootRange(trc, numArgs + isConstructing(), argv(), "baseline-args");
     }
 
     // Mark scope chain, if it exists.
     if (scopeChain_)
         TraceRoot(trc, &scopeChain_, "baseline-scopechain");
 
     // Mark return value.
     if (hasReturnValue())
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -10243,16 +10243,17 @@ TryAttachCallStub(JSContext* cx, ICCall_
         if (stub->nativeStubCount() >= ICCall_Fallback::MAX_NATIVE_STUBS) {
             JitSpew(JitSpew_BaselineIC,
                     "  Too many Call_Native stubs. TODO: add Call_AnyNative!");
             return true;
         }
 
         if (fun->native() == intrinsic_IsSuspendedStarGenerator) {
             // This intrinsic only appears in self-hosted code.
+            MOZ_ASSERT(op != JSOP_NEW);
             MOZ_ASSERT(argc == 1);
             JitSpew(JitSpew_BaselineIC, "  Generating Call_IsSuspendedStarGenerator stub");
 
             ICCall_IsSuspendedStarGenerator::Compiler compiler(cx);
             ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
@@ -10314,16 +10315,20 @@ TryAttachStringSplit(JSContext* cx, ICCa
 {
     if (stub->numOptimizedStubs() != 0)
         return true;
 
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
     Value* args = vp + 2;
 
+    // String.prototype.split will not yield a constructable.
+    if (JSOp(*pc) == JSOP_NEW)
+        return true;
+
     if (!IsOptimizableCallStringSplit(callee, thisv, argc, args))
         return true;
 
     MOZ_ASSERT(callee.isObject());
     MOZ_ASSERT(callee.toObject().is<JSFunction>());
 
     RootedString thisString(cx, thisv.toString());
     RootedString argString(cx, args[0].toString());
@@ -10359,52 +10364,51 @@ TryAttachStringSplit(JSContext* cx, ICCa
 
 static bool
 DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint32_t argc,
                Value* vp, MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICCall_Fallback*> stub(frame, stub_);
 
-    // Ensure vp array is rooted - we may GC in here.
-    AutoArrayRooter vpRoot(cx, argc + 2, vp);
-
     RootedScript script(cx, frame->script());
     jsbytecode* pc = stub->icEntry()->pc(script);
     JSOp op = JSOp(*pc);
     FallbackICSpew(cx, stub, "Call(%s)", js_CodeName[op]);
 
     MOZ_ASSERT(argc == GET_ARGC(pc));
+    bool constructing = (op == JSOP_NEW);
+
+    // Ensure vp array is rooted - we may GC in here.
+    AutoArrayRooter vpRoot(cx, argc + 2 + constructing, vp);
 
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
 
     Value* args = vp + 2;
 
     // Handle funapply with JSOP_ARGUMENTS
     if (op == JSOP_FUNAPPLY && argc == 2 && args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         CallArgs callArgs = CallArgsFromVp(argc, vp);
         if (!GuardFunApplyArgumentsOptimization(cx, frame, callArgs))
             return false;
     }
 
-    // Compute construcing and useNewGroup flags.
-    bool constructing = (op == JSOP_NEW);
     bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, pc);
 
     // Try attaching a call stub.
     bool handled = false;
     if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, false,
                            createSingleton, &handled))
     {
         return false;
     }
 
     if (op == JSOP_NEW) {
-        if (!InvokeConstructor(cx, callee, argc, args, res))
+        if (!InvokeConstructor(cx, callee, argc, args, true, res))
             return false;
     } else if ((op == JSOP_EVAL || op == JSOP_STRICTEVAL) &&
                frame->scopeChain()->global().valueIsEval(callee))
     {
         if (!DirectEval(cx, CallArgsFromVp(argc, vp)))
             return false;
         res.set(vp[0]);
     } else {
@@ -10443,40 +10447,40 @@ DoCallFallback(JSContext* cx, BaselineFr
 
 static bool
 DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, Value* vp,
                      MutableHandleValue res)
 {
     // This fallback stub may trigger debug mode toggling.
     DebugModeOSRVolatileStub<ICCall_Fallback*> stub(frame, stub_);
 
-    // Ensure vp array is rooted - we may GC in here.
-    AutoArrayRooter vpRoot(cx, 3, vp);
-
     RootedScript script(cx, frame->script());
     jsbytecode* pc = stub->icEntry()->pc(script);
     JSOp op = JSOp(*pc);
+    bool constructing = (op == JSOP_SPREADNEW);
     FallbackICSpew(cx, stub, "SpreadCall(%s)", js_CodeName[op]);
 
+    // Ensure vp array is rooted - we may GC in here.
+    AutoArrayRooter vpRoot(cx, 3 + constructing, vp);
+
     RootedValue callee(cx, vp[0]);
     RootedValue thisv(cx, vp[1]);
     RootedValue arr(cx, vp[2]);
-
-    bool constructing = (op == JSOP_SPREADNEW);
+    RootedValue newTarget(cx, constructing ? vp[3] : NullValue());
 
     // Try attaching a call stub.
     bool handled = false;
     if (op != JSOP_SPREADEVAL && op != JSOP_STRICTSPREADEVAL &&
         !TryAttachCallStub(cx, stub, script, pc, op, 1, vp, constructing, true, false,
                            &handled))
     {
         return false;
     }
 
-    if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, res))
+    if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget, res))
         return false;
 
     // Check if debug mode toggling made the stub invalid.
     if (stub.invalid())
         return true;
 
     // Attach a new TypeMonitor stub for this value.
     ICTypeMonitor_Fallback* typeMonFbStub = stub->fallbackMonitorStub();
@@ -10488,103 +10492,138 @@ DoSpreadCallFallback(JSContext* cx, Base
 
     if (!handled)
         stub->noteUnoptimizableCall();
     return true;
 }
 
 void
 ICCallStubCompiler::pushCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
-                                      Register argcReg, bool isJitCall)
+                                      Register argcReg, bool isJitCall, bool isConstructing)
 {
     MOZ_ASSERT(!regs.has(argcReg));
 
-    // Push the callee and |this| too.
+    // Account for new.target
     Register count = regs.takeAny();
+
     masm.mov(argcReg, count);
-    masm.add32(Imm32(2), count);
+
+    // If we are setting up for a jitcall, we have to align the stack taking
+    // into account the args and newTarget. We could also count callee and |this|,
+    // but it's a waste of stack space. Because we want to keep argcReg unchanged,
+    // just account for newTarget initially, and add the other 2 after assuring
+    // allignment.
+    if (isJitCall) {
+        if (isConstructing)
+            masm.add32(Imm32(1), count);
+    } else {
+        masm.add32(Imm32(2 + isConstructing), count);
+    }
 
     // argPtr initially points to the last argument.
     Register argPtr = regs.takeAny();
     masm.mov(BaselineStackReg, argPtr);
 
     // Skip 4 pointers pushed on top of the arguments: the frame descriptor,
     // return address, old frame pointer and stub reg.
     masm.addPtr(Imm32(STUB_FRAME_SIZE), argPtr);
 
     // Align the stack such that the JitFrameLayout is aligned on the
     // JitStackAlignment.
-    if (isJitCall)
-        masm.alignJitStackBasedOnNArgs(argcReg);
+    if (isJitCall) {
+        masm.alignJitStackBasedOnNArgs(count);
+
+        // Account for callee and |this|, skipped earlier
+        masm.add32(Imm32(2), count);
+    }
 
     // Push all values, starting at the last one.
     Label loop, done;
     masm.bind(&loop);
     masm.branchTest32(Assembler::Zero, count, count, &done);
     {
         masm.pushValue(Address(argPtr, 0));
         masm.addPtr(Imm32(sizeof(Value)), argPtr);
 
         masm.sub32(Imm32(1), count);
         masm.jump(&loop);
     }
     masm.bind(&done);
 }
 
 void
-ICCallStubCompiler::guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure)
-{
-    masm.unboxObject(Address(BaselineStackReg, ICStackValueOffset), argcReg);
+ICCallStubCompiler::guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure,
+                                    bool isConstructing)
+{
+    masm.unboxObject(Address(BaselineStackReg, isConstructing * sizeof(Value) + ICStackValueOffset), argcReg);
     masm.loadPtr(Address(argcReg, NativeObject::offsetOfElements()), argcReg);
     masm.load32(Address(argcReg, ObjectElements::offsetOfLength()), argcReg);
 
     // Limit actual argc to something reasonable (huge number of arguments can
     // blow the stack limit).
     static_assert(ICCall_Scripted::MAX_ARGS_SPREAD_LENGTH <= ARGS_LENGTH_MAX,
                   "maximum arguments length for optimized stub should be <= ARGS_LENGTH_MAX");
     masm.branch32(Assembler::Above, argcReg, Imm32(ICCall_Scripted::MAX_ARGS_SPREAD_LENGTH),
                   failure);
 }
 
 void
 ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler& masm,
                                             AllocatableGeneralRegisterSet regs,
-                                            Register argcReg, bool isJitCall)
-{
-    // Push arguments
+                                            Register argcReg, bool isJitCall,
+                                            bool isConstructing)
+{
+    // Pull the array off the stack before aligning.
     Register startReg = regs.takeAny();
+    masm.unboxObject(Address(BaselineStackReg, (isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg);
+    masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
+    
+    // Align the stack such that the JitFrameLayout is aligned on the
+    // JitStackAlignment.
+    if (isJitCall) {
+        Register alignReg = argcReg;
+        if (isConstructing) {
+            alignReg = regs.takeAny();
+            masm.mov(argcReg, alignReg);
+            masm.addPtr(Imm32(1), alignReg);
+        }
+        masm.alignJitStackBasedOnNArgs(alignReg);
+        if (isConstructing) {
+            MOZ_ASSERT(alignReg != argcReg);
+            regs.add(alignReg);
+        }
+    }
+
+    // Push newTarget, if necessary
+    if (isConstructing)
+        masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE));
+
+    // Push arguments: set up endReg to point to &array[argc]
     Register endReg = regs.takeAny();
-    masm.unboxObject(Address(BaselineStackReg, STUB_FRAME_SIZE), startReg);
-    masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
     masm.mov(argcReg, endReg);
     static_assert(sizeof(Value) == 8, "Value must be 8 bytes");
     masm.lshiftPtr(Imm32(3), endReg);
     masm.addPtr(startReg, endReg);
 
-    // Align the stack such that the JitFrameLayout is aligned on the
-    // JitStackAlignment.
-    if (isJitCall)
-        masm.alignJitStackBasedOnNArgs(argcReg);
-
     // Copying pre-decrements endReg by 8 until startReg is reached
     Label copyDone;
     Label copyStart;
     masm.bind(&copyStart);
     masm.branchPtr(Assembler::Equal, endReg, startReg, &copyDone);
     masm.subPtr(Imm32(sizeof(Value)), endReg);
     masm.pushValue(Address(endReg, 0));
     masm.jump(&copyStart);
     masm.bind(&copyDone);
 
     regs.add(startReg);
     regs.add(endReg);
 
     // Push the callee and |this|.
-    masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + 1 * sizeof(Value)));
-    masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + 2 * sizeof(Value)));
+    masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + (1 + isConstructing) * sizeof(Value)));
+    masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + (2 + isConstructing) * sizeof(Value)));
 }
 
 // (see Bug 1149377 comment 31) MSVC 2013 PGO miss-compiles branchTestObjClass
 // calls from this function.
 #if defined(_MSC_VER) && _MSC_VER == 1800
 # pragma optimize("g", off)
 #endif
 Register
@@ -10779,19 +10818,30 @@ ICCall_Fallback::Compiler::generateStubC
     // |this| and callee are pushed last.
 
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     if (MOZ_UNLIKELY(isSpread_)) {
         // Use BaselineFrameReg instead of BaselineStackReg, because
         // BaselineFrameReg and BaselineStackReg hold the same value just after
         // calling enterStubFrame.
-        masm.pushValue(Address(BaselineFrameReg, 0 * sizeof(Value) + STUB_FRAME_SIZE)); // array
-        masm.pushValue(Address(BaselineFrameReg, 1 * sizeof(Value) + STUB_FRAME_SIZE)); // this
-        masm.pushValue(Address(BaselineFrameReg, 2 * sizeof(Value) + STUB_FRAME_SIZE)); // callee
+        
+        // newTarget
+        if (isConstructing_)
+            masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE));
+        
+        // array
+        uint32_t valueOffset = isConstructing_;
+        masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
+        
+        // this
+        masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
+        
+        // callee
+        masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
 
         masm.push(BaselineStackReg);
         masm.push(BaselineStubReg);
 
         masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
         masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
 
         if (!callVM(DoSpreadCallFallbackInfo, masm))
@@ -10802,17 +10852,17 @@ ICCall_Fallback::Compiler::generateStubC
 
         // SPREADCALL is not yet supported in Ion, so do not generate asmcode for
         // bailout.
         return true;
     }
 
     regs.take(R0.scratchReg()); // argc.
 
-    pushCallArguments(masm, regs, R0.scratchReg(), /* isJitCall = */ false);
+    pushCallArguments(masm, regs, R0.scratchReg(), /* isJitCall = */ false, isConstructing_);
 
     masm.push(BaselineStackReg);
     masm.push(R0.scratchReg());
     masm.push(BaselineStubReg);
 
     // Load previous frame pointer, push BaselineFrame*.
     masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
     masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
@@ -10887,24 +10937,27 @@ ICCallScriptedCompiler::generateStubCode
     Register argcReg = R0.scratchReg();
     MOZ_ASSERT(argcReg != ArgumentsRectifierReg);
 
     regs.take(argcReg);
     regs.take(ArgumentsRectifierReg);
     regs.takeUnchecked(BaselineTailCallReg);
 
     if (isSpread_)
-        guardSpreadCall(masm, argcReg, &failure);
-
-    // Load the callee in R1.
-    // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ]
+        guardSpreadCall(masm, argcReg, &failure, isConstructing_);
+
+    // Load the callee in R1, accounting for newTarget, if necessary
+    // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, [newTarget] +ICStackValueOffset+ ]
     if (isSpread_) {
-        masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R1);
+        unsigned skipToCallee = (2 + isConstructing_) * sizeof(Value);
+        masm.loadValue(Address(BaselineStackReg, skipToCallee + ICStackValueOffset), R1);
     } else {
-        BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value));
+        // Account for newTarget, if necessary
+        unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value);
+        BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSkip);
         masm.loadValue(calleeSlot, R1);
     }
     regs.take(R1);
 
     // Ensure callee is an object.
     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
 
     // Ensure callee is a function.
@@ -10954,23 +11007,23 @@ ICCallScriptedCompiler::generateStubCode
 
     Label failureLeaveStubFrame;
 
     if (isConstructing_) {
         // Save argc before call.
         masm.push(argcReg);
 
         // Stack now looks like:
-        //      [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader, ArgC ]
+        //      [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ]
         if (isSpread_) {
             masm.loadValue(Address(BaselineStackReg,
-                                   2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1);
+                                   3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1);
         } else {
             BaseValueIndex calleeSlot2(BaselineStackReg, argcReg,
-                                       sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
+                                       2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t));
             masm.loadValue(calleeSlot2, R1);
         }
         masm.push(masm.extractObject(R1, ExtractTemp0));
         if (!callVM(CreateThisInfoBaseline, masm))
             return false;
 
         // Return of CreateThis must be an object.
 #ifdef DEBUG
@@ -10988,37 +11041,40 @@ ICCallScriptedCompiler::generateStubCode
         argcReg = regs.takeAny();
 
         // Restore saved argc so we can use it to calculate the address to save
         // the resulting this object to.
         masm.pop(argcReg);
 
         // Save "this" value back into pushed arguments on stack.  R0 can be clobbered after that.
         // Stack now looks like:
-        //      [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader ]
+        //      [..., Callee, ThisV, Arg0V, ..., ArgNV, [NewTarget], StubFrameHeader ]
         if (isSpread_) {
-            masm.storeValue(R0, Address(BaselineStackReg, sizeof(Value) + STUB_FRAME_SIZE));
+            masm.storeValue(R0, Address(BaselineStackReg, (1 + isConstructing_) * sizeof(Value) + STUB_FRAME_SIZE));
         } else {
-            BaseValueIndex thisSlot(BaselineStackReg, argcReg, STUB_FRAME_SIZE);
+            BaseValueIndex thisSlot(BaselineStackReg, argcReg, STUB_FRAME_SIZE + isConstructing_ * sizeof(Value));
             masm.storeValue(R0, thisSlot);
         }
 
         // Restore the stub register from the baseline stub frame.
         masm.loadPtr(Address(BaselineStackReg, STUB_FRAME_SAVED_STUB_OFFSET), BaselineStubReg);
 
         // Reload callee script. Note that a GC triggered by CreateThis may
         // have destroyed the callee BaselineScript and IonScript. CreateThis is
         // safely repeatable though, so in this case we just leave the stub frame
         // and jump to the next stub.
 
         // Just need to load the script now.
         if (isSpread_) {
-            masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + STUB_FRAME_SIZE), R0);
+            unsigned skipForCallee = (2 + isConstructing_) * sizeof(Value);
+            masm.loadValue(Address(BaselineStackReg, skipForCallee + STUB_FRAME_SIZE), R0);
         } else {
-            BaseValueIndex calleeSlot3(BaselineStackReg, argcReg, sizeof(Value) + STUB_FRAME_SIZE);
+            // Account for newTarget, if necessary
+            unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value);
+            BaseValueIndex calleeSlot3(BaselineStackReg, argcReg, nonArgsSkip + STUB_FRAME_SIZE);
             masm.loadValue(calleeSlot3, R0);
         }
         callee = masm.extractObject(R0, ExtractTemp0);
         regs.add(R0);
         regs.takeUnchecked(callee);
         masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
 
         code = regs.takeAny();
@@ -11034,19 +11090,19 @@ ICCallScriptedCompiler::generateStubCode
             regs.addUnchecked(BaselineTailCallReg);
     }
     Register scratch = regs.takeAny();
 
     // Values are on the stack left-to-right. Calling convention wants them
     // right-to-left so duplicate them on the stack in reverse order.
     // |this| and callee are pushed last.
     if (isSpread_)
-        pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ true);
+        pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ true, isConstructing_);
     else
-        pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true);
+        pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true, isConstructing_);
 
     // The callee is on top of the stack. Pop and unbox it.
     ValueOperand val = regs.takeAnyValue();
     masm.popValue(val);
     callee = masm.extractObject(val, ExtractTemp0);
 
     EmitCreateStubFrameDescriptor(masm, scratch);
 
@@ -11108,18 +11164,20 @@ ICCallScriptedCompiler::generateStubCode
         } else {
             Address argcAddr(BaselineStackReg, 2 * sizeof(size_t));
             masm.loadPtr(argcAddr, argcReg);
         }
 
         // Current stack: [ ThisVal, ARGVALS..., ...STUB FRAME..., <-- BaselineFrameReg
         //                  Padding?, ARGVALS..., ThisVal, ActualArgc, Callee, Descriptor ]
         //
-        // &ThisVal = BaselineFrameReg + argc * sizeof(Value) + STUB_FRAME_SIZE
-        BaseValueIndex thisSlotAddr(BaselineFrameReg, argcReg, STUB_FRAME_SIZE);
+        // &ThisVal = BaselineFrameReg + argc * sizeof(Value) + STUB_FRAME_SIZE + sizeof(Value)
+        // This last sizeof(Value) accounts for the newTarget on the end of the arguments vector
+        // which is not reflected in actualArgc
+        BaseValueIndex thisSlotAddr(BaselineFrameReg, argcReg, STUB_FRAME_SIZE + sizeof(Value));
         masm.loadValue(thisSlotAddr, JSReturnOperand);
 #ifdef DEBUG
         masm.branchTestObject(Assembler::Equal, JSReturnOperand, &skipThisReplace);
         masm.assumeUnreachable("Return of constructing call should be an object.");
 #endif
         masm.bind(&skipThisReplace);
     }
 
@@ -11281,23 +11339,24 @@ ICCall_Native::Compiler::generateStubCod
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     Register argcReg = R0.scratchReg();
     regs.take(argcReg);
     regs.takeUnchecked(BaselineTailCallReg);
 
     if (isSpread_)
-        guardSpreadCall(masm, argcReg, &failure);
+        guardSpreadCall(masm, argcReg, &failure, isConstructing_);
 
     // Load the callee in R1.
     if (isSpread_) {
         masm.loadValue(Address(BaselineStackReg, ICStackValueOffset + 2 * sizeof(Value)), R1);
     } else {
-        BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value));
+        unsigned nonArgsSlots = (1 + isConstructing_) * sizeof(Value);
+        BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSlots);
         masm.loadValue(calleeSlot, R1);
     }
     regs.take(R1);
 
     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
 
     // Ensure callee matches this stub's callee.
     Register callee = masm.extractObject(R1, ExtractTemp0);
@@ -11310,19 +11369,19 @@ ICCall_Native::Compiler::generateStubCod
     // Push a stub frame so that we can perform a non-tail call.
     // Note that this leaves the return address in TailCallReg.
     enterStubFrame(masm, regs.getAny());
 
     // Values are on the stack left-to-right. Calling convention wants them
     // right-to-left so duplicate them on the stack in reverse order.
     // |this| and callee are pushed last.
     if (isSpread_)
-        pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ false);
+        pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ false, isConstructing_);
     else
-        pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false);
+        pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false, isConstructing_);
 
     if (isConstructing_) {
         // Stack looks like: [ ..., Arg0Val, ThisVal, CalleeVal ]
         // Replace ThisVal with MagicValue(JS_IS_CONSTRUCTING)
         masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(BaselineStackReg, sizeof(Value)));
     }
 
     masm.checkStackAlignment();
@@ -11385,17 +11444,18 @@ ICCall_ClassHook::Compiler::generateStub
     Label failure;
     AllocatableGeneralRegisterSet regs(availableGeneralRegs(0));
 
     Register argcReg = R0.scratchReg();
     regs.take(argcReg);
     regs.takeUnchecked(BaselineTailCallReg);
 
     // Load the callee in R1.
-    BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value));
+    unsigned nonArgSlots = (1 + isConstructing_) * sizeof(Value);
+    BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgSlots);
     masm.loadValue(calleeSlot, R1);
     regs.take(R1);
 
     masm.branchTestObject(Assembler::NotEqual, R1, &failure);
 
     // Ensure the callee's class matches the one in this stub.
     Register callee = masm.extractObject(R1, ExtractTemp0);
     Register scratch = regs.takeAny();
@@ -11407,17 +11467,17 @@ ICCall_ClassHook::Compiler::generateStub
     regs.add(R1);
     regs.takeUnchecked(callee);
 
     // Push a stub frame so that we can perform a non-tail call.
     // Note that this leaves the return address in TailCallReg.
     enterStubFrame(masm, regs.getAny());
 
     regs.add(scratch);
-    pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false);
+    pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false, isConstructing_);
     regs.take(scratch);
 
     if (isConstructing_) {
         // Stack looks like: [ ..., Arg0Val, ThisVal, CalleeVal ]
         // Replace ThisVal with MagicValue(JS_IS_CONSTRUCTING)
         masm.storeValue(MagicValue(JS_IS_CONSTRUCTING), Address(BaselineStackReg, sizeof(Value)));
     }
 
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -5517,20 +5517,21 @@ class ICCallStubCompiler : public ICStub
     { }
 
     enum FunApplyThing {
         FunApply_MagicArgs,
         FunApply_Array
     };
 
     void pushCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
-                           Register argcReg, bool isJitCall);
+                           Register argcReg, bool isJitCall, bool isConstructing = false);
     void pushSpreadCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
-                                 Register argcReg, bool isJitCall);
-    void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure);
+                                 Register argcReg, bool isJitCall, bool isConstructing);
+    void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure,
+                         bool isConstructing);
     Register guardFunApply(MacroAssembler& masm, AllocatableGeneralRegisterSet regs,
                            Register argcReg, bool checkNative, FunApplyThing applyThing,
                            Label* failure);
     void pushCallerArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs);
     void pushArrayArguments(MacroAssembler& masm, Address arrayVal,
                             AllocatableGeneralRegisterSet regs);
 };
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2927,29 +2927,30 @@ static const VMFunction GetIntrinsicValu
 
 void
 CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     callVM(GetIntrinsicValueInfo, lir);
 }
 
-typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, uint32_t, Value*, MutableHandleValue);
+typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue);
 static const VMFunction InvokeFunctionInfo = FunctionInfo<InvokeFunctionFn>(InvokeFunction);
 
 void
 CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
-                                      uint32_t argc, uint32_t unusedStack)
+                                      bool constructing, uint32_t argc, uint32_t unusedStack)
 {
     // Nestle %esp up to the argument vector.
     // Each path must account for framePushed_ separately, for callVM to be valid.
     masm.freeStack(unusedStack);
 
     pushArg(masm.getStackPointer()); // argv.
     pushArg(Imm32(argc));            // argc.
+    pushArg(Imm32(constructing));    // constructing.
     pushArg(calleereg);              // JSFunction*.
 
     callVM(InvokeFunctionInfo, call);
 
     // Un-nestle %esp from the argument vector. No prefix was pushed.
     masm.reserveStack(unusedStack);
 }
 
@@ -2994,17 +2995,18 @@ CodeGenerator::visitCallGeneric(LCallGen
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
     masm.Push(Imm32(call->numActualArgs()));
     masm.PushCalleeToken(calleereg, call->mir()->isConstructing());
     masm.Push(Imm32(descriptor));
 
     // Check whether the provided arguments satisfy target argc.
     // We cannot have lowered to LCallGeneric with a known target. Assert that we didn't
     // add any undefineds in IonBuilder. NB: MCall::numStackArgs includes |this|.
-    MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - 1);
+    DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
+    MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - numNonArgsOnStack);
     masm.load16ZeroExtend(Address(calleereg, JSFunction::offsetOfNargs()), nargsreg);
     masm.branch32(Assembler::Above, nargsreg, Imm32(call->numActualArgs()), &thunk);
     masm.jump(&makeCall);
 
     // Argument fixed needed. Load the ArgumentsRectifier.
     masm.bind(&thunk);
     {
         MOZ_ASSERT(ArgumentsRectifierReg != objreg);
@@ -3021,43 +3023,65 @@ CodeGenerator::visitCallGeneric(LCallGen
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
     // The return address has already been removed from the Ion frame.
     int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
     masm.adjustStack(prefixGarbage - unusedStack);
     masm.jump(&end);
 
     // Handle uncompiled or native functions.
     masm.bind(&invoke);
-    emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
+    emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(),
+                           unusedStack);
 
     masm.bind(&end);
 
     // If the return value of the constructing function is Primitive,
     // replace the return value with the Object from CreateThis.
     if (call->mir()->isConstructing()) {
         Label notPrimitive;
         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
         masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand);
         masm.bind(&notPrimitive);
     }
 }
 
+typedef bool (*InvokeFunctionShuffleFn)(JSContext*, HandleObject, uint32_t, uint32_t, Value*,
+                                        MutableHandleValue);
+static const VMFunction InvokeFunctionShuffleInfo =
+    FunctionInfo<InvokeFunctionShuffleFn>(InvokeFunctionShuffleNewTarget);
+void
+CodeGenerator::emitCallInvokeFunctionShuffleNewTarget(LCallKnown* call, Register calleeReg,
+                                                      uint32_t numFormals, uint32_t unusedStack)
+{
+    masm.freeStack(unusedStack);
+
+    pushArg(masm.getStackPointer());
+    pushArg(Imm32(numFormals));
+    pushArg(Imm32(call->numActualArgs()));
+    pushArg(calleeReg);
+
+    callVM(InvokeFunctionShuffleInfo, call);
+
+    masm.reserveStack(unusedStack);
+}
+
 void
 CodeGenerator::visitCallKnown(LCallKnown* call)
 {
     Register calleereg = ToRegister(call->getFunction());
     Register objreg    = ToRegister(call->getTempObject());
     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
-    DebugOnly<JSFunction*> target = call->getSingleTarget();
+    JSFunction* target = call->getSingleTarget();
     Label end, uncompiled;
 
     // Native single targets are handled by LCallNative.
     MOZ_ASSERT(!target->isNative());
     // Missing arguments must have been explicitly appended by the IonBuilder.
-    MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - 1);
+    DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
+    MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack);
 
     MOZ_ASSERT_IF(call->mir()->isConstructing(), target->isConstructor());
 
     masm.checkStackAlignment();
 
     // The calleereg is known to be a non-native function, but might point to
     // a LazyScript instead of a JSScript.
     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
@@ -3087,17 +3111,20 @@ CodeGenerator::visitCallKnown(LCallKnown
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
     // The return address has already been removed from the Ion frame.
     int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
     masm.adjustStack(prefixGarbage - unusedStack);
     masm.jump(&end);
 
     // Handle uncompiled functions.
     masm.bind(&uncompiled);
-    emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack);
+    if (call->isConstructing() && target->nargs() > call->numActualArgs())
+        emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
+    else
+        emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack);
 
     masm.bind(&end);
 
     // If the return value of the constructing function is Primitive,
     // replace the return value with the Object from CreateThis.
     if (call->mir()->isConstructing()) {
         Label notPrimitive;
         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
@@ -3113,16 +3140,17 @@ CodeGenerator::emitCallInvokeFunction(LA
     MOZ_ASSERT(objreg != extraStackSize);
 
     // Push the space used by the arguments.
     masm.moveStackPtrTo(objreg);
     masm.Push(extraStackSize);
 
     pushArg(objreg);                           // argv.
     pushArg(ToRegister(apply->getArgc()));     // argc.
+    pushArg(Imm32(false));                     // isConstrucing.
     pushArg(ToRegister(apply->getFunction())); // JSFunction*.
 
     // This specialization og callVM restore the extraStackSize after the call.
     callVM(InvokeFunctionInfo, apply, &extraStackSize);
 
     masm.Pop(extraStackSize);
 }
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -125,18 +125,23 @@ class CodeGenerator : public CodeGenerat
     void visitTypeBarrierV(LTypeBarrierV* lir);
     void visitTypeBarrierO(LTypeBarrierO* lir);
     void visitMonitorTypes(LMonitorTypes* lir);
     void visitPostWriteBarrierO(LPostWriteBarrierO* lir);
     void visitPostWriteBarrierV(LPostWriteBarrierV* lir);
     void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
     void visitCallNative(LCallNative* call);
     void emitCallInvokeFunction(LInstruction* call, Register callereg,
-                                uint32_t argc, uint32_t unusedStack);
+                                bool isConstructing, uint32_t argc,
+                                uint32_t unusedStack);
     void visitCallGeneric(LCallGeneric* call);
+    void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call,
+                                                Register calleeReg,
+                                                uint32_t numFormals,
+                                                uint32_t unusedStack);
     void visitCallKnown(LCallKnown* call);
     void emitCallInvokeFunction(LApplyArgsGeneric* apply, Register extraStackSize);
     void emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace);
     void emitPopArguments(LApplyArgsGeneric* apply, Register extraStackSize);
     void visitApplyArgsGeneric(LApplyArgsGeneric* apply);
     void visitBail(LBail* lir);
     void visitUnreachable(LUnreachable* unreachable);
     void visitEncodeSnapshot(LEncodeSnapshot* lir);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2557,28 +2557,32 @@ jit::SetEnterJitData(JSContext* cx, Ente
         data.maxArgc = Max(args.length(), numFormals) + 1;
         data.scopeChain = nullptr;
         data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>(), data.constructing);
 
         if (data.numActualArgs >= numFormals) {
             data.maxArgv = args.base() + 1;
         } else {
             MOZ_ASSERT(vals.empty());
-            if (!vals.reserve(Max(args.length() + 1, numFormals + 1)))
+            unsigned numPushedArgs = Max(args.length(), numFormals);
+            if (!vals.reserve(numPushedArgs + 1 + data.constructing))
                 return false;
 
             // Append |this| and any provided arguments.
             for (size_t i = 1; i < args.length() + 2; ++i)
                 vals.infallibleAppend(args.base()[i]);
 
             // Pad missing arguments with |undefined|.
             while (vals.length() < numFormals + 1)
                 vals.infallibleAppend(UndefinedValue());
 
-            MOZ_ASSERT(vals.length() >= numFormals + 1);
+            if (data.constructing)
+                vals.infallibleAppend(args.newTarget());
+
+            MOZ_ASSERT(vals.length() >= numFormals + 1 + data.constructing);
             data.maxArgv = vals.begin();
         }
     } else {
         data.constructing = false;
         data.numActualArgs = 0;
         data.maxArgc = 1;
         data.maxArgv = state.asExecute()->addressOfThisv();
         data.scopeChain = state.asExecute()->scopeChain();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -5263,16 +5263,18 @@ IonBuilder::inlineCallsite(const ObjectV
         callInfo.fun()->setImplicitlyUsedUnchecked();
 
         // If the callee is not going to be a lambda (which may vary across
         // different invocations), then the callee definition can be replaced by a
         // constant.
         if (target->isSingleton()) {
             // Replace the function with an MConstant.
             MConstant* constFun = constant(ObjectValue(*target));
+            if (callInfo.constructing() && callInfo.getNewTarget() == callInfo.fun())
+                callInfo.setNewTarget(constFun);
             callInfo.setFun(constFun);
         }
 
         return inlineSingleCall(callInfo, target);
     }
 
     // Choose a subset of the targets for polymorphic inlining.
     BoolVector choiceSet(alloc());
@@ -6131,17 +6133,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
         } else if (*GetNextPc(pc) == JSOP_POS) {
             // Note: this is lame, overspecialized on the code patterns used
             // by asm.js and should be replaced by a more general mechanism.
             // See bug 870847.
             observed->addType(TypeSet::DoubleType(), alloc_->lifoAlloc());
         }
     }
 
-    int calleeDepth = -((int)argc + 2);
+    int calleeDepth = -((int)argc + 2 + constructing);
 
     // Acquire known call target if existent.
     ObjectVector targets(alloc());
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     if (calleeTypes && !getPolyCallTargets(calleeTypes, constructing, targets, 4))
         return false;
 
     CallInfo callInfo(alloc(), constructing);
@@ -6274,21 +6276,24 @@ IonBuilder::makeCallHelper(JSFunction* t
             thisTypes->getKnownMIRType() == MIRType_Object &&
             thisTypes->isDOMClass(constraints()) &&
             testShouldDOMCall(thisTypes, target, JSJitInfo::Method))
         {
             isDOMCall = true;
         }
     }
 
-    MCall* call = MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(),
-                             callInfo.constructing(), isDOMCall);
+    MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(),
+                             callInfo.argc(), callInfo.constructing(), isDOMCall);
     if (!call)
         return nullptr;
 
+    if (callInfo.constructing())
+        call->addArg(targetArgs + 1, callInfo.getNewTarget());
+
     // Explicitly pad any missing arguments with |undefined|.
     // This permits skipping the argumentsRectifier.
     for (int i = targetArgs; i > (int)callInfo.argc(); i--) {
         MOZ_ASSERT_IF(target, !target->isNative());
         MConstant* undef = constant(UndefinedValue());
         call->addArg(i, undef);
     }
 
@@ -9435,17 +9440,17 @@ IonBuilder::jsop_rest()
         MRest* rest = MRest::New(alloc(), constraints(), numActuals, info().nargs() - 1,
                                  templateObject);
         current->add(rest);
         current->push(rest);
         return true;
     }
 
     // We know the exact number of arguments the callee pushed.
-    unsigned numActuals = inlineCallInfo_->argv().length();
+    unsigned numActuals = inlineCallInfo_->argc();
     unsigned numFormals = info().nargs() - 1;
     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
 
     MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     current->add(templateConst);
 
     MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
                                       templateObject->group()->initialHeap(constraints()),
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -1239,48 +1239,57 @@ class IonBuilder
     void trackOptimizationSuccessUnchecked();
     void trackInlineSuccessUnchecked(InliningStatus status);
 };
 
 class CallInfo
 {
     MDefinition* fun_;
     MDefinition* thisArg_;
+    MDefinition* newTargetArg_;
     MDefinitionVector args_;
 
     bool constructing_;
     bool setter_;
 
   public:
     CallInfo(TempAllocator& alloc, bool constructing)
       : fun_(nullptr),
         thisArg_(nullptr),
+        newTargetArg_(nullptr),
         args_(alloc),
         constructing_(constructing),
         setter_(false)
     { }
 
     bool init(CallInfo& callInfo) {
         MOZ_ASSERT(constructing_ == callInfo.constructing());
 
         fun_ = callInfo.fun();
         thisArg_ = callInfo.thisArg();
 
+        if (constructing())
+            newTargetArg_ = callInfo.getNewTarget();
+
         if (!args_.appendAll(callInfo.argv()))
             return false;
 
         return true;
     }
 
     bool init(MBasicBlock* current, uint32_t argc) {
         MOZ_ASSERT(args_.empty());
 
         // Get the arguments in the right order
         if (!args_.reserve(argc))
             return false;
+
+        if (constructing())
+            setNewTarget(current->pop());
+
         for (int32_t i = argc; i > 0; i--)
             args_.infallibleAppend(current->peek(-i));
         current->popn(argc);
 
         // Get |this| and |fun|
         setThis(current->pop());
         setFun(current->pop());
 
@@ -1292,23 +1301,26 @@ class CallInfo
     }
 
     void pushFormals(MBasicBlock* current) {
         current->push(fun());
         current->push(thisArg());
 
         for (uint32_t i = 0; i < argc(); i++)
             current->push(getArg(i));
+
+        if (constructing())
+            current->push(getNewTarget());
     }
 
     uint32_t argc() const {
         return args_.length();
     }
     uint32_t numFormals() const {
-        return argc() + 2;
+        return argc() + 2 + constructing();
     }
 
     bool setArgs(const MDefinitionVector& args) {
         MOZ_ASSERT(args_.empty());
         return args_.appendAll(args);
     }
 
     MDefinitionVector& argv() {
@@ -1344,16 +1356,25 @@ class CallInfo
     void setThis(MDefinition* thisArg) {
         thisArg_ = thisArg;
     }
 
     bool constructing() const {
         return constructing_;
     }
 
+    void setNewTarget(MDefinition* newTarget) {
+        MOZ_ASSERT(constructing());
+        newTargetArg_ = newTarget;
+    }
+    MDefinition* getNewTarget() const {
+        MOZ_ASSERT(newTargetArg_);
+        return newTargetArg_;
+    }
+
     bool isSetter() const {
         return setter_;
     }
     void markAsSetter() {
         setter_ = true;
     }
 
     MDefinition* fun() const {
@@ -1363,16 +1384,18 @@ class CallInfo
 
     void setFun(MDefinition* fun) {
         fun_ = fun;
     }
 
     void setImplicitlyUsedUnchecked() {
         fun_->setImplicitlyUsedUnchecked();
         thisArg_->setImplicitlyUsedUnchecked();
+        if (newTargetArg_)
+            newTargetArg_->setImplicitlyUsedUnchecked();
         for (uint32_t i = 0; i < argc(); i++)
             getArg(i)->setImplicitlyUsedUnchecked();
     }
 };
 
 bool NeedsPostBarrier(CompileInfo& info, MDefinition* value);
 
 } // namespace jit
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -741,23 +741,24 @@ class InlineFrameIterator
                     // need to take them from there.
 
                     // The overflown arguments are not available in current frame.
                     // They are the last pushed arguments in the parent frame of
                     // this inlined frame.
                     InlineFrameIterator it(cx, this);
                     ++it;
                     unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
+                    bool hasNewTarget = isConstructing();
                     SnapshotIterator parent_s(it.snapshotIterator());
 
                     // Skip over all slots until we get to the last slots
                     // (= arguments slots of callee) the +3 is for [this], [returnvalue],
                     // [scopechain], and maybe +1 for [argsObj]
-                    MOZ_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
-                    unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj;
+                    MOZ_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj + hasNewTarget);
+                    unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj - hasNewTarget;
                     for (unsigned j = 0; j < skip; j++)
                         parent_s.skip();
 
                     // Get the overflown arguments
                     MaybeReadFallback unusedFallback;
                     parent_s.skip(); // scope chain
                     parent_s.skip(); // return value
                     parent_s.readFunctionFrameArgs(argOp, nullptr, nullptr,
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1042,18 +1042,19 @@ MarkThisAndArguments(JSTracer* trc, JitF
         nformals = fun->nonLazyScript()->argumentsHasVarBinding() ? 0 : fun->nargs();
     }
 
     Value* argv = layout->argv();
 
     // Trace |this|.
     TraceRoot(trc, argv, "ion-thisv");
 
-    // Trace actual arguments beyond the formals. Note + 1 for thisv.
-    for (size_t i = nformals + 1; i < nargs + 1; i++)
+    // Trace actual arguments and newTarget beyond the formals. Note + 1 for thisv.
+    bool constructing = CalleeTokenIsConstructing(layout->calleeToken());
+    for (size_t i = nformals + 1; i < nargs + 1 + constructing; i++)
         TraceRoot(trc, &argv[i], "ion-argv");
 }
 
 static void
 MarkThisAndArguments(JSTracer* trc, const JitFrameIterator& frame)
 {
     JitFrameLayout* layout = frame.jsFrame();
     MarkThisAndArguments(trc, layout);
@@ -2453,17 +2454,18 @@ InlineFrameIterator::findNextFrame()
         } else if (IsSetPropPC(pc_)) {
             numActualArgs_ = 1;
         }
 
         if (numActualArgs_ == 0xbadbad)
             MOZ_CRASH("Couldn't deduce the number of arguments of an ionmonkey frame");
 
         // Skip over non-argument slots, as well as |this|.
-        unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1;
+        bool skipNewTarget = JSOp(*pc_) == JSOP_NEW;
+        unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1 - skipNewTarget;
         for (unsigned j = 0; j < skipCount; j++)
             si_.skip();
 
         // This value should correspond to the function which is being inlined.
         // The value must be readable to iterate over the inline frame. Most of
         // the time, these functions are stored as JSFunction constants,
         // register which are holding the JSFunction pointer, or recover
         // instruction with Default value.
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -1528,16 +1528,20 @@ class LJSCallInstructionHelper : public 
     JSFunction* getSingleTarget() const {
         return mir()->getSingleTarget();
     }
 
     // Does not include |this|.
     uint32_t numActualArgs() const {
         return mir()->numActualArgs();
     }
+    
+    bool isConstructing() const {
+        return mir()->isConstructing();
+    }
 };
 
 // Generates a polymorphic callsite, wherein the function being called is
 // unknown and anticipated to vary.
 class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2>
 {
   public:
     LIR_HEADER(CallGeneric)
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2877,19 +2877,21 @@ IonBuilder::inlineBoundFunction(CallInfo
     if (!target->getBoundFunctionTarget()->is<JSFunction>())
         return InliningStatus_NotInlined;
 
     JSFunction* scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
 
     // Don't optimize if we're constructing and the callee is not a
     // constructor, so that CallKnown does not have to handle this case
     // (it should always throw).
-    if (nativeCallInfo.constructing() && !scriptedTarget->isConstructor()) {
+    if (nativeCallInfo.constructing() && !scriptedTarget->isConstructor())
         return InliningStatus_NotInlined;
-    }
+
+    if (nativeCallInfo.constructing() && nativeCallInfo.getNewTarget() != nativeCallInfo.fun())
+        return InliningStatus_NotInlined;
 
     if (gc::IsInsideNursery(scriptedTarget))
         return InliningStatus_NotInlined;
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
         const Value val = target->getBoundFunctionArgument(i);
         if (val.isObject() && gc::IsInsideNursery(&val.toObject()))
             return InliningStatus_NotInlined;
@@ -2918,16 +2920,21 @@ IonBuilder::inlineBoundFunction(CallInfo
 
     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
         MConstant* argConst = constant(target->getBoundFunctionArgument(i));
         callInfo.argv().infallibleAppend(argConst);
     }
     for (size_t i = 0; i < nativeCallInfo.argc(); i++)
         callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
 
+    // We only inline when it was not a super-call, so just set the newTarget
+    // to be the target function, per spec.
+    if (nativeCallInfo.constructing())
+        callInfo.setNewTarget(callInfo.fun());
+
     if (!makeCall(scriptedTarget, callInfo))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -52,35 +52,44 @@ VMFunction::addToFunctions()
         initialized = true;
         functions = nullptr;
     }
     this->next = functions;
     functions = this;
 }
 
 bool
-InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv,
+InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv,
                MutableHandleValue rval)
 {
-    AutoArrayRooter argvRoot(cx, argc + 1, argv);
+    AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv);
 
     // Data in the argument vector is arranged for a JIT -> JIT call.
     Value thisv = argv[0];
     Value* argvWithoutThis = argv + 1;
 
     // For constructing functions, |this| is constructed at caller side and we can just call Invoke.
     // When creating this failed / is impossible at caller site, i.e. MagicValue(JS_IS_CONSTRUCTING),
     // we use InvokeConstructor that creates it at the callee side.
     if (thisv.isMagic(JS_IS_CONSTRUCTING))
-        return InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, rval);
+        return InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, true, rval);
 
     return Invoke(cx, thisv, ObjectValue(*obj), argc, argvWithoutThis, rval);
 }
 
 bool
+InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
+                               uint32_t numFormalArgs, Value* argv, MutableHandleValue rval)
+{
+    MOZ_ASSERT(numFormalArgs > numActualArgs);
+    argv[1 + numActualArgs] = argv[1 + numFormalArgs];
+    return InvokeFunction(cx, obj, true, numActualArgs, argv, rval);
+}
+
+bool
 CheckOverRecursed(JSContext* cx)
 {
     // We just failed the jitStackLimit check. There are two possible reasons:
     //  - jitStackLimit was the real stack limit and we're over-recursed
     //  - jitStackLimit was set to UINTPTR_MAX by JSRuntime::requestInterrupt
     //    and we need to call JSRuntime::handleInterrupt.
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -626,18 +626,20 @@ class AutoDetectInvalidation
     }
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
             setReturnOverride();
     }
 };
 
-bool InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, Value* argv,
-                    MutableHandleValue rval);
+bool InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, uint32_t argc,
+                    Value* argv, MutableHandleValue rval);
+bool InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
+                                    uint32_t numFormalArgs, Value* argv, MutableHandleValue rval);
 
 bool CheckOverRecursed(JSContext* cx);
 bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
                                 uint32_t extra, uint32_t earlyCheck);
 
 bool DefVarOrConst(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
 bool SetConst(JSContext* cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval);
 bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value);
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -147,16 +147,26 @@ JitRuntime::generateEnterJIT(JSContext* 
     // Save stack pointer.
     if (type == EnterJitBaseline)
         masm.movePtr(sp, r11);
 
     // Load the number of actual arguments into r10.
     masm.loadPtr(slot_vp, r10);
     masm.unboxInt32(Address(r10, 0), r10);
 
+    {
+        Label noNewTarget;
+        masm.branchTest32(Assembler::Zero, r9, Imm32(CalleeToken_FunctionConstructing),
+                          &noNewTarget);
+
+        masm.add32(Imm32(1), r1);
+
+        masm.bind(&noNewTarget);
+    }
+
     // Guarantee stack alignment of Jit frames.
     //
     // This code moves the stack pointer to the location where it should be when
     // we enter the Jit frame.  It moves the stack pointer such that we have
     // enough space reserved for pushing the arguments, and the JitFrameLayout.
     // The stack pointer is also aligned on the alignment expected by the Jit
     // frames.
     //
@@ -460,36 +470,48 @@ JitRuntime::generateArgumentsRectifier(J
 
     // Load the number of |undefined|s to push into r6.
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(RectifierFrameLayout::offsetOfCalleeToken())), r1);
     masm.ma_and(Imm32(CalleeTokenMask), r1, r6);
     masm.ma_ldrh(EDtrAddr(r6, EDtrOffImm(JSFunction::offsetOfNargs())), r6);
 
     masm.ma_sub(r6, r8, r2);
 
-    masm.moveValue(UndefinedValue(), r5, r4);
+    // Get the topmost argument.
+    masm.ma_alu(sp, lsl(r8, 3), r3, OpAdd); // r3 <- r3 + nargs * 8
+    masm.ma_add(r3, Imm32(sizeof(RectifierFrameLayout)), r3);
+
+    {
+        Label notConstructing;
+
+        masm.branchTest32(Assembler::Zero, r1, Imm32(CalleeToken_FunctionConstructing),
+                          &notConstructing);
 
-    masm.ma_mov(sp, r3); // Save %sp.
-    masm.ma_mov(sp, r7); // Save %sp again.
+        // Add sizeof(Value) to overcome |this|
+        masm.ma_dataTransferN(IsLoad, 64, true, r3, Imm32(8), r4, Offset);
+        masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
+
+        // Include the newly pushed newTarget value in the frame size
+        // calculated below.
+        masm.add32(Imm32(1), r6);
+
+        masm.bind(&notConstructing);
+    }
 
     // Push undefined.
+    masm.moveValue(UndefinedValue(), r5, r4);
     {
         Label undefLoopTop;
         masm.bind(&undefLoopTop);
         masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
         masm.ma_sub(r2, Imm32(1), r2, SetCC);
 
         masm.ma_b(&undefLoopTop, Assembler::NonZero);
     }
 
-    // Get the topmost argument.
-
-    masm.ma_alu(r3, lsl(r8, 3), r3, OpAdd); // r3 <- r3 + nargs * 8
-    masm.ma_add(r3, Imm32(sizeof(RectifierFrameLayout)), r3);
-
     // Push arguments, |nargs| + 1 times (to include |this|).
     {
         Label copyLoopTop;
         masm.bind(&copyLoopTop);
         masm.ma_dataTransferN(IsLoad, 64, true, r3, Imm32(-8), r4, PostIndex);
         masm.ma_dataTransferN(IsStore, 64, true, sp, Imm32(-8), r4, PreIndex);
 
         masm.ma_sub(r8, Imm32(1), r8, SetCC);
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -82,16 +82,28 @@ JitRuntime::generateEnterJIT(JSContext* 
     // Save arguments passed in registers needed after function call.
     masm.push(result);
 
     // Remember stack depth without padding and arguments.
     masm.mov(rsp, r14);
 
     // Remember number of bytes occupied by argument vector
     masm.mov(reg_argc, r13);
+
+    // if we are constructing, that also needs to include newTarget
+    {
+        Label noNewTarget;
+        masm.branchTest32(Assembler::Zero, token, Imm32(CalleeToken_FunctionConstructing),
+                          &noNewTarget);
+
+        masm.addq(Imm32(1), r13);
+
+        masm.bind(&noNewTarget);
+    }
+
     masm.shll(Imm32(3), r13);   // r13 = argc * sizeof(Value)
     static_assert(sizeof(Value) == 1 << 3, "Constant is baked in assembly code");
 
     // Guarantee stack alignment of Jit frames.
     //
     // This code compensates for the offset created by the copy of the vector of
     // arguments, such that the jit frame will be aligned once the return
     // address is pushed on the stack.
@@ -106,17 +118,17 @@ JitRuntime::generateEnterJIT(JSContext* 
     masm.andl(Imm32(JitStackAlignment - 1), r12);
     masm.subq(r12, rsp);
 
     /***************************************************************
     Loop over argv vector, push arguments onto stack in reverse order
     ***************************************************************/
 
     // r13 still stores the number of bytes in the argument vector.
-    masm.addq(reg_argv, r13); // r13 points above last argument.
+    masm.addq(reg_argv, r13); // r13 points above last argument or newTarget
 
     // while r13 > rdx, push arguments.
     {
         Label header, footer;
         masm.bind(&header);
 
         masm.cmpPtr(r13, reg_argv);
         masm.j(AssemblerX86Shared::BelowOrEqual, &footer);
@@ -392,26 +404,37 @@ JitRuntime::generateArgumentsRectifier(J
     masm.addl(Imm32(1), r8);
 
     // Load |nformals| into %rcx.
     masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfCalleeToken()), rax);
     masm.mov(rax, rcx);
     masm.andq(Imm32(uint32_t(CalleeTokenMask)), rcx);
     masm.movzwl(Operand(rcx, JSFunction::offsetOfNargs()), rcx);
 
-    // Including |this|, there are (|nformals| + 1) arguments to push to the
-    // stack.  Then we push a JitFrameLayout.  We compute the padding expressed
-    // in the number of extra |undefined| values to push on the stack.
+    // Stash another copy in r11, since we are going to do destructive operations
+    // on rcx
+    masm.mov(rcx, r11);
+
+    static_assert(CalleeToken_FunctionConstructing == 1,
+      "Ensure that we can use the constructing bit to count the value");
+    masm.mov(rax, rdx);
+    masm.andq(Imm32(uint32_t(CalleeToken_FunctionConstructing)), rdx);
+
+    // Including |this|, and |new.target|, there are (|nformals| + 1 + isConstructing)
+    // arguments to push to the stack.  Then we push a JitFrameLayout.  We
+    // compute the padding expressed in the number of extra |undefined| values
+    // to push on the stack.
     static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
       "No need to consider the JitFrameLayout for aligning the stack");
     static_assert(JitStackAlignment % sizeof(Value) == 0,
       "Ensure that we can pad the stack by pushing extra UndefinedValue");
 
     MOZ_ASSERT(IsPowerOfTwo(JitStackValueAlignment));
     masm.addl(Imm32(JitStackValueAlignment - 1 /* for padding */ + 1 /* for |this| */), rcx);
+    masm.addl(rdx, rcx);
     masm.andl(Imm32(~(JitStackValueAlignment - 1)), rcx);
 
     // Load the number of |undefined|s to push into %rcx.
     masm.subq(r8, rcx);
 
     // Caller:
     // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp <- r9
     // '------ #r8 -------'
@@ -451,16 +474,38 @@ JitRuntime::generateArgumentsRectifier(J
 
         masm.bind(&copyLoopTop);
         masm.push(Operand(rcx, 0x0));
         masm.subq(Imm32(sizeof(Value)), rcx);
         masm.subl(Imm32(1), r8);
         masm.j(Assembler::NonZero, &copyLoopTop);
     }
 
+    // if constructing, copy newTarget
+    {
+        Label notConstructing;
+
+        masm.branchTest32(Assembler::Zero, rax, Imm32(CalleeToken_FunctionConstructing),
+                          &notConstructing);
+
+        // thisFrame[numFormals] = prevFrame[argc]
+        ValueOperand newTarget(r10);
+
+        // +1 for |this|. We want vp[argc], so don't subtract 1
+        BaseIndex newTargetSrc(r9, rdx, TimesEight, sizeof(RectifierFrameLayout) + sizeof(Value));
+        masm.loadValue(newTargetSrc, newTarget);
+
+        // Again, 1 for |this|
+        BaseIndex newTargetDest(rsp, r11, TimesEight, sizeof(Value));
+        masm.storeValue(newTarget, newTargetDest);
+
+        masm.bind(&notConstructing);
+    }
+
+
     // Caller:
     // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- r9
     //
     //
     // Rectifier frame:
     // [undef] [undef] [undef] [arg2] [arg1] [this] <- rsp [[argc] [callee] [descr] [raddr]]
     //
 
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -619,16 +619,21 @@ class MacroAssemblerX86Shared : public A
         test32(lhs, imm);
         j(cond, label);
     }
     void branchTest32(Condition cond, const Address& address, Imm32 imm, Label* label) {
         MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         test32(Operand(address), imm);
         j(cond, label);
     }
+    void branchTest32(Condition cond, const Operand& lhs, Imm32 imm, Label* label) {
+        MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
+        test32(lhs, imm);
+        j(cond, label);
+    }
 
     void jump(Label* label) {
         jmp(label);
     }
     void jump(JitCode* code) {
         jmp(code);
     }
     void jump(RepatchLabel* label) {
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -60,18 +60,32 @@ JitRuntime::generateEnterJIT(JSContext* 
     masm.push(ebx);
     masm.push(esi);
     masm.push(edi);
 
     // Keep track of the stack which has to be unwound after returning from the
     // compiled function.
     masm.movl(esp, esi);
 
-    // eax <- 8*argc, eax is now the offset betwen argv and the last
+    // Load the number of values to be copied (argc) into eax
     masm.loadPtr(Address(ebp, ARG_ARGC), eax);
+
+    // If we are constructing, that also needs to include newTarget
+    {
+        Label noNewTarget;
+        masm.loadPtr(Address(ebp, ARG_CALLEETOKEN), edx);
+        masm.branchTest32(Assembler::Zero, edx, Imm32(CalleeToken_FunctionConstructing),
+                          &noNewTarget);
+
+        masm.addl(Imm32(1), eax);
+
+        masm.bind(&noNewTarget);
+    }
+
+    // eax <- 8*numValues, eax is now the offset betwen argv and the last value.
     masm.shll(Imm32(3), eax);
 
     // Guarantee stack alignment of Jit frames.
     //
     // This code compensates for the offset created by the copy of the vector of
     // arguments, such that the jit frame will be aligned once the return
     // address is pushed on the stack.
     //
@@ -392,16 +406,24 @@ JitRuntime::generateArgumentsRectifier(J
       "No need to consider the JitFrameLayout for aligning the stack");
     static_assert((sizeof(Value) + 2 * sizeof(void*)) % JitStackAlignment == 0,
       "No need to consider |this| and the frame pointer and its padding for aligning the stack");
     static_assert(JitStackAlignment % sizeof(Value) == 0,
       "Ensure that we can pad the stack by pushing extra UndefinedValue");
 
     MOZ_ASSERT(IsPowerOfTwo(JitStackValueAlignment));
     masm.addl(Imm32(JitStackValueAlignment - 1 /* for padding */), ecx);
+
+    // Account for newTarget, if necessary.
+    static_assert(CalleeToken_FunctionConstructing == 1,
+      "Ensure that we can use the constructing bit to count an extra push");
+    masm.mov(eax, edx);
+    masm.andl(Imm32(CalleeToken_FunctionConstructing), edx);
+    masm.addl(edx, ecx);
+
     masm.andl(Imm32(~(JitStackValueAlignment - 1)), ecx);
     masm.subl(esi, ecx);
 
     // Copy the number of actual arguments.
     masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfNumActualArgs()), edx);
 
     masm.moveValue(UndefinedValue(), ebx, edi);
 
@@ -448,16 +470,41 @@ JitRuntime::generateArgumentsRectifier(J
         masm.bind(&copyLoopTop);
         masm.push(Operand(ecx, sizeof(Value)/2));
         masm.push(Operand(ecx, 0x0));
         masm.subl(Imm32(sizeof(Value)), ecx);
         masm.subl(Imm32(1), esi);
         masm.j(Assembler::NonZero, &copyLoopTop);
     }
 
+    {
+        Label notConstructing;
+
+        masm.mov(eax, ebx);
+        masm.branchTest32(Assembler::Zero, ebx, Imm32(CalleeToken_FunctionConstructing),
+                          &notConstructing);
+
+        BaseValueIndex src(FramePointer, edx,
+                           sizeof(RectifierFrameLayout) +
+                           sizeof(Value) +
+                           sizeof(void*));
+
+        masm.andl(Imm32(CalleeTokenMask), ebx);
+        masm.movzwl(Operand(ebx, JSFunction::offsetOfNargs()), ebx);
+
+        BaseValueIndex dst(esp, ebx, sizeof(Value));
+
+        ValueOperand newTarget(ecx, edi);
+
+        masm.loadValue(src, newTarget);
+        masm.storeValue(newTarget, dst);
+
+        masm.bind(&notConstructing);
+    }
+
     // Construct descriptor, accounting for pushed frame pointer above
     masm.lea(Operand(FramePointer, sizeof(void*)), ebx);
     masm.subl(esp, ebx);
     masm.makeFrameDescriptor(ebx, JitFrame_Rectifier);
 
     // Construct JitFrameLayout.
     masm.push(edx); // number of actual arguments
     masm.push(eax); // callee token
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4434,37 +4434,38 @@ JS_PUBLIC_API(bool)
 JS::Construct(JSContext* cx, HandleValue fval, const JS::HandleValueArray& args,
               MutableHandleValue rval)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, fval, args);
     AutoLastFrameCheck lfc(cx);
 
-    return InvokeConstructor(cx, fval, args.length(), args.begin(), rval);
+    return InvokeConstructor(cx, fval, args.length(), args.begin(), false, rval);
 }
 
 static JSObject*
 JS_NewHelper(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, ctor, inputArgs);
 
     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
     // is not a simple variation of JSOP_CALL. We have to determine what class
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
     InvokeArgs args(cx);
-    if (!args.init(inputArgs.length()))
+    if (!args.init(inputArgs.length(), true))
         return nullptr;
 
     args.setCallee(ObjectValue(*ctor));
     args.setThis(NullValue());
     PodCopy(args.array(), inputArgs.begin(), inputArgs.length());
+    args.newTarget().setObject(*ctor);
 
     if (!InvokeConstructor(cx, args))
         return nullptr;
 
     if (!args.rval().isObject()) {
         /*
          * Although constructors may return primitives (via proxies), this
          * API is asking for an object, so we report an error.
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3186,17 +3186,17 @@ array_of(JSContext* cx, unsigned argc, V
         return ArrayFromCallArgs(cx, group, args);
     }
 
     // Step 4.
     RootedObject obj(cx);
     {
         RootedValue v(cx);
         Value argv[1] = {NumberValue(args.length())};
-        if (!InvokeConstructor(cx, args.thisv(), 1, argv, &v))
+        if (!InvokeConstructor(cx, args.thisv(), 1, argv, false, &v))
             return false;
         obj = ToObject(cx, v);
         if (!obj)
             return false;
     }
 
     // Step 8.
     for (unsigned k = 0; k < args.length(); k++) {
@@ -3281,16 +3281,20 @@ static const JSFunctionSpec array_static
     JS_FS_END
 };
 
 /* ES5 15.4.2 */
 bool
 js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
+    
+    if (args.isConstructing())
+        MOZ_ASSERT(args.newTarget().toObject().as<JSFunction>().native() == js::ArrayConstructor);
+    
     RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array));
     if (!group)
         return false;
 
     if (args.length() != 1 || !args[0].isNumber())
         return ArrayFromCallArgs(cx, group, args);
 
     uint32_t length;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1547,31 +1547,39 @@ js::CallOrConstructBoundFunction(JSConte
 
     /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */
     RootedObject target(cx, fun->getBoundFunctionTarget());
 
     /* 15.3.4.5.1 step 2. */
     const Value& boundThis = fun->getBoundFunctionThis();
 
     InvokeArgs invokeArgs(cx);
-    if (!invokeArgs.init(args.length() + argslen))
+    if (!invokeArgs.init(args.length() + argslen, args.isConstructing()))
         return false;
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
     for (unsigned i = 0; i < argslen; i++)
         invokeArgs[i].set(fun->getBoundFunctionArgument(i));
     PodCopy(invokeArgs.array() + argslen, vp + 2, args.length());
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
     invokeArgs.setCallee(ObjectValue(*target));
 
     bool constructing = args.isConstructing();
     if (!constructing)
         invokeArgs.setThis(boundThis);
 
+    /* ES6 9.4.1.2 step 5 */
+    if (constructing) {
+        if (&args.newTarget().toObject() == fun)
+            invokeArgs.newTarget().setObject(*target);
+        else
+            invokeArgs.newTarget().set(args.newTarget());
+    }
+
     if (constructing ? !InvokeConstructor(cx, invokeArgs) : !Invoke(cx, invokeArgs))
         return false;
 
     args.rval().set(invokeArgs.rval());
     return true;
 }
 
 static bool
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -443,26 +443,24 @@ GetCustomIterator(JSContext* cx, HandleO
     if (!cx->runningWithTrustedPrincipals())
         ++sCustomIteratorCount;
 
     /* Otherwise call it and return that object. */
     Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
     if (!Invoke(cx, ObjectValue(*obj), rval, 1, &arg, &rval))
         return false;
     if (rval.isPrimitive()) {
-        /*
-         * We are always coming from js::ValueToIterator, and we are no longer on
-         * trace, so the object we are iterating over is on top of the stack (-1).
-         */
+        // Ignore the stack when throwing. We can't tell whether we were
+        // supposed to skip over a new.target or not.
         JSAutoByteString bytes;
         if (!AtomToPrintableString(cx, name, &bytes))
             return false;
         RootedValue val(cx, ObjectValue(*obj));
         ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-                          -1, val, nullptr, bytes.ptr());
+                          JSDVG_IGNORE_STACK, val, nullptr, bytes.ptr());
         return false;
     }
     objp.set(&rval.toObject());
     return true;
 }
 
 template <typename T>
 static inline bool
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -114,19 +114,21 @@ js::StackUses(JSScript* script, jsbyteco
     const JSCodeSpec& cs = js_CodeSpec[op];
     if (cs.nuses >= 0)
         return cs.nuses;
 
     MOZ_ASSERT(js_CodeSpec[op].nuses == -1);
     switch (op) {
       case JSOP_POPN:
         return GET_UINT16(pc);
+      case JSOP_NEW:
+        return 2 + GET_ARGC(pc) + 1;
       default:
         /* stack: fun, this, [argc arguments] */
-        MOZ_ASSERT(op == JSOP_NEW || op == JSOP_CALL || op == JSOP_EVAL ||
+        MOZ_ASSERT(op == JSOP_CALL || op == JSOP_EVAL ||
                    op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
         return 2 + GET_ARGC(pc);
     }
 }
 
 unsigned
 js::StackDefs(JSScript* script, jsbytecode* pc)
 {
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -299,16 +299,18 @@ CrossCompartmentWrapper::construct(JSCon
     RootedObject wrapped(cx, wrappedObject(wrapper));
     {
         AutoCompartment call(cx, wrapped);
 
         for (size_t n = 0; n < args.length(); ++n) {
             if (!cx->compartment()->wrap(cx, args[n]))
                 return false;
         }
+        if (!cx->compartment()->wrap(cx, args.newTarget()))
+            return false;
         if (!Wrapper::construct(cx, wrapper, args))
             return false;
     }
     return cx->compartment()->wrap(cx, args.rval());
 }
 
 bool
 CrossCompartmentWrapper::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
--- a/js/src/proxy/DirectProxyHandler.cpp
+++ b/js/src/proxy/DirectProxyHandler.cpp
@@ -77,17 +77,17 @@ DirectProxyHandler::call(JSContext* cx, 
     return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval());
 }
 
 bool
 DirectProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
     RootedValue target(cx, proxy->as<ProxyObject>().private_());
-    return InvokeConstructor(cx, target, args.length(), args.array(), args.rval());
+    return InvokeConstructor(cx, target, args.length(), args.array(), true, args.rval());
 }
 
 bool
 DirectProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                                CallArgs args) const
 {
     args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
     if (!test(args.thisv())) {
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1033,23 +1033,24 @@ ScriptedDirectProxyHandler::construct(JS
     // step 4-5
     RootedValue trap(cx);
     if (!GetProperty(cx, handler, handler, cx->names().construct, &trap))
         return false;
 
     // step 6
     if (trap.isUndefined()) {
         RootedValue targetv(cx, ObjectValue(*target));
-        return InvokeConstructor(cx, targetv, args.length(), args.array(), args.rval());
+        return InvokeConstructor(cx, targetv, args.length(), args.array(), true, args.rval());
     }
 
     // step 8-9
     Value constructArgv[] = {
         ObjectValue(*target),
-        ObjectValue(*argsArray)
+        ObjectValue(*argsArray),
+        args.newTarget()
     };
     RootedValue thisValue(cx, ObjectValue(*handler));
     if (!Invoke(cx, thisValue, trap, ArrayLength(constructArgv), constructArgv, args.rval()))
         return false;
 
     // step 10
     if (!args.rval().isObject()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_CONSTRUCT_OBJECT);
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -462,17 +462,17 @@ CallableScriptedIndirectProxyHandler::ca
 bool
 CallableScriptedIndirectProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
     RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
     MOZ_ASSERT(ccHolder->getClass() == &CallConstructHolder);
     RootedValue construct(cx, ccHolder->as<NativeObject>().getReservedSlot(1));
     MOZ_ASSERT(construct.isObject() && construct.toObject().isCallable());
-    return InvokeConstructor(cx, construct, args.length(), args.array(), args.rval());
+    return InvokeConstructor(cx, construct, args.length(), args.array(), true, args.rval());
 }
 
 const CallableScriptedIndirectProxyHandler CallableScriptedIndirectProxyHandler::singleton;
 
 bool
 js::proxy_create(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/newTargetCCW.js
@@ -0,0 +1,10 @@
+// Make sure we wrap the new target on CCW construct calls.
+var g = newGlobal();
+
+let f = g.eval('(function (expected) { this.accept = new.target === expected; })');
+
+for (let i = 0; i < 1100; i++)
+    assertEq(new f(f).accept, true);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
--- a/js/src/tests/js1_7/extensions/regress-354945-01.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-01.js
@@ -1,17 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //-----------------------------------------------------------------------------
 var BUGNUMBER = 354945;
 var summary = 'Do not crash with new Iterator';
-var expect = 'TypeError: trap __iterator__ for obj returned a primitive value';
+var expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
 var actual;
 
 
 //-----------------------------------------------------------------------------
 test();
 //-----------------------------------------------------------------------------
 
 function test()
--- a/js/src/tests/js1_7/extensions/regress-354945-02.js
+++ b/js/src/tests/js1_7/extensions/regress-354945-02.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = 'TypeError: trap __iterator__ for obj returned a primitive value';
+  expect = 'TypeError: trap __iterator__ for ({__iterator__:(function (){ })}) returned a primitive value';
   var obj = {};
   obj.__iterator__ = function(){ };
   try
   {
     for(t in (obj)) { }
   }
   catch(ex)
   {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -672,31 +672,32 @@ js::Invoke(JSContext* cx, CallArgs args,
     MOZ_ASSERT(!cx->zone()->types.activeAnalysis);
 
     /* Perform GC if necessary on exit from the function. */
     AutoGCIfRequested gcIfRequested(cx->runtime());
 
     /* MaybeConstruct is a subset of InitialFrameFlags */
     InitialFrameFlags initial = (InitialFrameFlags) construct;
 
+    unsigned skipForCallee = args.length() + 1 + (construct == CONSTRUCT);
     if (args.calleev().isPrimitive())
-        return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
+        return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
 
     const Class* clasp = args.callee().getClass();
 
     /* Invoke non-functions. */
     if (MOZ_UNLIKELY(clasp != &JSFunction::class_)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (MOZ_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.length(), args.base());
 #endif
         MOZ_ASSERT_IF(construct, !args.callee().constructHook());
         JSNative call = args.callee().callHook();
         if (!call)
-            return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
+            return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
         return CallJSNative(cx, call, args);
     }
 
     /* Invoke native functions. */
     JSFunction* fun = &args.callee().as<JSFunction>();
     if (fun->isNative()) {
         MOZ_ASSERT_IF(construct, !fun->isConstructor());
         return CallJSNative(cx, fun->native(), args);
@@ -765,54 +766,61 @@ js::Invoke(JSContext* cx, const Value& t
 
 bool
 js::InvokeConstructor(JSContext* cx, CallArgs args)
 {
     MOZ_ASSERT(!JSFunction::class_.construct);
 
     args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
+    // +2 here and below to pass over |this| and |new.target|
     if (!args.calleev().isObject())
-        return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev(), args.length() + 2, CONSTRUCT);
+
+    MOZ_ASSERT(args.newTarget().isObject());
 
     JSObject& callee = args.callee();
     if (callee.is<JSFunction>()) {
         RootedFunction fun(cx, &callee.as<JSFunction>());
 
         if (!fun->isConstructor())
-            return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
+            return ReportIsNotFunction(cx, args.calleev(), args.length() + 2, CONSTRUCT);
 
         if (fun->isNative())
             return CallJSNativeConstructor(cx, fun->native(), args);
 
         if (!Invoke(cx, args, CONSTRUCT))
             return false;
 
         MOZ_ASSERT(args.rval().isObject());
         return true;
     }
 
     JSNative construct = callee.constructHook();
     if (!construct)
-        return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev(), args.length() + 2, CONSTRUCT);
 
     return CallJSNativeConstructor(cx, construct, args);
 }
 
 bool
 js::InvokeConstructor(JSContext* cx, Value fval, unsigned argc, const Value* argv,
-                      MutableHandleValue rval)
+                      bool newTargetInArgv, MutableHandleValue rval)
 {
     InvokeArgs args(cx);
-    if (!args.init(argc))
+    if (!args.init(argc, true))
         return false;
 
     args.setCallee(fval);
     args.setThis(MagicValue(JS_THIS_POISON));
     PodCopy(args.array(), argv, argc);
+    if (newTargetInArgv)
+        args.newTarget().set(argv[argc]);
+    else
+        args.newTarget().set(fval);
 
     if (!InvokeConstructor(cx, args))
         return false;
 
     rval.set(args.rval());
     return true;
 }
 
@@ -2886,26 +2894,35 @@ CASE(JSOP_SPREADCALL)
         cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
     /* FALL THROUGH */
 
 CASE(JSOP_SPREADEVAL)
 CASE(JSOP_STRICTSPREADEVAL)
 {
     static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
                   "spreadeval and strictspreadeval must be the same size");
-    MOZ_ASSERT(REGS.stackDepth() >= 3);
-
-    HandleValue callee = REGS.stackHandleAt(-3);
-    HandleValue thisv = REGS.stackHandleAt(-2);
-    HandleValue arr = REGS.stackHandleAt(-1);
-    MutableHandleValue ret = REGS.stackHandleAt(-3);
-    if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr, ret))
+    bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW;
+
+    MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
+
+    HandleValue callee = REGS.stackHandleAt(-3 - construct);
+    HandleValue thisv = REGS.stackHandleAt(-2 - construct);
+    HandleValue arr = REGS.stackHandleAt(-1 - construct);
+    MutableHandleValue ret = REGS.stackHandleAt(-3 - construct);
+
+    RootedValue& newTarget = rootValue0;
+    if (construct)
+        newTarget = REGS.sp[-1];
+    else
+        newTarget = NullValue();
+
+    if (!SpreadCallOperation(cx, script, REGS.pc, thisv, callee, arr, newTarget, ret))
         goto error;
 
-    REGS.sp -= 2;
+    REGS.sp -= 2 + construct;
 }
 END_CASE(JSOP_SPREADCALL)
 
 CASE(JSOP_FUNAPPLY)
 {
     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
     if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args))
         goto error;
@@ -2914,20 +2931,21 @@ CASE(JSOP_FUNAPPLY)
 
 CASE(JSOP_NEW)
 CASE(JSOP_CALL)
 CASE(JSOP_FUNCALL)
 {
     if (REGS.fp()->hasPushedSPSFrame())
         cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
 
+    bool construct = (*REGS.pc == JSOP_NEW);
+    unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
+
     MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
-    CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
-
-    bool construct = (*REGS.pc == JSOP_NEW);
+    CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct);
 
     JSFunction* maybeFun;
     bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
 
     /* Don't bother trying to fast-path calls to scripted non-constructors. */
     if (!isFunction || !maybeFun->isInterpreted() || !maybeFun->isConstructor()) {
         if (construct) {
             if (!InvokeConstructor(cx, args))
@@ -4521,49 +4539,55 @@ js::InitGetterSetterOperation(JSContext*
     if (!ValueToId<CanGC>(cx, idval, &id))
         return false;
 
     return InitGetterSetterOperation(cx, pc, obj, id, val);
 }
 
 bool
 js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue thisv,
-                        HandleValue callee, HandleValue arr, MutableHandleValue res)
+                        HandleValue callee, HandleValue arr, HandleValue newTarget, MutableHandleValue res)
 {
     RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
     uint32_t length = aobj->length();
     JSOp op = JSOp(*pc);
+    bool constructing = op == JSOP_SPREADNEW;
 
     if (length > ARGS_LENGTH_MAX) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                             op == JSOP_SPREADNEW ? JSMSG_TOO_MANY_CON_SPREADARGS
-                                                  : JSMSG_TOO_MANY_FUN_SPREADARGS);
+                             constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
+                                          : JSMSG_TOO_MANY_FUN_SPREADARGS);
         return false;
     }
 
 #ifdef DEBUG
     // The object must be an array with dense elements and no holes. Baseline's
     // optimized spread call stubs rely on this.
     MOZ_ASSERT(aobj->getDenseInitializedLength() == length);
     MOZ_ASSERT(!aobj->isIndexed());
     for (uint32_t i = 0; i < length; i++)
         MOZ_ASSERT(!aobj->getDenseElement(i).isMagic());
 #endif
 
     InvokeArgs args(cx);
 
-    if (!args.init(length))
+    if (!args.init(length, constructing))
         return false;
 
     args.setCallee(callee);
     args.setThis(thisv);
 
     if (!GetElements(cx, aobj, length, args.array()))
         return false;
 
+    if (constructing) {
+        MOZ_ASSERT(newTarget.isObject());
+        args.newTarget().set(newTarget);
+    }
+
     switch (op) {
       case JSOP_SPREADNEW:
         if (!InvokeConstructor(cx, args))
             return false;
         break;
       case JSOP_SPREADCALL:
         if (!Invoke(cx, args))
             return false;
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -90,17 +90,17 @@ InvokeSetter(JSContext* cx, const Value&
  * (e.g. 'new') handling the the creation of the new 'this' object.
  */
 extern bool
 InvokeConstructor(JSContext* cx, CallArgs args);
 
 /* See the fval overload of Invoke. */
 extern bool
 InvokeConstructor(JSContext* cx, Value fval, unsigned argc, const Value* argv,
-                  MutableHandleValue rval);
+                  bool newTargetInArgv, MutableHandleValue rval);
 
 /*
  * Executes a script with the given scopeChain/this. The 'type' indicates
  * whether this is eval code or global code. To support debugging, the
  * evalFrame parameter can point to an arbitrary frame in the context's call
  * stack to simulate executing an eval in that frame.
  */
 extern bool
@@ -431,17 +431,17 @@ EnterWithOperation(JSContext* cx, Abstra
 
 
 bool
 InitGetterSetterOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval,
                           HandleObject val);
 
 bool
 SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue thisv,
-                    HandleValue callee, HandleValue arr, MutableHandleValue res);
+                    HandleValue callee, HandleValue arr, HandleValue newTarget, MutableHandleValue res);
 
 JSObject*
 NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
                    NewObjectKind newKind = GenericObject);
 
 JSObject*
 NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject);
 
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -386,19 +386,19 @@ 1234567890123456789012345678901234567890
     /*
      * spreadcall variant of JSOP_NEW
      *
      * Invokes 'callee' as a constructor with 'this' and 'args', pushes the
      * return value onto the stack.
      *   Category: Statements
      *   Type: Function
      *   Operands:
-     *   Stack: callee, this, args => rval
+     *   Stack: callee, this, args, newTarget => rval
      */ \
-    macro(JSOP_SPREADNEW, 42, "spreadnew",  NULL,         1,  3,  1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
+    macro(JSOP_SPREADNEW, 42, "spreadnew",  NULL,         1,  4,  1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
     /*
      * spreadcall variant of JSOP_EVAL
      *
      * Invokes 'eval' with 'args' and pushes the return value onto the stack.
      *
      * If 'eval' in global scope is not original one, invokes the function
      * with 'this' and 'args', and pushes return value onto the stack.
      *   Category: Statements
@@ -761,18 +761,18 @@ 1234567890123456789012345678901234567890
     macro(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  JOF_BYTE) \
     \
     /*
      * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
      * value onto the stack.
      *   Category: Statements
      *   Type: Function
      *   Operands: uint16_t argc
-     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
-     *   nuses: (argc+2)
+     *   Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
+     *   nuses: (argc+3)
      */ \
     macro(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
     /*
      * Pushes newly created object onto the stack with provided [[Prototype]].
      *
      *   Category: Literals
      *   Type: Object
      *   Operands:
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -287,29 +287,35 @@ InterpreterStack::getCallFrame(JSContext
         *pargv = args.array();
         uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
         return reinterpret_cast<InterpreterFrame*>(buffer);
     }
 
     // Pad any missing arguments with |undefined|.
     MOZ_ASSERT(args.length() < nformal);
 
-    nvals += nformal + 2; // Include callee, |this|.
+    bool isConstructing = *flags & InterpreterFrame::CONSTRUCTING;
+    unsigned nfunctionState = 2 + isConstructing; // callee, |this|, |new.target|
+
+    nvals += nformal + nfunctionState;
     uint8_t* buffer = allocateFrame(cx, sizeof(InterpreterFrame) + nvals * sizeof(Value));
     if (!buffer)
         return nullptr;
 
     Value* argv = reinterpret_cast<Value*>(buffer);
     unsigned nmissing = nformal - args.length();
 
     mozilla::PodCopy(argv, args.base(), 2 + args.length());
     SetValueRangeToUndefined(argv + 2 + args.length(), nmissing);
 
+    if (isConstructing)
+        argv[2 + nformal] = args.newTarget();
+
     *pargv = argv + 2;
-    return reinterpret_cast<InterpreterFrame*>(argv + 2 + nformal);
+    return reinterpret_cast<InterpreterFrame*>(argv + nfunctionState + nformal);
 }
 
 MOZ_ALWAYS_INLINE bool
 InterpreterStack::pushInlineFrame(JSContext* cx, InterpreterRegs& regs, const CallArgs& args,
                                   HandleScript script, InitialFrameFlags initial)
 {
     RootedFunction callee(cx, &args.callee().as<JSFunction>());
     MOZ_ASSERT(regs.sp == args.end());
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -392,17 +392,17 @@ InterpreterFrame::markValues(JSTracer* t
 
         // Mark live locals.
         markValues(trc, 0, nlivefixed);
     }
 
     if (hasArgs()) {
         // Mark callee, |this| and arguments.
         unsigned argc = Max(numActualArgs(), numFormalArgs());
-        TraceRootRange(trc, argc + 2, argv_ - 2, "fp argv");
+        TraceRootRange(trc, argc + 2 + isConstructing(), argv_ - 2, "fp argv");
     } else {
         // Mark callee and |this|
         TraceRootRange(trc, 2, ((Value*)this) - 2, "stack callee and this");
     }
 }
 
 static void
 MarkInterpreterActivation(JSTracer* trc, InterpreterActivation* act)
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -933,17 +933,17 @@ class InterpreterRegs
         fp_ = &to;
         sp = to.slots() + (from.sp - from.fp_->slots());
         pc = from.pc;
         MOZ_ASSERT(fp_);
     }
 
     void popInlineFrame() {
         pc = fp_->prevpc();
-        sp = fp_->prevsp() - fp_->numActualArgs() - 1;
+        sp = fp_->prevsp() - fp_->numActualArgs() - 1 - fp_->isConstructing();
         fp_ = fp_->prev();
         MOZ_ASSERT(fp_);
     }
     void prepareToRun(InterpreterFrame& fp, JSScript* script) {
         pc = script->code();
         sp = fp.slots() + script->nfixed();
         fp_ = &fp;
     }
@@ -1028,22 +1028,24 @@ void MarkInterpreterActivations(JSRuntim
 
 /*****************************************************************************/
 
 class InvokeArgs : public JS::CallArgs
 {
     AutoValueVector v_;
 
   public:
-    explicit InvokeArgs(JSContext* cx) : v_(cx) {}
+    explicit InvokeArgs(JSContext* cx, bool construct = false) : v_(cx) {}
 
-    bool init(unsigned argc) {
-        if (!v_.resize(2 + argc))
+    bool init(unsigned argc, bool construct = false) {
+        if (!v_.resize(2 + argc + construct))
             return false;
         ImplicitCast<CallArgs>(*this) = CallArgsFromVp(argc, v_.begin());
+        // Set the internal flag, since we are not initializing from a made array
+        constructing_ = construct;
         return true;
     }
 };
 
 template <>
 struct DefaultHasher<AbstractFramePtr> {
     typedef AbstractFramePtr Lookup;
 
--- 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 = 288;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 289;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
 static_assert(JSErr_Limit == 400,
               "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.");