Avoid heap allocating the root scope chain node for eval and closure free functions
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Mar 2008 06:36:26 +0000 (06:36 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Mar 2008 06:36:26 +0000 (06:36 +0000)
Reviewed by Maciej

Maciej suggested using an inline ScopeChainNode for functions that don't use eval
or closures as they are unable to ever capture the scope chain.  This gives us a 2.4%
win in sunspider, a 15% win in controlflow-recursive, and big (>5%) wins in a number
of other tests.

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

JavaScriptCore/ChangeLog
JavaScriptCore/kjs/ExecState.cpp
JavaScriptCore/kjs/ExecState.h
JavaScriptCore/kjs/scope_chain.h

index 8e69e1d..e4d6d18 100644 (file)
@@ -1,3 +1,20 @@
+2008-03-19  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Maciej.
+
+        Avoid heap allocating the root scope chain node for eval and closure free functions
+
+        Maciej suggested using an inline ScopeChainNode for functions that don't use eval
+        or closures as they are unable to ever capture the scope chain.  This gives us a 2.4%
+        win in sunspider, a 15% win in controlflow-recursive, and big (>5%) wins in a number 
+        of other tests.
+
+        * kjs/ExecState.cpp:
+        (KJS::ExecState::ExecState):
+        * kjs/ExecState.h:
+        * kjs/scope_chain.h:
+        (KJS::ScopeChain::push):
+
 2008-03-19  Mark Rowe  <mrowe@apple.com>
 
         Reviewed by Sam Weinig.
index 3a7a5e9..07f9206 100644 (file)
@@ -52,6 +52,7 @@ inline ExecState::ExecState(JSGlobalObject* globalObject)
     , m_arguments(0)
     , m_activation(0)
     , m_localStorage(&globalObject->localStorage())
+    , m_inlineScopeChainNode(0, 0)
     , m_variableObject(globalObject)
     , m_thisValue(globalObject)
     , m_iterationDepth(0)
@@ -72,6 +73,7 @@ inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* /*thisObject
     , m_arguments(0)
     , m_activation(0)
     , m_localStorage(&globalObject->localStorage())
+    , m_inlineScopeChainNode(0, 0)
     , m_variableObject(globalObject)
     , m_thisValue(globalObject)
     , m_iterationDepth(0)
@@ -97,6 +99,7 @@ inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisObject,
     , m_activation(0)
     , m_localStorage(callingExec->m_localStorage)
     , m_scopeChain(scopeChain)
+    , m_inlineScopeChainNode(0, 0)
     , m_variableObject(variableObject)
     , m_thisValue(thisObject)
     , m_iterationDepth(0)
@@ -118,6 +121,7 @@ inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisObject,
     , m_function(func)
     , m_arguments(&args)
     , m_scopeChain(func->scope())
+    , m_inlineScopeChainNode(0, 0)
     , m_thisValue(thisObject)
     , m_iterationDepth(0)
     , m_switchDepth(0) 
@@ -129,7 +133,14 @@ inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisObject,
     m_activation = activation;
     m_localStorage = &activation->localStorage();
     m_variableObject = activation;
-    m_scopeChain.push(activation);
+    if (functionBodyNode->usesEval() || functionBodyNode->needsClosure())
+        m_scopeChain.push(activation);
+    else {
+        m_inlineScopeChainNode.object = activation;
+        // The ScopeChain will ref this node itself, so we don't need to worry about
+        // anything trying to delete our scopenode
+        m_scopeChain.push(&m_inlineScopeChainNode);
+    }
 }
 
 inline ExecState::~ExecState()
index 4220a21..d9e94c6 100644 (file)
@@ -188,6 +188,7 @@ namespace KJS  {
         LocalStorage* m_localStorage;
 
         ScopeChain m_scopeChain;
+        ScopeChainNode m_inlineScopeChainNode;
         JSVariableObject* m_variableObject;
         JSObject* m_thisValue;
         
index 43050a4..7fa1e55 100644 (file)
@@ -90,6 +90,7 @@ namespace KJS {
         void clear() { deref(); _node = 0; }
         void push(JSObject *);
         void push(const ScopeChain &);
+        void push(ScopeChainNode*);
         void replaceTop(JSObject*);
         void pop();
         
@@ -140,6 +141,15 @@ inline void ScopeChain::push(JSObject *o)
     _node = new ScopeChainNode(_node, o);
 }
 
+inline void ScopeChain::push(ScopeChainNode *node)
+{
+    ASSERT(node);
+    ASSERT(node->object);
+    node->refCount++;
+    node->next = _node;
+    _node = node;
+}
+
 inline void ScopeChain::replaceTop(JSObject* o)
 {
     ASSERT(o);