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 5a8f023..e83b29a 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 92e58ca..2d6820c 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 abddfac..21402eb 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 a77f4b7..e4c3111 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 c720e52..00accf9 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 1aa539b..2c85a86 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 0d69079..1b6589a 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 0c679b1..bd0a198 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 bfb83a1..a214e36 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 b729ff0..e9b41c7 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 bba2256..f4e68d6 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 7ccebe0..ee9d064 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 6f9d92e..461167a 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();