Bug 25202: Improve performance of repeated callbacks into the VM

Reviewed by Cameron Zwarich

Add the concept of a CachedCall to native code for use in Array
prototype and similar functions where a single callback function
is called repeatedly with the same number of arguments.

Used Array.prototype.filter as the test function and got a 50% win
over a naive non-caching specialised version.  This makes the native
implementation of Array.prototype.filter faster than the JS one once
more.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@42537 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JavaScriptCore/interpreter/Interpreter.h b/JavaScriptCore/interpreter/Interpreter.h
index dc3e617..b651b31 100644
--- a/JavaScriptCore/interpreter/Interpreter.h
+++ b/JavaScriptCore/interpreter/Interpreter.h
@@ -67,7 +67,7 @@
     class Interpreter {
         friend class JIT;
         friend class JITStubs;
-
+        friend class CachedCall;
     public:
         Interpreter();
 
@@ -109,6 +109,36 @@
 
     private:
         enum ExecutionFlag { Normal, InitializeAndReturn };
+        
+        struct CallFrameClosure {
+            CallFrame* oldCallFrame;
+            CallFrame* newCallFrame;
+            JSFunction* function;
+            CodeBlock* codeBlock;
+            JSGlobalData* globalData;
+            Register* oldEnd;
+            ScopeChainNode* scopeChain;
+            int expectedParams;
+            int providedParams;
+
+            void setArgument(int arg, JSValuePtr value)
+            {
+                if (arg < expectedParams)
+                    newCallFrame[arg - RegisterFile::CallFrameHeaderSize - expectedParams] = value;
+                else
+                    newCallFrame[arg - RegisterFile::CallFrameHeaderSize - expectedParams - providedParams] = value;
+            }
+            void resetCallFrame()
+            {
+                newCallFrame->setScopeChain(scopeChain);
+                newCallFrame->setCalleeArguments(0);
+                for (int i = providedParams; i < expectedParams; ++i)
+                    newCallFrame[i - RegisterFile::CallFrameHeaderSize - expectedParams] = jsUndefined();
+            }
+        };
+        CallFrameClosure prepareForRepeatCall(FunctionBodyNode*, CallFrame*, JSFunction*, int argCount, ScopeChainNode*, JSValuePtr* exception);
+        void endRepeatCall(CallFrameClosure&);
+        JSValuePtr execute(CallFrameClosure&, JSValuePtr* exception);
 
         NEVER_INLINE JSValuePtr callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset, JSValuePtr& exceptionValue);
         JSValuePtr execute(EvalNode*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*, JSValuePtr* exception);
@@ -153,7 +183,7 @@
         HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling
 #endif
     };
-
+    
 } // namespace JSC
 
 #endif // Interpreter_h