Bug 39898 - Move arity check into callee.
        
Reviewed by Sam Weinig.

We can reduce the size of the virtual call trampolines by moving the arity check
into the callee functions.  As a following step we will be able to remove the
check for native function / codeblocks by performing translation in a lazy stub.
        
* interpreter/CallFrame.h:
(JSC::ExecState::init):
(JSC::ExecState::setReturnPC):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
(JSC::JIT::linkCall):
(JSC::JIT::linkConstruct):
* jit/JIT.h:
(JSC::JIT::compile):
* jit/JITOpcodes.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::privateCompileCTIMachineTrampolines):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.cpp:
(JSC::FunctionExecutable::generateJITCodeForCall):
(JSC::FunctionExecutable::generateJITCodeForConstruct):
(JSC::FunctionExecutable::reparseExceptionInfo):
* runtime/Executable.h:
(JSC::NativeExecutable::NativeExecutable):
(JSC::FunctionExecutable::generatedJITCodeForCallWithArityCheck):
(JSC::FunctionExecutable::generatedJITCodeForConstructWithArityCheck):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@60376 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 46027b0..30491e2 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,37 @@
+2010-05-28  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        Bug 39898 - Move arity check into callee.
+        
+        We can reduce the size of the virtual call trampolines by moving the arity check
+        into the callee functions.  As a following step we will be able to remove the
+        check for native function / codeblocks by performing translation in a lazy stub.
+        
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::init):
+        (JSC::ExecState::setReturnPC):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        (JSC::JIT::linkCall):
+        (JSC::JIT::linkConstruct):
+        * jit/JIT.h:
+        (JSC::JIT::compile):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::privateCompileCTIMachineTrampolines):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::privateCompileCTIMachineTrampolines):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * runtime/Executable.cpp:
+        (JSC::FunctionExecutable::generateJITCodeForCall):
+        (JSC::FunctionExecutable::generateJITCodeForConstruct):
+        (JSC::FunctionExecutable::reparseExceptionInfo):
+        * runtime/Executable.h:
+        (JSC::NativeExecutable::NativeExecutable):
+        (JSC::FunctionExecutable::generatedJITCodeForCallWithArityCheck):
+        (JSC::FunctionExecutable::generatedJITCodeForConstructWithArityCheck):
+
 2010-05-27  Luiz Agostini  <luiz.agostini@openbossa.org>
 
         Reviewed by Darin Adler.
diff --git a/JavaScriptCore/interpreter/CallFrame.h b/JavaScriptCore/interpreter/CallFrame.h
index bde4072..66045e2 100644
--- a/JavaScriptCore/interpreter/CallFrame.h
+++ b/JavaScriptCore/interpreter/CallFrame.h
@@ -125,7 +125,7 @@
             setCodeBlock(codeBlock);
             setScopeChain(scopeChain);
             setCallerFrame(callerFrame);
-            static_cast<Register*>(this)[RegisterFile::ReturnPC] = vPC; // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
+            setReturnPC(vPC); // This is either an Instruction* or a pointer into JIT generated code stored as an Instruction*.
             setArgumentCount(argc); // original argument count (for the sake of the "arguments" object)
             setCallee(function);
         }
@@ -142,6 +142,7 @@
         void setArgumentCount(int count) { static_cast<Register*>(this)[RegisterFile::ArgumentCount] = Register::withInt(count); }
         void setCallee(JSFunction* callee) { static_cast<Register*>(this)[RegisterFile::Callee] = callee; }
         void setCodeBlock(CodeBlock* codeBlock) { static_cast<Register*>(this)[RegisterFile::CodeBlock] = codeBlock; }
+        void setReturnPC(void* value) { static_cast<Register*>(this)[RegisterFile::ReturnPC] = (Instruction*)value; }
 
     private:
         static const intptr_t HostCallFrameFlag = 1;
diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp
index a6d817a..5d96847 100644
--- a/JavaScriptCore/jit/JIT.cpp
+++ b/JavaScriptCore/jit/JIT.cpp
@@ -456,17 +456,19 @@
 #endif
 }
 
