JavaScriptCore:
- replaced List class with a vector rather than a linked list, changed it to use a pool of instances instead of all the nodes allocated off of the heap; gives 10% gain on iBench * kjs/list.h: Complete rewrite. * kjs/list.cpp: Ditto. * kjs/array_object.cpp: (compareWithCompareFunctionForQSort): Go back to doing a clear and two appends here. Fast with the new list implementation. * kjs/collector.h: Remove _COLLECTOR hack and just make rootObjectClasses return a const void *. * kjs/collector.cpp: Remove _COLLECTOR hack, and various other minor tweaks. WebCore: * khtml/ecma/kjs_window.cpp: Remove _COLLECTOR hack. * kwq/WebCoreJavaScript.h: * kwq/WebCoreJavaScript.mm: (+[WebCoreJavaScript rootObjectClasses]): Update for name change -- root object classes, not all live object classes. * force-js-clean-timestamp: Make sure we don't have more build problems. WebKit: * Misc.subproj/WebCoreStatistics.h: * Misc.subproj/WebCoreStatistics.m: (+[WebCoreStatistics javaScriptRootObjectClasses]): Update for name change -- root object classes, not all live object classes. WebBrowser: * Debug/CacheController.m: (-[CacheController refreshJavaScriptStatisticsMatrix]): Update for name change -- root object classes, not all live object classes. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@2843 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Showing
// -*- c-basic-offset: 2 -*- | ||
/* | ||
* This file is part of the KDE libraries | ||
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | ||
* Copyright (C) 2001 Peter Kelly (pmk@post.com) | ||
* Copyright (C) 2002 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 | ||
... | ... | @@ -21,23 +19,38 @@ |
* | ||
*/ | ||
#include "value.h" | ||
#include "object.h" | ||
#include "types.h" | ||
#include "interpreter.h" | ||
#include <assert.h> | ||
#include <math.h> | ||
#include <stdio.h> | ||
#include "list.h" | ||
#include "internal.h" | ||
#include "collector.h" | ||
#include "operations.h" | ||
#include "error_object.h" | ||
#include "nodes.h" | ||
#define DUMP_STATISTICS 0 | ||
namespace KJS { | ||
// tunable parameters | ||
const int poolSize = 16; // must be a power of 2 | ||
const int inlineValuesSize = 4; | ||
// derived constants | ||
const int poolSizeMask = poolSize - 1; | ||
enum ListImpState { unusedInPool = 0, usedInPool, usedOnHeap, immortal }; | ||
struct ListImp : ListImpBase | ||
{ | ||
ListImpState state; | ||
ValueImp *values[inlineValuesSize]; | ||
int capacity; | ||
ValueImp **overflow; | ||
#if DUMP_STATISTICS | ||
int sizeHighWaterMark; | ||
#endif | ||
}; | ||
static ListImp pool[poolSize]; | ||
static int poolCursor; | ||
#if DUMP_STATISTICS | ||
static int numLists; | ||
... | ... | @@ -48,9 +61,6 @@ static int listSizeHighWaterMark; |
static int numListsDestroyed; | ||
static int numListsBiggerThan[17]; | ||
static int numNodesAllocated; | ||
static int numNodesWouldNeedToBeCopied; | ||
struct ListStatisticsExitLogger { ~ListStatisticsExitLogger(); }; | ||
static ListStatisticsExitLogger logger; | ||
... | ... | @@ -60,371 +70,171 @@ ListStatisticsExitLogger::~ListStatisticsExitLogger() |
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\n", listSizeHighWaterMark); | ||
printf("%d nodes were allocated\n", numNodesAllocated); | ||
printf("%d node copies would have been necessary if lists didn't share\n\n", numNodesWouldNeedToBeCopied); | ||
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"); | ||
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); | ||
} | ||
} | ||
#endif | ||
namespace KJS { | ||
struct ListNode { | ||
ListNode(const Value &val, ListNode *p, ListNode *n) | ||
: member(val.imp()), prev(p), next(n) { } | ||
ListNode(ValueImp *val, ListNode *p, ListNode *n) | ||
: member(val), prev(p), next(n) { } | ||
ValueImp *member; | ||
ListNode *prev, *next; | ||
}; | ||
struct ListHookNode : public ListNode { | ||
ListHookNode() : ListNode(0, this, this), listRefCount(1), nodesRefCount(1) | ||
#if DUMP_STATISTICS | ||
, sizeHighWaterMark(0) | ||
#endif | ||
{ } | ||
static inline ListImp *allocateListImp() | ||
{ | ||
// Find a free one in the pool. | ||
int c = poolCursor; | ||
int i = c; | ||
do { | ||
ListImp *imp = &pool[i]; | ||
ListImpState s = imp->state; | ||
i = (i + 1) & poolSizeMask; | ||
if (s == unusedInPool) { | ||
poolCursor = i; | ||
imp->state = usedInPool; | ||
return imp; | ||
} | ||
} while (i != c); | ||
int listRefCount; | ||
int nodesRefCount; | ||
#if DUMP_STATISTICS | ||
int sizeHighWaterMark; | ||
#endif | ||
}; | ||
// ------------------------------ ListIterator --------------------------------- | ||
ValueImp* ListIterator::operator->() const | ||
{ | ||
return node->member; | ||
} | ||
Value ListIterator::operator*() const | ||
{ | ||
return Value(node->member); | ||
ListImp *imp = new ListImp; | ||
imp->state = usedOnHeap; | ||
return imp; | ||
} | ||
Value ListIterator::operator++() | ||
static inline void deallocateListImp(ListImp *imp) | ||
{ | ||
node = node->next; | ||
return Value(node->member); | ||
if (imp->state == usedInPool) | ||
imp->state = unusedInPool; | ||
else | ||
delete imp; | ||
} | ||
Value ListIterator::operator++(int) | ||
List::List() : _impBase(allocateListImp()) | ||
{ | ||
const ListNode *n = node; | ||
++*this; | ||
return Value(n->member); | ||
} | ||
Value ListIterator::operator--() | ||
{ | ||
node = node->prev; | ||
return Value(node->member); | ||
} | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
imp->size = 0; | ||
imp->refCount = 1; | ||
imp->capacity = 0; | ||
imp->overflow = 0; | ||
Value ListIterator::operator--(int) | ||
{ | ||
const ListNode *n = node; | ||
--*this; | ||
return Value(n->member); | ||
} | ||
// ------------------------------ List ----------------------------------------- | ||
List::List() : hook(new ListHookNode) | ||
{ | ||
#if DUMP_STATISTICS | ||
if (++numLists > numListsHighWaterMark) | ||
numListsHighWaterMark = numLists; | ||
#endif | ||
} | ||
List::List(const List& l) : hook(l.hook) | ||
{ | ||
#if DUMP_STATISTICS | ||
if (++numLists > numListsHighWaterMark) | ||
numListsHighWaterMark = numLists; | ||
numNodesWouldNeedToBeCopied += size(); | ||
if (++numLists > numListsHighWaterMark) | ||
numListsHighWaterMark = numLists; | ||
imp->sizeHighWaterMark = 0; | ||
#endif | ||
++hook->listRefCount; | ||
if (hook->nodesRefCount++ == 0) | ||
refAll(); | ||
} | ||
List& List::operator=(const List& l) | ||
inline void List::derefValues() | ||
{ | ||
List(l).swap(*this); | ||
return *this; | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
int size = imp->size; | ||
int inlineSize = MIN(size, inlineValuesSize); | ||
for (int i = 0; i != inlineSize; ++i) | ||
imp->values[i]->deref(); | ||
int overflowSize = size - inlineSize; | ||
ValueImp **overflow = imp->overflow; | ||
for (int i = 0; i != overflowSize; ++i) | ||
overflow[i]->deref(); | ||
} | ||
List::~List() | ||
void List::release() | ||
{ | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
#if DUMP_STATISTICS | ||
--numLists; | ||
#endif | ||
if (--hook->nodesRefCount == 0) | ||
derefAll(); | ||
if (--hook->listRefCount == 0) { | ||
#if DUMP_STATISTICS | ||
--numLists; | ||
++numListsDestroyed; | ||
for (int i = 0; i < 17; i++) | ||
if (hook->sizeHighWaterMark > i) | ||
++numListsBiggerThan[i]; | ||
if (imp->sizeHighWaterMark > i) | ||
++numListsBiggerThan[i]; | ||
#endif | ||
assert(hook->nodesRefCount == 0); | ||
clearInternal(); | ||
delete hook; | ||
} | ||
derefValues(); | ||
delete [] imp->overflow; | ||
deallocateListImp(imp); | ||
} | ||
void List::append(const Value& val) | ||
ValueImp *List::impAt(int i) const | ||
{ | ||
ListNode *n = new ListNode(val, hook->prev, hook); | ||
if (hook->nodesRefCount) | ||
n->member->ref(); | ||
hook->prev->next = n; | ||
hook->prev = n; | ||
#if DUMP_STATISTICS | ||
++numNodesAllocated; | ||
int s = size(); | ||
if (s > hook->sizeHighWaterMark) { | ||
hook->sizeHighWaterMark = s; | ||
if (s > listSizeHighWaterMark) | ||
listSizeHighWaterMark = s; | ||
} | ||
#endif | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
if ((unsigned)i >= (unsigned)imp->size) | ||
return UndefinedImp::staticUndefined; | ||
if (i < inlineValuesSize) | ||
return imp->values[i]; | ||
return imp->overflow[i - inlineValuesSize]; | ||
} | ||
void List::append(ValueImp *val) | ||
void List::clear() | ||
{ | ||
ListNode *n = new ListNode(val, hook->prev, hook); | ||
if (hook->nodesRefCount) | ||
val->ref(); | ||
hook->prev->next = n; | ||
hook->prev = n; | ||
#if DUMP_STATISTICS | ||
++numNodesAllocated; | ||
int s = size(); | ||
if (s > hook->sizeHighWaterMark) { | ||
hook->sizeHighWaterMark = s; | ||
if (s > listSizeHighWaterMark) | ||
listSizeHighWaterMark = s; | ||
} | ||
#endif | ||
derefValues(); | ||
_impBase->size = 0; | ||
} | ||
#if 0 | ||
void List::prepend(const Value& val) | ||
void List::append(ValueImp *v) | ||
{ | ||
ListNode *n = new ListNode(val, hook, hook->next); | ||
if (hook->nodesRefCount) | ||
n->member->ref(); | ||
hook->next->prev = n; | ||
hook->next = n; | ||
#if DUMP_STATISTICS | ||
++numNodesAllocated; | ||
int s = size(); | ||
if (s > hook->sizeHighWaterMark) { | ||
hook->sizeHighWaterMark = s; | ||
if (s > listSizeHighWaterMark) | ||
listSizeHighWaterMark = s; | ||
} | ||
#endif | ||
} | ||
#endif | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
void List::prepend(ValueImp *val) | ||
{ | ||
ListNode *n = new ListNode(val, hook, hook->next); | ||
if (hook->nodesRefCount) | ||
val->ref(); | ||
hook->next->prev = n; | ||
hook->next = n; | ||
int i = imp->size++; | ||
#if DUMP_STATISTICS | ||
++numNodesAllocated; | ||
int s = size(); | ||
if (s > hook->sizeHighWaterMark) { | ||
hook->sizeHighWaterMark = s; | ||
if (s > listSizeHighWaterMark) | ||
listSizeHighWaterMark = s; | ||
} | ||
if (imp->size > listSizeHighWaterMark) | ||
listSizeHighWaterMark = imp->size; | ||
#endif | ||
} | ||
void List::prependList(const List& lst) | ||
{ | ||
ListNode *otherHook = lst.hook; | ||
ListNode *n = otherHook->prev; | ||
while (n != otherHook) { | ||
prepend(n->member); | ||
n = n->prev; | ||
} | ||
} | ||
void List::removeFirst() | ||
{ | ||
erase(hook->next); | ||
} | ||
#if 0 | ||
void List::removeLast() | ||
{ | ||
erase(hook->prev); | ||
} | ||
void List::remove(const Value &val) | ||
{ | ||
if (val.isNull()) | ||
return; | ||
for (ListNode *n = hook->next; n != hook; n = n->next) | ||
if (n->member == val.imp()) { | ||
erase(n); | ||
return; | ||
v->ref(); | ||
if (i < inlineValuesSize) { | ||
imp->values[i] = v; | ||
return; | ||
} | ||
if (i >= imp->capacity) { | ||
int newCapacity = i * 2; | ||
ValueImp **newOverflow = new ValueImp * [newCapacity - inlineValuesSize]; | ||
ValueImp **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; | ||
} | ||
imp->overflow[i - inlineValuesSize] = v; | ||
} | ||
#endif | ||
void List::clear() | ||
{ | ||
if (hook->nodesRefCount) | ||
derefAll(); | ||
clearInternal(); | ||
} | ||
void List::clearInternal() | ||
{ | ||
ListNode *n = hook->next; | ||
while (n != hook) { | ||
n = n->next; | ||
delete n->prev; | ||
} | ||
hook->next = hook; | ||
hook->prev = hook; | ||
} | ||
List List::copy() const | ||
{ | ||
List newList; | ||
newList.prependList(*this); | ||
return newList; | ||
} | ||
ListIterator List::begin() const | ||
{ | ||
return ListIterator(hook->next); | ||
} | ||
ListIterator List::end() const | ||
{ | ||
return ListIterator(hook); | ||
} | ||
bool List::isEmpty() const | ||
List List::copyTail() const | ||
{ | ||
return hook->prev == hook; | ||
} | ||
List copy; | ||
int List::size() const | ||
{ | ||
int s = 0; | ||
for (ListNode *n = hook->next; n != hook; n = n->next) | ||
s++; | ||
return s; | ||
} | ||
ListImp *imp = static_cast<ListImp *>(_impBase); | ||
Value List::at(int i) const | ||
{ | ||
if (i < 0 || i >= size()) | ||
return Undefined(); | ||
int size = imp->size; | ||
ListIterator it = begin(); | ||
int j = 0; | ||
while ((j++ < i)) | ||
it++; | ||
int inlineSize = MIN(size, inlineValuesSize); | ||
for (int i = 0; i != inlineSize; ++i) | ||
copy.append(imp->values[i]); | ||
return *it; | ||
} | ||
ValueImp **overflow = imp->overflow; | ||
int overflowSize = size - inlineSize; | ||
for (int i = 0; i != overflowSize; ++i) | ||
copy.append(overflow[i]); | ||
Value List::operator[](int i) const | ||
{ | ||
< |