+2015-02-24 Ryosuke Niwa <rniwa@webkit.org>
+
+ Use "this" instead of "callee" to get the constructor
+ https://bugs.webkit.org/show_bug.cgi?id=141019
+
+ Reviewed by Filip Pizlo.
+
+ This patch uses "this" register to pass the constructor (newTarget) to op_create_this from
+ op_construct or op_construct_varargs. This will allow future patches that implement ES6 class
+ to pass in the most derived class' constructor through "this" argument.
+
+ BytecodeGenerator's emitConstruct and emitConstructVarargs now passes thisRegister like
+ regular calls and emitCreateThis passes in this register to op_create_this as constructor.
+
+ The rest of the code change removes the code for special casing "this" register not being used
+ in call to construct.
+
+ * bytecode/BytecodeUseDef.h:
+ (JSC::computeUsesForBytecodeOffset):
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitCreateThis):
+ (JSC::BytecodeGenerator::emitConstructVarargs):
+ (JSC::BytecodeGenerator::emitConstruct):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::NewExprNode::emitBytecode):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
+ (JSC::DFG::ByteCodeParser::handleVarargsCall):
+ (JSC::DFG::ByteCodeParser::emitArgumentPhantoms):
+ (JSC::DFG::ByteCodeParser::attemptToInlineCall):
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ * dfg/DFGJITCode.cpp:
+ (JSC::DFG::JITCode::reconstruct):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * ftl/FTLJSCallVarargs.cpp:
+ (JSC::FTL::JSCallVarargs::emit):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileNativeCallOrConstruct):
+ (JSC::FTL::LowerDFGToLLVM::compileCallOrConstruct):
+ (JSC::FTL::LowerDFGToLLVM::compileCallOrConstructVarargs):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::executeConstruct):
+ * jit/JITOperations.cpp:
+
2015-02-24 Joseph Pecoraro <pecoraro@apple.com>
Web Inspector: Make Getter/Setter RemoteObject property and ObjectPreview handling consistent
int argCount = instruction[3].u.operand;
int registerOffset = -instruction[4].u.operand;
int lastArg = registerOffset + CallFrame::thisArgumentOffset();
- for (int i = opcodeID == op_construct ? 1 : 0; i < argCount; i++)
+ for (int i = 0; i < argCount; i++)
functor(codeBlock, instruction, opcodeID, lastArg + i);
return;
}
RegisterID* BytecodeGenerator::emitCreateThis(RegisterID* dst)
{
- RefPtr<RegisterID> func = newTemporary();
-
- m_codeBlock->addPropertyAccessInstruction(instructions().size());
- emitOpcode(op_get_callee);
- instructions().append(func->index());
- instructions().append(0);
-
size_t begin = instructions().size();
m_staticPropertyAnalyzer.createThis(m_thisRegister.index(), begin + 3);
emitOpcode(op_create_this);
instructions().append(m_thisRegister.index());
- instructions().append(func->index());
+ instructions().append(m_thisRegister.index());
instructions().append(0);
return dst;
}
return emitCallVarargs(op_call_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd);
}
-RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
{
- return emitCallVarargs(op_construct_varargs, dst, func, 0, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd);
+ return emitCallVarargs(op_construct_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd);
}
RegisterID* BytecodeGenerator::emitCallVarargs(OpcodeID opcode, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
argumentRegister = uncheckedLocalArgumentsRegister();
else
argumentRegister = expression->emitBytecode(*this, callArguments.argumentRegister(0));
- return emitConstructVarargs(dst, func, argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd);
+ return emitConstructVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd);
}
for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next)
RegisterID* emitInitLazyRegister(RegisterID*);
- RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+ RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
RegisterID* initializeCapturedVariable(RegisterID* dst, const Identifier&, RegisterID*);
RefPtr<RegisterID> func = generator.emitNode(m_expr);
RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
CallArguments callArguments(generator, m_args);
+ generator.emitMove(callArguments.thisRegister(), func.get());
return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
}
void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind);
void handleVarargsCall(Instruction* pc, NodeType op, CodeSpecializationKind);
void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt);
- void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind);
+ void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis);
unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CodeSpecializationKind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
// Handle inlining. Return true if it succeeded, false if we need to plant a call.
bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction);
if (parameterSlots > m_parameterSlots)
m_parameterSlots = parameterSlots;
- int dummyThisArgument = op == Call || op == NativeCall ? 0 : 1;
- for (int i = 0 + dummyThisArgument; i < argCount; ++i)
+ for (int i = 0; i < argCount; ++i)
addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
return addToGraph(Node::VarArg, op, opInfo, OpInfo(prediction));
CallVarargsData* data = m_graph.m_callVarargsData.add();
data->firstVarArgOffset = firstVarArgOffset;
- Node* thisChild;
- if (kind == CodeForCall)
- thisChild = get(VirtualRegister(thisReg));
- else
- thisChild = nullptr;
+ Node* thisChild = get(VirtualRegister(thisReg));
Node* call = addToGraph(op, OpInfo(data), OpInfo(prediction), callTarget, get(VirtualRegister(arguments)), thisChild);
VirtualRegister resultReg(result);
addToGraph(CheckCell, OpInfo(m_graph.freeze(calleeCell)), callTargetForCheck, thisArgument);
}
-void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind kind)
+void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis)
{
- for (int i = kind == CodeForCall ? 0 : 1; i < argumentCountIncludingThis; ++i)
+ for (int i = 0; i < argumentCountIncludingThis; ++i)
addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset)));
}
if (handleConstantInternalFunction(resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, insertChecksWithAccounting)) {
RELEASE_ASSERT(didInsertChecks);
addToGraph(Phantom, callTargetNode);
- emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
inliningBalance--;
return true;
}
if (handleIntrinsic(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
RELEASE_ASSERT(didInsertChecks);
addToGraph(Phantom, callTargetNode);
- emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
inliningBalance--;
return true;
}
callTargetNode, resultOperand, callLinkStatus[0], registerOffset,
argumentCountIncludingThis, nextOffset, kind, CallerDoesNormalLinking, prediction,
inliningBalance, [&] (CodeBlock* codeBlock) {
- emitFunctionChecks(callLinkStatus[0], callTargetNode, specializationKind == CodeForCall ? thisArgument : VirtualRegister());
+ emitFunctionChecks(callLinkStatus[0], callTargetNode, thisArgument);
// If we have a varargs call, we want to extract the arguments right now.
if (InlineCallFrame::isVarargs(kind)) {
countVariable->mergeIsProfitableToUnbox(true);
Node* setArgumentCount = addToGraph(SetArgument, OpInfo(countVariable));
m_currentBlock->variablesAtTail.setOperand(countVariable->local(), setArgumentCount);
-
- if (specializationKind == CodeForCall)
- set(VirtualRegister(argumentStart), get(thisArgument), ImmediateNakedSet);
+
+ set(VirtualRegister(argumentStart), get(thisArgument), ImmediateNakedSet);
for (unsigned argument = 1; argument < maxNumArguments; ++argument) {
VariableAccessData* variable = newVariableAccessData(
VirtualRegister(remappedArgumentStart + argument), false);
} else {
addToGraph(CheckBadCell);
addToGraph(Phantom, myCallTargetNode);
- emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
set(VirtualRegister(resultOperand), addToGraph(BottomValue));
}
return true;
}
+ // FIXME: Array constructor should use "this" as newTarget.
for (int i = 1; i < argumentCountIncludingThis; ++i)
addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
set(VirtualRegister(resultOperand),
// Initialize all locals to undefined.
for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i)
set(virtualRegisterForLocal(i), undefined, ImmediateNakedSet);
- if (m_inlineStackTop->m_codeBlock->specializationKind() == CodeForConstruct)
- set(virtualRegisterForArgument(0), undefined, ImmediateNakedSet);
NEXT_OPCODE(op_enter);
}
reconstruct(codeBlock, codeOrigin, streamIndex, recoveries);
result = Operands<JSValue>(OperandsLike, recoveries);
- for (size_t i = result.size(); i--;) {
- int operand = result.operandForIndex(i);
-
- if (codeOrigin == CodeOrigin(0)
- && operandIsArgument(operand)
- && !VirtualRegister(operand).toArgument()
- && codeBlock->codeType() == FunctionCode
- && codeBlock->specializationKind() == CodeForConstruct) {
- // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
- // also never be used. It doesn't matter what we put into the value for this,
- // but it has to be an actual value that can be grokked by subsequent DFG passes,
- // so we sanitize it here by turning it into Undefined.
- result[i] = jsUndefined();
- continue;
- }
-
+ for (size_t i = result.size(); i--;)
result[i] = recoveries[i].recover(exec);
- }
}
#if ENABLE(FTL_JIT)
void SpeculativeJIT::emitCall(Node* node)
{
CallLinkInfo::CallType callType;
- bool isCall;
bool isVarargs;
switch (node->op()) {
case Call:
callType = CallLinkInfo::Call;
- isCall = true;
isVarargs = false;
break;
case Construct:
callType = CallLinkInfo::Construct;
- isCall = false;
isVarargs = false;
break;
case CallVarargs:
case CallForwardVarargs:
callType = CallLinkInfo::CallVarargs;
- isCall = true;
isVarargs = true;
break;
case ConstructVarargs:
callType = CallLinkInfo::ConstructVarargs;
- isCall = false;
isVarargs = true;
break;
default:
if (node->op() != CallForwardVarargs)
use(node->child2());
+
+ // Now set up the "this" argument.
+ JSValueOperand thisArgument(this, node->op() == CallForwardVarargs ? node->child2() : node->child3());
+ GPRReg thisArgumentTagGPR = thisArgument.tagGPR();
+ GPRReg thisArgumentPayloadGPR = thisArgument.payloadGPR();
+ thisArgument.use();
- if (isCall) {
- // Now set up the "this" argument.
- JSValueOperand thisArgument(this, node->op() == CallForwardVarargs ? node->child2() : node->child3());
- GPRReg thisArgumentTagGPR = thisArgument.tagGPR();
- GPRReg thisArgumentPayloadGPR = thisArgument.payloadGPR();
- thisArgument.use();
-
- m_jit.store32(thisArgumentTagGPR, JITCompiler::calleeArgumentTagSlot(0));
- m_jit.store32(thisArgumentPayloadGPR, JITCompiler::calleeArgumentPayloadSlot(0));
- }
- } else {
- // For constructors, the this argument is not passed but we have to make space
- // for it.
- int dummyThisArgument = isCall ? 0 : 1;
-
+ m_jit.store32(thisArgumentTagGPR, JITCompiler::calleeArgumentTagSlot(0));
+ m_jit.store32(thisArgumentPayloadGPR, JITCompiler::calleeArgumentPayloadSlot(0));
+ } else {
// The call instruction's first child is either the function (normal call) or the
// receiver (method call). subsequent children are the arguments.
int numPassedArgs = node->numChildren() - 1;
-
- int numArgs = numPassedArgs + dummyThisArgument;
-
- m_jit.store32(MacroAssembler::TrustedImm32(numArgs), m_jit.calleeFramePayloadSlot(JSStack::ArgumentCount));
+
+ m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(JSStack::ArgumentCount));
for (int i = 0; i < numPassedArgs; i++) {
Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
GPRReg argPayloadGPR = arg.payloadGPR();
use(argEdge);
- m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i + dummyThisArgument));
- m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i + dummyThisArgument));
+ m_jit.store32(argTagGPR, m_jit.calleeArgumentTagSlot(i));
+ m_jit.store32(argPayloadGPR, m_jit.calleeArgumentPayloadSlot(i));
}
}
void SpeculativeJIT::emitCall(Node* node)
{
CallLinkInfo::CallType callType;
- bool isCall;
bool isVarargs;
switch (node->op()) {
case Call:
callType = CallLinkInfo::Call;
- isCall = true;
isVarargs = false;
break;
case Construct:
callType = CallLinkInfo::Construct;
- isCall = false;
isVarargs = false;
break;
case CallVarargs:
case CallForwardVarargs:
callType = CallLinkInfo::CallVarargs;
- isCall = true;
isVarargs = true;
break;
case ConstructVarargs:
callType = CallLinkInfo::ConstructVarargs;
- isCall = false;
isVarargs = true;
break;
default:
// We don't need the arguments array anymore.
if (node->op() != CallForwardVarargs)
use(node->child2());
+
+ // Now set up the "this" argument.
+ JSValueOperand thisArgument(this, node->op() == CallForwardVarargs ? node->child2() : node->child3());
+ GPRReg thisArgumentGPR = thisArgument.gpr();
+ thisArgument.use();
- if (isCall) {
- // Now set up the "this" argument.
- JSValueOperand thisArgument(this, node->op() == CallForwardVarargs ? node->child2() : node->child3());
- GPRReg thisArgumentGPR = thisArgument.gpr();
- thisArgument.use();
-
- m_jit.store64(thisArgumentGPR, JITCompiler::calleeArgumentSlot(0));
- }
+ m_jit.store64(thisArgumentGPR, JITCompiler::calleeArgumentSlot(0));
} else {
- // For constructors, the this argument is not passed but we have to make space
- // for it.
- int dummyThisArgument = isCall ? 0 : 1;
-
// The call instruction's first child is the function; the subsequent children are the
// arguments.
int numPassedArgs = node->numChildren() - 1;
-
- int numArgs = numPassedArgs + dummyThisArgument;
-
- m_jit.store32(MacroAssembler::TrustedImm32(numArgs), JITCompiler::calleeFramePayloadSlot(JSStack::ArgumentCount));
+
+ m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), JITCompiler::calleeFramePayloadSlot(JSStack::ArgumentCount));
for (int i = 0; i < numPassedArgs; i++) {
Edge argEdge = m_jit.graph().m_varArgChildren[node->firstChild() + 1 + i];
GPRReg argGPR = arg.gpr();
use(argEdge);
- m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i + dummyThisArgument));
+ m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
}
}
// - The callee.
// - The arguments object.
// - The "this" value, if it's a constructor call.
-
- bool isCall = m_node->op() != ConstructVarargs;
-
+
CallVarargsData* data = m_node->callVarargsData();
GPRReg calleeGPR = GPRInfo::argumentGPR0;
break;
case ConstructVarargs:
argumentsGPR = GPRInfo::argumentGPR1;
+ thisGPR = GPRInfo::argumentGPR2;
break;
default:
RELEASE_ASSERT_NOT_REACHED();
usedRegisters.set(calleeGPR);
if (argumentsGPR != InvalidGPRReg)
usedRegisters.set(argumentsGPR);
- if (thisGPR != InvalidGPRReg)
- usedRegisters.set(thisGPR);
+ ASSERT(thisGPR);
+ usedRegisters.set(thisGPR);
ScratchRegisterAllocator allocator(usedRegisters);
GPRReg scratchGPR1 = allocator.allocateScratchGPR();
GPRReg scratchGPR2 = allocator.allocateScratchGPR();
jit.store64(calleeGPR, CCallHelpers::addressFor(spillSlotsOffset + calleeSpillSlot));
if (!argumentsOnStack)
jit.store64(argumentsGPR, CCallHelpers::addressFor(spillSlotsOffset + argumentsSpillSlot));
- if (isCall)
- jit.store64(thisGPR, CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot));
+ jit.store64(thisGPR, CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot));
unsigned extraStack = sizeof(CallerFrameAndPC) +
WTF::roundUpToMultipleOf(stackAlignmentBytes(), 5 * sizeof(void*));
callWithExceptionCheck(bitwise_cast<void*>(operationSetupVarargsFrame));
jit.move(GPRInfo::returnValueGPR, scratchGPR2);
-
- if (isCall)
- jit.load64(CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot), thisGPR);
+
+ jit.load64(CCallHelpers::addressFor(spillSlotsOffset + thisSpillSlot), thisGPR);
jit.load64(CCallHelpers::addressFor(spillSlotsOffset + calleeSpillSlot), GPRInfo::regT0);
if (m_node->op() == CallForwardVarargs)
haveArguments.link(&jit);
jit.addPtr(CCallHelpers::TrustedImm32(sizeof(CallerFrameAndPC)), scratchGPR2, CCallHelpers::stackPointerRegister);
-
- if (isCall)
- jit.store64(thisGPR, CCallHelpers::calleeArgumentSlot(0));
+
+ jit.store64(thisGPR, CCallHelpers::calleeArgumentSlot(0));
// Henceforth we make the call. The base FTL call machinery expects the callee in regT0 and for the
// stack frame to already be set up, which it is.
#if ENABLE(FTL_NATIVE_CALL_INLINING)
void compileNativeCallOrConstruct()
{
- int dummyThisArgument = m_node->op() == NativeCall ? 0 : 1;
int numPassedArgs = m_node->numChildren() - 1;
- int numArgs = numPassedArgs + dummyThisArgument;
+ int numArgs = numPassedArgs;
JSFunction* knownFunction = jsCast<JSFunction*>(m_node->cellOperand()->value().asCell());
NativeFunction function = knownFunction->nativeFunction();
m_out.store64(m_out.constInt64(numArgs), addressFor(m_execStorage, JSStack::ArgumentCount));
- if (dummyThisArgument)
- m_out.storePtr(getUndef(m_out.int64), addressFor(m_execStorage, JSStack::ThisArgument));
-
for (int i = 0; i < numPassedArgs; ++i) {
m_out.storePtr(lowJSValue(m_graph.varArgChild(m_node, 1 + i)),
- addressFor(m_execStorage, dummyThisArgument ? JSStack::FirstArgument : JSStack::ThisArgument, i * sizeof(Register)));
+ addressFor(m_execStorage, JSStack::ThisArgument, i * sizeof(Register)));
}
LValue calleeCallFrame = m_out.address(m_execState, m_heaps.CallFrame_callerFrame).value();
void compileCallOrConstruct()
{
- int dummyThisArgument = m_node->op() == Call ? 0 : 1;
int numPassedArgs = m_node->numChildren() - 1;
- int numArgs = numPassedArgs + dummyThisArgument;
+ int numArgs = numPassedArgs;
LValue jsCallee = lowJSValue(m_graph.varArgChild(m_node, 0));
arguments.append(getUndef(m_out.int64)); // code block
arguments.append(jsCallee); // callee -> stack
arguments.append(m_out.constInt64(numArgs)); // argument count and zeros for the tag
- if (dummyThisArgument)
- arguments.append(getUndef(m_out.int64));
for (int i = 0; i < numPassedArgs; ++i)
arguments.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i)));
break;
case ConstructVarargs:
jsArguments = lowJSValue(m_node->child2());
+ thisArg = lowJSValue(m_node->child3());
break;
default:
DFG_CRASH(m_graph, m_node, "bad node type");
arguments.append(m_out.constInt64(stackmapID));
arguments.append(m_out.constInt32(sizeOfICFor(m_node)));
arguments.append(constNull(m_out.ref8));
- arguments.append(m_out.constInt32(1 + !!jsArguments + !!thisArg));
+ arguments.append(m_out.constInt32(2 + !!jsArguments));
arguments.append(jsCallee);
if (jsArguments)
arguments.append(jsArguments);
- if (thisArg)
- arguments.append(thisArg);
+ ASSERT(thisArg);
+ arguments.append(thisArg);
callPreflight();
return throwTerminatedExecutionException(callFrame);
ProtoCallFrame protoCallFrame;
- protoCallFrame.init(newCodeBlock, constructor, jsUndefined(), argsCount, args.data());
+ protoCallFrame.init(newCodeBlock, constructor, constructor, argsCount, args.data());
if (LegacyProfiler* profiler = vm.enabledProfiler())
profiler->willExecute(callFrame, constructor);
Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
for (size_t i = 0; i < mustHandleValues.size(); ++i) {
int operand = mustHandleValues.operandForIndex(i);
- if (operandIsArgument(operand)
- && !VirtualRegister(operand).toArgument()
- && codeBlock->codeType() == FunctionCode
- && codeBlock->specializationKind() == CodeForConstruct) {
- // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
- // also never be used. It doesn't matter what we put into the value for this,
- // but it has to be an actual value that can be grokked by subsequent DFG passes,
- // so we sanitize it here by turning it into Undefined.
- mustHandleValues[i] = jsUndefined();
- } else
- mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
+ mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
}
RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();