-JITCode JIT::privateCompile()
+JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck)
 {
+    // Could use a pop_m, but would need to offset the following instruction if so.
+    preserveReturnAddressAfterCall(regT2);
+    emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
+
+    Label beginLabel(this);
+
     sampleCodeBlock(m_codeBlock);
 #if ENABLE(OPCODE_SAMPLING)
     sampleInstruction(m_codeBlock->instructions().begin());
 #endif
 
-    // Could use a pop_m, but would need to offset the following instruction if so.
-    preserveReturnAddressAfterCall(regT2);
-    emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
-
     Jump registerFileCheck;
     if (m_codeBlock->codeType() == FunctionCode) {
         // In the case of a fast linked call, we do not set this up in the caller.
@@ -483,6 +485,8 @@
     privateCompileLinkPass();
     privateCompileSlowCases();
 
+    Label arityCheck;
+    Call callArityCheck;
     if (m_codeBlock->codeType() == FunctionCode) {
         registerFileCheck.link(this);
         m_bytecodeOffset = 0;
@@ -491,6 +495,15 @@
         m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
 #endif
         jump(functionBody);
+
+        arityCheck = label();
+        preserveReturnAddressAfterCall(regT2);
+        emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC);
+        branch32(Equal, regT1, Imm32(m_codeBlock->m_numParameters)).linkTo(beginLabel, this);
+        restoreArgumentReference();
+        callArityCheck = call();
+        move(regT0, callFrameRegister);
+        jump(beginLabel);
     }
 
     ASSERT(m_jmpTable.isEmpty());
@@ -569,6 +582,11 @@
         info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation;
     }
 
+    if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck) {
+        patchBuffer.link(callArityCheck, FunctionPtr(m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck));
+        *functionEntryArityCheck = patchBuffer.locationOf(arityCheck);
+    }
+
     return patchBuffer.finalizeCode();
 }
 
@@ -602,7 +620,7 @@
 #endif
 }
 
-void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
+void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
 {
     RepatchBuffer repatchBuffer(callerCodeBlock);
 
@@ -615,14 +633,14 @@
             calleeCodeBlock->addCaller(callLinkInfo);
     
         repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee);
-        repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall());
+        repatchBuffer.relink(callLinkInfo->hotPathOther, code);
     }
 
     // patch the call so we do not continue to try to link.
     repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs.ctiVirtualCall());
 }
 
-void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
+void JIT::linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData)
 {
     RepatchBuffer repatchBuffer(callerCodeBlock);
 
@@ -635,7 +653,7 @@
             calleeCodeBlock->addCaller(callLinkInfo);
     
         repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee);
-        repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall());
+        repatchBuffer.relink(callLinkInfo->hotPathOther, code);
     }
 
     // patch the call so we do not continue to try to link.
diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h
index da4c98b..529a1d6 100644
--- a/JavaScriptCore/jit/JIT.h
+++ b/JavaScriptCore/jit/JIT.h
@@ -178,9 +178,9 @@
         static const int patchGetByIdDefaultOffset = 256;
 
     public:
-        static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock)
+        static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock, CodePtr* functionEntryArityCheck = 0)
         {
-            return JIT(globalData, codeBlock).privateCompile();
+            return JIT(globalData, codeBlock).privateCompile(functionEntryArityCheck);
         }
 
         static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress)
@@ -239,8 +239,8 @@
             return jit.privateCompilePatchGetArrayLength(returnAddress);
         }
 
-        static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*);
-        static void linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode&, CallLinkInfo*, int callerArgCount, JSGlobalData*);
+        static void linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
+        static void linkConstruct(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, CodePtr, CallLinkInfo*, int callerArgCount, JSGlobalData*);
         static void unlinkCallOrConstruct(CallLinkInfo*);
 
     private:
@@ -260,7 +260,7 @@
         void privateCompileMainPass();
         void privateCompileLinkPass();
         void privateCompileSlowCases();
-        JITCode privateCompile();
+        JITCode privateCompile(CodePtr* functionEntryArityCheck);
         void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame);
         void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, const Identifier&, const PropertySlot&, size_t cachedOffset);
         void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, const Identifier&, const PropertySlot&, size_t cachedOffset, CallFrame* callFrame);
diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp
index 6534901..2d938d0 100644
--- a/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/JavaScriptCore/jit/JITOpcodes.cpp
@@ -78,9 +78,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
-    Jump hasCodeBlock1 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+    Jump hasCodeBlock1 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction1 = call();
@@ -89,20 +87,6 @@
     restoreReturnAddressBeforeReturn(regT3);
     hasCodeBlock1.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck1 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    arityCheckOkay1.link(this);
-
-    isNativeFunc1.link(this);
-
     preserveReturnAddressAfterCall(regT3);
     emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
     restoreArgumentReference();
