File indexing completed on 2024-05-12 15:43:25

0001 /*
0002  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
0003  *
0004  *  This library is free software; you can redistribute it and/or
0005  *  modify it under the terms of the GNU Library General Public
0006  *  License as published by the Free Software Foundation; either
0007  *  version 2 of the License, or (at your option) any later version.
0008  *
0009  *  This library is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  *  Library General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU Library General Public License
0015  *  along with this library; see the file COPYING.LIB.  If not, write to
0016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  *  Boston, MA 02110-1301, USA.
0018  *
0019  */
0020 
0021 #include "list.h"
0022 
0023 #include "internal.h"
0024 #include <algorithm>
0025 
0026 #define DUMP_STATISTICS 0
0027 
0028 using std::min;
0029 
0030 namespace KJS
0031 {
0032 
0033 // tunable parameters
0034 const int poolSize = 512;
0035 
0036 enum ListImpState { unusedInPool = 0, usedInPool, usedOnHeap, immortal };
0037 
0038 struct ListImp : ListImpBase {
0039     ListImpState state;
0040 
0041     union {
0042         int capacity; // or 0 if data is inline
0043         ListImp *nextInFreeList;
0044     };
0045 
0046     LocalStorageEntry values[inlineListValuesSize];
0047 
0048 #if DUMP_STATISTICS
0049     int sizeHighWaterMark;
0050 #endif
0051 
0052     void markValues();
0053 };
0054 
0055 struct HeapListImp : ListImp {
0056     HeapListImp *nextInHeapList;
0057     HeapListImp *prevInHeapList;
0058 };
0059 
0060 static ListImp pool[poolSize];
0061 static ListImp *poolFreeList;
0062 static HeapListImp *heapList;
0063 static int poolUsed;
0064 
0065 #if DUMP_STATISTICS
0066 
0067 static int numLists;
0068 static int numListsHighWaterMark;
0069 
0070 static int listSizeHighWaterMark;
0071 
0072 static int numListsDestroyed;
0073 static int numListsBiggerThan[17];
0074 
0075 struct ListStatisticsExitLogger {
0076     ~ListStatisticsExitLogger();
0077 };
0078 
0079 static ListStatisticsExitLogger logger;
0080 
0081 ListStatisticsExitLogger::~ListStatisticsExitLogger()
0082 {
0083     printf("\nKJS::List statistics:\n\n");
0084     printf("%d lists were allocated\n", numLists);
0085     printf("%d lists was the high water mark\n", numListsHighWaterMark);
0086     printf("largest list had %d elements\n", listSizeHighWaterMark);
0087     if (numListsDestroyed) {
0088         putc('\n', stdout);
0089         for (int i = 0; i < 17; i++) {
0090             printf("%.1f%% of the lists (%d) had more than %d element%s\n",
0091                    100.0 * numListsBiggerThan[i] / numListsDestroyed,
0092                    numListsBiggerThan[i],
0093                    i, i == 1 ? "" : "s");
0094         }
0095         putc('\n', stdout);
0096     }
0097 }
0098 
0099 #endif
0100 
0101 inline void ListImp::markValues()
0102 {
0103     for (int i = 0; i != size; ++i) {
0104         if (!JSValue::marked(data[i].val.valueVal)) {
0105             JSValue::mark(data[i].val.valueVal);
0106         }
0107     }
0108 }
0109 
0110 void List::markProtectedLists()
0111 {
0112     int seen = 0;
0113     int used = poolUsed;
0114 
0115     for (int i = 0; i < poolSize && seen < used; i++) {
0116         if (pool[i].state == usedInPool) {
0117             seen++;
0118             pool[i].markValues();
0119         }
0120     }
0121 
0122     for (HeapListImp *l = heapList; l; l = l->nextInHeapList) {
0123         l->markValues();
0124     }
0125 }
0126 
0127 static inline ListImp *allocateListImp()
0128 {
0129     // Find a free one in the pool.
0130     if (poolUsed < poolSize) {
0131         ListImp *imp = poolFreeList ? poolFreeList : &pool[0];
0132         poolFreeList = imp->nextInFreeList ? imp->nextInFreeList : imp + 1;
0133         imp->state = usedInPool;
0134         poolUsed++;
0135         return imp;
0136     }
0137 
0138     HeapListImp *imp = new HeapListImp;
0139     imp->state = usedOnHeap;
0140     // link into heap list
0141     if (heapList) {
0142         heapList->prevInHeapList = imp;
0143     }
0144     imp->nextInHeapList = heapList;
0145     imp->prevInHeapList = nullptr;
0146     heapList = imp;
0147 
0148     return imp;
0149 }
0150 
0151 List::List() : _impBase(allocateListImp())
0152 {
0153     ListImp *imp = static_cast<ListImp *>(_impBase);
0154     imp->size = 0;
0155     imp->refCount = 1;
0156     imp->capacity = 0;
0157     imp->data     = imp->values;
0158 
0159 #if DUMP_STATISTICS
0160     if (++numLists > numListsHighWaterMark) {
0161         numListsHighWaterMark = numLists;
0162     }
0163     imp->sizeHighWaterMark = 0;
0164 #endif
0165 }
0166 
0167 void List::release()
0168 {
0169     ListImp *imp = static_cast<ListImp *>(_impBase);
0170 
0171 #if DUMP_STATISTICS
0172     if (imp->size > imp->sizeHighWaterMark) {
0173         imp->sizeHighWaterMark = imp->size;
0174     }
0175 
0176     --numLists;
0177     ++numListsDestroyed;
0178     for (int i = 0; i < 17; i++)
0179         if (imp->sizeHighWaterMark > i) {
0180             ++numListsBiggerThan[i];
0181         }
0182 #endif
0183 
0184     if (imp->capacity) {
0185         delete [] imp->data;
0186     }
0187     imp->data = nullptr;
0188 
0189     if (imp->state == usedInPool) {
0190         imp->state = unusedInPool;
0191         imp->nextInFreeList = poolFreeList;
0192         poolFreeList = imp;
0193         poolUsed--;
0194     } else {
0195         assert(imp->state == usedOnHeap);
0196         HeapListImp *list = static_cast<HeapListImp *>(imp);
0197 
0198         // unlink from heap list
0199         if (!list->prevInHeapList) {
0200             heapList = list->nextInHeapList;
0201             if (heapList) {
0202                 heapList->prevInHeapList = nullptr;
0203             }
0204         } else {
0205             list->prevInHeapList->nextInHeapList = list->nextInHeapList;
0206             if (list->nextInHeapList) {
0207                 list->nextInHeapList->prevInHeapList = list->prevInHeapList;
0208             }
0209         }
0210 
0211         delete list;
0212     }
0213 }
0214 
0215 void List::appendSlowCase(JSValue *v)
0216 {
0217     ListImp *imp = static_cast<ListImp *>(_impBase);
0218 
0219     int i = imp->size++; // insert index/old size
0220 
0221 #if DUMP_STATISTICS
0222     if (imp->size > listSizeHighWaterMark) {
0223         listSizeHighWaterMark = imp->size;
0224     }
0225 #endif
0226 
0227     // If we got here, we need to use an out-of-line buffer.
0228 
0229     if (i >= imp->capacity) {
0230         int newCapacity = i * 2;
0231 
0232         LocalStorageEntry *newBuffer = new LocalStorageEntry[newCapacity];
0233 
0234         // Copy everything over
0235         for (int c = 0; c < i; ++c) {
0236             newBuffer[c] = imp->data[c];
0237         }
0238 
0239         if (imp->capacity) { // had an old out-of-line buffer
0240             delete[] imp->data;
0241         }
0242 
0243         imp->data     = newBuffer;
0244         imp->capacity = newCapacity;
0245     }
0246 
0247     imp->data[i].val.valueVal = v;
0248 }
0249 
0250 List List::copy() const
0251 {
0252     List copy;
0253     copy.copyFrom(*this);
0254     return copy;
0255 }
0256 
0257 void List::copyFrom(const List &other)
0258 {
0259     // Assumption: we're empty (e.g. called from copy)
0260     ListImpBase *otherImp = other._impBase;
0261     ListImp *ourImp       = static_cast<ListImp *>(_impBase);
0262 
0263     assert(ourImp->size == 0 && ourImp->capacity == 0);
0264 
0265     int size = otherImp->size;
0266     ourImp->size     = size;
0267 
0268     if (size > inlineListValuesSize) {
0269         // need an out-of-line buffer
0270         ourImp->capacity = size;
0271         ourImp->data     = new LocalStorageEntry[size];
0272     } else {
0273         ourImp->capacity = 0;
0274     }
0275 
0276     for (int c = 0; c < size; ++c) {
0277         ourImp->data[c] = otherImp->data[c];
0278     }
0279 }
0280 
0281 List List::copyTail() const
0282 {
0283     List copy;
0284 
0285     ListImpBase *inImp  = _impBase;
0286     ListImp     *outImp = static_cast<ListImp *>(copy._impBase);
0287 
0288     int size      = inImp->size - 1;
0289 
0290     if (size < 0) {
0291         size = 0;    // copyTail on empty list.
0292     }
0293 
0294     outImp->size  = size;
0295 
0296     if (size > inlineListValuesSize) {
0297         // need an out-of-line buffer
0298         outImp->capacity = size;
0299         outImp->data     = new LocalStorageEntry[size];
0300     } else {
0301         outImp->capacity = 0;
0302     }
0303 
0304     for (int c = 0; c < size; ++c) {
0305         outImp->data[c] = inImp->data[c + 1];
0306     }
0307 
0308     return copy;
0309 }
0310 
0311 const List &List::empty()
0312 {
0313     static List emptyList;
0314     return emptyList;
0315 }
0316 
0317 List &List::operator=(const List &b)
0318 {
0319     ListImpBase *bImpBase = b._impBase;
0320     ++bImpBase->refCount;
0321     deref();
0322     _impBase = bImpBase;
0323     return *this;
0324 }
0325 
0326 } // namespace KJS
0327