26 #define DUMP_STATISTICS 0
34 const int poolSize = 512;
36 enum ListImpState { unusedInPool = 0, usedInPool, usedOnHeap, immortal };
38 struct ListImp : ListImpBase {
43 ListImp *nextInFreeList;
46 LocalStorageEntry
values[inlineListValuesSize];
49 int sizeHighWaterMark;
55 struct HeapListImp : ListImp {
56 HeapListImp *nextInHeapList;
57 HeapListImp *prevInHeapList;
60 static ListImp pool[poolSize];
61 static ListImp *poolFreeList;
62 static HeapListImp *heapList;
68 static int numListsHighWaterMark;
70 static int listSizeHighWaterMark;
72 static int numListsDestroyed;
73 static int numListsBiggerThan[17];
75 struct ListStatisticsExitLogger {
76 ~ListStatisticsExitLogger();
79 static ListStatisticsExitLogger
logger;
81 ListStatisticsExitLogger::~ListStatisticsExitLogger()
83 printf(
"\nKJS::List statistics:\n\n");
84 printf(
"%d lists were allocated\n", numLists);
85 printf(
"%d lists was the high water mark\n", numListsHighWaterMark);
86 printf(
"largest list had %d elements\n", listSizeHighWaterMark);
87 if (numListsDestroyed) {
89 for (
int i = 0; i < 17; i++) {
90 printf(
"%.1f%% of the lists (%d) had more than %d element%s\n",
91 100.0 * numListsBiggerThan[i] / numListsDestroyed,
92 numListsBiggerThan[i],
93 i, i == 1 ?
"" :
"s");
101 inline void ListImp::markValues()
103 for (
int i = 0; i != size; ++i) {
104 if (!JSValue::marked(data[i].val.valueVal)) {
105 JSValue::mark(data[i].val.valueVal);
110 void List::markProtectedLists()
115 for (
int i = 0; i < poolSize && seen < used; i++) {
116 if (pool[i].state == usedInPool) {
118 pool[i].markValues();
122 for (HeapListImp *l = heapList; l; l = l->nextInHeapList) {
127 static inline ListImp *allocateListImp()
130 if (poolUsed < poolSize) {
131 ListImp *imp = poolFreeList ? poolFreeList : &pool[0];
132 poolFreeList = imp->nextInFreeList ? imp->nextInFreeList : imp + 1;
133 imp->state = usedInPool;
138 HeapListImp *imp =
new HeapListImp;
139 imp->state = usedOnHeap;
142 heapList->prevInHeapList = imp;
144 imp->nextInHeapList = heapList;
145 imp->prevInHeapList =
nullptr;
151 List::List() : _impBase(allocateListImp())
153 ListImp *imp =
static_cast<ListImp *
>(_impBase);
157 imp->data = imp->values;
160 if (++numLists > numListsHighWaterMark) {
161 numListsHighWaterMark = numLists;
163 imp->sizeHighWaterMark = 0;
169 ListImp *imp =
static_cast<ListImp *
>(_impBase);
172 if (imp->size > imp->sizeHighWaterMark) {
173 imp->sizeHighWaterMark = imp->size;
178 for (
int i = 0; i < 17; i++)
179 if (imp->sizeHighWaterMark > i) {
180 ++numListsBiggerThan[i];
189 if (imp->state == usedInPool) {
190 imp->state = unusedInPool;
191 imp->nextInFreeList = poolFreeList;
195 assert(imp->state == usedOnHeap);
196 HeapListImp *
list =
static_cast<HeapListImp *
>(imp);
199 if (!
list->prevInHeapList) {
200 heapList =
list->nextInHeapList;
202 heapList->prevInHeapList =
nullptr;
205 list->prevInHeapList->nextInHeapList =
list->nextInHeapList;
206 if (
list->nextInHeapList) {
207 list->nextInHeapList->prevInHeapList =
list->prevInHeapList;
215 void List::appendSlowCase(JSValue *v)
217 ListImp *imp =
static_cast<ListImp *
>(_impBase);
222 if (imp->size > listSizeHighWaterMark) {
223 listSizeHighWaterMark = imp->size;
229 if (i >= imp->capacity) {
230 int newCapacity = i * 2;
232 LocalStorageEntry *newBuffer =
new LocalStorageEntry[newCapacity];
235 for (
int c = 0; c < i; ++c) {
236 newBuffer[c] = imp->data[c];
243 imp->data = newBuffer;
244 imp->capacity = newCapacity;
247 imp->data[i].val.valueVal = v;
253 copy.copyFrom(*
this);
257 void List::copyFrom(
const List &other)
260 ListImpBase *otherImp = other._impBase;
261 ListImp *ourImp =
static_cast<ListImp *
>(_impBase);
263 assert(ourImp->size == 0 && ourImp->capacity == 0);
265 int size = otherImp->size;
268 if (size > inlineListValuesSize) {
270 ourImp->capacity = size;
271 ourImp->data =
new LocalStorageEntry[size];
273 ourImp->capacity = 0;
276 for (
int c = 0; c < size; ++c) {
277 ourImp->data[c] = otherImp->data[c];
285 ListImpBase *inImp = _impBase;
286 ListImp *outImp =
static_cast<ListImp *
>(copy._impBase);
288 int size = inImp->size - 1;
296 if (size > inlineListValuesSize) {
298 outImp->capacity = size;
299 outImp->data =
new LocalStorageEntry[size];
301 outImp->capacity = 0;
304 for (
int c = 0; c < size; ++c) {
305 outImp->data[c] = inImp->data[c + 1];
313 static List emptyList;
317 List &List::operator=(
const List &b)
319 ListImpBase *bImpBase = b._impBase;
320 ++bImpBase->refCount;