@@ -117,9 +101,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
-    Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+    Jump hasCodeBlock2 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction2 = call();
@@ -128,20 +110,6 @@
     restoreReturnAddressBeforeReturn(regT3);
     hasCodeBlock2.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck2 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    arityCheckOkay2.link(this);
-
-    isNativeFunc2.link(this);
-
     preserveReturnAddressAfterCall(regT3);
     emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
     restoreArgumentReference();
@@ -156,9 +124,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
-    Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+    Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction3 = call();
@@ -166,23 +132,8 @@
     restoreReturnAddressBeforeReturn(regT3);
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
     hasCodeBlock3.link(this);
-    
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck3 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-    arityCheckOkay3.link(this);
 
-    isNativeFunc3.link(this);
-
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
     jump(regT0);
 
     // VirtualConstruct Trampoline
@@ -192,9 +143,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
-    Jump hasCodeBlock4 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+    Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction4 = call();
@@ -202,23 +151,8 @@
     restoreReturnAddressBeforeReturn(regT3);
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
     hasCodeBlock4.link(this);
-    
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck4 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-    arityCheckOkay4.link(this);
 
-    isNativeFunc4.link(this);
-
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
     jump(regT0);
 
     // NativeCall Trampoline
@@ -240,16 +174,12 @@
     patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
 #endif
 #if ENABLE(JIT_OPTIMIZE_CALL)
-    patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
     patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_jitCompile));
     patchBuffer.link(callLazyLinkCall1, FunctionPtr(cti_vm_lazyLinkCall));
-    patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_construct_arityCheck));
     patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_construct_jitCompile));
     patchBuffer.link(callLazyLinkCall2, FunctionPtr(cti_vm_lazyLinkConstruct));
 #endif
-    patchBuffer.link(callArityCheck3, FunctionPtr(cti_op_call_arityCheck));
     patchBuffer.link(callJSFunction3, FunctionPtr(cti_op_call_jitCompile));
-    patchBuffer.link(callArityCheck4, FunctionPtr(cti_op_construct_arityCheck));
     patchBuffer.link(callJSFunction4, FunctionPtr(cti_op_construct_jitCompile));
 
     CodeRef finalCode = patchBuffer.finalizeCode();
diff --git a/JavaScriptCore/jit/JITOpcodes32_64.cpp b/JavaScriptCore/jit/JITOpcodes32_64.cpp
index f254c7e..f2bb351 100644
--- a/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -75,9 +75,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
-    Jump hasCodeBlock1 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+    Jump hasCodeBlock1 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction1 = call();
@@ -86,25 +84,12 @@
     restoreReturnAddressBeforeReturn(regT3);
     hasCodeBlock1.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay1 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck1 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    arityCheckOkay1.link(this);
-
-    isNativeFunc1.link(this);
-
     preserveReturnAddressAfterCall(regT3);
     emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
     restoreArgumentReference();
     Call callLazyLinkCall1 = call();
     restoreReturnAddressBeforeReturn(regT3);
+    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
     jump(regT0);
 
     // VirtualConstructLink Trampoline
@@ -114,9 +99,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
-    Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+    Jump hasCodeBlock2 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction2 = call();
@@ -125,25 +108,12 @@
     restoreReturnAddressBeforeReturn(regT3);
     hasCodeBlock2.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck2 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    arityCheckOkay2.link(this);
-
-    isNativeFunc2.link(this);
-
     preserveReturnAddressAfterCall(regT3);
     emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
     restoreArgumentReference();
     Call callLazyLinkCall2 = call();
     restoreReturnAddressBeforeReturn(regT3);
+    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
     jump(regT0);
 #endif // ENABLE(JIT_OPTIMIZE_CALL)
 
@@ -154,9 +124,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
-
-    Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
+    Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction3 = call();
@@ -165,22 +133,7 @@
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
     hasCodeBlock3.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck3 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-    arityCheckOkay3.link(this);
-
-    isNativeFunc3.link(this);
-
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCall)), regT0);
+    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
     jump(regT0);
 
     // VirtualConstruct Trampoline
@@ -190,9 +143,7 @@
 
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
 
-    Jump isNativeFunc4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
-
-    Jump hasCodeBlock4 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
+    Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), Imm32(0));
     preserveReturnAddressAfterCall(regT3);
     restoreArgumentReference();
     Call callJSFunction4 = call();
