[JSC] Remove arity fixup check if the number of parameters is 1
https://bugs.webkit.org/show_bug.cgi?id=183984

Reviewed by Mark Lam.

If the number of parameters is one (|this|), we never hit arity fixup check.
We do not need to emit arity fixup check code.

* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGJITCompiler.h:
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* jit/JIT.cpp:
(JSC::JIT::compileWithoutLinking):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231160 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index e429ca4..e90eb94 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,25 @@
 2018-04-30  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        [JSC] Remove arity fixup check if the number of parameters is 1
+        https://bugs.webkit.org/show_bug.cgi?id=183984
+
+        Reviewed by Mark Lam.
+
+        If the number of parameters is one (|this|), we never hit arity fixup check.
+        We do not need to emit arity fixup check code.
+
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compileImpl):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::compileFunction):
+        * dfg/DFGJITCompiler.h:
+        * ftl/FTLLink.cpp:
+        (JSC::FTL::link):
+        * jit/JIT.cpp:
+        (JSC::JIT::compileWithoutLinking):
+
+2018-04-30  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         Use WordLock instead of std::mutex for Threading
         https://bugs.webkit.org/show_bug.cgi?id=185121
 
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 72e793f..2ec0b5a 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -89,6 +89,7 @@
     
     // Make sure that any stubs that the DFG is going to use are initialized. We want to
     // make sure that all JIT code generation does finalization on the main thread.
+    vm.getCTIStub(arityFixupGenerator);
     vm.getCTIStub(osrExitThunkGenerator);
     vm.getCTIStub(osrExitGenerationThunkGenerator);
     vm.getCTIStub(throwExceptionFromCallSlowPathGenerator);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index ed970ff..5c5b673 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -446,6 +446,7 @@
     makeCatchOSREntryBuffer();
 
     setStartOfCode();
+    Label entryLabel(this);
     compileEntry();
 
     // === Function header code generation ===
@@ -492,22 +493,28 @@
     // determine the correct number of arguments have been passed, or have already checked).
     // In cases where an arity check is necessary, we enter here.
     // FIXME: change this from a cti call to a DFG style operation (normal C calling conventions).
-    m_arityCheck = label();
-    compileEntry();
+    Call callArityFixup;
+    Label arityCheck;
+    bool requiresArityFixup = m_codeBlock->numParameters() != 1;
+    if (requiresArityFixup) {
+        arityCheck = label();
+        compileEntry();
 
-    load32(AssemblyHelpers::payloadFor((VirtualRegister)CallFrameSlot::argumentCount), GPRInfo::regT1);
-    branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this);
-    emitStoreCodeOrigin(CodeOrigin(0));
-    if (maxFrameExtentForSlowPathCall)
-        addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
-    m_speculative->callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck, GPRInfo::regT0);
-    if (maxFrameExtentForSlowPathCall)
-        addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
-    branchTest32(Zero, GPRInfo::returnValueGPR).linkTo(fromArityCheck, this);
-    emitStoreCodeOrigin(CodeOrigin(0));
-    move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
-    Call callArityFixup = nearCall();
-    jump(fromArityCheck);
+        load32(AssemblyHelpers::payloadFor((VirtualRegister)CallFrameSlot::argumentCount), GPRInfo::regT1);
+        branch32(AboveOrEqual, GPRInfo::regT1, TrustedImm32(m_codeBlock->numParameters())).linkTo(fromArityCheck, this);
+        emitStoreCodeOrigin(CodeOrigin(0));
+        if (maxFrameExtentForSlowPathCall)
+            addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
+        m_speculative->callOperationWithCallFrameRollbackOnException(m_codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck, GPRInfo::regT0);
+        if (maxFrameExtentForSlowPathCall)
+            addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
+        branchTest32(Zero, GPRInfo::returnValueGPR).linkTo(fromArityCheck, this);
+        emitStoreCodeOrigin(CodeOrigin(0));
+        move(GPRInfo::returnValueGPR, GPRInfo::argumentGPR0);
+        callArityFixup = nearCall();
+        jump(fromArityCheck);
+    } else
+        arityCheck = entryLabel;
 
     // Generate slow path code.
     m_speculative->runSlowPathGenerators(m_pcToCodeOriginMapBuilder);
@@ -532,11 +539,12 @@
     m_jitCode->shrinkToFit();
     codeBlock()->shrinkToFit(CodeBlock::LateShrink);
 
-    linkBuffer->link(callArityFixup, FunctionPtr<JITThunkPtrTag>(vm()->getCTIStub(arityFixupGenerator).code()));
+    if (requiresArityFixup)
+        linkBuffer->link(callArityFixup, FunctionPtr<JITThunkPtrTag>(vm()->getCTIStub(arityFixupGenerator).code()));
 
     disassemble(*linkBuffer);
 
-    MacroAssemblerCodePtr<JSEntryPtrTag> withArityCheck = linkBuffer->locationOf<JSEntryPtrTag>(m_arityCheck);
+    MacroAssemblerCodePtr<JSEntryPtrTag> withArityCheck = linkBuffer->locationOf<JSEntryPtrTag>(arityCheck);
 
     m_graph.m_plan.finalizer = std::make_unique<JITFinalizer>(
         m_graph.m_plan, m_jitCode.releaseNonNull(), WTFMove(linkBuffer), withArityCheck);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index b6b2e2d..6e9fac4 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -368,7 +368,6 @@
     };
     Vector<ExceptionHandlingOSRExitInfo> m_exceptionHandlerOSRExitCallSites;
     
-    Label m_arityCheck;
     std::unique_ptr<SpeculativeJIT> m_speculative;
     PCToCodeOriginMapBuilder m_pcToCodeOriginMapBuilder;
 };
diff --git a/Source/JavaScriptCore/ftl/FTLLink.cpp b/Source/JavaScriptCore/ftl/FTLLink.cpp
index e36db5cf..174fce9 100644
--- a/Source/JavaScriptCore/ftl/FTLLink.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLink.cpp
@@ -128,7 +128,8 @@
     
     switch (graph.m_plan.mode) {
     case FTLMode: {
-        if (codeBlock->codeType() == FunctionCode) {
+        bool requiresArityFixup = codeBlock->numParameters() != 1;
+        if (codeBlock->codeType() == FunctionCode && requiresArityFixup) {
             CCallHelpers::JumpList mainPathJumps;
     
             jit.load32(
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index 07c7705..9daf6b9 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -720,7 +720,9 @@
         addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
     callOperationWithCallFrameRollbackOnException(operationThrowStackOverflowError, m_codeBlock);
 
-    if (m_codeBlock->codeType() == FunctionCode) {
+    // If the number of parameters is 1, we never require arity fixup.
+    bool requiresArityFixup = m_codeBlock->m_numParameters != 1;
+    if (m_codeBlock->codeType() == FunctionCode && requiresArityFixup) {
         m_arityCheck = label();
         store8(TrustedImm32(0), &m_codeBlock->m_shouldAlwaysBeInlined);
         emitFunctionPrologue();
@@ -746,7 +748,7 @@
 
         jump(beginLabel);
     } else
-        m_arityCheck = entryLabel; // Not a function.
+        m_arityCheck = entryLabel; // Never require arity fixup.
 
     ASSERT(m_jmpTable.isEmpty());