Eval handling attempts literal parsing even when the eval
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Aug 2011 17:48:40 +0000 (17:48 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Aug 2011 17:48:40 +0000 (17:48 +0000)
string is in the cache
https://bugs.webkit.org/show_bug.cgi?id=65675

Reviewed by Oliver Hunt.

This is a 25% speed-up on date-format-tofte and a 1.5% speed-up overall
in SunSpider.  It's neutral on V8.

* bytecode/EvalCodeCache.h:
(JSC::EvalCodeCache::tryGet):
(JSC::EvalCodeCache::getSlow):
(JSC::EvalCodeCache::get):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::callEval):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/EvalCodeCache.h
Source/JavaScriptCore/interpreter/Interpreter.cpp

index 90cb275..240a64f 100644 (file)
@@ -1,3 +1,21 @@
+2011-08-04  Filip Pizlo  <fpizlo@apple.com>
+
+        Eval handling attempts literal parsing even when the eval
+        string is in the cache
+        https://bugs.webkit.org/show_bug.cgi?id=65675
+
+        Reviewed by Oliver Hunt.
+        
+        This is a 25% speed-up on date-format-tofte and a 1.5% speed-up overall
+        in SunSpider.  It's neutral on V8.
+
+        * bytecode/EvalCodeCache.h:
+        (JSC::EvalCodeCache::tryGet):
+        (JSC::EvalCodeCache::getSlow):
+        (JSC::EvalCodeCache::get):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::callEval):
+
 2011-08-03  Mark Rowe  <mrowe@apple.com>
 
         Bring some order to FeatureDefines.xcconfig to make it easier to follow.
index 22489b0..fba1d32 100644 (file)
@@ -45,22 +45,32 @@ namespace JSC {
 
     class EvalCodeCache {
     public:
-        EvalExecutable* get(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
+        EvalExecutable* tryGet(bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain)
         {
-            EvalExecutable* evalExecutable = 0;
-
             if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
-                evalExecutable = m_cacheMap.get(evalSource.impl()).get();
-
-            if (!evalExecutable) {
-                evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext);
-                exceptionValue = evalExecutable->compile(exec, scopeChain);
-                if (exceptionValue)
-                    return 0;
+                return m_cacheMap.get(evalSource.impl()).get();
+            return 0;
+        }
+        
+        EvalExecutable* getSlow(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
+        {
+            EvalExecutable* evalExecutable = EvalExecutable::create(exec, makeSource(evalSource), inStrictContext);
+            exceptionValue = evalExecutable->compile(exec, scopeChain);
+            if (exceptionValue)
+                return 0;
+            
+            if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
+                m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->globalData(), owner, evalExecutable));
+            
+            return evalExecutable;
+        }
+        
+        EvalExecutable* get(ExecState* exec, ScriptExecutable* owner, bool inStrictContext, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue)
+        {
+            EvalExecutable* evalExecutable = tryGet(inStrictContext, evalSource, scopeChain);
 
-                if (!inStrictContext && evalSource.length() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries)
-                    m_cacheMap.set(evalSource.impl(), WriteBarrier<EvalExecutable>(exec->globalData(), owner, evalExecutable));
-            }
+            if (!evalExecutable)
+                evalExecutable = getSlow(exec, owner, inStrictContext, evalSource, scopeChain, exceptionValue);
 
             return evalExecutable;
         }
index 3f3e80b..c7b336e 100644 (file)
@@ -437,21 +437,26 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r
         return JSValue();
     
     CodeBlock* codeBlock = callFrame->codeBlock();
-    if (!codeBlock->isStrictMode()) {
-        // FIXME: We can use the preparser in strict mode, we just need additional logic
-        // to prevent duplicates.
-        LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
-        if (JSValue parsedObject = preparser.tryLiteralParse())
-            return parsedObject;
-    }
-
+    
     ScopeChainNode* scopeChain = callFrame->scopeChain();
-    JSValue exceptionValue;
-    EvalExecutable* eval = codeBlock->evalCodeCache().get(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
+    EvalExecutable* eval = codeBlock->evalCodeCache().tryGet(codeBlock->isStrictMode(), programSource, scopeChain);
+
+    if (!eval) {
+        if (!codeBlock->isStrictMode()) {
+            // FIXME: We can use the preparser in strict mode, we just need additional logic
+            // to prevent duplicates.
+            LiteralParser preparser(callFrame, programSource.characters(), programSource.length(), LiteralParser::NonStrictJSON);
+            if (JSValue parsedObject = preparser.tryLiteralParse())
+                return parsedObject;
+        }
 
-    ASSERT(!eval == exceptionValue);
-    if (UNLIKELY(!eval))
-        return throwError(callFrame, exceptionValue);
+        JSValue exceptionValue;
+        eval = codeBlock->evalCodeCache().getSlow(callFrame, codeBlock->ownerExecutable(), codeBlock->isStrictMode(), programSource, scopeChain, exceptionValue);
+        
+        ASSERT(!eval == exceptionValue);
+        if (UNLIKELY(!eval))
+            return throwError(callFrame, exceptionValue);
+    }
 
     JSValue thisValue = callFrame->uncheckedR(codeBlock->thisRegister()).jsValue();
     ASSERT(isValidThisObject(thisValue, callFrame));