2008-07-02 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Jul 2008 00:47:00 +0000 (00:47 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Jul 2008 00:47:00 +0000 (00:47 +0000)
        Reviewed by Oliver Hunt.

        Optimized a[n] get for cases where a is an array or a string, and a[n]
        put for cases where a is an array.

        SunSpider says 9.0% faster.

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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/kjs/JSArray.cpp
JavaScriptCore/kjs/JSArray.h
JavaScriptCore/kjs/JSCell.h
JavaScriptCore/kjs/JSString.h
JavaScriptCore/kjs/JSValue.h

index 8792e39..7f412fb 100644 (file)
@@ -1,3 +1,12 @@
+2008-07-02  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Optimized a[n] get for cases where a is an array or a string, and a[n]
+        put for cases where a is an array.
+        
+        SunSpider says 9.0% faster.
+
 2008-07-02  Kevin McCullough  <kmccullough@apple.com>
 
         Reviewed by Darin.
index a116b86..5fbc049 100644 (file)
@@ -45,6 +45,7 @@
 #include "RegExpObject.h"
 #include "RegExpPrototype.h"
 #include "Register.h"
+#include "collector.h"
 #include "debugger.h"
 #include "operations.h"
 #include <stdio.h>
@@ -475,6 +476,19 @@ Machine::Machine()
     , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold)
 {
     privateExecute(InitializeAndReturn);
+    
+    // Bizarrely, calling fastMalloc here is faster than allocating space on the stack.
+    void* storage = fastMalloc(sizeof(CollectorBlock));
+
+    JSArray* jsArray = new (storage) JSArray(jsNull(), 0);
+    m_jsArrayVptr = jsArray->vptr();
+    jsArray->~JSCell();
+
+    JSString* jsString = new (storage) JSString("");
+    m_jsStringVptr = jsString->vptr();
+    jsString->~JSCell();
+    
+    fastFree(storage);
 }
 
 void Machine::dumpCallFrame(const CodeBlock* codeBlock, ScopeChainNode* scopeChain, RegisterFile* registerFile, const Register* r)
@@ -1834,9 +1848,18 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         unsigned i;
 
         bool isUInt32 = JSImmediate::getUInt32(subscript, i);
-        if (LIKELY(isUInt32))
-            result = baseValue->get(exec, i);
-        else {
+        if (LIKELY(isUInt32)) {
+            if (isJSArray(baseValue)) {
+                JSArray* jsArray = static_cast<JSArray*>(baseValue);
+                if (jsArray->canGetIndex(i))
+                    result = jsArray->getIndex(i);
+                else
+                    result = jsArray->JSArray::get(exec, i);
+            } else if (isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i))
+                result = static_cast<JSString*>(baseValue)->getIndex(exec, i);
+            else
+                result = baseValue->get(exec, i);
+        } else {
             Identifier property(exec, subscript->toString(exec));
             result = baseValue->get(exec, property);
         }
@@ -1867,9 +1890,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         unsigned i;
 
         bool isUInt32 = JSImmediate::getUInt32(subscript, i);
