2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
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.
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.
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
24 #include "ArrayConventions.h"
25 #include "ButterflyInlines.h"
31 class LLIntOffsetsExtractor
;
33 class JSArray
: public JSNonFinalObject
{
34 friend class LLIntOffsetsExtractor
;
39 typedef JSNonFinalObject Base
;
42 explicit JSArray(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
43 : JSNonFinalObject(vm
, structure
, butterfly
)
48 static JSArray
* create(VM
&, Structure
*, unsigned initialLength
= 0);
50 // tryCreateUninitialized is used for fast construction of arrays whose size and
51 // contents are known at time of creation. Clients of this interface must:
52 // - null-check the result (indicating out of memory, or otherwise unable to allocate vector).
53 // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength.
54 static JSArray
* tryCreateUninitialized(VM
&, Structure
*, unsigned initialLength
);
56 JS_EXPORT_PRIVATE
static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&, bool throwException
);
58 static bool getOwnPropertySlot(JSCell
*, ExecState
*, PropertyName
, PropertySlot
&);
59 static bool getOwnPropertyDescriptor(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&);
61 static JS_EXPORTDATA
const ClassInfo s_info
;
63 unsigned length() const { return getArrayLength(); }
64 // OK to use on new arrays, but not if it might be a RegExpMatchArray.
65 bool setLength(ExecState
*, unsigned, bool throwException
= false);
67 void sort(ExecState
*);
68 void sort(ExecState
*, JSValue compareFunction
, CallType
, const CallData
&);
69 void sortNumeric(ExecState
*, JSValue compareFunction
, CallType
, const CallData
&);
71 void push(ExecState
*, JSValue
);
72 JSValue
pop(ExecState
*);
75 // This form of shift hints that we're doing queueing. With this assumption in hand,
76 // we convert to ArrayStorage, which has queue optimizations.
79 // This form of shift hints that we're just doing care and feeding on an array that
80 // is probably typically used for ordinary accesses. With this assumption in hand,
81 // we try to preserve whatever indexing type it has already.
85 bool shiftCountForShift(ExecState
* exec
, unsigned startIndex
, unsigned count
)
87 return shiftCountWithArrayStorage(startIndex
, count
, ensureArrayStorage(exec
->vm()));
89 bool shiftCountForSplice(ExecState
* exec
, unsigned startIndex
, unsigned count
)
91 return shiftCountWithAnyIndexingType(exec
, startIndex
, count
);
93 template<ShiftCountMode shiftCountMode
>
94 bool shiftCount(ExecState
* exec
, unsigned startIndex
, unsigned count
)
96 switch (shiftCountMode
) {
97 case ShiftCountForShift
:
98 return shiftCountForShift(exec
, startIndex
, count
);
99 case ShiftCountForSplice
:
100 return shiftCountForSplice(exec
, startIndex
, count
);
107 bool unshiftCountForShift(ExecState
* exec
, unsigned startIndex
, unsigned count
)
109 return unshiftCountWithArrayStorage(exec
, startIndex
, count
, ensureArrayStorage(exec
->vm()));
111 bool unshiftCountForSplice(ExecState
* exec
, unsigned startIndex
, unsigned count
)
113 return unshiftCountWithAnyIndexingType(exec
, startIndex
, count
);
115 template<ShiftCountMode shiftCountMode
>
116 bool unshiftCount(ExecState
* exec
, unsigned startIndex
, unsigned count
)
118 switch (shiftCountMode
) {
119 case ShiftCountForShift
:
120 return unshiftCountForShift(exec
, startIndex
, count
);
121 case ShiftCountForSplice
:
122 return unshiftCountForSplice(exec
, startIndex
, count
);
129 void fillArgList(ExecState
*, MarkedArgumentBuffer
&);
130 void copyToArguments(ExecState
*, CallFrame
*, uint32_t length
);
132 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
, IndexingType indexingType
)
134 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), &s_info
, indexingType
);
138 static const unsigned StructureFlags
= OverridesGetOwnPropertySlot
| OverridesGetPropertyNames
| JSObject::StructureFlags
;
139 static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
141 static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
142 JS_EXPORT_PRIVATE
static void getOwnNonIndexPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
145 bool isLengthWritable()
147 ArrayStorage
* storage
= arrayStorageOrNull();
150 SparseArrayValueMap
* map
= storage
->m_sparseMap
.get();
151 return !map
|| !map
->lengthIsReadOnly();
154 bool shiftCountWithAnyIndexingType(ExecState
*, unsigned startIndex
, unsigned count
);
155 bool shiftCountWithArrayStorage(unsigned startIndex
, unsigned count
, ArrayStorage
*);
157 bool unshiftCountWithAnyIndexingType(ExecState
*, unsigned startIndex
, unsigned count
);
158 bool unshiftCountWithArrayStorage(ExecState
*, unsigned startIndex
, unsigned count
, ArrayStorage
*);
159 bool unshiftCountSlowCase(VM
&, bool, unsigned);
161 template<IndexingType indexingType
>
162 void sortNumericVector(ExecState
*, JSValue compareFunction
, CallType
, const CallData
&);
164 template<IndexingType indexingType
, typename StorageType
>
165 void sortCompactedVector(ExecState
*, ContiguousData
<StorageType
>, unsigned relevantLength
);
167 template<IndexingType indexingType
>
168 void sortVector(ExecState
*, JSValue compareFunction
, CallType
, const CallData
&);
170 bool setLengthWithArrayStorage(ExecState
*, unsigned newLength
, bool throwException
, ArrayStorage
*);
171 void setLengthWritable(ExecState
*, bool writable
);
173 template<IndexingType indexingType
>
174 void compactForSorting(unsigned& numDefined
, unsigned& newRelevantLength
);
177 inline Butterfly
* createContiguousArrayButterfly(VM
& vm
, unsigned length
, unsigned& vectorLength
)
179 IndexingHeader header
;
180 vectorLength
= std::max(length
, BASE_VECTOR_LEN
);
181 header
.setVectorLength(vectorLength
);
182 header
.setPublicLength(length
);
183 Butterfly
* result
= Butterfly::create(
184 vm
, 0, 0, true, header
, vectorLength
* sizeof(EncodedJSValue
));
188 inline Butterfly
* createArrayButterfly(VM
& vm
, unsigned initialLength
)
190 Butterfly
* butterfly
= Butterfly::create(
191 vm
, 0, 0, true, baseIndexingHeaderForArray(initialLength
), ArrayStorage::sizeFor(BASE_VECTOR_LEN
));
192 ArrayStorage
* storage
= butterfly
->arrayStorage();
193 storage
->m_indexBias
= 0;
194 storage
->m_sparseMap
.clear();
195 storage
->m_numValuesInVector
= 0;
199 Butterfly
* createArrayButterflyInDictionaryIndexingMode(VM
&, unsigned initialLength
);
201 inline JSArray
* JSArray::create(VM
& vm
, Structure
* structure
, unsigned initialLength
)
203 Butterfly
* butterfly
;
204 if (LIKELY(!hasArrayStorage(structure
->indexingType()))) {
206 hasUndecided(structure
->indexingType())
207 || hasInt32(structure
->indexingType())
208 || hasDouble(structure
->indexingType())
209 || hasContiguous(structure
->indexingType()));
210 unsigned vectorLength
;
211 butterfly
= createContiguousArrayButterfly(vm
, initialLength
, vectorLength
);
212 ASSERT(initialLength
< MIN_SPARSE_ARRAY_INDEX
);
213 if (hasDouble(structure
->indexingType())) {
214 for (unsigned i
= 0; i
< vectorLength
; ++i
)
215 butterfly
->contiguousDouble()[i
] = QNaN
;
219 structure
->indexingType() == ArrayWithSlowPutArrayStorage
220 || structure
->indexingType() == ArrayWithArrayStorage
);
221 butterfly
= createArrayButterfly(vm
, initialLength
);
223 JSArray
* array
= new (NotNull
, allocateCell
<JSArray
>(vm
.heap
)) JSArray(vm
, structure
, butterfly
);
224 array
->finishCreation(vm
);
228 inline JSArray
* JSArray::tryCreateUninitialized(VM
& vm
, Structure
* structure
, unsigned initialLength
)
230 unsigned vectorLength
= std::max(BASE_VECTOR_LEN
, initialLength
);
231 if (vectorLength
> MAX_STORAGE_VECTOR_LENGTH
)
234 Butterfly
* butterfly
;
235 if (LIKELY(!hasArrayStorage(structure
->indexingType()))) {
237 hasUndecided(structure
->indexingType())
238 || hasInt32(structure
->indexingType())
239 || hasDouble(structure
->indexingType())
240 || hasContiguous(structure
->indexingType()));
243 if (!vm
.heap
.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength
* sizeof(EncodedJSValue
)), &temp
))
245 butterfly
= Butterfly::fromBase(temp
, 0, 0);
246 butterfly
->setVectorLength(vectorLength
);
247 butterfly
->setPublicLength(initialLength
);
248 if (hasDouble(structure
->indexingType())) {
249 for (unsigned i
= initialLength
; i
< vectorLength
; ++i
)
250 butterfly
->contiguousDouble()[i
] = QNaN
;
254 if (!vm
.heap
.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength
)), &temp
))
256 butterfly
= Butterfly::fromBase(temp
, 0, 0);
257 *butterfly
->indexingHeader() = indexingHeaderForArray(initialLength
, vectorLength
);
258 ArrayStorage
* storage
= butterfly
->arrayStorage();
259 storage
->m_indexBias
= 0;
260 storage
->m_sparseMap
.clear();
261 storage
->m_numValuesInVector
= initialLength
;
264 JSArray
* array
= new (NotNull
, allocateCell
<JSArray
>(vm
.heap
)) JSArray(vm
, structure
, butterfly
);
265 array
->finishCreation(vm
);
269 JSArray
* asArray(JSValue
);
271 inline JSArray
* asArray(JSCell
* cell
)
273 ASSERT(cell
->inherits(&JSArray::s_info
));
274 return jsCast
<JSArray
*>(cell
);
277 inline JSArray
* asArray(JSValue value
)
279 return asArray(value
.asCell());
282 inline bool isJSArray(JSCell
* cell
) { return cell
->classInfo() == &JSArray::s_info
; }
283 inline bool isJSArray(JSValue v
) { return v
.isCell() && isJSArray(v
.asCell()); }
285 inline JSArray
* constructArray(ExecState
* exec
, Structure
* arrayStructure
, const ArgList
& values
)
288 unsigned length
= values
.size();
289 JSArray
* array
= JSArray::tryCreateUninitialized(vm
, arrayStructure
, length
);
291 // FIXME: we should probably throw an out of memory error here, but
292 // when making this change we should check that all clients of this
293 // function will correctly handle an exception being thrown from here.
294 RELEASE_ASSERT(array
);
296 for (unsigned i
= 0; i
< length
; ++i
)
297 array
->initializeIndex(vm
, i
, values
.at(i
));
301 inline JSArray
* constructArray(ExecState
* exec
, Structure
* arrayStructure
, const JSValue
* values
, unsigned length
)
304 JSArray
* array
= JSArray::tryCreateUninitialized(vm
, arrayStructure
, length
);
306 // FIXME: we should probably throw an out of memory error here, but
307 // when making this change we should check that all clients of this
308 // function will correctly handle an exception being thrown from here.
309 RELEASE_ASSERT(array
);
311 for (unsigned i
= 0; i
< length
; ++i
)
312 array
->initializeIndex(vm
, i
, values
[i
]);