@@ -201,22 +152,7 @@
     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
     hasCodeBlock4.link(this);
 
-    // Check argCount matches callee arity.
-    Jump arityCheckOkay4 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), regT1);
-    preserveReturnAddressAfterCall(regT3);
-    emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
-    restoreArgumentReference();
-    Call callArityCheck4 = call();
-    move(regT0, callFrameRegister);
-    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
-    emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
-    restoreReturnAddressBeforeReturn(regT3);
-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
-    arityCheckOkay4.link(this);
-
-    isNativeFunc4.link(this);
-
-    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstruct)), regT0);
+    loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
     jump(regT0);
 
     // NativeCall Trampoline
@@ -238,16 +174,12 @@
     patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
 #endif
 #if ENABLE(JIT_OPTIMIZE_CALL)
-    patchBuffer.link(callArityCheck1, FunctionPtr(cti_op_call_arityCheck));
     patchBuffer.link(callJSFunction1, FunctionPtr(cti_op_call_jitCompile));
     patchBuffer.link(callLazyLinkCall1, FunctionPtr(cti_vm_lazyLinkCall));
-    patchBuffer.link(callArityCheck2, FunctionPtr(cti_op_construct_arityCheck));
     patchBuffer.link(callJSFunction2, FunctionPtr(cti_op_construct_jitCompile));
     patchBuffer.link(callLazyLinkCall2, FunctionPtr(cti_vm_lazyLinkConstruct));
 #endif
-    patchBuffer.link(callArityCheck3, FunctionPtr(cti_op_call_arityCheck));
     patchBuffer.link(callJSFunction3, FunctionPtr(cti_op_call_jitCompile));
-    patchBuffer.link(callArityCheck4, FunctionPtr(cti_op_construct_arityCheck));
     patchBuffer.link(callJSFunction4, FunctionPtr(cti_op_construct_jitCompile));
 
     CodeRef finalCode = patchBuffer.finalizeCode();
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index d5141eb..86aeefd 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -1844,6 +1844,7 @@
     ASSERT(!callee->isHostFunction());
     CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForCall();
     int argCount = callFrame->argumentCount();
+    ReturnAddressPtr pc = callFrame->returnPC();
 
     ASSERT(argCount != newCodeBlock->m_numParameters);
 
@@ -1858,7 +1859,7 @@
             // Rewind to the previous call frame because op_call already optimistically
             // moved the call frame forward.
             stackFrame.callFrame = oldCallFrame;
-            throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+            throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
             return 0;
         }
 
@@ -1873,7 +1874,7 @@
             // Rewind to the previous call frame because op_call already optimistically
             // moved the call frame forward.
             stackFrame.callFrame = oldCallFrame;
-            throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+            throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
             return 0;
         }
 
@@ -1887,6 +1888,7 @@
     callFrame->setArgumentCount(argCount);
     callFrame->setCallee(callee);
     callFrame->setScopeChain(callee->scope().node());
+    callFrame->setReturnPC(pc.value());
 
     ASSERT((void*)callFrame <= stackFrame.registerFile->end());
     return callFrame;
@@ -1901,6 +1903,7 @@
     ASSERT(!callee->isHostFunction());
     CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeForConstruct();
     int argCount = callFrame->argumentCount();
+    ReturnAddressPtr pc = callFrame->returnPC();
 
     ASSERT(argCount != newCodeBlock->m_numParameters);
 
@@ -1915,7 +1918,7 @@
             // Rewind to the previous call frame because op_call already optimistically
             // moved the call frame forward.
             stackFrame.callFrame = oldCallFrame;
-            throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+            throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
             return 0;
         }
 
@@ -1930,7 +1933,7 @@
             // Rewind to the previous call frame because op_call already optimistically
             // moved the call frame forward.
             stackFrame.callFrame = oldCallFrame;
-            throwStackOverflowError(oldCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
+            throwStackOverflowError(oldCallFrame, stackFrame.globalData, pc, STUB_RETURN_ADDRESS);
             return 0;
         }
 
@@ -1944,6 +1947,7 @@
     callFrame->setArgumentCount(argCount);
     callFrame->setCallee(callee);
     callFrame->setScopeChain(callee->scope().node());
+    callFrame->setReturnPC(pc.value());
 
     ASSERT((void*)callFrame <= stackFrame.registerFile->end());
     return callFrame;
@@ -1956,19 +1960,26 @@
     CallFrame* callFrame = stackFrame.callFrame;
     JSFunction* callee = callFrame->callee();
     ExecutableBase* executable = callee->executable();
