]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSArray.h
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / JSArray.h
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
ed1e77d3 3 * Copyright (C) 2003, 2007, 2008, 2009, 2012, 2015 Apple Inc. All rights reserved.
9dae56ea
A
4 *
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
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21#ifndef JSArray_h
22#define JSArray_h
23
93a37866
A
24#include "ArrayConventions.h"
25#include "ButterflyInlines.h"
9dae56ea
A
26#include "JSObject.h"
27
28namespace JSC {
29
93a37866
A
30class JSArray;
31class LLIntOffsetsExtractor;
6fe7ccc8 32
93a37866
A
33class JSArray : public JSNonFinalObject {
34 friend class LLIntOffsetsExtractor;
35 friend class Walker;
36 friend class JIT;
6fe7ccc8 37
93a37866
A
38public:
39 typedef JSNonFinalObject Base;
ed1e77d3 40 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
6fe7ccc8 41
81345200
A
42 static size_t allocationSize(size_t inlineCapacity)
43 {
44 ASSERT_UNUSED(inlineCapacity, !inlineCapacity);
45 return sizeof(JSArray);
46 }
47
93a37866
A
48protected:
49 explicit JSArray(VM& vm, Structure* structure, Butterfly* butterfly)
50 : JSNonFinalObject(vm, structure, butterfly)
51 {
52 }
6fe7ccc8 53
93a37866
A
54public:
55 static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
ed1e77d3 56 static JSArray* createWithButterfly(VM&, Structure*, Butterfly*);
9dae56ea 57
93a37866
A
58 // tryCreateUninitialized is used for fast construction of arrays whose size and
59 // contents are known at time of creation. Clients of this interface must:
60 // - null-check the result (indicating out of memory, or otherwise unable to allocate vector).
61 // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength.
62 static JSArray* tryCreateUninitialized(VM&, Structure*, unsigned initialLength);
14957cd0 63
81345200 64 JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
9dae56ea 65
ed1e77d3 66 JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
9dae56ea 67
81345200 68 DECLARE_EXPORT_INFO;
ed1e77d3
A
69
70 // OK if we know this is a JSArray, but not if it could be an object of a derived class; for RuntimeArray this always returns 0.
93a37866 71 unsigned length() const { return getArrayLength(); }
9dae56ea 72
ed1e77d3
A
73 // OK to use on new arrays, but not if it might be a RegExpMatchArray or RuntimeArray.
74 JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false);
75
76 JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
77 JS_EXPORT_PRIVATE JSValue pop(ExecState*);
9dae56ea 78
ed1e77d3
A
79 JSArray* fastSlice(ExecState&, unsigned startIndex, unsigned count);
80
81 static IndexingType fastConcatType(VM& vm, JSArray& firstArray, JSArray& secondArray)
82 {
83 IndexingType type = firstArray.indexingType();
84 if (type != secondArray.indexingType())
85 return NonArray;
86 if (type != ArrayWithDouble && type != ArrayWithInt32 && type != ArrayWithContiguous)
87 return NonArray;
88 if (firstArray.structure(vm)->holesMustForwardToPrototype(vm)
89 || secondArray.structure(vm)->holesMustForwardToPrototype(vm))
90 return NonArray;
91 return type;
92 }
93 EncodedJSValue fastConcatWith(ExecState&, JSArray&);
9dae56ea 94
93a37866
A
95 enum ShiftCountMode {
96 // This form of shift hints that we're doing queueing. With this assumption in hand,
97 // we convert to ArrayStorage, which has queue optimizations.
98 ShiftCountForShift,
14957cd0 99
93a37866
A
100 // This form of shift hints that we're just doing care and feeding on an array that
101 // is probably typically used for ordinary accesses. With this assumption in hand,
102 // we try to preserve whatever indexing type it has already.
103 ShiftCountForSplice
104 };
9dae56ea 105
93a37866
A
106 bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
107 {
81345200 108 return shiftCountWithArrayStorage(exec->vm(), startIndex, count, ensureArrayStorage(exec->vm()));
93a37866 109 }
81345200 110 bool shiftCountForSplice(ExecState* exec, unsigned& startIndex, unsigned count)
93a37866
A
111 {
112 return shiftCountWithAnyIndexingType(exec, startIndex, count);
113 }
114 template<ShiftCountMode shiftCountMode>
81345200 115 bool shiftCount(ExecState* exec, unsigned& startIndex, unsigned count)
93a37866
A
116 {
117 switch (shiftCountMode) {
118 case ShiftCountForShift:
119 return shiftCountForShift(exec, startIndex, count);
120 case ShiftCountForSplice:
121 return shiftCountForSplice(exec, startIndex, count);
122 default:
123 CRASH();
124 return false;
6fe7ccc8 125 }
93a37866 126 }
9dae56ea 127
93a37866 128 bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
6fe7ccc8 129 {
93a37866 130 return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->vm()));
6fe7ccc8 131 }
93a37866 132 bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
6fe7ccc8 133 {
93a37866 134 return unshiftCountWithAnyIndexingType(exec, startIndex, count);
6fe7ccc8 135 }
93a37866
A
136 template<ShiftCountMode shiftCountMode>
137 bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count)
f9bf01c6 138 {
93a37866
A
139 switch (shiftCountMode) {
140 case ShiftCountForShift:
141 return unshiftCountForShift(exec, startIndex, count);
142 case ShiftCountForSplice:
143 return unshiftCountForSplice(exec, startIndex, count);
144 default:
145 CRASH();
146 return false;
147 }
f9bf01c6 148 }
9dae56ea 149
ed1e77d3
A
150 JS_EXPORT_PRIVATE void fillArgList(ExecState*, MarkedArgumentBuffer&);
151 JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
93a37866
A
152
153 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
9dae56ea 154 {
81345200 155 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), indexingType);
f9bf01c6 156 }
93a37866
A
157
158protected:
93a37866 159 static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
f9bf01c6 160
93a37866
A
161 static bool deleteProperty(JSCell*, ExecState*, PropertyName);
162 JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
9dae56ea 163
93a37866
A
164private:
165 bool isLengthWritable()
f9bf01c6 166 {
93a37866
A
167 ArrayStorage* storage = arrayStorageOrNull();
168 if (!storage)
169 return true;
170 SparseArrayValueMap* map = storage->m_sparseMap.get();
171 return !map || !map->lengthIsReadOnly();
f9bf01c6 172 }
93a37866 173
81345200 174 bool shiftCountWithAnyIndexingType(ExecState*, unsigned& startIndex, unsigned count);
ed1e77d3 175 JS_EXPORT_PRIVATE bool shiftCountWithArrayStorage(VM&, unsigned startIndex, unsigned count, ArrayStorage*);
ba379fdc 176
93a37866
A
177 bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
178 bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
179 bool unshiftCountSlowCase(VM&, bool, unsigned);
180
93a37866
A
181 bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
182 void setLengthWritable(ExecState*, bool writable);
93a37866
A
183};
184
81345200 185inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned length, unsigned& vectorLength)
93a37866
A
186{
187 IndexingHeader header;
188 vectorLength = std::max(length, BASE_VECTOR_LEN);
189 header.setVectorLength(vectorLength);
190 header.setPublicLength(length);
191 Butterfly* result = Butterfly::create(
81345200 192 vm, intendedOwner, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
93a37866
A
193 return result;
194}
195
81345200 196inline Butterfly* createArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
93a37866
A
197{
198 Butterfly* butterfly = Butterfly::create(
81345200
A
199 vm, intendedOwner, 0, 0, true, baseIndexingHeaderForArray(initialLength),
200 ArrayStorage::sizeFor(BASE_VECTOR_LEN));
93a37866
A
201 ArrayStorage* storage = butterfly->arrayStorage();
202 storage->m_indexBias = 0;
203 storage->m_sparseMap.clear();
204 storage->m_numValuesInVector = 0;
205 return butterfly;
206}
207
81345200
A
208Butterfly* createArrayButterflyInDictionaryIndexingMode(
209 VM&, JSCell* intendedOwner, unsigned initialLength);
93a37866
A
210
211inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
212{
213 Butterfly* butterfly;
81345200 214 if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) {
93a37866
A
215 ASSERT(
216 hasUndecided(structure->indexingType())
217 || hasInt32(structure->indexingType())
218 || hasDouble(structure->indexingType())
219 || hasContiguous(structure->indexingType()));
220 unsigned vectorLength;
81345200 221 butterfly = createContiguousArrayButterfly(vm, 0, initialLength, vectorLength);
ed1e77d3 222 ASSERT(initialLength < MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH);
93a37866
A
223 if (hasDouble(structure->indexingType())) {
224 for (unsigned i = 0; i < vectorLength; ++i)
81345200 225 butterfly->contiguousDouble()[i] = PNaN;
93a37866
A
226 }
227 } else {
228 ASSERT(
229 structure->indexingType() == ArrayWithSlowPutArrayStorage
230 || structure->indexingType() == ArrayWithArrayStorage);
81345200 231 butterfly = createArrayButterfly(vm, 0, initialLength);
6fe7ccc8 232 }
ed1e77d3
A
233
234 return createWithButterfly(vm, structure, butterfly);
93a37866
A
235}
236
237inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength)
238{
239 unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
240 if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
241 return 0;
242
243 Butterfly* butterfly;
81345200 244 if (LIKELY(!hasAnyArrayStorage(structure->indexingType()))) {
93a37866
A
245 ASSERT(
246 hasUndecided(structure->indexingType())
247 || hasInt32(structure->indexingType())
248 || hasDouble(structure->indexingType())
249 || hasContiguous(structure->indexingType()));
250
251 void* temp;
81345200 252 if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
93a37866
A
253 return 0;
254 butterfly = Butterfly::fromBase(temp, 0, 0);
255 butterfly->setVectorLength(vectorLength);
256 butterfly->setPublicLength(initialLength);
257 if (hasDouble(structure->indexingType())) {
258 for (unsigned i = initialLength; i < vectorLength; ++i)
81345200 259 butterfly->contiguousDouble()[i] = PNaN;
93a37866
A
260 }
261 } else {
262 void* temp;
81345200 263 if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
93a37866
A
264 return 0;
265 butterfly = Butterfly::fromBase(temp, 0, 0);
266 *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
267 ArrayStorage* storage = butterfly->arrayStorage();
268 storage->m_indexBias = 0;
269 storage->m_sparseMap.clear();
270 storage->m_numValuesInVector = initialLength;
271 }
ed1e77d3
A
272
273 return createWithButterfly(vm, structure, butterfly);
274}
275
276inline JSArray* JSArray::createWithButterfly(VM& vm, Structure* structure, Butterfly* butterfly)
277{
93a37866
A
278 JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
279 array->finishCreation(vm);
280 return array;
281}
282
283JSArray* asArray(JSValue);
284
285inline JSArray* asArray(JSCell* cell)
286{
81345200 287 ASSERT(cell->inherits(JSArray::info()));
93a37866
A
288 return jsCast<JSArray*>(cell);
289}
290
291inline JSArray* asArray(JSValue value)
292{
293 return asArray(value.asCell());
294}
295
81345200 296inline bool isJSArray(JSCell* cell) { return cell->classInfo() == JSArray::info(); }
93a37866
A
297inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); }
298
299inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values)
300{
301 VM& vm = exec->vm();
302 unsigned length = values.size();
303 JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
304
305 // FIXME: we should probably throw an out of memory error here, but
306 // when making this change we should check that all clients of this
307 // function will correctly handle an exception being thrown from here.
308 RELEASE_ASSERT(array);
309
310 for (unsigned i = 0; i < length; ++i)
311 array->initializeIndex(vm, i, values.at(i));
312 return array;
313}
6fe7ccc8 314
93a37866
A
315inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
316{
317 VM& vm = exec->vm();
318 JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
319
320 // FIXME: we should probably throw an out of memory error here, but
321 // when making this change we should check that all clients of this
322 // function will correctly handle an exception being thrown from here.
323 RELEASE_ASSERT(array);
324
325 for (unsigned i = 0; i < length; ++i)
326 array->initializeIndex(vm, i, values[i]);
327 return array;
328}
329
81345200
A
330inline JSArray* constructArrayNegativeIndexed(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
331{
332 VM& vm = exec->vm();
333 JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
334
335 // FIXME: we should probably throw an out of memory error here, but
336 // when making this change we should check that all clients of this
337 // function will correctly handle an exception being thrown from here.
338 RELEASE_ASSERT(array);
339
340 for (int i = 0; i < static_cast<int>(length); ++i)
341 array->initializeIndex(vm, i, values[-i]);
342 return array;
343}
344
93a37866 345} // namespace JSC
9dae56ea
A
346
347#endif // JSArray_h