JavaScriptCore:
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Nov 2007 21:27:15 +0000 (21:27 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Nov 2007 21:27:15 +0000 (21:27 +0000)
        Reviewed by Darin Adler.

        http://bugs.webkit.org/show_bug.cgi?id=15835

        Switched List implementation from a custom heap allocator to an inline
        Vector, for a disappointing .5% SunSpider speedup.

        Also renamed List::slice to List::getSlice because "get" is the
        conventional prefix for functions returning a value through an out
        parameter.

        * kjs/array_object.cpp:
        (KJS::ArrayProtoFunc::callAsFunction): Removed some redundant function
        calls and memory accesses.

        * kjs/bool_object.cpp:
        (BooleanObjectImp::construct): Removed questionable use of iterator.

        * kjs/list.cpp:
        * kjs/list.h: New List class, implemented in terms of Vector. Two
        interesting differences:
            1. The inline capacity is 8, not 5. Many of the Lists constructed
            during a SunSpider run are larger than 5; almost none are larger
            than 8.

            2. The growth factor is 4, not 2. Since we can guarantee that Lists
            aren't long-lived, we can grow them more aggressively, to avoid
            excessive copying.

        * kjs/regexp_object.cpp:
        (RegExpObjectImp::construct): Removed redundant function calls.

        * kjs/string_object.cpp:
        (KJS::StringObjectImp::construct): Removed questionable use of iterator.

        * wtf/Vector.h:
        (WTF::::uncheckedAppend): Added a fast, unchecked version of append.

WebCore:

        Reviewed by Darin Adler.

        http://bugs.webkit.org/show_bug.cgi?id=15835

        Small adaptations to new KJS::List class.

        * bindings/js/kjs_window.cpp:
        (KJS::WindowFunc::callAsFunction):
        (KJS::ScheduledAction::ScheduledAction):

WebKit:

        Reviewed by Darin Adler.

        http://bugs.webkit.org/show_bug.cgi?id=15835

        Small adaptations to new KJS::List class.

        * ForwardingHeaders/kjs/value.h: Added.

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

16 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/array_instance.cpp
JavaScriptCore/kjs/array_object.cpp
JavaScriptCore/kjs/bool_object.cpp
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/function_object.cpp
JavaScriptCore/kjs/list.cpp
JavaScriptCore/kjs/list.h
JavaScriptCore/kjs/regexp_object.cpp
JavaScriptCore/kjs/string_object.cpp
JavaScriptCore/wtf/Vector.h
WebCore/ChangeLog
WebCore/bindings/js/kjs_window.cpp
WebKit/ChangeLog
WebKit/ForwardingHeaders/kjs/value.h [new file with mode: 0644]

index 932a651f59acc4390c5e09d95750a937330ff272..998ef3fabd34e40ddd70e37b3261a67e3e87e113 100644 (file)
@@ -1,3 +1,43 @@
+2007-11-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler.
+        
+        http://bugs.webkit.org/show_bug.cgi?id=15835
+
+        Switched List implementation from a custom heap allocator to an inline
+        Vector, for a disappointing .5% SunSpider speedup.
+        
+        Also renamed List::slice to List::getSlice because "get" is the 
+        conventional prefix for functions returning a value through an out 
+        parameter.
+
+        * kjs/array_object.cpp:
+        (KJS::ArrayProtoFunc::callAsFunction): Removed some redundant function
+        calls and memory accesses.
+
+        * kjs/bool_object.cpp:
+        (BooleanObjectImp::construct): Removed questionable use of iterator.
+
+        * kjs/list.cpp:
+        * kjs/list.h: New List class, implemented in terms of Vector. Two 
+        interesting differences:
+            1. The inline capacity is 8, not 5. Many of the Lists constructed 
+            during a SunSpider run are larger than 5; almost none are larger
+            than 8.
+
+            2. The growth factor is 4, not 2. Since we can guarantee that Lists
+            aren't long-lived, we can grow them more aggressively, to avoid
+            excessive copying.
+
+        * kjs/regexp_object.cpp:
+        (RegExpObjectImp::construct): Removed redundant function calls.
+
+        * kjs/string_object.cpp:
+        (KJS::StringObjectImp::construct): Removed questionable use of iterator.
+
+        * wtf/Vector.h:
+        (WTF::::uncheckedAppend): Added a fast, unchecked version of append.
+
 2007-11-05  Mark Rowe  <mrowe@apple.com>
 
         Reviewed by Alp Toker.
index b4e244d51d69be33f7001cd7c5ca9ee454af7aa7..ee66ff9c4bc26e81cf71d06a2bef60e7963f6b0c 100644 (file)
@@ -123,6 +123,7 @@ __ZN3KJS11Interpreter6s_hookE
 __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiPKNS_5UCharEiPNS_7JSValueE
 __ZN3KJS11Interpreter8evaluateERKNS_7UStringEiS3_PNS_7JSValueE
 __ZN3KJS11InterpreterC1EPNS_14JSGlobalObjectE
+__ZN3KJS11InterpreterC1EPNS_14JSGlobalObjectE
 __ZN3KJS11InterpreterC1Ev
 __ZN3KJS11InterpreterC2EPNS_14JSGlobalObjectE
 __ZN3KJS11InterpreterD1Ev
@@ -157,9 +158,8 @@ __ZN3KJS16RuntimeObjectImpC1EPNS_8Bindings8InstanceE
 __ZN3KJS17PropertyNameArray3addERKNS_10IdentifierE
 __ZN3KJS19InternalFunctionImp4infoE
 __ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
-__ZN3KJS4List6appendEPNS_7JSValueE
-__ZN3KJS4List7releaseEv
-__ZN3KJS4ListC1Ev
+__ZN3KJS4List15expandAndAppendEPNS_7JSValueE
+__ZN3KJS4List7markSetEv
 __ZN3KJS6JSCell9getObjectEv
 __ZN3KJS6JSCellnwEm
 __ZN3KJS6JSLock12DropAllLocksC1Ev
@@ -241,10 +241,11 @@ __ZNK3KJS12DateInstance7getTimeERdRi
 __ZNK3KJS13ArrayInstance7getItemEj
 __ZNK3KJS19InternalFunctionImp14implementsCallEv
 __ZNK3KJS19InternalFunctionImp21implementsHasInstanceEv
-__ZNK3KJS4List2atEi
-__ZNK3KJS4List5sliceEiRS0_
+__ZNK3KJS4List8getSliceEiRS0_
+__ZNK3KJS6JSCell17getTruncatedInt32ERi
 __ZNK3KJS6JSCell17getTruncatedInt32ERi
 __ZNK3KJS6JSCell18getTruncatedUInt32ERj
+__ZNK3KJS6JSCell18getTruncatedUInt32ERj
 __ZNK3KJS6JSCell9getNumberERd
 __ZNK3KJS6JSCell9getNumberEv
 __ZNK3KJS6JSCell9getStringERNS_7UStringE
@@ -266,6 +267,7 @@ __ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE
 __ZNK3KJS8JSObject14implementsCallEv
 __ZNK3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERd
+__ZNK3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERd
 __ZNK3KJS8JSObject19implementsConstructEv
 __ZNK3KJS8JSObject21implementsHasInstanceEv
 __ZNK3KJS8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE
index 1d75090de9d6d92d6ab1511a0bc8d76905529bb7..64a249c2204bc815f43b27fffc9cec0deb30d9da 100644 (file)
@@ -93,9 +93,10 @@ ArrayInstance::ArrayInstance(JSObject* prototype, const List& list)
     storage->m_numValuesInVector = length;
     storage->m_sparseValueMap = 0;
 
-    ListIterator it = list.begin();
-    for (unsigned i = 0; i < length; ++i)
-        storage->m_vector[i] = it++;
+    size_t i = 0;
+    List::const_iterator end = list.end();
+    for (List::const_iterator it = list.begin(); it != end; ++it, ++i)
+        storage->m_vector[i] = *it;
 
     m_storage = storage;
 
index 8642acf8abdec8e07ea09c6670ef23398cb818ad..98b8d53c7ca9b3ee30e4884250ff747193847033 100644 (file)
@@ -164,7 +164,8 @@ JSValue* ArrayProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, cons
     int n = 0;
     JSValue *curArg = thisObj;
     JSObject *curObj = static_cast<JSObject *>(thisObj);
-    ListIterator it = args.begin();
+    List::const_iterator it = args.begin();
+    List::const_iterator end = args.end();
     for (;;) {
       if (curArg->isObject() &&
           curObj->inherits(&ArrayInstance::info)) {
@@ -182,10 +183,11 @@ JSValue* ArrayProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, cons
         arr->put(exec, n, curArg);
         n++;
       }
-      if (it == args.end())
+      if (it == end)
         break;
       curArg = *it;
-      curObj = static_cast<JSObject *>(it++); // may be 0
+      curObj = static_cast<JSObject*>(curArg); // may be 0
+      ++it;
     }
     arr->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
 
index b72d3c17a209e13d17b5fae25de84e5b55bf0d23..916fe53ce555198321291424dbda3e83148407d4 100644 (file)
@@ -105,7 +105,7 @@ JSObject *BooleanObjectImp::construct(ExecState *exec, const List &args)
 
   bool b;
   if (args.size() > 0)
-    b = args.begin()->toBoolean(exec);
+    b = args[0]->toBoolean(exec);
   else
     b = false;
 
index 435bd1ca9b19ea75073fd4122f061dfe7f813ac2..569ca18024467450c56b12a3504397b435abfef8 100644 (file)
@@ -273,8 +273,8 @@ IndexToNameMap::IndexToNameMap(FunctionImp* func, const List& args)
   this->size = args.size();
   
   int i = 0;
-  ListIterator iterator = args.begin(); 
-  for (; iterator != args.end(); i++, iterator++)
+  List::const_iterator end = args.end();
+  for (List::const_iterator it = args.begin(); it != end; ++i, ++it)
     _map[i] = func->getParameterName(i); // null if there is no corresponding parameter
 }
 