-        if (LIKELY(isUInt32))
-            baseValue->put(exec, i, r[value].u.jsValue);
-        else {
+        if (LIKELY(isUInt32)) {
+            if (isJSArray(baseValue)) {
+                JSArray* jsArray = static_cast<JSArray*>(baseValue);
+                if (jsArray->canSetIndex(i))
+                    jsArray->setIndex(i, r[value].u.jsValue);
+                else
+                    jsArray->JSArray::put(exec, i, r[value].u.jsValue);
+            } else
+                baseValue->put(exec, i, r[value].u.jsValue);
+        } else {
             Identifier property(exec, subscript->toString(exec));
             if (!exec->hadException()) // Don't put to an object if toString threw an exception.
                 baseValue->put(exec, property, r[value].u.jsValue);
index 38c97af..228cf04 100644 (file)
@@ -29,6 +29,8 @@
 #ifndef Machine_h
 #define Machine_h
 
+#include "JSCell.h"
+#include "JSValue.h"
 #include "Opcode.h"
 #include "RegisterFile.h"
 #include <kjs/list.h>
@@ -140,6 +142,9 @@ namespace KJS {
         JSValue* checkTimeout(JSGlobalObject*);
         void resetTimeoutCheck();
 
+        bool isJSArray(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsArrayVptr; }
+        bool isJSString(JSValue* v) { return !JSImmediate::isImmediate(v) && v->asCell()->vptr() == m_jsStringVptr; }
+        
         int m_reentryDepth;
         unsigned m_timeoutTime;
         unsigned m_timeAtLastCheckTimeout;
@@ -148,6 +153,9 @@ namespace KJS {
         unsigned m_ticksUntilNextTimeoutCheck;
 
         RegisterFile m_registerFile;
+        
+        void* m_jsArrayVptr;
+        void* m_jsStringVptr;
 
 #if HAVE(COMPUTED_GOTO)
         Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling
index 492e077..7e27227 100644 (file)
@@ -34,16 +34,6 @@ using namespace std;
 
 namespace KJS {
 
-typedef HashMap<unsigned, JSValue*> SparseArrayValueMap;
-
-struct ArrayStorage {
-    unsigned m_vectorLength;
-    unsigned m_numValuesInVector;
-    SparseArrayValueMap* m_sparseValueMap;
-    void* lazyCreationData; // An JSArray subclass can use this to fill the vector lazily.
-    JSValue* m_vector[1];
-};
-
 // 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer.
 static const unsigned maxArrayIndex = 0xFFFFFFFEU;
 
@@ -81,7 +71,7 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
 
 #endif
 
-JSArray::JSArray(JSObject* prototype, unsigned initialLength)
+JSArray::JSArray(JSValue* prototype, unsigned initialLength)
     : JSObject(prototype)
 {
     unsigned initialCapacity = min(initialLength, sparseArrayCutoff);
index b33bff9..d4c6298 100644 (file)
 
 namespace KJS {
 
-  struct ArrayStorage;
+  typedef HashMap<unsigned, JSValue*> SparseArrayValueMap;
+
+  struct ArrayStorage {
+      unsigned m_vectorLength;
+      unsigned m_numValuesInVector;
+      SparseArrayValueMap* m_sparseValueMap;
+      void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily.
+      JSValue* m_vector[1];
+  };
 
   class JSArray : public JSObject {
   public:
-    JSArray(JSObject* prototype, unsigned initialLength);
+    JSArray(JSValue* prototype, unsigned initialLength);
     JSArray(JSObject* prototype, const ArgList& initialValues);
     virtual ~JSArray();
 
@@ -46,6 +54,20 @@ namespace KJS {
     void sort(ExecState*);
     void sort(ExecState*, JSValue* compareFunction, CallType, const CallData&);
 
+    bool canGetIndex(unsigned i) { return i < m_fastAccessCutoff; }
+    JSValue* getIndex(unsigned i)
+    {
+        ASSERT(canGetIndex(i));
+        return m_storage->m_vector[i];
+    }
+
+    bool canSetIndex(unsigned i) { return i < m_fastAccessCutoff; }
+    JSValue* setIndex(unsigned i, JSValue* v)
+    {
+        ASSERT(canSetIndex(i));
+        return m_storage->m_vector[i] = v;
+    }
+
   protected:
     virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
     virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
index 63e5d4e..1956247 100644 (file)
@@ -36,6 +36,7 @@ class JSCell : public JSValue {
     friend class JSValue;
     friend class JSNumberCell;
     friend class JSString;
+    friend class Machine;
 private:
     JSCell();
     virtual ~JSCell();
@@ -74,6 +75,7 @@ public:
 
     // Garbage collection.
     void* operator new(size_t, ExecState*);
+    void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; }
     virtual void mark();
     bool marked() const;
 
@@ -88,6 +90,7 @@ public:
     virtual UString toThisString(ExecState*) const;
     virtual JSString* toThisJSString(ExecState*);
     virtual JSValue* getJSNumber();
+    void* vptr() { return *reinterpret_cast<void**>(this); }
 
 private:
     // Base implementation, but for non-object classes implements getPropertySlot.
index 4bb174b..72a9502 100644 (file)
@@ -43,6 +43,13 @@ namespace KJS {
     bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
     bool getStringPropertySlot(unsigned propertyName, PropertySlot&);
 
+    bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); }
+    JSValue* getIndex(ExecState* exec, unsigned i)
+    {
+        ASSERT(canGetIndex(i));
+        return new (exec) JSString(m_value.substr(i, 1));
+    }
+
   private:
     virtual JSType type() const { return StringType; }
 
index 71ee27d..ae4d1d2 100644 (file)
@@ -52,6 +52,7 @@ struct Instruction;
 class JSValue : Noncopyable {
     friend class JSCell; // so it can derive from this class
     friend class Heap; // so it can call asCell()
+    friend class Machine; // so it can call asCell()
 private:
     JSValue();
     virtual ~JSValue();