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