@@ -338,10 +338,10 @@ indexToNameMap(func, args)
   putDirect(exec->propertyNames().length, args.size(), DontEnum);
   
   int i = 0;
-  ListIterator iterator = args.begin(); 
-  for (; iterator != args.end(); i++, iterator++) {
+  List::const_iterator end = args.end();
+  for (List::const_iterator it = args.begin(); it != end; ++it, ++i) {
     if (!indexToNameMap.isMapped(Identifier::from(i))) {
-      JSObject::put(exec, Identifier::from(i), *iterator, DontEnum);
+      JSObject::put(exec, Identifier::from(i), *it, DontEnum);
     }
   }
 }
index 7ea33a4d4dd1f56ae21fe014bb3dd4418b6d9efe..922db9b91716bd40fa52bf5ffa31112969440b46 100644 (file)
@@ -138,7 +138,7 @@ JSValue* FunctionProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, c
       callThis = thisArg->toObject(exec);
 
     List argsTail;
-    args.slice(1, argsTail);
+    args.getSlice(1, argsTail);
     result = func->call(exec, callThis, argsTail);
     }
     break;
index 9e4990a92e9bd2c946ea5c73ced88d7e8b17e695..34adf282f6f6b51b69fc45313e990064250b484f 100644 (file)
 #include "config.h"
 #include "list.h"
 
