Use "this" instead of "callee" to get the constructor
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Feb 2015 00:41:35 +0000 (00:41 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Feb 2015 00:41:35 +0000 (00:41 +0000)
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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@180595 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGJITCode.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JITOperations.cpp

index 5a8f0233901b06c8c918d1518767ffac59914d72..e83b29a403099becb7bd6945830be1744d9d8e58 100644 (file)
@@ -1,3 +1,53 @@
+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
index 92e58ca36ea7499bddc4c9979180d66d294e452e..2d6820c1fdcddd029f849f70af6b5b090a0d956d 100644 (file)
@@ -218,7 +218,7 @@ void computeUsesForBytecodeOffset(
         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;
     }
index abddfac9337c1dbd6c3f6f47468ec2768d254a08..21402ebeed151a5afd0255f43e283c0be80afff3 100644 (file)
@@ -1564,19 +1564,12 @@ RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index,
 
 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;
 }
@@ -1881,9 +1874,9 @@ RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func
     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)
@@ -1979,7 +1972,7 @@ RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func,
                 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)
index a77f4b7b2aa00b857a08c58cf640e8481693c940..e4c31115fdbc93460e83b4568d16766f89f59f1c 100644 (file)
@@ -667,7 +667,7 @@ namespace JSC {
 
         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*);
 
index c720e52c259bda0017731a9e65887b3625997289..00accf9f04bcc720d5b0bf94ff62d5e0721e9864 100644 (file)
@@ -453,6 +453,7 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, 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());
 }
 
index 1aa539b7f652765b4fbcf6981dea2d467ae76b89..2c85a8610cd443360b8a39b3724d96d2332f150e 100644 (file)
@@ -185,7 +185,7 @@ private:
     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);
@@ -694,8 +694,7 @@ private:
         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));
@@ -1141,11 +1140,7 @@ void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CodeSpecial
     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);
@@ -1175,9 +1170,9 @@ void ByteCodeParser::emitFunctionChecks(CallVariant callee, Node* callTarget, Vi
     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)));
 }
 
@@ -1447,7 +1442,7 @@ bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand
         if (handleConstantInternalFunction(resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, insertChecksWithAccounting)) {
             RELEASE_ASSERT(didInsertChecks);
             addToGraph(Phantom, callTargetNode);
-            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
             inliningBalance--;
             return true;
         }
@@ -1460,7 +1455,7 @@ bool ByteCodeParser::attemptToInlineCall(Node* callTargetNode, int resultOperand
         if (handleIntrinsic(resultOperand, intrinsic, registerOffset, argumentCountIncludingThis, prediction, insertChecksWithAccounting)) {
             RELEASE_ASSERT(didInsertChecks);
             addToGraph(Phantom, callTargetNode);
-            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+            emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
             inliningBalance--;
             return true;
         }
@@ -1545,7 +1540,7 @@ bool ByteCodeParser::handleInlining(
             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)) {
@@ -1579,9 +1574,8 @@ bool ByteCodeParser::handleInlining(
                     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);
@@ -1762,7 +1756,7 @@ bool ByteCodeParser::handleInlining(
     } else {
         addToGraph(CheckBadCell);
         addToGraph(Phantom, myCallTargetNode);
-        emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind);
+        emitArgumentPhantoms(registerOffset, argumentCountIncludingThis);
         
         set(VirtualRegister(resultOperand), addToGraph(BottomValue));
     }
@@ -2150,6 +2144,7 @@ bool ByteCodeParser::handleConstantInternalFunction(
             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),
@@ -2588,8 +2583,6 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             // 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);
         }
             
index 0d690791840211258d3b3f072ed23110da006e51..1b6589a8f2c060b0cef8bd66e8fb0cfeca5e8400 100644 (file)
@@ -82,24 +82,8 @@ void JITCode::reconstruct(
     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)
index 0c679b1e726ac7d202b487abf3bd0c8161a81f46..bd0a198860bb04b3474ef2e55e6fe4576f0d4903 100644 (file)
@@ -640,28 +640,23 @@ void SpeculativeJIT::compileMiscStrictEq(Node* node)
 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:
@@ -770,29 +765,21 @@ void SpeculativeJIT::emitCall(Node* node)
         
         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];
@@ -801,8 +788,8 @@ void SpeculativeJIT::emitCall(Node* node)
             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));
         }
     }
 
index bfb83a19c12e979fa4d36b773f23d61fc7fa821a..a214e360b87f0d5f8f76ba3eb3d08644a467281a 100644 (file)
@@ -626,28 +626,23 @@ void SpeculativeJIT::compileMiscStrictEq(Node* node)
 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:
@@ -746,27 +741,19 @@ void SpeculativeJIT::emitCall(Node* node)
         // 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];
@@ -774,7 +761,7 @@ void SpeculativeJIT::emitCall(Node* node)
             GPRReg argGPR = arg.gpr();
             use(argEdge);
         
-            m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i + dummyThisArgument));
+            m_jit.store64(argGPR, JITCompiler::calleeArgumentSlot(i));
         }
     }
 
index b729ff0858dc7768f5602cc08a204d36561d2d31..e9b41c7123bab58e97d7ff591c17df7773c6ce1f 100644 (file)
@@ -69,9 +69,7 @@ void JSCallVarargs::emit(CCallHelpers& jit, Graph& graph, int32_t spillSlotsOffs
     // - 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;
@@ -91,6 +89,7 @@ void JSCallVarargs::emit(CCallHelpers& jit, Graph& graph, int32_t spillSlotsOffs
         break;
     case ConstructVarargs:
         argumentsGPR = GPRInfo::argumentGPR1;
+        thisGPR = GPRInfo::argumentGPR2;
         break;
     default:
         RELEASE_ASSERT_NOT_REACHED();
@@ -110,8 +109,8 @@ void JSCallVarargs::emit(CCallHelpers& jit, Graph& graph, int32_t spillSlotsOffs
     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();
@@ -182,8 +181,7 @@ void JSCallVarargs::emit(CCallHelpers& jit, Graph& graph, int32_t spillSlotsOffs
     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*));
@@ -201,18 +199,16 @@ void JSCallVarargs::emit(CCallHelpers& jit, Graph& graph, int32_t spillSlotsOffs
     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.
index bba2256f0081d3e86ac9374fb860e54cb7332591..f4e68d6abc4b9c59468e57c4053e8e2d4b1226af 100644 (file)
@@ -3766,9 +3766,8 @@ private:
 #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();
@@ -3789,12 +3788,9 @@ private:
 
         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();
@@ -3817,9 +3813,8 @@ private:
 
     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));
 
@@ -3834,8 +3829,6 @@ private:
         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)));
         
@@ -3866,6 +3859,7 @@ private:
             break;
         case ConstructVarargs:
             jsArguments = lowJSValue(m_node->child2());
+            thisArg = lowJSValue(m_node->child3());
             break;
         default:
             DFG_CRASH(m_graph, m_node, "bad node type");
@@ -3878,12 +3872,12 @@ private:
         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();
         
index 7ccebe04264c5352b6fe60a94aaa296c789a3a81..ee9d0646800c18877062400d02df93809fc246b1 100644 (file)
@@ -975,7 +975,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
         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);
index 6f9d92e7e7c9ef5f1ea50cde3854166755803cff..461167ae65410f426d7e87842078e02008a71555 100644 (file)
@@ -1159,17 +1159,7 @@ SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t byte
         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();