-    JITCode& jitCode = executable->generatedJITCodeForCall();
-    
+
+    MacroAssemblerCodePtr codePtr;
     CodeBlock* codeBlock = 0;
-    if (!executable->isHostFunction())
+    if (executable->isHostFunction())
+        codePtr = executable->generatedJITCodeForCall().addressForCall();
+    else {
         codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForCall(stackFrame.callFrame, callee->scope().node());
+        if (callFrame->argumentCount() == codeBlock->m_numParameters)
+            codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForCall().addressForCall();
+        else
+            codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForCallWithArityCheck();
+    }
     CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
 
     if (!callLinkInfo->seenOnce())
         callLinkInfo->setSeen();
     else
-        JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
+        JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
 
-    return jitCode.addressForCall().executableAddress();
+    return codePtr.executableAddress();
 }
 
 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
@@ -1977,19 +1988,26 @@
     CallFrame* callFrame = stackFrame.callFrame;
     JSFunction* callee = callFrame->callee();
     ExecutableBase* executable = callee->executable();
-    JITCode& jitCode = executable->generatedJITCodeForConstruct();
-    
+
+    MacroAssemblerCodePtr codePtr;
     CodeBlock* codeBlock = 0;
-    if (!executable->isHostFunction())
+    if (executable->isHostFunction())
+        codePtr = executable->generatedJITCodeForConstruct().addressForCall();
+    else {
         codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecodeForConstruct(stackFrame.callFrame, callee->scope().node());
+        if (callFrame->argumentCount() == codeBlock->m_numParameters)
+            codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForConstruct().addressForCall();
+        else
+            codePtr = static_cast<FunctionExecutable*>(executable)->generatedJITCodeForConstructWithArityCheck();
+    }
     CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
 
     if (!callLinkInfo->seenOnce())
         callLinkInfo->setSeen();
     else
-        JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
+        JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCount(), stackFrame.globalData);
 
-    return jitCode.addressForCall().executableAddress();
+    return codePtr.executableAddress();
 }
 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
 
diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp
index 8cb3c56..2176e36 100644
--- a/JavaScriptCore/runtime/Executable.cpp
+++ b/JavaScriptCore/runtime/Executable.cpp
@@ -188,7 +188,7 @@
 void FunctionExecutable::generateJITCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
 {
     CodeBlock* codeBlock = &bytecodeForCall(exec, scopeChainNode);
-    m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock);
+    m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForCallWithArityCheck);
 
 #if !ENABLE(OPCODE_SAMPLING)
     if (!BytecodeGenerator::dumpsGeneratedCode())
@@ -199,7 +199,7 @@
 void FunctionExecutable::generateJITCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
 {
     CodeBlock* codeBlock = &bytecodeForConstruct(exec, scopeChainNode);
-    m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock);
+    m_jitCodeForConstruct = JIT::compile(scopeChainNode->globalData, codeBlock, &m_jitCodeForConstructWithArityCheck);
 
 #if !ENABLE(OPCODE_SAMPLING)
     if (!BytecodeGenerator::dumpsGeneratedCode())
diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h
index 146cd00..39ddf49 100644
--- a/JavaScriptCore/runtime/Executable.h
+++ b/JavaScriptCore/runtime/Executable.h
@@ -86,6 +86,8 @@
     protected:
         JITCode m_jitCodeForCall;
         JITCode m_jitCodeForConstruct;
+        MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+        MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
 #endif
     };
 
@@ -110,6 +112,8 @@
         {
             m_jitCodeForCall = callThunk;
             m_jitCodeForConstruct = constructThunk;
+            m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+            m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
         }
 
         NativeFunction m_function;
@@ -407,6 +411,20 @@
             return m_jitCodeForConstruct;
         }
 
+        MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
+        {
+            ASSERT(m_jitCodeForCall);
+            ASSERT(m_jitCodeForCallWithArityCheck);
+            return m_jitCodeForCallWithArityCheck;
+        }
+
+        MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+        {
+            ASSERT(m_jitCodeForConstruct);
+            ASSERT(m_jitCodeForConstructWithArityCheck);
+            return m_jitCodeForConstructWithArityCheck;
+        }
+
     private:
         void generateJITCodeForCall(ExecState*, ScopeChainNode*);
         void generateJITCodeForConstruct(ExecState*, ScopeChainNode*);