Commit ff399e06 authored by darin's avatar darin

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
parent 4a05ba7d
2002-11-22 Darin Adler <darin@apple.com>
- 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.
2002-11-22 Darin Adler <darin@apple.com>
- prepare to reimplement KJS::List; move to its own file, add statistics
......
2002-11-22 Darin Adler <darin@apple.com>
- 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.
2002-11-22 Darin Adler <darin@apple.com>
- prepare to reimplement KJS::List; move to its own file, add statistics
......
2002-11-22 Darin Adler <darin@apple.com>
- 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.
2002-11-22 Darin Adler <darin@apple.com>
- prepare to reimplement KJS::List; move to its own file, add statistics
......
......@@ -267,8 +267,9 @@ static int compareWithCompareFunctionForQSort(const void *a, const void *b)
{
CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments;
args->arguments.replaceFirst(*(ValueImp **)a);
args->arguments.replaceLast(*(ValueImp **)b);
args->arguments.clear();
args->arguments.append(*(ValueImp **)a);
args->arguments.append(*(ValueImp **)b);
return args->compareFunction->call(args->exec, args->globalObject, args->arguments)
.toInt32(args->exec);
}
......
// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 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 Lesser General Public
......@@ -20,17 +19,17 @@
*
*/
#include "collector.h"
#include "value.h"
#include "internal.h"
#if APPLE_CHANGES
#define _COLLECTOR
#include <CoreFoundation/CoreFoundation.h>
#include <cxxabi.h>
#endif
#include <collector.h>
#include <value.h>
#include <internal.h>
using namespace KJS;
namespace KJS {
// tunable parameters
static const int CELL_SIZE = 56;
......@@ -359,8 +358,7 @@ int Collector::numReferencedObjects()
return count;
}
// FIXME: Rename. Root object classes are more useful than live object classes.
CFSetRef Collector::liveObjectClasses()
const void *Collector::rootObjectClasses()
{
CFMutableSetRef classes = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
......@@ -404,3 +402,5 @@ CFSetRef Collector::liveObjectClasses()
}
#endif // APPLE_CHANGES
} // namespace KJS
......@@ -23,12 +23,6 @@
#ifndef _KJSCOLLECTOR_H_
#define _KJSCOLLECTOR_H_
#if APPLE_CHANGES
#if !defined(__OBJC__) && !defined(_COLLECTOR)
typedef void *CFSetRef;
#endif
#endif
#define KJS_MEM_LIMIT 500000
namespace KJS {
......@@ -70,7 +64,7 @@ namespace KJS {
static int numInterpreters();
static int numGCNotAllowedObjects();
static int numReferencedObjects();
static CFSetRef liveObjectClasses();
static const void *rootObjectClasses(); // actually returns CFSetRef
#endif
private:
static bool memoryFull;
......@@ -78,5 +72,4 @@ namespace KJS {
};
#endif /* _KJSCOLLECTOR_H_ */
// -*- 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
{
<