Changeset 128400 in webkit for trunk/Source/JavaScriptCore/runtime/JSArray.h
- Timestamp:
- Sep 12, 2012, 9:18:52 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/runtime/JSArray.h
r127349 r128400 1 1 /* 2 2 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 3 * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.3 * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved. 4 4 * 5 5 * This library is free software; you can redistribute it and/or … … 22 22 #define JSArray_h 23 23 24 #include "ArrayConventions.h" 25 #include "ButterflyInlineMethods.h" 24 26 #include "JSObject.h" 25 26 #define CHECK_ARRAY_CONSISTENCY 027 27 28 28 namespace JSC { … … 30 30 class JSArray; 31 31 class LLIntOffsetsExtractor; 32 33 enum PutDirectIndexMode { PutDirectIndexLikePutDirect, PutDirectIndexShouldNotThrow, PutDirectIndexShouldThrow };34 35 struct SparseArrayEntry : public WriteBarrier<Unknown> {36 typedef WriteBarrier<Unknown> Base;37 38 SparseArrayEntry() : attributes(0) {}39 40 JSValue get(ExecState*, JSArray*) const;41 void get(PropertySlot&) const;42 void get(PropertyDescriptor&) const;43 JSValue getNonSparseMode() const;44 45 unsigned attributes;46 };47 48 class SparseArrayValueMap {49 typedef HashMap<uint64_t, SparseArrayEntry, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t> > Map;50 51 enum Flags {52 Normal = 0,53 SparseMode = 1,54 LengthIsReadOnly = 2,55 };56 57 public:58 typedef Map::iterator iterator;59 typedef Map::const_iterator const_iterator;60 typedef Map::AddResult AddResult;61 62 SparseArrayValueMap()63 : m_flags(Normal)64 , m_reportedCapacity(0)65 {66 }67 68 void visitChildren(SlotVisitor&);69 70 bool sparseMode()71 {72 return m_flags & SparseMode;73 }74 75 void setSparseMode()76 {77 m_flags = static_cast<Flags>(m_flags | SparseMode);78 }79 80 bool lengthIsReadOnly()81 {82 return m_flags & LengthIsReadOnly;83 }84 85 void setLengthIsReadOnly()86 {87 m_flags = static_cast<Flags>(m_flags | LengthIsReadOnly);88 }89 90 // These methods may mutate the contents of the map91 void put(ExecState*, JSArray*, unsigned, JSValue, bool shouldThrow);92 bool putDirect(ExecState*, JSArray*, unsigned, JSValue, PutDirectIndexMode);93 AddResult add(JSArray*, unsigned);94 iterator find(unsigned i) { return m_map.find(i); }95 // This should ASSERT the remove is valid (check the result of the find).96 void remove(iterator it) { m_map.remove(it); }97 void remove(unsigned i) { m_map.remove(i); }98 99 // These methods do not mutate the contents of the map.100 iterator notFound() { return m_map.end(); }101 bool isEmpty() const { return m_map.isEmpty(); }102 bool contains(unsigned i) const { return m_map.contains(i); }103 size_t size() const { return m_map.size(); }104 // Only allow const begin/end iteration.105 const_iterator begin() const { return m_map.begin(); }106 const_iterator end() const { return m_map.end(); }107 108 private:109 Map m_map;110 Flags m_flags;111 size_t m_reportedCapacity;112 };113 114 // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage115 // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and116 // setStorage() methods. It is important to note that there may be space before the ArrayStorage that117 // is used to quick unshift / shift operation. The actual allocated pointer is available by using:118 // getStorage() - m_indexBias * sizeof(JSValue)119 struct ArrayStorage {120 unsigned m_length; // The "length" property on the array121 unsigned m_numValuesInVector;122 void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.123 #if CHECK_ARRAY_CONSISTENCY124 // Needs to be a uintptr_t for alignment purposes.125 uintptr_t m_initializationIndex;126 uintptr_t m_inCompactInitialization;127 #else128 uintptr_t m_padding;129 #endif130 WriteBarrier<Unknown> m_vector[1];131 132 static ptrdiff_t lengthOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_length); }133 static ptrdiff_t numValuesInVectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector); }134 static ptrdiff_t allocBaseOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_allocBase); }135 static ptrdiff_t vectorOffset() { return OBJECT_OFFSETOF(ArrayStorage, m_vector); }136 };137 32 138 33 class JSArray : public JSNonFinalObject { … … 141 36 friend class JIT; 142 37 38 public: 39 typedef JSNonFinalObject Base; 40 143 41 protected: 144 explicit JSArray(JSGlobalData& globalData, Structure* structure) 145 : JSNonFinalObject(globalData, structure) 146 , m_indexBias(0) 147 , m_storage(0) 148 , m_sparseValueMap(0) 42 explicit JSArray(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly) 43 : JSNonFinalObject(globalData, structure, butterfly) 149 44 { 150 45 } 151 46 152 JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, unsigned initialLength = 0);153 JS_EXPORT_PRIVATE JSArray* tryFinishCreationUninitialized(JSGlobalData&, unsigned initialLength);154 155 47 public: 156 typedef JSNonFinalObject Base;157 158 static void finalize(JSCell*);159 160 48 static JSArray* create(JSGlobalData&, Structure*, unsigned initialLength = 0); 161 49 … … 170 58 171 59 static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); 172 JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);173 60 static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); 174 static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);175 // This is similar to the JSObject::putDirect* methods:176 // - the prototype chain is not consulted177 // - accessors are not called.178 // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).179 // This method creates a property with attributes writable, enumerable and configurable all set to true.180 bool putDirectIndex(ExecState* exec, unsigned propertyName, JSValue value, PutDirectIndexMode mode = PutDirectIndexLikePutDirect)181 {182 if (canSetIndex(propertyName)) {183 setIndex(exec->globalData(), propertyName, value);184 return true;185 }186 return putDirectIndexBeyondVectorLength(exec, propertyName, value, mode);187 }188 61 189 62 static JS_EXPORTDATA const ClassInfo s_info; 190 63 191 unsigned length() const { return m_storage->m_length; }64 unsigned length() const { return getArrayLength(); } 192 65 // OK to use on new arrays, but not if it might be a RegExpMatchArray. 193 66 bool setLength(ExecState*, unsigned, bool throwException = false); … … 203 76 bool unshiftCount(ExecState*, unsigned count); 204 77 205 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; }206 JSValue getIndex(unsigned i)207 {208 ASSERT(canGetIndex(i));209 return m_storage->m_vector[i].get();210 }211 212 bool canSetIndex(unsigned i) { return i < m_vectorLength; }213 void setIndex(JSGlobalData& globalData, unsigned i, JSValue v)214 {215 ASSERT(canSetIndex(i));216 217 WriteBarrier<Unknown>& x = m_storage->m_vector[i];218 if (!x) {219 ArrayStorage *storage = m_storage;220 ++storage->m_numValuesInVector;221 if (i >= storage->m_length)222 storage->m_length = i + 1;223 }224 x.set(globalData, this, v);225 }226 227 inline void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)228 {229 ASSERT(canSetIndex(i));230 ArrayStorage *storage = m_storage;231 #if CHECK_ARRAY_CONSISTENCY232 ASSERT(storage->m_inCompactInitialization);233 // Check that we are initializing the next index in sequence.234 ASSERT(i == storage->m_initializationIndex);235 // tryCreateUninitialized set m_numValuesInVector to the initialLength,236 // check we do not try to initialize more than this number of properties.237 ASSERT(storage->m_initializationIndex < storage->m_numValuesInVector);238 storage->m_initializationIndex++;239 #endif240 ASSERT(i < storage->m_length);241 ASSERT(i < storage->m_numValuesInVector);242 storage->m_vector[i].set(globalData, this, v);243 }244 245 inline void completeInitialization(unsigned newLength)246 {247 // Check that we have initialized as meny properties as we think we have.248 ASSERT_UNUSED(newLength, newLength == m_storage->m_length);249 #if CHECK_ARRAY_CONSISTENCY250 // Check that the number of propreties initialized matches the initialLength.251 ASSERT(m_storage->m_initializationIndex == m_storage->m_numValuesInVector);252 ASSERT(m_storage->m_inCompactInitialization);253 m_storage->m_inCompactInitialization = false;254 #endif255 }256 257 bool inSparseMode()258 {259 SparseArrayValueMap* map = m_sparseValueMap;260 return map && map->sparseMode();261 }262 263 78 void fillArgList(ExecState*, MarkedArgumentBuffer&); 264 79 void copyToArguments(ExecState*, CallFrame*, uint32_t length); … … 266 81 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) 267 82 { 268 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info );83 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info, ArrayWithArrayStorage); 269 84 } 270 85 271 static ptrdiff_t storageOffset()272 {273 return OBJECT_OFFSETOF(JSArray, m_storage);274 }275 276 static ptrdiff_t vectorLengthOffset()277 {278 return OBJECT_OFFSETOF(JSArray, m_vectorLength);279 }280 281 JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);282 283 void enterDictionaryMode(JSGlobalData&);284 285 86 protected: 286 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | Overrides VisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;87 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; 287 88 static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); 288 89 289 90 static bool deleteProperty(JSCell*, ExecState*, PropertyName); 290 static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName); 291 static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 91 JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); 292 92 293 93 private: 294 static size_t storageSize(unsigned vectorLength);295 94 bool isLengthWritable() 296 95 { 297 SparseArrayValueMap* map = m_sparseValueMap; 96 ArrayStorage* storage = arrayStorageOrNull(); 97 if (!storage) 98 return false; 99 SparseArrayValueMap* map = storage->m_sparseMap.get(); 298 100 return !map || !map->lengthIsReadOnly(); 299 101 } 300 102 301 103 void setLengthWritable(ExecState*, bool writable); 302 void putDescriptor(ExecState*, SparseArrayEntry*, PropertyDescriptor&, PropertyDescriptor& old); 303 bool defineOwnNumericProperty(ExecState*, unsigned, PropertyDescriptor&, bool throwException); 304 void allocateSparseMap(JSGlobalData&); 305 void deallocateSparseMap(); 306 307 void putByIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, bool shouldThrow); 308 JS_EXPORT_PRIVATE bool putDirectIndexBeyondVectorLength(ExecState*, unsigned propertyName, JSValue, PutDirectIndexMode); 309 310 unsigned getNewVectorLength(unsigned desiredLength); 311 bool increaseVectorLength(JSGlobalData&, unsigned newLength); 104 312 105 bool unshiftCountSlowCase(JSGlobalData&, unsigned count); 313 106 314 107 unsigned compactForSorting(JSGlobalData&); 315 316 enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };317 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);318 319 unsigned m_vectorLength; // The valid length of m_vector320 unsigned m_indexBias; // The number of JSValue sized blocks before ArrayStorage.321 ArrayStorage *m_storage;322 323 // FIXME: Maybe SparseArrayValueMap should be put into its own JSCell?324 SparseArrayValueMap* m_sparseValueMap;325 326 static ptrdiff_t sparseValueMapOffset() { return OBJECT_OFFSETOF(JSArray, m_sparseValueMap); }327 static ptrdiff_t indexBiasOffset() { return OBJECT_OFFSETOF(JSArray, m_indexBias); }328 108 }; 329 109 110 inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength) 111 { 112 Butterfly* butterfly = Butterfly::create( 113 globalData, 0, 0, true, baseIndexingHeaderForArray(initialLength), ArrayStorage::sizeFor(BASE_VECTOR_LEN)); 114 ArrayStorage* storage = butterfly->arrayStorage(); 115 storage->m_indexBias = 0; 116 storage->m_sparseMap.clear(); 117 storage->m_numValuesInVector = 0; 118 #if CHECK_ARRAY_CONSISTENCY 119 storage->m_initializationIndex = 0; 120 storage->m_inCompactInitialization = 0; 121 #endif 122 return butterfly; 123 } 124 125 Butterfly* createArrayButterflyInDictionaryIndexingMode(JSGlobalData&, unsigned initialLength); 126 330 127 inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) 331 128 { 332 JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); 333 array->finishCreation(globalData, initialLength); 129 Butterfly* butterfly = createArrayButterfly(globalData, initialLength); 130 JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); 131 array->finishCreation(globalData); 334 132 return array; 335 133 } … … 337 135 inline JSArray* JSArray::tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength) 338 136 { 339 JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure); 340 return array->tryFinishCreationUninitialized(globalData, initialLength); 137 unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength); 138 if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) 139 return 0; 140 141 void* temp; 142 if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) 143 return 0; 144 Butterfly* butterfly = Butterfly::fromBase(temp, 0, 0); 145 *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength); 146 ArrayStorage* storage = butterfly->arrayStorage(); 147 storage->m_indexBias = 0; 148 storage->m_sparseMap.clear(); 149 storage->m_numValuesInVector = initialLength; 150 #if CHECK_ARRAY_CONSISTENCY 151 storage->m_initializationIndex = 0; 152 storage->m_inCompactInitialization = true; 153 #endif 154 155 JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); 156 array->finishCreation(globalData); 157 return array; 341 158 } 342 159 … … 356 173 inline bool isJSArray(JSCell* cell) { return cell->classInfo() == &JSArray::s_info; } 357 174 inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); } 358 359 // The definition of MAX_STORAGE_VECTOR_LENGTH is dependant on the definition storageSize360 // function below - the MAX_STORAGE_VECTOR_LENGTH limit is defined such that the storage361 // size calculation cannot overflow. (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) +362 // (vectorLength * sizeof(WriteBarrier<Unknown>)) must be <= 0xFFFFFFFFU (which is maximum value of size_t).363 #define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>))364 365 // These values have to be macros to be used in max() and min() without introducing366 // a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.367 #define MIN_SPARSE_ARRAY_INDEX 10000U368 #define MAX_STORAGE_VECTOR_INDEX (MAX_STORAGE_VECTOR_LENGTH - 1)369 inline size_t JSArray::storageSize(unsigned vectorLength)370 {371 ASSERT(vectorLength <= MAX_STORAGE_VECTOR_LENGTH);372 373 // MAX_STORAGE_VECTOR_LENGTH is defined such that provided (vectorLength <= MAX_STORAGE_VECTOR_LENGTH)374 // - as asserted above - the following calculation cannot overflow.375 size_t size = (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>)) + (vectorLength * sizeof(WriteBarrier<Unknown>));376 // Assertion to detect integer overflow in previous calculation (should not be possible, provided that377 // MAX_STORAGE_VECTOR_LENGTH is correctly defined).378 ASSERT(((size - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))));379 380 return size;381 }382 175 383 176 inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values)
Note:
See TracChangeset
for help on using the changeset viewer.