author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Wed, 03 Jun 2015 12:44:59 +0200 | |
changeset 246986 | 23fcf07dcd9edda77c36a361eb752ac0d6f067e4 |
parent 246985 | 28087e3f22f8740104eb345379ae2980381d5bd7 |
child 246987 | 8d2064e2c5111114ba60a0c475bc6482f62a5ccf |
push id | 28848 |
push user | ryanvm@gmail.com |
push date | Wed, 03 Jun 2015 20:00:13 +0000 |
treeherder | mozilla-central@0920f2325a6d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1141865 |
milestone | 41.0a1 |
backs out | d038c5da19b0d926d7c6ca3a7d78389548312ee3 |
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
|
--- a/js/public/CallArgs.h +++ b/js/public/CallArgs.h @@ -280,17 +280,16 @@ 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_); @@ -310,69 +309,63 @@ 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_ + constructing_; } + Value* end() const { return this->argv_ + argc_; } }; } // namespace detail class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval> { private: friend CallArgs CallArgsFromVp(unsigned argc, Value* vp); - friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing); + friend CallArgs CallArgsFromSp(unsigned argc, Value* sp); - static CallArgs create(unsigned argc, Value* argv, bool constructing) { + static CallArgs create(unsigned argc, Value* argv) { 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, vp[1].isMagic(JS_IS_CONSTRUCTING)); + return CallArgs::create(argc, vp + 2); } // 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 stackSlots, Value* sp, bool constructing = false) +CallArgsFromSp(unsigned argc, Value* sp) { - return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing); + return CallArgs::create(argc, sp - argc); } } // 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,44 +6442,31 @@ 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()))
deleted file mode 100644 --- a/js/src/jit-test/tests/basic/newTargetRectifier.js +++ /dev/null @@ -1,12 +0,0 @@ -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();
deleted file mode 100644 --- a/js/src/jit-test/tests/debug/Frame-newTargetOverflow-01.js +++ /dev/null @@ -1,37 +0,0 @@ -// 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,12 +1,10 @@ // 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 (p of [new Proxy(target, {}), Proxy.revocable(target, {}).proxy]) { +for (let 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,21 +1,19 @@ 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, newTarget) { + construct: function (target1, args) { assertEq(this, handler); assertEq(target1, target); assertEq(args.length, 2); assertEq(args[0], 2); assertEq(args[1], 3); - assertEq(newTarget, p); } } -for (p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) +for (let 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,18 +971,16 @@ 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 @@ -1029,24 +1027,21 @@ 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 + pushedNewTarget) * sizeof(Value); + frameSize += (numCallArgs + 2) * sizeof(Value); blFrame->setFrameSize(frameSize); JitSpew(JitSpew_BaselineBailouts, " Adjusted framesize += %d: %d", - (int) ((numCallArgs + 2 + pushedNewTarget) * sizeof(Value)), - (int) frameSize); + (int) ((numCallArgs + 2) * 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); @@ -1228,23 +1223,22 @@ 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 + pushedNewTarget) * sizeof(Value) + - JitFrameLayout::Size(); + size_t afterFrameSize = (actualArgc + 1) * sizeof(Value) + JitFrameLayout::Size(); if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding")) return false; - MOZ_ASSERT(actualArgc + 2 + pushedNewTarget <= exprStackSlots); - for (unsigned i = 0; i < actualArgc + 1 + pushedNewTarget; i++) { + MOZ_ASSERT(actualArgc + 2 <= exprStackSlots); + for (unsigned i = 0; i < actualArgc + 1; 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. @@ -1261,17 +1255,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 + pushedNewTarget); + uint32_t calleeStackSlot = exprStackSlots - uint32_t(actualArgc + 2); 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>(); @@ -1332,28 +1326,20 @@ 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 + pushedNewTarget) * sizeof(Value) + - RectifierFrameLayout::Size(); + size_t afterFrameSize = (calleeFun->nargs() + 1) * 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,30 +2732,29 @@ 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 = */ construct, + ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_NEW, /* isSpread = */ false); if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) return false; // Update FrameInfo. - frame.popn(2 + argc + construct); + frame.popn(argc + 2); frame.push(R0); return true; } bool BaselineCompiler::emitSpreadCall() { MOZ_ASSERT(IsCallPC(pc)); @@ -2765,18 +2764,17 @@ 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. - bool construct = JSOp(*pc) == JSOP_SPREADNEW; - frame.popn(3 + construct); + frame.popn(3); 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 + isConstructing(), argv(), "baseline-args"); + TraceRootRange(trc, numArgs, 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,17 +10243,16 @@ 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; @@ -10315,20 +10314,16 @@ 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()); @@ -10364,51 +10359,52 @@ 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, true, res)) + if (!InvokeConstructor(cx, callee, argc, args, 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 { @@ -10447,40 +10443,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]); - RootedValue newTarget(cx, constructing ? vp[3] : NullValue()); + + bool constructing = (op == JSOP_SPREADNEW); // 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, newTarget, res)) + if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, 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(); @@ -10492,138 +10488,103 @@ DoSpreadCallFallback(JSContext* cx, Base if (!handled) stub->noteUnoptimizableCall(); return true; } void ICCallStubCompiler::pushCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs, - Register argcReg, bool isJitCall, bool isConstructing) + Register argcReg, bool isJitCall) { MOZ_ASSERT(!regs.has(argcReg)); - // Account for new.target + // Push the callee and |this| too. Register count = regs.takeAny(); - masm.mov(argcReg, 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); - } + masm.add32(Imm32(2), 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(count); - - // Account for callee and |this|, skipped earlier - masm.add32(Imm32(2), count); - } + if (isJitCall) + masm.alignJitStackBasedOnNArgs(argcReg); // 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, - bool isConstructing) -{ - masm.unboxObject(Address(BaselineStackReg, isConstructing * sizeof(Value) + ICStackValueOffset), argcReg); +ICCallStubCompiler::guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure) +{ + masm.unboxObject(Address(BaselineStackReg, 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, - bool isConstructing) -{ - // Pull the array off the stack before aligning. + Register argcReg, bool isJitCall) +{ + // Push arguments Register startReg = regs.takeAny(); - masm.unboxObject(Address(BaselineStackReg, (isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg); + Register endReg = regs.takeAny(); + masm.unboxObject(Address(BaselineStackReg, 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.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(©Start); masm.branchPtr(Assembler::Equal, endReg, startReg, ©Done); masm.subPtr(Imm32(sizeof(Value)), endReg); masm.pushValue(Address(endReg, 0)); masm.jump(©Start); masm.bind(©Done); regs.add(startReg); regs.add(endReg); // Push the callee and |this|. - masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + (1 + isConstructing) * sizeof(Value))); - masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + (2 + isConstructing) * sizeof(Value))); + masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + 1 * sizeof(Value))); + masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE + 2 * 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 @@ -10818,30 +10779,19 @@ 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. - - // 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.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 masm.push(BaselineStackReg); masm.push(BaselineStubReg); masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg()); masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg()); if (!callVM(DoSpreadCallFallbackInfo, masm)) @@ -10852,17 +10802,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, isConstructing_); + pushCallArguments(masm, regs, R0.scratchReg(), /* isJitCall = */ false); 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()); @@ -10937,27 +10887,24 @@ 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, isConstructing_); - - // Load the callee in R1, accounting for newTarget, if necessary - // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, [newTarget] +ICStackValueOffset+ ] + guardSpreadCall(masm, argcReg, &failure); + + // Load the callee in R1. + // Stack Layout: [ ..., CalleeVal, ThisVal, Arg0Val, ..., ArgNVal, +ICStackValueOffset+ ] if (isSpread_) { - unsigned skipToCallee = (2 + isConstructing_) * sizeof(Value); - masm.loadValue(Address(BaselineStackReg, skipToCallee + ICStackValueOffset), R1); + masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R1); } else { - // Account for newTarget, if necessary - unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value); - BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSkip); + BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value)); masm.loadValue(calleeSlot, R1); } regs.take(R1); // Ensure callee is an object. masm.branchTestObject(Assembler::NotEqual, R1, &failure); // Ensure callee is a function. @@ -11007,23 +10954,23 @@ ICCallScriptedCompiler::generateStubCode Label failureLeaveStubFrame; if (isConstructing_) { // Save argc before call. masm.push(argcReg); // Stack now looks like: - // [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader, ArgC ] + // [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader, ArgC ] if (isSpread_) { masm.loadValue(Address(BaselineStackReg, - 3 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1); + 2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)), R1); } else { BaseValueIndex calleeSlot2(BaselineStackReg, argcReg, - 2 * sizeof(Value) + STUB_FRAME_SIZE + sizeof(size_t)); + 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 @@ -11041,40 +10988,37 @@ 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, [NewTarget], StubFrameHeader ] + // [..., Callee, ThisV, Arg0V, ..., ArgNV, StubFrameHeader ] if (isSpread_) { - masm.storeValue(R0, Address(BaselineStackReg, (1 + isConstructing_) * sizeof(Value) + STUB_FRAME_SIZE)); + masm.storeValue(R0, Address(BaselineStackReg, sizeof(Value) + STUB_FRAME_SIZE)); } else { - BaseValueIndex thisSlot(BaselineStackReg, argcReg, STUB_FRAME_SIZE + isConstructing_ * sizeof(Value)); + BaseValueIndex thisSlot(BaselineStackReg, argcReg, STUB_FRAME_SIZE); 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_) { - unsigned skipForCallee = (2 + isConstructing_) * sizeof(Value); - masm.loadValue(Address(BaselineStackReg, skipForCallee + STUB_FRAME_SIZE), R0); + masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + STUB_FRAME_SIZE), R0); } else { - // Account for newTarget, if necessary - unsigned nonArgsSkip = (1 + isConstructing_) * sizeof(Value); - BaseValueIndex calleeSlot3(BaselineStackReg, argcReg, nonArgsSkip + STUB_FRAME_SIZE); + BaseValueIndex calleeSlot3(BaselineStackReg, argcReg, sizeof(Value) + 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(); @@ -11090,19 +11034,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, isConstructing_); + pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ true); else - pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true, isConstructing_); + pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true); // 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); @@ -11164,20 +11108,18 @@ 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 + 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)); + // &ThisVal = BaselineFrameReg + argc * sizeof(Value) + STUB_FRAME_SIZE + BaseValueIndex thisSlotAddr(BaselineFrameReg, argcReg, STUB_FRAME_SIZE); 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); } @@ -11339,24 +11281,23 @@ 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, isConstructing_); + guardSpreadCall(masm, argcReg, &failure); // Load the callee in R1. if (isSpread_) { masm.loadValue(Address(BaselineStackReg, ICStackValueOffset + 2 * sizeof(Value)), R1); } else { - unsigned nonArgsSlots = (1 + isConstructing_) * sizeof(Value); - BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgsSlots); + BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value)); 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); @@ -11369,19 +11310,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, isConstructing_); + pushSpreadCallArguments(masm, regs, argcReg, /* isJitCall = */ false); else - pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false, isConstructing_); + pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false); 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(); @@ -11444,18 +11385,17 @@ 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. - unsigned nonArgSlots = (1 + isConstructing_) * sizeof(Value); - BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + nonArgSlots); + BaseValueIndex calleeSlot(BaselineStackReg, argcReg, ICStackValueOffset + sizeof(Value)); 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(); @@ -11467,17 +11407,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, isConstructing_); + pushCallArguments(masm, regs, argcReg, /* isJitCall = */ false); 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,21 +5517,20 @@ class ICCallStubCompiler : public ICStub { } enum FunApplyThing { FunApply_MagicArgs, FunApply_Array }; void pushCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs, - Register argcReg, bool isJitCall, bool isConstructing = false); + Register argcReg, bool isJitCall); void pushSpreadCallArguments(MacroAssembler& masm, AllocatableGeneralRegisterSet regs, - Register argcReg, bool isJitCall, bool isConstructing); - void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure, - bool isConstructing); + Register argcReg, bool isJitCall); + void guardSpreadCall(MacroAssembler& masm, Register argcReg, Label* failure); 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,30 +2927,29 @@ static const VMFunction GetIntrinsicValu void CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir) { pushArg(ImmGCPtr(lir->mir()->name())); callVM(GetIntrinsicValueInfo, lir); } -typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue); +typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, uint32_t, Value*, MutableHandleValue); static const VMFunction InvokeFunctionInfo = FunctionInfo<InvokeFunctionFn>(InvokeFunction); void CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg, - bool constructing, uint32_t argc, uint32_t unusedStack) + 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); } @@ -2995,18 +2994,17 @@ 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|. - DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing(); - MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - numNonArgsOnStack); + MOZ_ASSERT(call->numActualArgs() == call->mir()->numStackArgs() - 1); 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); @@ -3023,65 +3021,43 @@ 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->isConstructing(), call->numActualArgs(), - unusedStack); + emitCallInvokeFunction(call, calleereg, 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, ¬Primitive); masm.loadValue(Address(masm.getStackPointer(), unusedStack), JSReturnOperand); masm.bind(¬Primitive); } } -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()); - JSFunction* target = call->getSingleTarget(); + DebugOnly<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. - DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing(); - MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack); + MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - 1); 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); @@ -3111,20 +3087,17 @@ 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); - if (call->isConstructing() && target->nargs() > call->numActualArgs()) - emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack); - else - emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack); + emitCallInvokeFunction(call, calleereg, 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, ¬Primitive); @@ -3140,17 +3113,16 @@ 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,23 +125,18 @@ 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, - bool isConstructing, uint32_t argc, - uint32_t unusedStack); + 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,32 +2557,28 @@ 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()); - unsigned numPushedArgs = Max(args.length(), numFormals); - if (!vals.reserve(numPushedArgs + 1 + data.constructing)) + if (!vals.reserve(Max(args.length() + 1, numFormals + 1))) 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()); - if (data.constructing) - vals.infallibleAppend(args.newTarget()); - - MOZ_ASSERT(vals.length() >= numFormals + 1 + data.constructing); + MOZ_ASSERT(vals.length() >= numFormals + 1); 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,18 +5263,16 @@ 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()); @@ -6133,17 +6131,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 + constructing); + int calleeDepth = -((int)argc + 2); // 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); @@ -6276,24 +6274,21 @@ 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.constructing(), - callInfo.argc(), callInfo.constructing(), isDOMCall); + MCall* call = MCall::New(alloc(), target, targetArgs + 1, 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); } @@ -9440,17 +9435,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_->argc(); + unsigned numActuals = inlineCallInfo_->argv().length(); 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,57 +1239,48 @@ 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()); @@ -1301,26 +1292,23 @@ 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 + constructing(); + return argc() + 2; } bool setArgs(const MDefinitionVector& args) { MOZ_ASSERT(args_.empty()); return args_.appendAll(args); } MDefinitionVector& argv() { @@ -1356,25 +1344,16 @@ 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 { @@ -1384,18 +1363,16 @@ 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,24 +741,23 @@ 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 + hasNewTarget); - unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj - hasNewTarget; + MOZ_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj); + unsigned skip = parent_s.numAllocations() - nactual - 3 - argsObjAdj; 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,19 +1042,18 @@ 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 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++) + // Trace actual arguments beyond the formals. Note + 1 for thisv. + for (size_t i = nformals + 1; i < nargs + 1; i++) TraceRoot(trc, &argv[i], "ion-argv"); } static void MarkThisAndArguments(JSTracer* trc, const JitFrameIterator& frame) { JitFrameLayout* layout = frame.jsFrame(); MarkThisAndArguments(trc, layout); @@ -2454,18 +2453,17 @@ 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|. - bool skipNewTarget = JSOp(*pc_) == JSOP_NEW; - unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1 - skipNewTarget; + unsigned skipCount = (si_.numAllocations() - 1) - numActualArgs_ - 1; 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,20 +1528,16 @@ 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,21 +2877,19 @@ 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; @@ -2920,21 +2918,16 @@ 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,44 +52,35 @@ VMFunction::addToFunctions() initialized = true; functions = nullptr; } this->next = functions; functions = this; } bool -InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv, +InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv, MutableHandleValue rval) { - AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv); + AutoArrayRooter argvRoot(cx, argc + 1, 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, true, rval); + return InvokeConstructor(cx, ObjectValue(*obj), argc, argvWithoutThis, 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,20 +626,18 @@ class AutoDetectInvalidation } ~AutoDetectInvalidation() { if (!disabled_ && ionScript_->invalidated()) setReturnOverride(); } }; -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 InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, 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,26 +147,16 @@ 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. // @@ -470,48 +460,36 @@ 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); - // 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), - ¬Constructing); + masm.moveValue(UndefinedValue(), r5, r4); - // 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(¬Constructing); - } + masm.ma_mov(sp, r3); // Save %sp. + masm.ma_mov(sp, r7); // Save %sp again. // 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(©LoopTop); 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,28 +82,16 @@ 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. @@ -118,17 +106,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 or newTarget + masm.addq(reg_argv, r13); // r13 points above last argument. // while r13 > rdx, push arguments. { Label header, footer; masm.bind(&header); masm.cmpPtr(r13, reg_argv); masm.j(AssemblerX86Shared::BelowOrEqual, &footer); @@ -404,37 +392,26 @@ 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); - // 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. + // 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. 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 -------' @@ -474,38 +451,16 @@ JitRuntime::generateArgumentsRectifier(J masm.bind(©LoopTop); masm.push(Operand(rcx, 0x0)); masm.subq(Imm32(sizeof(Value)), rcx); masm.subl(Imm32(1), r8); masm.j(Assembler::NonZero, ©LoopTop); } - // if constructing, copy newTarget - { - Label notConstructing; - - masm.branchTest32(Assembler::Zero, rax, Imm32(CalleeToken_FunctionConstructing), - ¬Constructing); - - // 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(¬Constructing); - } - - // 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,21 +619,16 @@ 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,32 +60,18 @@ 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); - // Load the number of values to be copied (argc) into eax + // eax <- 8*argc, eax is now the offset betwen argv and the last 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. // @@ -406,24 +392,16 @@ 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); @@ -470,41 +448,16 @@ JitRuntime::generateArgumentsRectifier(J masm.bind(©LoopTop); 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, ©LoopTop); } - { - Label notConstructing; - - masm.mov(eax, ebx); - masm.branchTest32(Assembler::Zero, ebx, Imm32(CalleeToken_FunctionConstructing), - ¬Constructing); - - 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(¬Constructing); - } - // 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,38 +4434,37 @@ 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(), false, rval); + return InvokeConstructor(cx, fval, args.length(), args.begin(), 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(), true)) + if (!args.init(inputArgs.length())) 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, false, &v)) + if (!InvokeConstructor(cx, args.thisv(), 1, argv, &v)) return false; obj = ToObject(cx, v); if (!obj) return false; } // Step 8. for (unsigned k = 0; k < args.length(); k++) { @@ -3281,20 +3281,16 @@ 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,39 +1547,31 @@ 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, args.isConstructing())) + if (!invokeArgs.init(args.length() + argslen)) 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,24 +443,26 @@ 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()) { - // Ignore the stack when throwing. We can't tell whether we were - // supposed to skip over a new.target or not. + /* + * 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). + */ JSAutoByteString bytes; if (!AtomToPrintableString(cx, name, &bytes)) return false; RootedValue val(cx, ObjectValue(*obj)); ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE, - JSDVG_IGNORE_STACK, val, nullptr, bytes.ptr()); + -1, 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,21 +114,19 @@ 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_CALL || op == JSOP_EVAL || + MOZ_ASSERT(op == JSOP_NEW || 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,18 +299,16 @@ 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(), true, args.rval()); + return InvokeConstructor(cx, target, args.length(), args.array(), 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,24 +1033,23 @@ 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(), true, args.rval()); + return InvokeConstructor(cx, targetv, args.length(), args.array(), args.rval()); } // step 8-9 Value constructArgv[] = { ObjectValue(*target), - ObjectValue(*argsArray), - args.newTarget() + ObjectValue(*argsArray) }; 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(), true, args.rval()); + return InvokeConstructor(cx, construct, args.length(), args.array(), args.rval()); } const CallableScriptedIndirectProxyHandler CallableScriptedIndirectProxyHandler::singleton; bool js::proxy_create(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp);
deleted file mode 100644 --- a/js/src/tests/ecma_6/Class/newTargetCCW.js +++ /dev/null @@ -1,10 +0,0 @@ -// 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 ({__iterator__:(function (){ })}) returned a primitive value'; +var expect = 'TypeError: trap __iterator__ for obj 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 ({__iterator__:(function (){ })}) returned a primitive value'; + expect = 'TypeError: trap __iterator__ for obj 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,32 +672,31 @@ 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(), skipForCallee, construct); + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, 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(), skipForCallee, construct); + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, 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); @@ -766,61 +765,54 @@ 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() + 2, CONSTRUCT); - - MOZ_ASSERT(args.newTarget().isObject()); + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT); JSObject& callee = args.callee(); if (callee.is<JSFunction>()) { RootedFunction fun(cx, &callee.as<JSFunction>()); if (!fun->isConstructor()) - return ReportIsNotFunction(cx, args.calleev(), args.length() + 2, CONSTRUCT); + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, 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() + 2, CONSTRUCT); + return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT); return CallJSNativeConstructor(cx, construct, args); } bool js::InvokeConstructor(JSContext* cx, Value fval, unsigned argc, const Value* argv, - bool newTargetInArgv, MutableHandleValue rval) + MutableHandleValue rval) { InvokeArgs args(cx); - if (!args.init(argc, true)) + if (!args.init(argc)) 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; } @@ -2894,35 +2886,26 @@ 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"); - 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)) + 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)) goto error; - REGS.sp -= 2 + construct; + REGS.sp -= 2; } END_CASE(JSOP_SPREADCALL) CASE(JSOP_FUNAPPLY) { CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp); if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args)) goto error; @@ -2931,21 +2914,20 @@ CASE(JSOP_FUNAPPLY) CASE(JSOP_NEW) CASE(JSOP_CALL) CASE(JSOP_FUNCALL) { if (REGS.fp()->hasPushedSPSFrame()) cx->runtime()->spsProfiler.updatePC(script, REGS.pc); + MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc)); + CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp); + 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(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)) @@ -4539,55 +4521,49 @@ 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, HandleValue newTarget, MutableHandleValue res) + HandleValue callee, HandleValue arr, 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, - constructing ? JSMSG_TOO_MANY_CON_SPREADARGS - : JSMSG_TOO_MANY_FUN_SPREADARGS); + op == JSOP_SPREADNEW ? 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, constructing)) + if (!args.init(length)) 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, - bool newTargetInArgv, MutableHandleValue rval); + 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, HandleValue newTarget, MutableHandleValue res); + HandleValue callee, HandleValue arr, 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, newTarget => rval + * Stack: callee, this, args => rval */ \ - macro(JSOP_SPREADNEW, 42, "spreadnew", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \ + macro(JSOP_SPREADNEW, 42, "spreadnew", NULL, 1, 3, 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], newTarget => rval - * nuses: (argc+3) + * Stack: callee, this, args[0], ..., args[argc-1] => rval + * nuses: (argc+2) */ \ 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,35 +287,29 @@ 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); - bool isConstructing = *flags & InterpreterFrame::CONSTRUCTING; - unsigned nfunctionState = 2 + isConstructing; // callee, |this|, |new.target| - - nvals += nformal + nfunctionState; + nvals += nformal + 2; // Include callee, |this|. 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 + nfunctionState + nformal); + return reinterpret_cast<InterpreterFrame*>(argv + 2 + 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 + isConstructing(), argv_ - 2, "fp argv"); + TraceRootRange(trc, argc + 2, 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 - fp_->isConstructing(); + sp = fp_->prevsp() - fp_->numActualArgs() - 1; fp_ = fp_->prev(); MOZ_ASSERT(fp_); } void prepareToRun(InterpreterFrame& fp, JSScript* script) { pc = script->code(); sp = fp.slots() + script->nfixed(); fp_ = &fp; } @@ -1028,24 +1028,22 @@ void MarkInterpreterActivations(JSRuntim /*****************************************************************************/ class InvokeArgs : public JS::CallArgs { AutoValueVector v_; public: - explicit InvokeArgs(JSContext* cx, bool construct = false) : v_(cx) {} + explicit InvokeArgs(JSContext* cx) : v_(cx) {} - bool init(unsigned argc, bool construct = false) { - if (!v_.resize(2 + argc + construct)) + bool init(unsigned argc) { + if (!v_.resize(2 + argc)) 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 = 289; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 288; 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.");