-#include "internal.h"
-#include <algorithm>
-
-#define DUMP_STATISTICS 0
-
-using std::min;
-
 namespace KJS {
 
-// tunable parameters
-const int poolSize = 512;
-const int inlineValuesSize = 5;
-
-enum ListImpState { unusedInPool = 0, usedInPool, usedOnHeap, immortal };
-
-struct ListImp : ListImpBase
-{
-    ListImpState state;
-    int capacity;
-    JSValue** overflow;
-
-    union {
-        JSValue *values[inlineValuesSize];
-        ListImp *nextInFreeList;
-    };
-
-#if DUMP_STATISTICS
-    int sizeHighWaterMark;
-#endif
-
-    void markValues();
-};
-
-struct HeapListImp : ListImp
-{
-    HeapListImp *nextInHeapList;
-    HeapListImp *prevInHeapList;
-};
-
-static ListImp pool[poolSize];
-static ListImp *poolFreeList;
-static HeapListImp *heapList;
-static int poolUsed;
-
-#if DUMP_STATISTICS
-
-static int numLists;
-static int numListsHighWaterMark;
-
-static int listSizeHighWaterMark;
-
-static int numListsDestroyed;
-static int numListsBiggerThan[17];
-
-struct ListStatisticsExitLogger { ~ListStatisticsExitLogger(); };
-
-static ListStatisticsExitLogger logger;
-
-ListStatisticsExitLogger::~ListStatisticsExitLogger()
+void List::getSlice(int startIndex, List& result) const
 {
-    printf("\nKJS::List statistics:\n\n");
-    printf("%d lists were allocated\n", numLists);
-    printf("%d lists was the high water mark\n", numListsHighWaterMark);
-    printf("largest list had %d elements\n", listSizeHighWaterMark);
-    if (numListsDestroyed) {
-        putc('\n', stdout);
-        for (int i = 0; i < 17; i++) {
-            printf("%.1f%% of the lists (%d) had more than %d element%s\n",
-                100.0 * numListsBiggerThan[i] / numListsDestroyed,
-                numListsBiggerThan[i],
-                i, i == 1 ? "" : "s");
-        }
-        putc('\n', stdout);
-    }
+    const_iterator start = min(begin() + startIndex, end());
+    result.m_vector.appendRange(start, end());
 }
 
-#endif
-
-inline void ListImp::markValues()
-{
-    int inlineSize = min(size, inlineValuesSize);
-    for (int i = 0; i != inlineSize; ++i) {
-        if (!values[i]->marked()) {
-            values[i]->mark();
-        }
-    }
-
-    int overflowSize = size - inlineSize;
-    for (int i = 0; i != overflowSize; ++i) {
-        if (!overflow[i]->marked()) {
-            overflow[i]->mark();
-        }
-    }
-}
-
-void List::markProtectedLists()
-{
-    int seen = 0;
-    int used = poolUsed;
-
-    for (int i = 0; i < poolSize && seen < used; i++) {
-        if (pool[i].state == usedInPool) {
-            seen++;
-            if (pool[i].valueRefCount > 0) {
-                pool[i].markValues();
-            }
-        }
-    }
-
-    for (HeapListImp *l = heapList; l; l = l->nextInHeapList) {
-        if (l->valueRefCount > 0) {
-            l->markValues();
-        }
-    }
-}
-
-
-static inline ListImp *allocateListImp()
+const List& List::empty()
 {
-    ASSERT(JSLock::lockCount() > 0);
-    
-    // Find a free one in the pool.
-    if (poolUsed < poolSize) {
-        ListImp *imp = poolFreeList ? poolFreeList : &pool[0];
-        poolFreeList = imp->nextInFreeList ? imp->nextInFreeList : imp + 1;
-        imp->state = usedInPool;
-        poolUsed++;
-        return imp;
-    }
-    
-    HeapListImp *imp = new HeapListImp;
-    imp->state = usedOnHeap;
-    // link into heap list
-    if (heapList) {
-        heapList->prevInHeapList = imp;
-    }
-    imp->nextInHeapList = heapList;
-    imp->prevInHeapList = NULL;
-    heapList = imp;
-
-    return imp;
+    static const List staticList;
+    return staticList;
 }
 
-List::List() : _impBase(allocateListImp())
+List::ListSet& List::markSet()
 {
-    ListImp *imp = static_cast<ListImp *>(_impBase);
-    imp->size = 0;
-    imp->refCount = 1;
-    imp->valueRefCount = 1;
-    imp->capacity = 0;
-    imp->overflow = 0;
-
-#if DUMP_STATISTICS
-    if (++numLists > numListsHighWaterMark)
-        numListsHighWaterMark = numLists;
-    imp->sizeHighWaterMark = 0;
-#endif
+    static ListSet staticMarkSet;
+    return staticMarkSet;
 }
 
-void List::markValues()
+void List::markProtectedListsSlowCase()
 {
-    static_cast<ListImp *>(_impBase)->markValues();
-}
-
-void List::release()
-{   
-    ASSERT(JSLock::lockCount() > 0);
-    
-    ListImp *imp = static_cast<ListImp *>(_impBase);
-    
-#if DUMP_STATISTICS
-    --numLists;
-    ++numListsDestroyed;
-    for (int i = 0; i < 17; i++)
-        if (imp->sizeHighWaterMark > i)
-            ++numListsBiggerThan[i];
-#endif
-
-    delete [] imp->overflow;
-    imp->overflow = 0;
-
-    if (imp->state == usedInPool) {
-        imp->state = unusedInPool;
-        imp->nextInFreeList = poolFreeList;
-        poolFreeList = imp;
-        poolUsed--;
-    } else {
-        ASSERT(imp->state == usedOnHeap);
-        HeapListImp *list = static_cast<HeapListImp *>(imp);
-
-        // unlink from heap list
-        if (!list->prevInHeapList) {
-            heapList = list->nextInHeapList;
-            if (heapList) {
-                heapList->prevInHeapList = NULL;
-            }
-        } else {
-            list->prevInHeapList->nextInHeapList = list->nextInHeapList;
-            if (list->nextInHeapList) {
-                list->nextInHeapList->prevInHeapList = list->prevInHeapList;
-            }
+    ListSet::iterator end = markSet().end();
+    for (ListSet::iterator it = markSet().begin(); it != end; ++it) {
+        List* list = *it;
+
+        iterator end2 = list->end();
+        for (iterator it2 = list->begin(); it2 != end2; ++it2) {
+            JSValue* v = *it2;
+            if (!v->marked())
+                v->mark();
         }
-
-        delete list;
     }
 }
 
-JSValue *List::at(int i) const
+void List::expandAndAppend(JSValue* v)
 {
-    ListImp *imp = static_cast<ListImp *>(_impBase);
-    if ((unsigned)i >= (unsigned)imp->size)
-        return jsUndefined();
-    if (i < inlineValuesSize)
-        return imp->values[i];
-    return imp->overflow[i - inlineValuesSize];
-}
-
-void List::clear()
-{
-    _impBase->size = 0;
-}
-
-void List::append(JSValue *v)
-{
-    ASSERT(JSLock::lockCount() > 0);
+    ASSERT(m_vector.size() == m_vector.capacity());
     
-    ListImp *imp = static_cast<ListImp *>(_impBase);
-
-    int i = imp->size++;
-
-#if DUMP_STATISTICS
-    if (imp->size > listSizeHighWaterMark)
-        listSizeHighWaterMark = imp->size;
-#endif
-
-    if (i < inlineValuesSize) {
-        imp->values[i] = v;
-        return;
-    }
+    // 4x growth would be excessive for a normal vector, but it's OK for Lists 
+    // because they're short-lived.
+    m_vector.reserveCapacity(m_vector.capacity() * 4);
     
-    if (i >= imp->capacity) {
-        int newCapacity = i * 2;
-        JSValue** newOverflow = new JSValue* [newCapacity - inlineValuesSize];
-        JSValue** oldOverflow = imp->overflow;
-        int oldOverflowSize = i - inlineValuesSize;
-        for (int j = 0; j != oldOverflowSize; j++)
-            newOverflow[j] = oldOverflow[j];
-        delete [] oldOverflow;
-        imp->overflow = newOverflow;
-        imp->capacity = newCapacity;
+    // As long as our size stays within our Vector's inline 
+    // capacity, all our values are allocated on the stack, and 
+    // therefore don't need explicit marking. Once our size exceeds
+    // our Vector's inline capacity, though, our values move to the 
+    // heap, where they do need explicit marking.
+    if (!m_isInMarkSet) {
+        markSet().add(this);
+        m_isInMarkSet = true;
     }
-    
-    imp->overflow[i - inlineValuesSize] = v;
-}
-
-void List::slice(int startIndex, List& result) const
-{
-    ListImp *imp = static_cast<ListImp *>(_impBase);
-
-    int size = imp->size;
-
-    int inlineSize = min(size, inlineValuesSize);
-    for (int i = startIndex; i < inlineSize; ++i)
-        result.append(imp->values[i]);
 
-    JSValue** overflow = imp->overflow;
-    int overflowSize = size - inlineSize;
-    for (int i = 0; i < overflowSize; ++i)
-        result.append(overflow[i]);
-}
-
-const List& List::empty()
-{
-    static List* staticEmptyList = new List;
-    return *staticEmptyList;
+    m_vector.uncheckedAppend(v);
 }
 
 } // namespace KJS
index fd7fa6bd3426c48ccce7bbc8a38c483e2c645781..a0701a6bea6fcab7c4a1daed666bac03669a7a0b 100644 (file)
@@ -1,7 +1,6 @@
 /*
- *  This file is part of the KDE libraries
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003 Apple Computer, Inc.
+ *  Copyright (C) 2003, 2007 Apple Computer, Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #ifndef KJS_LIST_H
 #define KJS_LIST_H
 
-#include "value.h"
+#include <kjs/value.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
 
 namespace KJS {
 
-    struct ListImpBase {
-        int size;
-        int refCount;
-        int valueRefCount; // FIXME: Get rid of this.
-    };
+    class JSValue;
+    class List;
     
-    class ListIterator;
-
-    /**
-     * @short Native list type.
-     *
-     * List is a native ECMAScript type. List values are only used for
-     * intermediate results of expression evaluation and cannot be stored
-     * as properties of objects.
-     */
     class List : Noncopyable {
-    public:
-        List();
-        ~List() { deref(); }
-
-        /**
-         * Append an object to the end of the list.
-         *
-         * @param val Pointer to object.
-         */
-        void append(JSValue *val);
-        /**
-         * Remove all elements from the list.
-         */
-        void clear();
-
-        void reset() { deref(); ++(_impBase = empty()._impBase)->refCount; }
-
-        /**
-         * Make a copy of the list, starting from startIndex.
-         */
-        void slice(int startIndex, List& result) const;
-        /**
-         * @return true if the list is empty. false otherwise.
-         */
-        bool isEmpty() const { return _impBase->size == 0; }
-        /**
-         * @return the current size of the list.
-         */
-        int size() const { return _impBase->size; }
-        /**
-         * @return A KJS::ListIterator pointing to the first element.
-         */
-        ListIterator begin() const;
-        /**
-         * @return A KJS::ListIterator pointing to the last element.
-         */
-        ListIterator end() const;
-        
-        /**
-         * Retrieve an element at an indexed position. If you want to iterate
-         * trough the whole list using KJS::ListIterator will be faster.
-         *
-         * @param i List index.
-         * @return Return the element at position i. KJS::Undefined if the
-         * index is out of range.
-         */
-        JSValue *at(int i) const;
-        /**
-         * Equivalent to at.
-         */
-        JSValue *operator[](int i) const { return at(i); }
-    
-        /**
-         * Returns a pointer to a static instance of an empty list. Useful if a
-         * function has a KJS::List parameter.
-         */
-        static const List &empty();
-        
-        static void markProtectedLists();
     private:
-        ListImpBase *_impBase;
-        
-        void deref() { --_impBase->valueRefCount; if (--_impBase->refCount == 0) release(); }
+        typedef Vector<JSValue*, 8> VectorType;
+        typedef HashSet<List*> ListSet;
 
-        void release();
-        void markValues();
-    };
-  
-    /**
-     * @short Iterator for KJS::List objects.
-     */
-    class ListIterator {
     public:
-        /**
-         * Construct an iterator that points to the first element of the list.
-         * @param l The list the iterator will operate on.
-         */
-        ListIterator(const List &l) : _list(&l), _i(0) { }
-        ListIterator(const List &l, int index) : _list(&l), _i(index) { }
-        /**
-         * Dereference the iterator.
-         * @return A pointer to the element the iterator operates on.
-         */
-        JSValue *operator->() const { return _list->at(_i); }
-        JSValue *operator*() const { return _list->at(_i); }
-        /**
-         * Prefix increment operator.
-         * @return The element after the increment.
-         */
-        JSValue *operator++() { return _list->at(++_i); }
-        /**
-         * Postfix increment operator.
-         */
-        JSValue *operator++(int) { return _list->at(_i++); }
-        /**
-         * Prefix decrement operator.
-         */
-        JSValue *operator--() { return _list->at(--_i); }
-        /**
-         * Postfix decrement operator.
-         */
-        JSValue *operator--(int) { return _list->at(_i--); }
-        /**
-         * Compare the iterator with another one.
-         * @return True if the two iterators operate on the same list element.
-         * False otherwise.
-         */
-        bool operator==(const ListIterator &it) const { return _i == it._i; }
-        /**
-         * Check for inequality with another iterator.
-         * @return True if the two iterators operate on different list elements.
-         */
-        bool operator!=(const ListIterator &it) const { return _i != it._i; }
+        typedef VectorType::iterator iterator;
+        typedef VectorType::const_iterator const_iterator;
+
+        List()
+            : m_isInMarkSet(false)
+        {
+        }
+
+        ~List()
+        {
+            if (m_isInMarkSet)
+                markSet().remove(this);
+        }
+
+        int size() const { return m_vector.size(); }
+        bool isEmpty() const { return m_vector.isEmpty(); }
+
+        JSValue* at(size_t i) const
+        {
+            if (i < m_vector.size())
+                return m_vector.at(i);
+            return jsUndefined();
+        }
+
+        JSValue* operator[](int i) const { return at(i); }
+
+        void clear() { m_vector.clear(); }
+
+        void append(JSValue* v)
+        {
+            if (m_vector.size() < m_vector.capacity())
+                m_vector.uncheckedAppend(v);
+            else
+                // Putting the slow "expand and append" case all in one 
+                // function measurably improves the performance of the fast 
+                // "just append" case.
+                expandAndAppend(v);
+        }
+
+        void getSlice(int startIndex, List& result) const;
+
+        iterator begin() { return m_vector.begin(); }
+        iterator end() { return m_vector.end(); }
+
+        const_iterator begin() const { return m_vector.begin(); }
+        const_iterator end() const { return m_vector.end(); }
+
+        static void markProtectedLists()
+        {
+            if (!markSet().size())
+                return;
+            markProtectedListsSlowCase();
+        }
+
+        static const List& empty(); // Fast path for an empty list.
 
     private:
-        const List *_list;
-        int _i;
-    };
+        static ListSet& markSet();
+        static void markProtectedListsSlowCase();
+
+        void expandAndAppend(JSValue*);
 
-    inline ListIterator List::begin() const { return ListIterator(*this); }
-    inline ListIterator List::end() const { return ListIterator(*this, size()); }
+        VectorType m_vector;
+        bool m_isInMarkSet;
+
+    private:
+        // Prohibits new / delete, which would break GC.
+        void* operator new(size_t);
+        void operator delete(void*);
+
+        void* operator new[](size_t);
+        void operator delete[](void*);
+
+        void* operator new(size_t, void*);
+        void operator delete(void*, size_t);
+    };
+    
 } // namespace KJS
 
 #endif // KJS_LIST_H
index 8ab9bbdbbac324a38ddb29edbd6eec95318c1d6f..fbb1cc91e33aa96de3defb12f03795266354160e 100644 (file)
@@ -416,15 +416,18 @@ bool RegExpObjectImp::implementsConstruct() const
 // ECMA 15.10.4
 JSObject *RegExpObjectImp::construct(ExecState *exec, const List &args)
 {
-  JSObject *o = args[0]->getObject();
+  JSValue* arg0 = args[0];
+  JSValue* arg1 = args[1];
+  
+  JSObject* o = arg0->getObject();
   if (o && o->inherits(&RegExpImp::info)) {
-    if (!args[1]->isUndefined())
+    if (!arg1->isUndefined())
       return throwError(exec, TypeError);
     return o;
   }
   
-  UString p = args[0]->isUndefined() ? UString("") : args[0]->toString(exec);
-  UString flags = args[1]->isUndefined() ? UString("") : args[1]->toString(exec);
+  UString p = arg0->isUndefined() ? UString("") : arg0->toString(exec);
+  UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
 
   RegExpPrototype* proto = static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype());
 
index 91d6e7cef83eb74f93bb765bab08f18995b86f7a..39dd76161b67ac509bb1de2854c807b8f62a99d7 100644 (file)
@@ -480,9 +480,9 @@ JSValue* StringProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, con
       result = jsNaN();
     break;
   case Concat: {
-    ListIterator it = args.begin();
-    for ( ; it != args.end() ; ++it) {
-        s += it->toString(exec);
+    List::const_iterator end = args.end();
+    for (List::const_iterator it = args.begin(); it != end; ++it) {
+        s += (*it)->toString(exec);
     }
     result = jsString(s);
     break;
@@ -808,7 +808,7 @@ JSObject *StringObjectImp::construct(ExecState *exec, const List &args)
   JSObject *proto = exec->lexicalInterpreter()->builtinStringPrototype();
   if (args.size() == 0)
     return new StringInstance(proto);
-  return new StringInstance(proto, args.begin()->toString(exec));
+  return new StringInstance(proto, args[0]->toString(exec));
 }
 
 // ECMA 15.5.1
@@ -837,11 +837,10 @@ JSValue *StringObjectFuncImp::callAsFunction(ExecState *exec, JSObject* /*thisOb
   if (args.size()) {
     UChar *buf = static_cast<UChar *>(fastMalloc(args.size() * sizeof(UChar)));
     UChar *p = buf;
-    ListIterator it = args.begin();
-    while (it != args.end()) {
-      unsigned short u = static_cast<unsigned short>(it->toUInt32(exec));
+    List::const_iterator end = args.end();
+    for (List::const_iterator it = args.begin(); it != end; ++it) {
+      unsigned short u = static_cast<unsigned short>((*it)->toUInt32(exec));
       *p++ = UChar(u);
-      it++;
     }
     s = UString(buf, args.size(), false);
   } else
index 0d571420c075ceca462b75b85720c6bf78e31e3e..f9b920b9f3f60f23586615250043dd8959f15079 100644 (file)
@@ -456,6 +456,7 @@ namespace WTF {
 
         template<typename U> void append(const U*, size_t);
         template<typename U> void append(const U&);
+        template<typename U> void uncheckedAppend(const U& val);
         template<typename U, size_t c> void append(const Vector<U, c>&);
 
         template<typename U> void insert(size_t position, const U*, size_t);
@@ -669,6 +670,18 @@ namespace WTF {
         ++m_size;
     }
 
+    // This version of append saves a branch in the case where you know that the
+    // vector's capacity is large enough for the append to succeed.
+
+    template<typename T, size_t inlineCapacity> template<typename U>
+    inline void Vector<T, inlineCapacity>::uncheckedAppend(const U& val)
+    {
+        ASSERT(size() < capacity());
+        const U* ptr = &val;
+        new (end()) T(*ptr);
+        ++m_size;
+    }
+
     template<typename T, size_t inlineCapacity> template<typename U, size_t c>
     inline void Vector<T, inlineCapacity>::append(const Vector<U, c>& val)
     {
index f44b975194cc7fef1a1fda8806cfd6719adc0238..ad7d2e86ddc942ae12875b8210a70740dcef2039 100644 (file)
@@ -1,3 +1,15 @@
+2007-11-04  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler.
+        
+        http://bugs.webkit.org/show_bug.cgi?id=15835
+
+        Small adaptations to new KJS::List class.
+
+        * bindings/js/kjs_window.cpp:
+        (KJS::WindowFunc::callAsFunction):
+        (KJS::ScheduledAction::ScheduledAction):
+
 2007-11-05  Adam Roben  <aroben@apple.com>
 
         Allow passing a base class pointer to COMPtr::copyRefTo
index bdcd39297cc49aafc6fb6a017eb88e6a07b75475..519a829c4a88f7878ad4685f0223a96287a01ee3 100644 (file)
@@ -1390,7 +1390,7 @@ JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const Li
       int i = args[1]->toInt32(exec);
       
       List argsTail;
-      args.slice(2, argsTail);
+      args.getSlice(2, argsTail);
 
       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, true /*single shot*/);
       return jsNumber(r);
@@ -1410,7 +1410,7 @@ JSValue *WindowFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const Li
       int i = args[1]->toInt32(exec);
 
       List argsTail;
-      args.slice(2, argsTail);
+      args.getSlice(2, argsTail);
 
       int r = (const_cast<Window*>(window))->installTimeout(func, argsTail, i, false);
       return jsNumber(r);
@@ -1559,9 +1559,8 @@ int Window::installTimeout(ScheduledAction* a, int t, bool singleShot)
 ScheduledAction::ScheduledAction(JSValue* func, const List& args)
     : m_func(func)
 {
-    ListIterator it = args.begin();
-    ListIterator end = args.end();
-    while (it != end)
+    List::const_iterator end = args.end();
+    for (List::const_iterator it = args.begin(); it != end; ++it)
         m_args.append(*it);
 }
 
index e8f2c9d95e1a6d248f88a14116dd95673735b05a..f2afcab716af312eff6417c462731048807d56c9 100644 (file)
@@ -1,3 +1,13 @@
+2007-11-05  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler.
+        
+        http://bugs.webkit.org/show_bug.cgi?id=15835
+
+        Small adaptations to new KJS::List class.
+
+        * ForwardingHeaders/kjs/value.h: Added.
+
 2007-11-03  David D. Kilzer  <ddkilzer@webkit.org>
 
         Sort files(...); sections of Xcode project files.
diff --git a/WebKit/ForwardingHeaders/kjs/value.h b/WebKit/ForwardingHeaders/kjs/value.h
new file mode 100644 (file)
index 0000000..cf0b9c8
--- /dev/null
@@ -0,0 +1 @@
+#import <JavaScriptCore/value.h>