blob: 7ff5e23849236bed0b1b10e19e660ef351fcd67b [file] [log] [blame]
darinc758b282002-11-20 21:12:14 +00001/*
darinc758b282002-11-20 21:12:14 +00002 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
oliver@apple.com5fca29f2009-08-11 04:35:02 +00003 * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
darinc758b282002-11-20 21:12:14 +00004 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
mjscdff33b2006-01-23 21:41:36 +000017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
darinc758b282002-11-20 21:12:14 +000018 *
19 */
20
darin@apple.com5c0863d2008-06-16 04:17:44 +000021#ifndef JSArray_h
22#define JSArray_h
darinc758b282002-11-20 21:12:14 +000023
darin@apple.com3dcb6362008-06-16 04:00:19 +000024#include "JSObject.h"
darinc758b282002-11-20 21:12:14 +000025
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +000026#define CHECK_ARRAY_CONSISTENCY 0
27
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +000028namespace JSC {
darinc758b282002-11-20 21:12:14 +000029
oliver@apple.com168e5062011-01-31 20:07:21 +000030 typedef HashMap<unsigned, WriteBarrier<Unknown> > SparseArrayValueMap;
ggaren@apple.com1d72f772008-07-03 00:47:00 +000031
barraclough@apple.coma3812102010-07-29 23:29:17 +000032 // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage
33 // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and
34 // setStorage() methods. It is important to note that there may be space before the ArrayStorage that
35 // is used to quick unshift / shift operation. The actual allocated pointer is available by using:
36 // getStorage() - m_indexBias * sizeof(JSValue)
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000037 struct ArrayStorage {
barraclough@apple.coma3812102010-07-29 23:29:17 +000038 unsigned m_length; // The "length" property on the array
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000039 unsigned m_numValuesInVector;
40 SparseArrayValueMap* m_sparseValueMap;
ap@apple.com8c4e21b2010-02-26 00:22:34 +000041 void* subclassData; // A JSArray subclass can use this to fill the vector lazily.
barraclough@apple.com35490122010-08-03 21:29:32 +000042 void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.
ggaren@apple.comc1fb8e42010-01-09 01:02:38 +000043 size_t reportedMapCapacity;
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +000044#if CHECK_ARRAY_CONSISTENCY
45 bool m_inCompactInitialization;
46#endif
oliver@apple.com168e5062011-01-31 20:07:21 +000047 WriteBarrier<Unknown> m_vector[1];
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000048 };
darinf860d022007-10-22 13:35:17 +000049
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +000050 // The CreateCompact creation mode is used for fast construction of arrays
51 // whose size and contents are known at time of creation.
52 //
53 // There are two obligations when using this mode:
54 //
55 // - uncheckedSetIndex() must be used when initializing the array.
56 // - setLength() must be called after initialization.
57
58 enum ArrayCreationMode { CreateCompact, CreateInitialized };
59
barraclough@apple.com77da1082011-02-16 21:35:19 +000060 class JSArray : public JSNonFinalObject {
oliver@apple.com29443c42009-08-27 08:39:38 +000061 friend class Walker;
mrowe@apple.comf88a4632008-09-07 05:44:58 +000062
oliver@apple.comfcacd3c2011-07-18 17:47:13 +000063 protected:
oliver@apple.comb2fa0dc2011-04-15 23:55:42 +000064 explicit JSArray(JSGlobalData&, Structure*);
65 JSArray(JSGlobalData&, Structure*, unsigned initialLength, ArrayCreationMode);
66 JSArray(JSGlobalData&, Structure*, const ArgList& initialValues);
oliver@apple.comfcacd3c2011-07-18 17:47:13 +000067
68 public:
commit-queue@webkit.org6c25c522011-08-09 20:46:17 +000069 typedef JSNonFinalObject Base;
70
oliver@apple.comfcacd3c2011-07-18 17:47:13 +000071 JSArray(VPtrStealingHackType);
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000072 virtual ~JSArray();
darinc758b282002-11-20 21:12:14 +000073
oliver@apple.comfcacd3c2011-07-18 17:47:13 +000074 static JSArray* create(JSGlobalData& globalData, Structure* structure)
75 {
76 return new (allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure);
77 }
78
79 static JSArray* create(JSGlobalData& globalData, Structure* structure, unsigned initialLength, ArrayCreationMode createMode)
80 {
81 return new (allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, initialLength, createMode);
82 }
83
84 static JSArray* create(JSGlobalData& globalData, Structure* structure, const ArgList& initialValues)
85 {
86 return new (allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, initialValues);
87 }
88
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000089 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
90 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
oliver@apple.com4b4f7852009-08-26 16:52:15 +000091 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
ggaren@apple.comdc067b62009-05-01 22:43:39 +000092 virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem.
darinc758b282002-11-20 21:12:14 +000093
barraclough@apple.coma5540da2011-02-19 21:55:44 +000094 static JS_EXPORTDATA const ClassInfo s_info;
barraclough@apple.coma3812102010-07-29 23:29:17 +000095
eric@webkit.org29a10d72010-08-08 05:29:38 +000096 unsigned length() const { return m_storage->m_length; }
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000097 void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray.
darinf860d022007-10-22 13:35:17 +000098
weinig@apple.com0e2d66e2008-07-06 05:26:58 +000099 void sort(ExecState*);
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000100 void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
101 void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
darinf860d022007-10-22 13:35:17 +0000102
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000103 void push(ExecState*, JSValue);
104 JSValue pop();
darin@apple.comef5124b2008-09-22 21:04:45 +0000105
barraclough@apple.coma3812102010-07-29 23:29:17 +0000106 void shiftCount(ExecState*, int count);
107 void unshiftCount(ExecState*, int count);
108
eric@webkit.org29a10d72010-08-08 05:29:38 +0000109 bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; }
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000110 JSValue getIndex(unsigned i)
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000111 {
112 ASSERT(canGetIndex(i));
oliver@apple.com168e5062011-01-31 20:07:21 +0000113 return m_storage->m_vector[i].get();
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000114 }
ggaren@apple.com1d72f772008-07-03 00:47:00 +0000115
ggaren@apple.com570483e2009-10-03 17:01:14 +0000116 bool canSetIndex(unsigned i) { return i < m_vectorLength; }
oliver@apple.com168e5062011-01-31 20:07:21 +0000117 void setIndex(JSGlobalData& globalData, unsigned i, JSValue v)
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000118 {
119 ASSERT(canSetIndex(i));
barraclough@apple.coma3812102010-07-29 23:29:17 +0000120
oliver@apple.com168e5062011-01-31 20:07:21 +0000121 WriteBarrier<Unknown>& x = m_storage->m_vector[i];
ggaren@apple.com570483e2009-10-03 17:01:14 +0000122 if (!x) {
eric@webkit.org29a10d72010-08-08 05:29:38 +0000123 ArrayStorage *storage = m_storage;
barraclough@apple.coma3812102010-07-29 23:29:17 +0000124 ++storage->m_numValuesInVector;
125 if (i >= storage->m_length)
126 storage->m_length = i + 1;
ggaren@apple.com570483e2009-10-03 17:01:14 +0000127 }
oliver@apple.com168e5062011-01-31 20:07:21 +0000128 x.set(globalData, this, v);
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000129 }
barraclough@apple.coma3812102010-07-29 23:29:17 +0000130
oliver@apple.com168e5062011-01-31 20:07:21 +0000131 void uncheckedSetIndex(JSGlobalData& globalData, unsigned i, JSValue v)
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +0000132 {
133 ASSERT(canSetIndex(i));
eric@webkit.org29a10d72010-08-08 05:29:38 +0000134 ArrayStorage *storage = m_storage;
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +0000135#if CHECK_ARRAY_CONSISTENCY
barraclough@apple.coma3812102010-07-29 23:29:17 +0000136 ASSERT(storage->m_inCompactInitialization);
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +0000137#endif
oliver@apple.com168e5062011-01-31 20:07:21 +0000138 storage->m_vector[i].set(globalData, this, v);
andreas.kling@nokia.comd9acc422010-07-14 00:29:32 +0000139 }
140
oliver@apple.comf32186e2009-04-30 01:21:52 +0000141 void fillArgList(ExecState*, MarkedArgumentBuffer&);
oliver@apple.com65e286e2009-04-08 23:08:28 +0000142 void copyToRegisters(ExecState*, Register*, uint32_t);
weinig@apple.comcbf3ca92008-09-22 21:20:52 +0000143
oliver@apple.comb2fa0dc2011-04-15 23:55:42 +0000144 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
darin@apple.com74e6ed62008-10-23 00:11:11 +0000145 {
oliver@apple.com90cf7d52011-03-16 20:09:07 +0000146 return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
darin@apple.com74e6ed62008-10-23 00:11:11 +0000147 }
oliver@apple.com52000e72009-08-14 05:35:33 +0000148
oliver@apple.com433d02f2011-04-21 23:08:15 +0000149 inline void visitChildrenDirect(SlotVisitor&);
darin@apple.com74e6ed62008-10-23 00:11:11 +0000150
barraclough@apple.com66184e22011-03-13 21:16:29 +0000151 static ptrdiff_t storageOffset()
152 {
153 return OBJECT_OFFSETOF(JSArray, m_storage);
154 }
155
156 static ptrdiff_t vectorLengthOffset()
157 {
158 return OBJECT_OFFSETOF(JSArray, m_vectorLength);
159 }
160
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000161 protected:
oliver@apple.com433d02f2011-04-21 23:08:15 +0000162 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000163 virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000164 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
165 virtual bool deleteProperty(ExecState*, unsigned propertyName);
eric@webkit.orgc293f4c2010-01-13 00:58:21 +0000166 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
oliver@apple.com433d02f2011-04-21 23:08:15 +0000167 virtual void visitChildren(SlotVisitor&);
darin@apple.com1edff432008-06-24 05:23:17 +0000168
ap@apple.com8c4e21b2010-02-26 00:22:34 +0000169 void* subclassData() const;
170 void setSubclassData(void*);
barraclough@apple.com66184e22011-03-13 21:16:29 +0000171
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000172 private:
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000173 bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&);
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000174 void putSlowCase(ExecState*, unsigned propertyName, JSValue);
mjs70d74212005-08-07 06:17:49 +0000175
barraclough@apple.coma3812102010-07-29 23:29:17 +0000176 unsigned getNewVectorLength(unsigned desiredLength);
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000177 bool increaseVectorLength(unsigned newLength);
barraclough@apple.coma3812102010-07-29 23:29:17 +0000178 bool increaseVectorPrefixLength(unsigned newLength);
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000179
180 unsigned compactForSorting();
darin@apple.com772b7732008-06-11 19:37:44 +0000181
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000182 enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
183 void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);
mjs1a9f1132002-11-24 07:49:26 +0000184
barraclough@apple.coma3812102010-07-29 23:29:17 +0000185 unsigned m_vectorLength; // The valid length of m_vector
186 int m_indexBias; // The number of JSValue sized blocks before ArrayStorage.
eric@webkit.org29a10d72010-08-08 05:29:38 +0000187 ArrayStorage *m_storage;
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000188 };
darinc758b282002-11-20 21:12:14 +0000189
ggaren@apple.comdc067b62009-05-01 22:43:39 +0000190 JSArray* asArray(JSValue);
darin@apple.com5a494422008-10-18 23:08:12 +0000191
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000192 inline JSArray* asArray(JSCell* cell)
darin@apple.com5a494422008-10-18 23:08:12 +0000193 {
barraclough@apple.coma5540da2011-02-19 21:55:44 +0000194 ASSERT(cell->inherits(&JSArray::s_info));
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000195 return static_cast<JSArray*>(cell);
darin@apple.com5a494422008-10-18 23:08:12 +0000196 }
197
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000198 inline JSArray* asArray(JSValue value)
199 {
200 return asArray(value.asCell());
201 }
202
oliver@apple.com29443c42009-08-27 08:39:38 +0000203 inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; }
barraclough@apple.com66184e22011-03-13 21:16:29 +0000204 inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && isJSArray(globalData, v.asCell()); }
ggaren@apple.comc3343bd2009-02-24 03:58:09 +0000205
oliver@apple.com433d02f2011-04-21 23:08:15 +0000206 inline void JSArray::visitChildrenDirect(SlotVisitor& visitor)
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000207 {
oliver@apple.com433d02f2011-04-21 23:08:15 +0000208 JSObject::visitChildrenDirect(visitor);
oliver@apple.com52000e72009-08-14 05:35:33 +0000209
eric@webkit.org29a10d72010-08-08 05:29:38 +0000210 ArrayStorage* storage = m_storage;
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000211
ggaren@apple.com570483e2009-10-03 17:01:14 +0000212 unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength);
ggaren@apple.com053223f2011-05-25 19:37:18 +0000213 visitor.appendValues(storage->m_vector, usedVectorLength);
darin@apple.com8a1a5b52009-09-04 19:03:33 +0000214
oliver@apple.com52000e72009-08-14 05:35:33 +0000215 if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
216 SparseArrayValueMap::iterator end = map->end();
217 for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
oliver@apple.com433d02f2011-04-21 23:08:15 +0000218 visitor.append(&it->second);
oliver@apple.com52000e72009-08-14 05:35:33 +0000219 }
220 }
221
barraclough@apple.com3158a382010-08-13 07:35:45 +0000222 // Rule from ECMA 15.2 about what an array index is.
223 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
barraclough@apple.com794f4612010-08-18 07:41:22 +0000224 inline unsigned Identifier::toArrayIndex(bool& ok) const
barraclough@apple.com3158a382010-08-13 07:35:45 +0000225 {
barraclough@apple.com794f4612010-08-18 07:41:22 +0000226 unsigned i = toUInt32(ok);
barraclough@apple.com3158a382010-08-13 07:35:45 +0000227 if (ok && i >= 0xFFFFFFFFU)
barraclough@apple.com794f4612010-08-18 07:41:22 +0000228 ok = false;
barraclough@apple.com3158a382010-08-13 07:35:45 +0000229 return i;
230 }
231
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +0000232} // namespace JSC
darinc758b282002-11-20 21:12:14 +0000233
weinig@apple.com0e2d66e2008-07-06 05:26:58 +0000234#endif // JSArray_h