The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / src / elements.cc @ f230a1cf
History | View | Annotate | Download (77.7 KB)
1 |
// Copyright 2012 the V8 project authors. All rights reserved.
|
---|---|
2 |
// Redistribution and use in source and binary forms, with or without
|
3 |
// modification, are permitted provided that the following conditions are
|
4 |
// met:
|
5 |
//
|
6 |
// * Redistributions of source code must retain the above copyright
|
7 |
// notice, this list of conditions and the following disclaimer.
|
8 |
// * Redistributions in binary form must reproduce the above
|
9 |
// copyright notice, this list of conditions and the following
|
10 |
// disclaimer in the documentation and/or other materials provided
|
11 |
// with the distribution.
|
12 |
// * Neither the name of Google Inc. nor the names of its
|
13 |
// contributors may be used to endorse or promote products derived
|
14 |
// from this software without specific prior written permission.
|
15 |
//
|
16 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17 |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18 |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19 |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
20 |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23 |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24 |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25 |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26 |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27 |
|
28 |
#include "v8.h" |
29 |
|
30 |
#include "arguments.h" |
31 |
#include "objects.h" |
32 |
#include "elements.h" |
33 |
#include "utils.h" |
34 |
#include "v8conversions.h" |
35 |
|
36 |
// Each concrete ElementsAccessor can handle exactly one ElementsKind,
|
37 |
// several abstract ElementsAccessor classes are used to allow sharing
|
38 |
// common code.
|
39 |
//
|
40 |
// Inheritance hierarchy:
|
41 |
// - ElementsAccessorBase (abstract)
|
42 |
// - FastElementsAccessor (abstract)
|
43 |
// - FastSmiOrObjectElementsAccessor
|
44 |
// - FastPackedSmiElementsAccessor
|
45 |
// - FastHoleySmiElementsAccessor
|
46 |
// - FastPackedObjectElementsAccessor
|
47 |
// - FastHoleyObjectElementsAccessor
|
48 |
// - FastDoubleElementsAccessor
|
49 |
// - FastPackedDoubleElementsAccessor
|
50 |
// - FastHoleyDoubleElementsAccessor
|
51 |
// - ExternalElementsAccessor (abstract)
|
52 |
// - ExternalByteElementsAccessor
|
53 |
// - ExternalUnsignedByteElementsAccessor
|
54 |
// - ExternalShortElementsAccessor
|
55 |
// - ExternalUnsignedShortElementsAccessor
|
56 |
// - ExternalIntElementsAccessor
|
57 |
// - ExternalUnsignedIntElementsAccessor
|
58 |
// - ExternalFloatElementsAccessor
|
59 |
// - ExternalDoubleElementsAccessor
|
60 |
// - PixelElementsAccessor
|
61 |
// - DictionaryElementsAccessor
|
62 |
// - NonStrictArgumentsElementsAccessor
|
63 |
|
64 |
|
65 |
namespace v8 {
|
66 |
namespace internal {
|
67 |
|
68 |
|
69 |
static const int kPackedSizeNotKnown = -1; |
70 |
|
71 |
|
72 |
// First argument in list is the accessor class, the second argument is the
|
73 |
// accessor ElementsKind, and the third is the backing store class. Use the
|
74 |
// fast element handler for smi-only arrays. The implementation is currently
|
75 |
// identical. Note that the order must match that of the ElementsKind enum for
|
76 |
// the |accessor_array[]| below to work.
|
77 |
#define ELEMENTS_LIST(V) \
|
78 |
V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \ |
79 |
V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \ |
80 |
FixedArray) \ |
81 |
V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \ |
82 |
V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \ |
83 |
V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \ |
84 |
FixedDoubleArray) \ |
85 |
V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \ |
86 |
FixedDoubleArray) \ |
87 |
V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \ |
88 |
SeededNumberDictionary) \ |
89 |
V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \ |
90 |
FixedArray) \ |
91 |
V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS, \ |
92 |
ExternalByteArray) \ |
93 |
V(ExternalUnsignedByteElementsAccessor, \ |
94 |
EXTERNAL_UNSIGNED_BYTE_ELEMENTS, ExternalUnsignedByteArray) \ |
95 |
V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS, \ |
96 |
ExternalShortArray) \ |
97 |
V(ExternalUnsignedShortElementsAccessor, \ |
98 |
EXTERNAL_UNSIGNED_SHORT_ELEMENTS, ExternalUnsignedShortArray) \ |
99 |
V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS, \ |
100 |
ExternalIntArray) \ |
101 |
V(ExternalUnsignedIntElementsAccessor, \ |
102 |
EXTERNAL_UNSIGNED_INT_ELEMENTS, ExternalUnsignedIntArray) \ |
103 |
V(ExternalFloatElementsAccessor, \ |
104 |
EXTERNAL_FLOAT_ELEMENTS, ExternalFloatArray) \ |
105 |
V(ExternalDoubleElementsAccessor, \ |
106 |
EXTERNAL_DOUBLE_ELEMENTS, ExternalDoubleArray) \ |
107 |
V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS, ExternalPixelArray) |
108 |
|
109 |
|
110 |
template<ElementsKind Kind> class ElementsKindTraits { |
111 |
public:
|
112 |
typedef FixedArrayBase BackingStore;
|
113 |
}; |
114 |
|
115 |
#define ELEMENTS_TRAITS(Class, KindParam, Store) \
|
116 |
template<> class ElementsKindTraits<KindParam> { \ |
117 |
public: \
|
118 |
static const ElementsKind Kind = KindParam; \ |
119 |
typedef Store BackingStore; \
|
120 |
}; |
121 |
ELEMENTS_LIST(ELEMENTS_TRAITS) |
122 |
#undef ELEMENTS_TRAITS
|
123 |
|
124 |
|
125 |
ElementsAccessor** ElementsAccessor::elements_accessors_; |
126 |
|
127 |
|
128 |
static bool HasKey(FixedArray* array, Object* key) { |
129 |
int len0 = array->length();
|
130 |
for (int i = 0; i < len0; i++) { |
131 |
Object* element = array->get(i); |
132 |
if (element->IsSmi() && element == key) return true; |
133 |
if (element->IsString() &&
|
134 |
key->IsString() && String::cast(element)->Equals(String::cast(key))) { |
135 |
return true; |
136 |
} |
137 |
} |
138 |
return false; |
139 |
} |
140 |
|
141 |
|
142 |
static Failure* ThrowArrayLengthRangeError(Heap* heap) {
|
143 |
HandleScope scope(heap->isolate()); |
144 |
return heap->isolate()->Throw(
|
145 |
*heap->isolate()->factory()->NewRangeError("invalid_array_length",
|
146 |
HandleVector<Object>(NULL, 0))); |
147 |
} |
148 |
|
149 |
|
150 |
static void CopyObjectToObjectElements(FixedArrayBase* from_base, |
151 |
ElementsKind from_kind, |
152 |
uint32_t from_start, |
153 |
FixedArrayBase* to_base, |
154 |
ElementsKind to_kind, |
155 |
uint32_t to_start, |
156 |
int raw_copy_size) {
|
157 |
ASSERT(to_base->map() != |
158 |
from_base->GetIsolate()->heap()->fixed_cow_array_map()); |
159 |
DisallowHeapAllocation no_allocation; |
160 |
int copy_size = raw_copy_size;
|
161 |
if (raw_copy_size < 0) { |
162 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
163 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
164 |
copy_size = Min(from_base->length() - from_start, |
165 |
to_base->length() - to_start); |
166 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
167 |
int start = to_start + copy_size;
|
168 |
int length = to_base->length() - start;
|
169 |
if (length > 0) { |
170 |
Heap* heap = from_base->GetHeap(); |
171 |
MemsetPointer(FixedArray::cast(to_base)->data_start() + start, |
172 |
heap->the_hole_value(), length); |
173 |
} |
174 |
} |
175 |
} |
176 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
177 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
178 |
if (copy_size == 0) return; |
179 |
FixedArray* from = FixedArray::cast(from_base); |
180 |
FixedArray* to = FixedArray::cast(to_base); |
181 |
ASSERT(IsFastSmiOrObjectElementsKind(from_kind)); |
182 |
ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); |
183 |
Address to_address = to->address() + FixedArray::kHeaderSize; |
184 |
Address from_address = from->address() + FixedArray::kHeaderSize; |
185 |
CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
|
186 |
reinterpret_cast<Object**>(from_address) + from_start,
|
187 |
static_cast<size_t>(copy_size));
|
188 |
if (IsFastObjectElementsKind(from_kind) &&
|
189 |
IsFastObjectElementsKind(to_kind)) { |
190 |
Heap* heap = from->GetHeap(); |
191 |
if (!heap->InNewSpace(to)) {
|
192 |
heap->RecordWrites(to->address(), |
193 |
to->OffsetOfElementAt(to_start), |
194 |
copy_size); |
195 |
} |
196 |
heap->incremental_marking()->RecordWrites(to); |
197 |
} |
198 |
} |
199 |
|
200 |
|
201 |
static void CopyDictionaryToObjectElements(FixedArrayBase* from_base, |
202 |
uint32_t from_start, |
203 |
FixedArrayBase* to_base, |
204 |
ElementsKind to_kind, |
205 |
uint32_t to_start, |
206 |
int raw_copy_size) {
|
207 |
SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); |
208 |
DisallowHeapAllocation no_allocation; |
209 |
int copy_size = raw_copy_size;
|
210 |
Heap* heap = from->GetHeap(); |
211 |
if (raw_copy_size < 0) { |
212 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
213 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
214 |
copy_size = from->max_number_key() + 1 - from_start;
|
215 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
216 |
int start = to_start + copy_size;
|
217 |
int length = to_base->length() - start;
|
218 |
if (length > 0) { |
219 |
Heap* heap = from->GetHeap(); |
220 |
MemsetPointer(FixedArray::cast(to_base)->data_start() + start, |
221 |
heap->the_hole_value(), length); |
222 |
} |
223 |
} |
224 |
} |
225 |
ASSERT(to_base != from_base); |
226 |
ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); |
227 |
if (copy_size == 0) return; |
228 |
FixedArray* to = FixedArray::cast(to_base); |
229 |
uint32_t to_length = to->length(); |
230 |
if (to_start + copy_size > to_length) {
|
231 |
copy_size = to_length - to_start; |
232 |
} |
233 |
for (int i = 0; i < copy_size; i++) { |
234 |
int entry = from->FindEntry(i + from_start);
|
235 |
if (entry != SeededNumberDictionary::kNotFound) {
|
236 |
Object* value = from->ValueAt(entry); |
237 |
ASSERT(!value->IsTheHole()); |
238 |
to->set(i + to_start, value, SKIP_WRITE_BARRIER); |
239 |
} else {
|
240 |
to->set_the_hole(i + to_start); |
241 |
} |
242 |
} |
243 |
if (IsFastObjectElementsKind(to_kind)) {
|
244 |
if (!heap->InNewSpace(to)) {
|
245 |
heap->RecordWrites(to->address(), |
246 |
to->OffsetOfElementAt(to_start), |
247 |
copy_size); |
248 |
} |
249 |
heap->incremental_marking()->RecordWrites(to); |
250 |
} |
251 |
} |
252 |
|
253 |
|
254 |
MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
|
255 |
FixedArrayBase* from_base, |
256 |
uint32_t from_start, |
257 |
FixedArrayBase* to_base, |
258 |
ElementsKind to_kind, |
259 |
uint32_t to_start, |
260 |
int raw_copy_size) {
|
261 |
ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); |
262 |
int copy_size = raw_copy_size;
|
263 |
if (raw_copy_size < 0) { |
264 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
265 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
266 |
copy_size = Min(from_base->length() - from_start, |
267 |
to_base->length() - to_start); |
268 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
269 |
// Also initialize the area that will be copied over since HeapNumber
|
270 |
// allocation below can cause an incremental marking step, requiring all
|
271 |
// existing heap objects to be propertly initialized.
|
272 |
int start = to_start;
|
273 |
int length = to_base->length() - start;
|
274 |
if (length > 0) { |
275 |
Heap* heap = from_base->GetHeap(); |
276 |
MemsetPointer(FixedArray::cast(to_base)->data_start() + start, |
277 |
heap->the_hole_value(), length); |
278 |
} |
279 |
} |
280 |
} |
281 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
282 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
283 |
if (copy_size == 0) return from_base; |
284 |
FixedDoubleArray* from = FixedDoubleArray::cast(from_base); |
285 |
FixedArray* to = FixedArray::cast(to_base); |
286 |
for (int i = 0; i < copy_size; ++i) { |
287 |
if (IsFastSmiElementsKind(to_kind)) {
|
288 |
UNIMPLEMENTED(); |
289 |
return Failure::Exception();
|
290 |
} else {
|
291 |
MaybeObject* maybe_value = from->get(i + from_start); |
292 |
Object* value; |
293 |
ASSERT(IsFastObjectElementsKind(to_kind)); |
294 |
// Because Double -> Object elements transitions allocate HeapObjects
|
295 |
// iteratively, the allocate must succeed within a single GC cycle,
|
296 |
// otherwise the retry after the GC will also fail. In order to ensure
|
297 |
// that no GC is triggered, allocate HeapNumbers from old space if they
|
298 |
// can't be taken from new space.
|
299 |
if (!maybe_value->ToObject(&value)) {
|
300 |
ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory()); |
301 |
Heap* heap = from->GetHeap(); |
302 |
MaybeObject* maybe_value_object = |
303 |
heap->AllocateHeapNumber(from->get_scalar(i + from_start), |
304 |
TENURED); |
305 |
if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
306 |
} |
307 |
to->set(i + to_start, value, UPDATE_WRITE_BARRIER); |
308 |
} |
309 |
} |
310 |
return to;
|
311 |
} |
312 |
|
313 |
|
314 |
static void CopyDoubleToDoubleElements(FixedArrayBase* from_base, |
315 |
uint32_t from_start, |
316 |
FixedArrayBase* to_base, |
317 |
uint32_t to_start, |
318 |
int raw_copy_size) {
|
319 |
int copy_size = raw_copy_size;
|
320 |
if (raw_copy_size < 0) { |
321 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
322 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
323 |
copy_size = Min(from_base->length() - from_start, |
324 |
to_base->length() - to_start); |
325 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
326 |
for (int i = to_start + copy_size; i < to_base->length(); ++i) { |
327 |
FixedDoubleArray::cast(to_base)->set_the_hole(i); |
328 |
} |
329 |
} |
330 |
} |
331 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
332 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
333 |
if (copy_size == 0) return; |
334 |
FixedDoubleArray* from = FixedDoubleArray::cast(from_base); |
335 |
FixedDoubleArray* to = FixedDoubleArray::cast(to_base); |
336 |
Address to_address = to->address() + FixedDoubleArray::kHeaderSize; |
337 |
Address from_address = from->address() + FixedDoubleArray::kHeaderSize; |
338 |
to_address += kDoubleSize * to_start; |
339 |
from_address += kDoubleSize * from_start; |
340 |
int words_per_double = (kDoubleSize / kPointerSize);
|
341 |
CopyWords(reinterpret_cast<Object**>(to_address),
|
342 |
reinterpret_cast<Object**>(from_address),
|
343 |
static_cast<size_t>(words_per_double * copy_size));
|
344 |
} |
345 |
|
346 |
|
347 |
static void CopySmiToDoubleElements(FixedArrayBase* from_base, |
348 |
uint32_t from_start, |
349 |
FixedArrayBase* to_base, |
350 |
uint32_t to_start, |
351 |
int raw_copy_size) {
|
352 |
int copy_size = raw_copy_size;
|
353 |
if (raw_copy_size < 0) { |
354 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
355 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
356 |
copy_size = from_base->length() - from_start; |
357 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
358 |
for (int i = to_start + copy_size; i < to_base->length(); ++i) { |
359 |
FixedDoubleArray::cast(to_base)->set_the_hole(i); |
360 |
} |
361 |
} |
362 |
} |
363 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
364 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
365 |
if (copy_size == 0) return; |
366 |
FixedArray* from = FixedArray::cast(from_base); |
367 |
FixedDoubleArray* to = FixedDoubleArray::cast(to_base); |
368 |
Object* the_hole = from->GetHeap()->the_hole_value(); |
369 |
for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size); |
370 |
from_start < from_end; from_start++, to_start++) { |
371 |
Object* hole_or_smi = from->get(from_start); |
372 |
if (hole_or_smi == the_hole) {
|
373 |
to->set_the_hole(to_start); |
374 |
} else {
|
375 |
to->set(to_start, Smi::cast(hole_or_smi)->value()); |
376 |
} |
377 |
} |
378 |
} |
379 |
|
380 |
|
381 |
static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base, |
382 |
uint32_t from_start, |
383 |
FixedArrayBase* to_base, |
384 |
uint32_t to_start, |
385 |
int packed_size,
|
386 |
int raw_copy_size) {
|
387 |
int copy_size = raw_copy_size;
|
388 |
uint32_t to_end; |
389 |
if (raw_copy_size < 0) { |
390 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
391 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
392 |
copy_size = packed_size - from_start; |
393 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
394 |
to_end = to_base->length(); |
395 |
for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
|
396 |
FixedDoubleArray::cast(to_base)->set_the_hole(i); |
397 |
} |
398 |
} else {
|
399 |
to_end = to_start + static_cast<uint32_t>(copy_size);
|
400 |
} |
401 |
} else {
|
402 |
to_end = to_start + static_cast<uint32_t>(copy_size);
|
403 |
} |
404 |
ASSERT(static_cast<int>(to_end) <= to_base->length()); |
405 |
ASSERT(packed_size >= 0 && packed_size <= copy_size);
|
406 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
407 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
408 |
if (copy_size == 0) return; |
409 |
FixedArray* from = FixedArray::cast(from_base); |
410 |
FixedDoubleArray* to = FixedDoubleArray::cast(to_base); |
411 |
for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size); |
412 |
from_start < from_end; from_start++, to_start++) { |
413 |
Object* smi = from->get(from_start); |
414 |
ASSERT(!smi->IsTheHole()); |
415 |
to->set(to_start, Smi::cast(smi)->value()); |
416 |
} |
417 |
} |
418 |
|
419 |
|
420 |
static void CopyObjectToDoubleElements(FixedArrayBase* from_base, |
421 |
uint32_t from_start, |
422 |
FixedArrayBase* to_base, |
423 |
uint32_t to_start, |
424 |
int raw_copy_size) {
|
425 |
int copy_size = raw_copy_size;
|
426 |
if (raw_copy_size < 0) { |
427 |
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || |
428 |
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
429 |
copy_size = from_base->length() - from_start; |
430 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
431 |
for (int i = to_start + copy_size; i < to_base->length(); ++i) { |
432 |
FixedDoubleArray::cast(to_base)->set_the_hole(i); |
433 |
} |
434 |
} |
435 |
} |
436 |
ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && |
437 |
(copy_size + static_cast<int>(from_start)) <= from_base->length()); |
438 |
if (copy_size == 0) return; |
439 |
FixedArray* from = FixedArray::cast(from_base); |
440 |
FixedDoubleArray* to = FixedDoubleArray::cast(to_base); |
441 |
Object* the_hole = from->GetHeap()->the_hole_value(); |
442 |
for (uint32_t from_end = from_start + copy_size;
|
443 |
from_start < from_end; from_start++, to_start++) { |
444 |
Object* hole_or_object = from->get(from_start); |
445 |
if (hole_or_object == the_hole) {
|
446 |
to->set_the_hole(to_start); |
447 |
} else {
|
448 |
to->set(to_start, hole_or_object->Number()); |
449 |
} |
450 |
} |
451 |
} |
452 |
|
453 |
|
454 |
static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, |
455 |
uint32_t from_start, |
456 |
FixedArrayBase* to_base, |
457 |
uint32_t to_start, |
458 |
int raw_copy_size) {
|
459 |
SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); |
460 |
int copy_size = raw_copy_size;
|
461 |
if (copy_size < 0) { |
462 |
ASSERT(copy_size == ElementsAccessor::kCopyToEnd || |
463 |
copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); |
464 |
copy_size = from->max_number_key() + 1 - from_start;
|
465 |
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
|
466 |
for (int i = to_start + copy_size; i < to_base->length(); ++i) { |
467 |
FixedDoubleArray::cast(to_base)->set_the_hole(i); |
468 |
} |
469 |
} |
470 |
} |
471 |
if (copy_size == 0) return; |
472 |
FixedDoubleArray* to = FixedDoubleArray::cast(to_base); |
473 |
uint32_t to_length = to->length(); |
474 |
if (to_start + copy_size > to_length) {
|
475 |
copy_size = to_length - to_start; |
476 |
} |
477 |
for (int i = 0; i < copy_size; i++) { |
478 |
int entry = from->FindEntry(i + from_start);
|
479 |
if (entry != SeededNumberDictionary::kNotFound) {
|
480 |
to->set(i + to_start, from->ValueAt(entry)->Number()); |
481 |
} else {
|
482 |
to->set_the_hole(i + to_start); |
483 |
} |
484 |
} |
485 |
} |
486 |
|
487 |
|
488 |
static void TraceTopFrame(Isolate* isolate) { |
489 |
StackFrameIterator it(isolate); |
490 |
if (it.done()) {
|
491 |
PrintF("unknown location (no JavaScript frames present)");
|
492 |
return;
|
493 |
} |
494 |
StackFrame* raw_frame = it.frame(); |
495 |
if (raw_frame->is_internal()) {
|
496 |
Code* apply_builtin = isolate->builtins()->builtin( |
497 |
Builtins::kFunctionApply); |
498 |
if (raw_frame->unchecked_code() == apply_builtin) {
|
499 |
PrintF("apply from ");
|
500 |
it.Advance(); |
501 |
raw_frame = it.frame(); |
502 |
} |
503 |
} |
504 |
JavaScriptFrame::PrintTop(isolate, stdout, false, true); |
505 |
} |
506 |
|
507 |
|
508 |
void CheckArrayAbuse(JSObject* obj, const char* op, uint32_t key, |
509 |
bool allow_appending) {
|
510 |
Object* raw_length = NULL;
|
511 |
const char* elements_type = "array"; |
512 |
if (obj->IsJSArray()) {
|
513 |
JSArray* array = JSArray::cast(obj); |
514 |
raw_length = array->length(); |
515 |
} else {
|
516 |
raw_length = Smi::FromInt(obj->elements()->length()); |
517 |
elements_type = "object";
|
518 |
} |
519 |
|
520 |
if (raw_length->IsNumber()) {
|
521 |
double n = raw_length->Number();
|
522 |
if (FastI2D(FastD2UI(n)) == n) {
|
523 |
int32_t int32_length = DoubleToInt32(n); |
524 |
uint32_t compare_length = static_cast<uint32_t>(int32_length);
|
525 |
if (allow_appending) compare_length++;
|
526 |
if (key >= compare_length) {
|
527 |
PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
|
528 |
elements_type, op, elements_type, |
529 |
static_cast<int>(int32_length), |
530 |
static_cast<int>(key)); |
531 |
TraceTopFrame(obj->GetIsolate()); |
532 |
PrintF("]\n");
|
533 |
} |
534 |
} else {
|
535 |
PrintF("[%s elements length not integer value in ", elements_type);
|
536 |
TraceTopFrame(obj->GetIsolate()); |
537 |
PrintF("]\n");
|
538 |
} |
539 |
} else {
|
540 |
PrintF("[%s elements length not a number in ", elements_type);
|
541 |
TraceTopFrame(obj->GetIsolate()); |
542 |
PrintF("]\n");
|
543 |
} |
544 |
} |
545 |
|
546 |
|
547 |
// Base class for element handler implementations. Contains the
|
548 |
// the common logic for objects with different ElementsKinds.
|
549 |
// Subclasses must specialize method for which the element
|
550 |
// implementation differs from the base class implementation.
|
551 |
//
|
552 |
// This class is intended to be used in the following way:
|
553 |
//
|
554 |
// class SomeElementsAccessor :
|
555 |
// public ElementsAccessorBase<SomeElementsAccessor,
|
556 |
// BackingStoreClass> {
|
557 |
// ...
|
558 |
// }
|
559 |
//
|
560 |
// This is an example of the Curiously Recurring Template Pattern (see
|
561 |
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
|
562 |
// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
|
563 |
// specialization of SomeElementsAccessor methods).
|
564 |
template <typename ElementsAccessorSubclass, |
565 |
typename ElementsTraitsParam>
|
566 |
class ElementsAccessorBase : public ElementsAccessor { |
567 |
protected:
|
568 |
explicit ElementsAccessorBase(const char* name) |
569 |
: ElementsAccessor(name) { } |
570 |
|
571 |
typedef ElementsTraitsParam ElementsTraits;
|
572 |
typedef typename ElementsTraitsParam::BackingStore BackingStore; |
573 |
|
574 |
virtual ElementsKind kind() const { return ElementsTraits::Kind; } |
575 |
|
576 |
static void ValidateContents(JSObject* holder, int length) { |
577 |
} |
578 |
|
579 |
static void ValidateImpl(JSObject* holder) { |
580 |
FixedArrayBase* fixed_array_base = holder->elements(); |
581 |
// When objects are first allocated, its elements are Failures.
|
582 |
if (fixed_array_base->IsFailure()) return; |
583 |
if (!fixed_array_base->IsHeapObject()) return; |
584 |
// Arrays that have been shifted in place can't be verified.
|
585 |
if (fixed_array_base->IsFiller()) return; |
586 |
int length = 0; |
587 |
if (holder->IsJSArray()) {
|
588 |
Object* length_obj = JSArray::cast(holder)->length(); |
589 |
if (length_obj->IsSmi()) {
|
590 |
length = Smi::cast(length_obj)->value(); |
591 |
} |
592 |
} else {
|
593 |
length = fixed_array_base->length(); |
594 |
} |
595 |
ElementsAccessorSubclass::ValidateContents(holder, length); |
596 |
} |
597 |
|
598 |
virtual void Validate(JSObject* holder) { |
599 |
ElementsAccessorSubclass::ValidateImpl(holder); |
600 |
} |
601 |
|
602 |
static bool HasElementImpl(Object* receiver, |
603 |
JSObject* holder, |
604 |
uint32_t key, |
605 |
FixedArrayBase* backing_store) { |
606 |
return ElementsAccessorSubclass::GetAttributesImpl(
|
607 |
receiver, holder, key, backing_store) != ABSENT; |
608 |
} |
609 |
|
610 |
virtual bool HasElement(Object* receiver, |
611 |
JSObject* holder, |
612 |
uint32_t key, |
613 |
FixedArrayBase* backing_store) { |
614 |
if (backing_store == NULL) { |
615 |
backing_store = holder->elements(); |
616 |
} |
617 |
return ElementsAccessorSubclass::HasElementImpl(
|
618 |
receiver, holder, key, backing_store); |
619 |
} |
620 |
|
621 |
MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
|
622 |
JSObject* holder, |
623 |
uint32_t key, |
624 |
FixedArrayBase* backing_store) { |
625 |
if (backing_store == NULL) { |
626 |
backing_store = holder->elements(); |
627 |
} |
628 |
|
629 |
if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
|
630 |
FLAG_trace_js_array_abuse) { |
631 |
CheckArrayAbuse(holder, "elements read", key);
|
632 |
} |
633 |
|
634 |
if (IsExternalArrayElementsKind(ElementsTraits::Kind) &&
|
635 |
FLAG_trace_external_array_abuse) { |
636 |
CheckArrayAbuse(holder, "external elements read", key);
|
637 |
} |
638 |
|
639 |
return ElementsAccessorSubclass::GetImpl(
|
640 |
receiver, holder, key, backing_store); |
641 |
} |
642 |
|
643 |
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
|
644 |
JSObject* obj, |
645 |
uint32_t key, |
646 |
FixedArrayBase* backing_store) { |
647 |
return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
|
648 |
? BackingStore::cast(backing_store)->get(key) |
649 |
: backing_store->GetHeap()->the_hole_value(); |
650 |
} |
651 |
|
652 |
MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
|
653 |
Object* receiver, |
654 |
JSObject* holder, |
655 |
uint32_t key, |
656 |
FixedArrayBase* backing_store) { |
657 |
if (backing_store == NULL) { |
658 |
backing_store = holder->elements(); |
659 |
} |
660 |
return ElementsAccessorSubclass::GetAttributesImpl(
|
661 |
receiver, holder, key, backing_store); |
662 |
} |
663 |
|
664 |
MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
|
665 |
Object* receiver, |
666 |
JSObject* obj, |
667 |
uint32_t key, |
668 |
FixedArrayBase* backing_store) { |
669 |
if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
|
670 |
return ABSENT;
|
671 |
} |
672 |
return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE;
|
673 |
} |
674 |
|
675 |
MUST_USE_RESULT virtual PropertyType GetType(
|
676 |
Object* receiver, |
677 |
JSObject* holder, |
678 |
uint32_t key, |
679 |
FixedArrayBase* backing_store) { |
680 |
if (backing_store == NULL) { |
681 |
backing_store = holder->elements(); |
682 |
} |
683 |
return ElementsAccessorSubclass::GetTypeImpl(
|
684 |
receiver, holder, key, backing_store); |
685 |
} |
686 |
|
687 |
MUST_USE_RESULT static PropertyType GetTypeImpl(
|
688 |
Object* receiver, |
689 |
JSObject* obj, |
690 |
uint32_t key, |
691 |
FixedArrayBase* backing_store) { |
692 |
if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
|
693 |
return NONEXISTENT;
|
694 |
} |
695 |
return BackingStore::cast(backing_store)->is_the_hole(key)
|
696 |
? NONEXISTENT : FIELD; |
697 |
} |
698 |
|
699 |
MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
|
700 |
Object* receiver, |
701 |
JSObject* holder, |
702 |
uint32_t key, |
703 |
FixedArrayBase* backing_store) { |
704 |
if (backing_store == NULL) { |
705 |
backing_store = holder->elements(); |
706 |
} |
707 |
return ElementsAccessorSubclass::GetAccessorPairImpl(
|
708 |
receiver, holder, key, backing_store); |
709 |
} |
710 |
|
711 |
MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
|
712 |
Object* receiver, |
713 |
JSObject* obj, |
714 |
uint32_t key, |
715 |
FixedArrayBase* backing_store) { |
716 |
return NULL; |
717 |
} |
718 |
|
719 |
MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
|
720 |
Object* length) { |
721 |
return ElementsAccessorSubclass::SetLengthImpl(
|
722 |
array, length, array->elements()); |
723 |
} |
724 |
|
725 |
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
|
726 |
JSObject* obj, |
727 |
Object* length, |
728 |
FixedArrayBase* backing_store); |
729 |
|
730 |
MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
|
731 |
JSArray* array, |
732 |
int capacity,
|
733 |
int length) {
|
734 |
return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
|
735 |
array, |
736 |
capacity, |
737 |
length); |
738 |
} |
739 |
|
740 |
MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
|
741 |
JSObject* obj, |
742 |
int capacity,
|
743 |
int length) {
|
744 |
UNIMPLEMENTED(); |
745 |
return obj;
|
746 |
} |
747 |
|
748 |
MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
|
749 |
uint32_t key, |
750 |
JSReceiver::DeleteMode mode) = 0;
|
751 |
|
752 |
MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
|
753 |
uint32_t from_start, |
754 |
FixedArrayBase* to, |
755 |
ElementsKind from_kind, |
756 |
uint32_t to_start, |
757 |
int packed_size,
|
758 |
int copy_size) {
|
759 |
UNREACHABLE(); |
760 |
return NULL; |
761 |
} |
762 |
|
763 |
MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder,
|
764 |
uint32_t from_start, |
765 |
ElementsKind from_kind, |
766 |
FixedArrayBase* to, |
767 |
uint32_t to_start, |
768 |
int copy_size,
|
769 |
FixedArrayBase* from) { |
770 |
int packed_size = kPackedSizeNotKnown;
|
771 |
if (from == NULL) { |
772 |
from = from_holder->elements(); |
773 |
} |
774 |
|
775 |
if (from_holder) {
|
776 |
bool is_packed = IsFastPackedElementsKind(from_kind) &&
|
777 |
from_holder->IsJSArray(); |
778 |
if (is_packed) {
|
779 |
packed_size = Smi::cast(JSArray::cast(from_holder)->length())->value(); |
780 |
if (copy_size >= 0 && packed_size > copy_size) { |
781 |
packed_size = copy_size; |
782 |
} |
783 |
} |
784 |
} |
785 |
return ElementsAccessorSubclass::CopyElementsImpl(
|
786 |
from, from_start, to, from_kind, to_start, packed_size, copy_size); |
787 |
} |
788 |
|
789 |
MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
|
790 |
Object* receiver, |
791 |
JSObject* holder, |
792 |
FixedArray* to, |
793 |
FixedArrayBase* from) { |
794 |
int len0 = to->length();
|
795 |
#ifdef ENABLE_SLOW_ASSERTS
|
796 |
if (FLAG_enable_slow_asserts) {
|
797 |
for (int i = 0; i < len0; i++) { |
798 |
ASSERT(!to->get(i)->IsTheHole()); |
799 |
} |
800 |
} |
801 |
#endif
|
802 |
if (from == NULL) { |
803 |
from = holder->elements(); |
804 |
} |
805 |
|
806 |
// Optimize if 'other' is empty.
|
807 |
// We cannot optimize if 'this' is empty, as other may have holes.
|
808 |
uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from); |
809 |
if (len1 == 0) return to; |
810 |
|
811 |
// Compute how many elements are not in other.
|
812 |
uint32_t extra = 0;
|
813 |
for (uint32_t y = 0; y < len1; y++) { |
814 |
uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); |
815 |
if (ElementsAccessorSubclass::HasElementImpl(
|
816 |
receiver, holder, key, from)) { |
817 |
MaybeObject* maybe_value = |
818 |
ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); |
819 |
Object* value; |
820 |
if (!maybe_value->To(&value)) return maybe_value; |
821 |
ASSERT(!value->IsTheHole()); |
822 |
if (!HasKey(to, value)) {
|
823 |
extra++; |
824 |
} |
825 |
} |
826 |
} |
827 |
|
828 |
if (extra == 0) return to; |
829 |
|
830 |
// Allocate the result
|
831 |
FixedArray* result; |
832 |
MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra); |
833 |
if (!maybe_obj->To(&result)) return maybe_obj; |
834 |
|
835 |
// Fill in the content
|
836 |
{ |
837 |
DisallowHeapAllocation no_gc; |
838 |
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); |
839 |
for (int i = 0; i < len0; i++) { |
840 |
Object* e = to->get(i); |
841 |
ASSERT(e->IsString() || e->IsNumber()); |
842 |
result->set(i, e, mode); |
843 |
} |
844 |
} |
845 |
// Fill in the extra values.
|
846 |
uint32_t index = 0;
|
847 |
for (uint32_t y = 0; y < len1; y++) { |
848 |
uint32_t key = |
849 |
ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); |
850 |
if (ElementsAccessorSubclass::HasElementImpl(
|
851 |
receiver, holder, key, from)) { |
852 |
MaybeObject* maybe_value = |
853 |
ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); |
854 |
Object* value; |
855 |
if (!maybe_value->To(&value)) return maybe_value; |
856 |
if (!value->IsTheHole() && !HasKey(to, value)) {
|
857 |
result->set(len0 + index, value); |
858 |
index++; |
859 |
} |
860 |
} |
861 |
} |
862 |
ASSERT(extra == index); |
863 |
return result;
|
864 |
} |
865 |
|
866 |
protected:
|
867 |
static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
|
868 |
return backing_store->length();
|
869 |
} |
870 |
|
871 |
virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
|
872 |
return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
|
873 |
} |
874 |
|
875 |
static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
|
876 |
uint32_t index) { |
877 |
return index;
|
878 |
} |
879 |
|
880 |
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
|
881 |
uint32_t index) { |
882 |
return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
|
883 |
} |
884 |
|
885 |
private:
|
886 |
DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); |
887 |
}; |
888 |
|
889 |
|
890 |
// Super class for all fast element arrays.
|
891 |
template<typename FastElementsAccessorSubclass, |
892 |
typename KindTraits,
|
893 |
int ElementSize>
|
894 |
class FastElementsAccessor |
895 |
: public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
|
896 |
public:
|
897 |
explicit FastElementsAccessor(const char* name) |
898 |
: ElementsAccessorBase<FastElementsAccessorSubclass, |
899 |
KindTraits>(name) {} |
900 |
protected:
|
901 |
friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>; |
902 |
friend class NonStrictArgumentsElementsAccessor; |
903 |
|
904 |
typedef typename KindTraits::BackingStore BackingStore; |
905 |
|
906 |
// Adjusts the length of the fast backing store or returns the new length or
|
907 |
// undefined in case conversion to a slow backing store should be performed.
|
908 |
static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
|
909 |
JSArray* array, |
910 |
Object* length_object, |
911 |
uint32_t length) { |
912 |
uint32_t old_capacity = backing_store->length(); |
913 |
Object* old_length = array->length(); |
914 |
bool same_or_smaller_size = old_length->IsSmi() &&
|
915 |
static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length;
|
916 |
ElementsKind kind = array->GetElementsKind(); |
917 |
|
918 |
if (!same_or_smaller_size && IsFastElementsKind(kind) &&
|
919 |
!IsFastHoleyElementsKind(kind)) { |
920 |
kind = GetHoleyElementsKind(kind); |
921 |
MaybeObject* maybe_obj = array->TransitionElementsKind(kind); |
922 |
if (maybe_obj->IsFailure()) return maybe_obj; |
923 |
} |
924 |
|
925 |
// Check whether the backing store should be shrunk.
|
926 |
if (length <= old_capacity) {
|
927 |
if (array->HasFastSmiOrObjectElements()) {
|
928 |
MaybeObject* maybe_obj = array->EnsureWritableFastElements(); |
929 |
if (!maybe_obj->To(&backing_store)) return maybe_obj; |
930 |
} |
931 |
if (2 * length <= old_capacity) { |
932 |
// If more than half the elements won't be used, trim the array.
|
933 |
if (length == 0) { |
934 |
array->initialize_elements(); |
935 |
} else {
|
936 |
backing_store->set_length(length); |
937 |
Address filler_start = backing_store->address() + |
938 |
BackingStore::OffsetOfElementAt(length); |
939 |
int filler_size = (old_capacity - length) * ElementSize;
|
940 |
array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size); |
941 |
} |
942 |
} else {
|
943 |
// Otherwise, fill the unused tail with holes.
|
944 |
int old_length = FastD2IChecked(array->length()->Number());
|
945 |
for (int i = length; i < old_length; i++) { |
946 |
BackingStore::cast(backing_store)->set_the_hole(i); |
947 |
} |
948 |
} |
949 |
return length_object;
|
950 |
} |
951 |
|
952 |
// Check whether the backing store should be expanded.
|
953 |
uint32_t min = JSObject::NewElementsCapacity(old_capacity); |
954 |
uint32_t new_capacity = length > min ? length : min; |
955 |
if (!array->ShouldConvertToSlowElements(new_capacity)) {
|
956 |
MaybeObject* result = FastElementsAccessorSubclass:: |
957 |
SetFastElementsCapacityAndLength(array, new_capacity, length); |
958 |
if (result->IsFailure()) return result; |
959 |
array->ValidateElements(); |
960 |
return length_object;
|
961 |
} |
962 |
|
963 |
// Request conversion to slow elements.
|
964 |
return array->GetHeap()->undefined_value();
|
965 |
} |
966 |
|
967 |
static MaybeObject* DeleteCommon(JSObject* obj,
|
968 |
uint32_t key, |
969 |
JSReceiver::DeleteMode mode) { |
970 |
ASSERT(obj->HasFastSmiOrObjectElements() || |
971 |
obj->HasFastDoubleElements() || |
972 |
obj->HasFastArgumentsElements()); |
973 |
Heap* heap = obj->GetHeap(); |
974 |
Object* elements = obj->elements(); |
975 |
if (elements == heap->empty_fixed_array()) {
|
976 |
return heap->true_value();
|
977 |
} |
978 |
typename KindTraits::BackingStore* backing_store =
|
979 |
KindTraits::BackingStore::cast(elements); |
980 |
bool is_non_strict_arguments_elements_map =
|
981 |
backing_store->map() == heap->non_strict_arguments_elements_map(); |
982 |
if (is_non_strict_arguments_elements_map) {
|
983 |
backing_store = KindTraits::BackingStore::cast( |
984 |
FixedArray::cast(backing_store)->get(1));
|
985 |
} |
986 |
uint32_t length = static_cast<uint32_t>(
|
987 |
obj->IsJSArray() |
988 |
? Smi::cast(JSArray::cast(obj)->length())->value() |
989 |
: backing_store->length()); |
990 |
if (key < length) {
|
991 |
if (!is_non_strict_arguments_elements_map) {
|
992 |
ElementsKind kind = KindTraits::Kind; |
993 |
if (IsFastPackedElementsKind(kind)) {
|
994 |
MaybeObject* transitioned = |
995 |
obj->TransitionElementsKind(GetHoleyElementsKind(kind)); |
996 |
if (transitioned->IsFailure()) return transitioned; |
997 |
} |
998 |
if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
|
999 |
Object* writable; |
1000 |
MaybeObject* maybe = obj->EnsureWritableFastElements(); |
1001 |
if (!maybe->ToObject(&writable)) return maybe; |
1002 |
backing_store = KindTraits::BackingStore::cast(writable); |
1003 |
} |
1004 |
} |
1005 |
backing_store->set_the_hole(key); |
1006 |
// If an old space backing store is larger than a certain size and
|
1007 |
// has too few used values, normalize it.
|
1008 |
// To avoid doing the check on every delete we require at least
|
1009 |
// one adjacent hole to the value being deleted.
|
1010 |
const int kMinLengthForSparsenessCheck = 64; |
1011 |
if (backing_store->length() >= kMinLengthForSparsenessCheck &&
|
1012 |
!heap->InNewSpace(backing_store) && |
1013 |
((key > 0 && backing_store->is_the_hole(key - 1)) || |
1014 |
(key + 1 < length && backing_store->is_the_hole(key + 1)))) { |
1015 |
int num_used = 0; |
1016 |
for (int i = 0; i < backing_store->length(); ++i) { |
1017 |
if (!backing_store->is_the_hole(i)) ++num_used;
|
1018 |
// Bail out early if more than 1/4 is used.
|
1019 |
if (4 * num_used > backing_store->length()) break; |
1020 |
} |
1021 |
if (4 * num_used <= backing_store->length()) { |
1022 |
MaybeObject* result = obj->NormalizeElements(); |
1023 |
if (result->IsFailure()) return result; |
1024 |
} |
1025 |
} |
1026 |
} |
1027 |
return heap->true_value();
|
1028 |
} |
1029 |
|
1030 |
virtual MaybeObject* Delete(JSObject* obj,
|
1031 |
uint32_t key, |
1032 |
JSReceiver::DeleteMode mode) { |
1033 |
return DeleteCommon(obj, key, mode);
|
1034 |
} |
1035 |
|
1036 |
static bool HasElementImpl( |
1037 |
Object* receiver, |
1038 |
JSObject* holder, |
1039 |
uint32_t key, |
1040 |
FixedArrayBase* backing_store) { |
1041 |
if (key >= static_cast<uint32_t>(backing_store->length())) { |
1042 |
return false; |
1043 |
} |
1044 |
return !BackingStore::cast(backing_store)->is_the_hole(key);
|
1045 |
} |
1046 |
|
1047 |
static void ValidateContents(JSObject* holder, int length) { |
1048 |
#if DEBUG
|
1049 |
FixedArrayBase* elements = holder->elements(); |
1050 |
Heap* heap = elements->GetHeap(); |
1051 |
Map* map = elements->map(); |
1052 |
ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) && |
1053 |
(map == heap->fixed_array_map() || |
1054 |
map == heap->fixed_cow_array_map())) || |
1055 |
(IsFastDoubleElementsKind(KindTraits::Kind) == |
1056 |
((map == heap->fixed_array_map() && length == 0) ||
|
1057 |
map == heap->fixed_double_array_map()))); |
1058 |
for (int i = 0; i < length; i++) { |
1059 |
typename KindTraits::BackingStore* backing_store =
|
1060 |
KindTraits::BackingStore::cast(elements); |
1061 |
ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) || |
1062 |
static_cast<Object*>(backing_store->get(i))->IsSmi()) ||
|
1063 |
(IsFastHoleyElementsKind(KindTraits::Kind) == |
1064 |
backing_store->is_the_hole(i))); |
1065 |
} |
1066 |
#endif
|
1067 |
} |
1068 |
}; |
1069 |
|
1070 |
|
1071 |
static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) { |
1072 |
switch (array->map()->instance_type()) {
|
1073 |
case FIXED_ARRAY_TYPE:
|
1074 |
if (array->IsDictionary()) {
|
1075 |
return DICTIONARY_ELEMENTS;
|
1076 |
} else {
|
1077 |
return FAST_HOLEY_ELEMENTS;
|
1078 |
} |
1079 |
case FIXED_DOUBLE_ARRAY_TYPE:
|
1080 |
return FAST_HOLEY_DOUBLE_ELEMENTS;
|
1081 |
case EXTERNAL_BYTE_ARRAY_TYPE:
|
1082 |
return EXTERNAL_BYTE_ELEMENTS;
|
1083 |
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
|
1084 |
return EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
|
1085 |
case EXTERNAL_SHORT_ARRAY_TYPE:
|
1086 |
return EXTERNAL_SHORT_ELEMENTS;
|
1087 |
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
|
1088 |
return EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
|
1089 |
case EXTERNAL_INT_ARRAY_TYPE:
|
1090 |
return EXTERNAL_INT_ELEMENTS;
|
1091 |
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
|
1092 |
return EXTERNAL_UNSIGNED_INT_ELEMENTS;
|
1093 |
case EXTERNAL_FLOAT_ARRAY_TYPE:
|
1094 |
return EXTERNAL_FLOAT_ELEMENTS;
|
1095 |
case EXTERNAL_DOUBLE_ARRAY_TYPE:
|
1096 |
return EXTERNAL_DOUBLE_ELEMENTS;
|
1097 |
case EXTERNAL_PIXEL_ARRAY_TYPE:
|
1098 |
return EXTERNAL_PIXEL_ELEMENTS;
|
1099 |
default:
|
1100 |
UNREACHABLE(); |
1101 |
} |
1102 |
return FAST_HOLEY_ELEMENTS;
|
1103 |
} |
1104 |
|
1105 |
|
1106 |
template<typename FastElementsAccessorSubclass, |
1107 |
typename KindTraits>
|
1108 |
class FastSmiOrObjectElementsAccessor |
1109 |
: public FastElementsAccessor<FastElementsAccessorSubclass,
|
1110 |
KindTraits, |
1111 |
kPointerSize> { |
1112 |
public:
|
1113 |
explicit FastSmiOrObjectElementsAccessor(const char* name) |
1114 |
: FastElementsAccessor<FastElementsAccessorSubclass, |
1115 |
KindTraits, |
1116 |
kPointerSize>(name) {} |
1117 |
|
1118 |
static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
|
1119 |
uint32_t from_start, |
1120 |
FixedArrayBase* to, |
1121 |
ElementsKind from_kind, |
1122 |
uint32_t to_start, |
1123 |
int packed_size,
|
1124 |
int copy_size) {
|
1125 |
ElementsKind to_kind = KindTraits::Kind; |
1126 |
switch (from_kind) {
|
1127 |
case FAST_SMI_ELEMENTS:
|
1128 |
case FAST_HOLEY_SMI_ELEMENTS:
|
1129 |
case FAST_ELEMENTS:
|
1130 |
case FAST_HOLEY_ELEMENTS:
|
1131 |
CopyObjectToObjectElements( |
1132 |
from, from_kind, from_start, to, to_kind, to_start, copy_size); |
1133 |
return to->GetHeap()->undefined_value();
|
1134 |
case FAST_DOUBLE_ELEMENTS:
|
1135 |
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
1136 |
return CopyDoubleToObjectElements(
|
1137 |
from, from_start, to, to_kind, to_start, copy_size); |
1138 |
case DICTIONARY_ELEMENTS:
|
1139 |
CopyDictionaryToObjectElements( |
1140 |
from, from_start, to, to_kind, to_start, copy_size); |
1141 |
return to->GetHeap()->undefined_value();
|
1142 |
case NON_STRICT_ARGUMENTS_ELEMENTS: {
|
1143 |
// TODO(verwaest): This is a temporary hack to support extending
|
1144 |
// NON_STRICT_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
|
1145 |
// This case should be UNREACHABLE().
|
1146 |
FixedArray* parameter_map = FixedArray::cast(from); |
1147 |
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
|
1148 |
ElementsKind from_kind = ElementsKindForArray(arguments); |
1149 |
return CopyElementsImpl(arguments, from_start, to, from_kind,
|
1150 |
to_start, packed_size, copy_size); |
1151 |
} |
1152 |
case EXTERNAL_BYTE_ELEMENTS:
|
1153 |
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
1154 |
case EXTERNAL_SHORT_ELEMENTS:
|
1155 |
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
1156 |
case EXTERNAL_INT_ELEMENTS:
|
1157 |
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
1158 |
case EXTERNAL_FLOAT_ELEMENTS:
|
1159 |
case EXTERNAL_DOUBLE_ELEMENTS:
|
1160 |
case EXTERNAL_PIXEL_ELEMENTS:
|
1161 |
UNREACHABLE(); |
1162 |
} |
1163 |
return NULL; |
1164 |
} |
1165 |
|
1166 |
|
1167 |
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
|
1168 |
uint32_t capacity, |
1169 |
uint32_t length) { |
1170 |
JSObject::SetFastElementsCapacitySmiMode set_capacity_mode = |
1171 |
obj->HasFastSmiElements() |
1172 |
? JSObject::kAllowSmiElements |
1173 |
: JSObject::kDontAllowSmiElements; |
1174 |
return obj->SetFastElementsCapacityAndLength(capacity,
|
1175 |
length, |
1176 |
set_capacity_mode); |
1177 |
} |
1178 |
}; |
1179 |
|
1180 |
|
1181 |
class FastPackedSmiElementsAccessor |
1182 |
: public FastSmiOrObjectElementsAccessor<
|
1183 |
FastPackedSmiElementsAccessor, |
1184 |
ElementsKindTraits<FAST_SMI_ELEMENTS> > { |
1185 |
public:
|
1186 |
explicit FastPackedSmiElementsAccessor(const char* name) |
1187 |
: FastSmiOrObjectElementsAccessor< |
1188 |
FastPackedSmiElementsAccessor, |
1189 |
ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {} |
1190 |
}; |
1191 |
|
1192 |
|
1193 |
class FastHoleySmiElementsAccessor |
1194 |
: public FastSmiOrObjectElementsAccessor<
|
1195 |
FastHoleySmiElementsAccessor, |
1196 |
ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > { |
1197 |
public:
|
1198 |
explicit FastHoleySmiElementsAccessor(const char* name) |
1199 |
: FastSmiOrObjectElementsAccessor< |
1200 |
FastHoleySmiElementsAccessor, |
1201 |
ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {} |
1202 |
}; |
1203 |
|
1204 |
|
1205 |
class FastPackedObjectElementsAccessor |
1206 |
: public FastSmiOrObjectElementsAccessor<
|
1207 |
FastPackedObjectElementsAccessor, |
1208 |
ElementsKindTraits<FAST_ELEMENTS> > { |
1209 |
public:
|
1210 |
explicit FastPackedObjectElementsAccessor(const char* name) |
1211 |
: FastSmiOrObjectElementsAccessor< |
1212 |
FastPackedObjectElementsAccessor, |
1213 |
ElementsKindTraits<FAST_ELEMENTS> >(name) {} |
1214 |
}; |
1215 |
|
1216 |
|
1217 |
class FastHoleyObjectElementsAccessor |
1218 |
: public FastSmiOrObjectElementsAccessor<
|
1219 |
FastHoleyObjectElementsAccessor, |
1220 |
ElementsKindTraits<FAST_HOLEY_ELEMENTS> > { |
1221 |
public:
|
1222 |
explicit FastHoleyObjectElementsAccessor(const char* name) |
1223 |
: FastSmiOrObjectElementsAccessor< |
1224 |
FastHoleyObjectElementsAccessor, |
1225 |
ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {} |
1226 |
}; |
1227 |
|
1228 |
|
1229 |
template<typename FastElementsAccessorSubclass, |
1230 |
typename KindTraits>
|
1231 |
class FastDoubleElementsAccessor |
1232 |
: public FastElementsAccessor<FastElementsAccessorSubclass,
|
1233 |
KindTraits, |
1234 |
kDoubleSize> { |
1235 |
public:
|
1236 |
explicit FastDoubleElementsAccessor(const char* name) |
1237 |
: FastElementsAccessor<FastElementsAccessorSubclass, |
1238 |
KindTraits, |
1239 |
kDoubleSize>(name) {} |
1240 |
|
1241 |
static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
|
1242 |
uint32_t capacity, |
1243 |
uint32_t length) { |
1244 |
return obj->SetFastDoubleElementsCapacityAndLength(capacity,
|
1245 |
length); |
1246 |
} |
1247 |
|
1248 |
protected:
|
1249 |
static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
|
1250 |
uint32_t from_start, |
1251 |
FixedArrayBase* to, |
1252 |
ElementsKind from_kind, |
1253 |
uint32_t to_start, |
1254 |
int packed_size,
|
1255 |
int copy_size) {
|
1256 |
switch (from_kind) {
|
1257 |
case FAST_SMI_ELEMENTS:
|
1258 |
CopyPackedSmiToDoubleElements( |
1259 |
from, from_start, to, to_start, packed_size, copy_size); |
1260 |
break;
|
1261 |
case FAST_HOLEY_SMI_ELEMENTS:
|
1262 |
CopySmiToDoubleElements(from, from_start, to, to_start, copy_size); |
1263 |
break;
|
1264 |
case FAST_DOUBLE_ELEMENTS:
|
1265 |
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
1266 |
CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size); |
1267 |
break;
|
1268 |
case FAST_ELEMENTS:
|
1269 |
case FAST_HOLEY_ELEMENTS:
|
1270 |
CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size); |
1271 |
break;
|
1272 |
case DICTIONARY_ELEMENTS:
|
1273 |
CopyDictionaryToDoubleElements( |
1274 |
from, from_start, to, to_start, copy_size); |
1275 |
break;
|
1276 |
case NON_STRICT_ARGUMENTS_ELEMENTS:
|
1277 |
case EXTERNAL_BYTE_ELEMENTS:
|
1278 |
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
1279 |
case EXTERNAL_SHORT_ELEMENTS:
|
1280 |
case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
|
1281 |
case EXTERNAL_INT_ELEMENTS:
|
1282 |
case EXTERNAL_UNSIGNED_INT_ELEMENTS:
|
1283 |
case EXTERNAL_FLOAT_ELEMENTS:
|
1284 |
case EXTERNAL_DOUBLE_ELEMENTS:
|
1285 |
case EXTERNAL_PIXEL_ELEMENTS:
|
1286 |
UNREACHABLE(); |
1287 |
} |
1288 |
return to->GetHeap()->undefined_value();
|
1289 |
} |
1290 |
}; |
1291 |
|
1292 |
|
1293 |
class FastPackedDoubleElementsAccessor |
1294 |
: public FastDoubleElementsAccessor<
|
1295 |
FastPackedDoubleElementsAccessor, |
1296 |
ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > { |
1297 |
public:
|
1298 |
friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor, |
1299 |
ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >; |
1300 |
explicit FastPackedDoubleElementsAccessor(const char* name) |
1301 |
: FastDoubleElementsAccessor< |
1302 |
FastPackedDoubleElementsAccessor, |
1303 |
ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {} |
1304 |
}; |
1305 |
|
1306 |
|
1307 |
class FastHoleyDoubleElementsAccessor |
1308 |
: public FastDoubleElementsAccessor<
|
1309 |
FastHoleyDoubleElementsAccessor, |
1310 |
ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > { |
1311 |
public:
|
1312 |
friend class ElementsAccessorBase< |
1313 |
FastHoleyDoubleElementsAccessor, |
1314 |
ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >; |
1315 |
explicit FastHoleyDoubleElementsAccessor(const char* name) |
1316 |
: FastDoubleElementsAccessor< |
1317 |
FastHoleyDoubleElementsAccessor, |
1318 |
ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {} |
1319 |
}; |
1320 |
|
1321 |
|
1322 |
// Super class for all external element arrays.
|
1323 |
template<typename ExternalElementsAccessorSubclass, |
1324 |
ElementsKind Kind> |
1325 |
class ExternalElementsAccessor |
1326 |
: public ElementsAccessorBase<ExternalElementsAccessorSubclass,
|
1327 |
ElementsKindTraits<Kind> > { |
1328 |
public:
|
1329 |
explicit ExternalElementsAccessor(const char* name) |
1330 |
: ElementsAccessorBase<ExternalElementsAccessorSubclass, |
1331 |
ElementsKindTraits<Kind> >(name) {} |
1332 |
|
1333 |
protected:
|
1334 |
typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore; |
1335 |
|
1336 |
friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, |
1337 |
ElementsKindTraits<Kind> >; |
1338 |
|
1339 |
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
|
1340 |
JSObject* obj, |
1341 |
uint32_t key, |
1342 |
FixedArrayBase* backing_store) { |
1343 |
return
|
1344 |
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) |
1345 |
? BackingStore::cast(backing_store)->get(key) |
1346 |
: backing_store->GetHeap()->undefined_value(); |
1347 |
} |
1348 |
|
1349 |
MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
|
1350 |
Object* receiver, |
1351 |
JSObject* obj, |
1352 |
uint32_t key, |
1353 |
FixedArrayBase* backing_store) { |
1354 |
return
|
1355 |
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) |
1356 |
? NONE : ABSENT; |
1357 |
} |
1358 |
|
1359 |
MUST_USE_RESULT static PropertyType GetTypeImpl(
|
1360 |
Object* receiver, |
1361 |
JSObject* obj, |
1362 |
uint32_t key, |
1363 |
FixedArrayBase* backing_store) { |
1364 |
return
|
1365 |
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) |
1366 |
? FIELD : NONEXISTENT; |
1367 |
} |
1368 |
|
1369 |
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
|
1370 |
JSObject* obj, |
1371 |
Object* length, |
1372 |
FixedArrayBase* backing_store) { |
1373 |
// External arrays do not support changing their length.
|
1374 |
UNREACHABLE(); |
1375 |
return obj;
|
1376 |
} |
1377 |
|
1378 |
MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
|
1379 |
uint32_t key, |
1380 |
JSReceiver::DeleteMode mode) { |
1381 |
// External arrays always ignore deletes.
|
1382 |
return obj->GetHeap()->true_value();
|
1383 |
} |
1384 |
|
1385 |
static bool HasElementImpl(Object* receiver, |
1386 |
JSObject* holder, |
1387 |
uint32_t key, |
1388 |
FixedArrayBase* backing_store) { |
1389 |
uint32_t capacity = |
1390 |
ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store); |
1391 |
return key < capacity;
|
1392 |
} |
1393 |
}; |
1394 |
|
1395 |
|
1396 |
class ExternalByteElementsAccessor |
1397 |
: public ExternalElementsAccessor<ExternalByteElementsAccessor,
|
1398 |
EXTERNAL_BYTE_ELEMENTS> { |
1399 |
public:
|
1400 |
explicit ExternalByteElementsAccessor(const char* name) |
1401 |
: ExternalElementsAccessor<ExternalByteElementsAccessor, |
1402 |
EXTERNAL_BYTE_ELEMENTS>(name) {} |
1403 |
}; |
1404 |
|
1405 |
|
1406 |
class ExternalUnsignedByteElementsAccessor |
1407 |
: public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
|
1408 |
EXTERNAL_UNSIGNED_BYTE_ELEMENTS> { |
1409 |
public:
|
1410 |
explicit ExternalUnsignedByteElementsAccessor(const char* name) |
1411 |
: ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, |
1412 |
EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {} |
1413 |
}; |
1414 |
|
1415 |
|
1416 |
class ExternalShortElementsAccessor |
1417 |
: public ExternalElementsAccessor<ExternalShortElementsAccessor,
|
1418 |
EXTERNAL_SHORT_ELEMENTS> { |
1419 |
public:
|
1420 |
explicit ExternalShortElementsAccessor(const char* name) |
1421 |
: ExternalElementsAccessor<ExternalShortElementsAccessor, |
1422 |
EXTERNAL_SHORT_ELEMENTS>(name) {} |
1423 |
}; |
1424 |
|
1425 |
|
1426 |
class ExternalUnsignedShortElementsAccessor |
1427 |
: public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
|
1428 |
EXTERNAL_UNSIGNED_SHORT_ELEMENTS> { |
1429 |
public:
|
1430 |
explicit ExternalUnsignedShortElementsAccessor(const char* name) |
1431 |
: ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, |
1432 |
EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {} |
1433 |
}; |
1434 |
|
1435 |
|
1436 |
class ExternalIntElementsAccessor |
1437 |
: public ExternalElementsAccessor<ExternalIntElementsAccessor,
|
1438 |
EXTERNAL_INT_ELEMENTS> { |
1439 |
public:
|
1440 |
explicit ExternalIntElementsAccessor(const char* name) |
1441 |
: ExternalElementsAccessor<ExternalIntElementsAccessor, |
1442 |
EXTERNAL_INT_ELEMENTS>(name) {} |
1443 |
}; |
1444 |
|
1445 |
|
1446 |
class ExternalUnsignedIntElementsAccessor |
1447 |
: public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
|
1448 |
EXTERNAL_UNSIGNED_INT_ELEMENTS> { |
1449 |
public:
|
1450 |
explicit ExternalUnsignedIntElementsAccessor(const char* name) |
1451 |
: ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, |
1452 |
EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {} |
1453 |
}; |
1454 |
|
1455 |
|
1456 |
class ExternalFloatElementsAccessor |
1457 |
: public ExternalElementsAccessor<ExternalFloatElementsAccessor,
|
1458 |
EXTERNAL_FLOAT_ELEMENTS> { |
1459 |
public:
|
1460 |
explicit ExternalFloatElementsAccessor(const char* name) |
1461 |
: ExternalElementsAccessor<ExternalFloatElementsAccessor, |
1462 |
EXTERNAL_FLOAT_ELEMENTS>(name) {} |
1463 |
}; |
1464 |
|
1465 |
|
1466 |
class ExternalDoubleElementsAccessor |
1467 |
: public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
|
1468 |
EXTERNAL_DOUBLE_ELEMENTS> { |
1469 |
public:
|
1470 |
explicit ExternalDoubleElementsAccessor(const char* name) |
1471 |
: ExternalElementsAccessor<ExternalDoubleElementsAccessor, |
1472 |
EXTERNAL_DOUBLE_ELEMENTS>(name) {} |
1473 |
}; |
1474 |
|
1475 |
|
1476 |
class PixelElementsAccessor |
1477 |
: public ExternalElementsAccessor<PixelElementsAccessor,
|
1478 |
EXTERNAL_PIXEL_ELEMENTS> { |
1479 |
public:
|
1480 |
explicit PixelElementsAccessor(const char* name) |
1481 |
: ExternalElementsAccessor<PixelElementsAccessor, |
1482 |
EXTERNAL_PIXEL_ELEMENTS>(name) {} |
1483 |
}; |
1484 |
|
1485 |
|
1486 |
class DictionaryElementsAccessor |
1487 |
: public ElementsAccessorBase<DictionaryElementsAccessor,
|
1488 |
ElementsKindTraits<DICTIONARY_ELEMENTS> > { |
1489 |
public:
|
1490 |
explicit DictionaryElementsAccessor(const char* name) |
1491 |
: ElementsAccessorBase<DictionaryElementsAccessor, |
1492 |
ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {} |
1493 |
|
1494 |
// Adjusts the length of the dictionary backing store and returns the new
|
1495 |
// length according to ES5 section 15.4.5.2 behavior.
|
1496 |
MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
|
1497 |
FixedArrayBase* store, |
1498 |
JSArray* array, |
1499 |
Object* length_object, |
1500 |
uint32_t length) { |
1501 |
SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); |
1502 |
Heap* heap = array->GetHeap(); |
1503 |
int capacity = dict->Capacity();
|
1504 |
uint32_t new_length = length; |
1505 |
uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
|
1506 |
if (new_length < old_length) {
|
1507 |
// Find last non-deletable element in range of elements to be
|
1508 |
// deleted and adjust range accordingly.
|
1509 |
for (int i = 0; i < capacity; i++) { |
1510 |
Object* key = dict->KeyAt(i); |
1511 |
if (key->IsNumber()) {
|
1512 |
uint32_t number = static_cast<uint32_t>(key->Number());
|
1513 |
if (new_length <= number && number < old_length) {
|
1514 |
PropertyDetails details = dict->DetailsAt(i); |
1515 |
if (details.IsDontDelete()) new_length = number + 1; |
1516 |
} |
1517 |
} |
1518 |
} |
1519 |
if (new_length != length) {
|
1520 |
MaybeObject* maybe_object = heap->NumberFromUint32(new_length); |
1521 |
if (!maybe_object->To(&length_object)) return maybe_object; |
1522 |
} |
1523 |
} |
1524 |
|
1525 |
if (new_length == 0) { |
1526 |
// If the length of a slow array is reset to zero, we clear
|
1527 |
// the array and flush backing storage. This has the added
|
1528 |
// benefit that the array returns to fast mode.
|
1529 |
Object* obj; |
1530 |
MaybeObject* maybe_obj = array->ResetElements(); |
1531 |
if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
1532 |
} else {
|
1533 |
// Remove elements that should be deleted.
|
1534 |
int removed_entries = 0; |
1535 |
Object* the_hole_value = heap->the_hole_value(); |
1536 |
for (int i = 0; i < capacity; i++) { |
1537 |
Object* key = dict->KeyAt(i); |
1538 |
if (key->IsNumber()) {
|
1539 |
uint32_t number = static_cast<uint32_t>(key->Number());
|
1540 |
if (new_length <= number && number < old_length) {
|
1541 |
dict->SetEntry(i, the_hole_value, the_hole_value); |
1542 |
removed_entries++; |
1543 |
} |
1544 |
} |
1545 |
} |
1546 |
|
1547 |
// Update the number of elements.
|
1548 |
dict->ElementsRemoved(removed_entries); |
1549 |
} |
1550 |
return length_object;
|
1551 |
} |
1552 |
|
1553 |
MUST_USE_RESULT static MaybeObject* DeleteCommon(
|
1554 |
JSObject* obj, |
1555 |
uint32_t key, |
1556 |
JSReceiver::DeleteMode mode) { |
1557 |
Isolate* isolate = obj->GetIsolate(); |
1558 |
Heap* heap = isolate->heap(); |
1559 |
FixedArray* backing_store = FixedArray::cast(obj->elements()); |
1560 |
bool is_arguments =
|
1561 |
(obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); |
1562 |
if (is_arguments) {
|
1563 |
backing_store = FixedArray::cast(backing_store->get(1));
|
1564 |
} |
1565 |
SeededNumberDictionary* dictionary = |
1566 |
SeededNumberDictionary::cast(backing_store); |
1567 |
int entry = dictionary->FindEntry(key);
|
1568 |
if (entry != SeededNumberDictionary::kNotFound) {
|
1569 |
Object* result = dictionary->DeleteProperty(entry, mode); |
1570 |
if (result == heap->false_value()) {
|
1571 |
if (mode == JSObject::STRICT_DELETION) {
|
1572 |
// Deleting a non-configurable property in strict mode.
|
1573 |
HandleScope scope(isolate); |
1574 |
Handle<Object> holder(obj, isolate); |
1575 |
Handle<Object> name = isolate->factory()->NewNumberFromUint(key); |
1576 |
Handle<Object> args[2] = { name, holder };
|
1577 |
Handle<Object> error = |
1578 |
isolate->factory()->NewTypeError("strict_delete_property",
|
1579 |
HandleVector(args, 2));
|
1580 |
return isolate->Throw(*error);
|
1581 |
} |
1582 |
return heap->false_value();
|
1583 |
} |
1584 |
MaybeObject* maybe_elements = dictionary->Shrink(key); |
1585 |
FixedArray* new_elements = NULL;
|
1586 |
if (!maybe_elements->To(&new_elements)) {
|
1587 |
return maybe_elements;
|
1588 |
} |
1589 |
if (is_arguments) {
|
1590 |
FixedArray::cast(obj->elements())->set(1, new_elements);
|
1591 |
} else {
|
1592 |
obj->set_elements(new_elements); |
1593 |
} |
1594 |
} |
1595 |
return heap->true_value();
|
1596 |
} |
1597 |
|
1598 |
MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
|
1599 |
uint32_t from_start, |
1600 |
FixedArrayBase* to, |
1601 |
ElementsKind from_kind, |
1602 |
uint32_t to_start, |
1603 |
int packed_size,
|
1604 |
int copy_size) {
|
1605 |
UNREACHABLE(); |
1606 |
return NULL; |
1607 |
} |
1608 |
|
1609 |
|
1610 |
protected:
|
1611 |
friend class ElementsAccessorBase<DictionaryElementsAccessor, |
1612 |
ElementsKindTraits<DICTIONARY_ELEMENTS> >; |
1613 |
|
1614 |
MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
|
1615 |
uint32_t key, |
1616 |
JSReceiver::DeleteMode mode) { |
1617 |
return DeleteCommon(obj, key, mode);
|
1618 |
} |
1619 |
|
1620 |
MUST_USE_RESULT static MaybeObject* GetImpl(
|
1621 |
Object* receiver, |
1622 |
JSObject* obj, |
1623 |
uint32_t key, |
1624 |
FixedArrayBase* store) { |
1625 |
SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); |
1626 |
int entry = backing_store->FindEntry(key);
|
1627 |
if (entry != SeededNumberDictionary::kNotFound) {
|
1628 |
Object* element = backing_store->ValueAt(entry); |
1629 |
PropertyDetails details = backing_store->DetailsAt(entry); |
1630 |
if (details.type() == CALLBACKS) {
|
1631 |
return obj->GetElementWithCallback(receiver,
|
1632 |
element, |
1633 |
key, |
1634 |
obj); |
1635 |
} else {
|
1636 |
return element;
|
1637 |
} |
1638 |
} |
1639 |
return obj->GetHeap()->the_hole_value();
|
1640 |
} |
1641 |
|
1642 |
MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
|
1643 |
Object* receiver, |
1644 |
JSObject* obj, |
1645 |
uint32_t key, |
1646 |
FixedArrayBase* backing_store) { |
1647 |
SeededNumberDictionary* dictionary = |
1648 |
SeededNumberDictionary::cast(backing_store); |
1649 |
int entry = dictionary->FindEntry(key);
|
1650 |
if (entry != SeededNumberDictionary::kNotFound) {
|
1651 |
return dictionary->DetailsAt(entry).attributes();
|
1652 |
} |
1653 |
return ABSENT;
|
1654 |
} |
1655 |
|
1656 |
MUST_USE_RESULT static PropertyType GetTypeImpl(
|
1657 |
Object* receiver, |
1658 |
JSObject* obj, |
1659 |
uint32_t key, |
1660 |
FixedArrayBase* store) { |
1661 |
SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); |
1662 |
int entry = backing_store->FindEntry(key);
|
1663 |
if (entry != SeededNumberDictionary::kNotFound) {
|
1664 |
return backing_store->DetailsAt(entry).type();
|
1665 |
} |
1666 |
return NONEXISTENT;
|
1667 |
} |
1668 |
|
1669 |
MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
|
1670 |
Object* receiver, |
1671 |
JSObject* obj, |
1672 |
uint32_t key, |
1673 |
FixedArrayBase* store) { |
1674 |
SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); |
1675 |
int entry = backing_store->FindEntry(key);
|
1676 |
if (entry != SeededNumberDictionary::kNotFound &&
|
1677 |
backing_store->DetailsAt(entry).type() == CALLBACKS && |
1678 |
backing_store->ValueAt(entry)->IsAccessorPair()) { |
1679 |
return AccessorPair::cast(backing_store->ValueAt(entry));
|
1680 |
} |
1681 |
return NULL; |
1682 |
} |
1683 |
|
1684 |
static bool HasElementImpl(Object* receiver, |
1685 |
JSObject* holder, |
1686 |
uint32_t key, |
1687 |
FixedArrayBase* backing_store) { |
1688 |
return SeededNumberDictionary::cast(backing_store)->FindEntry(key) !=
|
1689 |
SeededNumberDictionary::kNotFound; |
1690 |
} |
1691 |
|
1692 |
static uint32_t GetKeyForIndexImpl(FixedArrayBase* store,
|
1693 |
uint32_t index) { |
1694 |
SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); |
1695 |
Object* key = dict->KeyAt(index); |
1696 |
return Smi::cast(key)->value();
|
1697 |
} |
1698 |
}; |
1699 |
|
1700 |
|
1701 |
class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< |
1702 |
NonStrictArgumentsElementsAccessor, |
1703 |
ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > { |
1704 |
public:
|
1705 |
explicit NonStrictArgumentsElementsAccessor(const char* name) |
1706 |
: ElementsAccessorBase< |
1707 |
NonStrictArgumentsElementsAccessor, |
1708 |
ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {} |
1709 |
protected:
|
1710 |
friend class ElementsAccessorBase< |
1711 |
NonStrictArgumentsElementsAccessor, |
1712 |
ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >; |
1713 |
|
1714 |
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
|
1715 |
JSObject* obj, |
1716 |
uint32_t key, |
1717 |
FixedArrayBase* parameters) { |
1718 |
FixedArray* parameter_map = FixedArray::cast(parameters); |
1719 |
Object* probe = GetParameterMapArg(obj, parameter_map, key); |
1720 |
if (!probe->IsTheHole()) {
|
1721 |
Context* context = Context::cast(parameter_map->get(0));
|
1722 |
int context_index = Smi::cast(probe)->value();
|
1723 |
ASSERT(!context->get(context_index)->IsTheHole()); |
1724 |
return context->get(context_index);
|
1725 |
} else {
|
1726 |
// Object is not mapped, defer to the arguments.
|
1727 |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
1728 |
MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get( |
1729 |
receiver, obj, key, arguments); |
1730 |
Object* result; |
1731 |
if (!maybe_result->ToObject(&result)) return maybe_result; |
1732 |
// Elements of the arguments object in slow mode might be slow aliases.
|
1733 |
if (result->IsAliasedArgumentsEntry()) {
|
1734 |
AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result); |
1735 |
Context* context = Context::cast(parameter_map->get(0));
|
1736 |
int context_index = entry->aliased_context_slot();
|
1737 |
ASSERT(!context->get(context_index)->IsTheHole()); |
1738 |
return context->get(context_index);
|
1739 |
} else {
|
1740 |
return result;
|
1741 |
} |
1742 |
} |
1743 |
} |
1744 |
|
1745 |
MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
|
1746 |
Object* receiver, |
1747 |
JSObject* obj, |
1748 |
uint32_t key, |
1749 |
FixedArrayBase* backing_store) { |
1750 |
FixedArray* parameter_map = FixedArray::cast(backing_store); |
1751 |
Object* probe = GetParameterMapArg(obj, parameter_map, key); |
1752 |
if (!probe->IsTheHole()) {
|
1753 |
return NONE;
|
1754 |
} else {
|
1755 |
// If not aliased, check the arguments.
|
1756 |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
1757 |
return ElementsAccessor::ForArray(arguments)->GetAttributes(
|
1758 |
receiver, obj, key, arguments); |
1759 |
} |
1760 |
} |
1761 |
|
1762 |
MUST_USE_RESULT static PropertyType GetTypeImpl(
|
1763 |
Object* receiver, |
1764 |
JSObject* obj, |
1765 |
uint32_t key, |
1766 |
FixedArrayBase* parameters) { |
1767 |
FixedArray* parameter_map = FixedArray::cast(parameters); |
1768 |
Object* probe = GetParameterMapArg(obj, parameter_map, key); |
1769 |
if (!probe->IsTheHole()) {
|
1770 |
return FIELD;
|
1771 |
} else {
|
1772 |
// If not aliased, check the arguments.
|
1773 |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
1774 |
return ElementsAccessor::ForArray(arguments)->GetType(
|
1775 |
receiver, obj, key, arguments); |
1776 |
} |
1777 |
} |
1778 |
|
1779 |
MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
|
1780 |
Object* receiver, |
1781 |
JSObject* obj, |
1782 |
uint32_t key, |
1783 |
FixedArrayBase* parameters) { |
1784 |
FixedArray* parameter_map = FixedArray::cast(parameters); |
1785 |
Object* probe = GetParameterMapArg(obj, parameter_map, key); |
1786 |
if (!probe->IsTheHole()) {
|
1787 |
return NULL; |
1788 |
} else {
|
1789 |
// If not aliased, check the arguments.
|
1790 |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
1791 |
return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
|
1792 |
receiver, obj, key, arguments); |
1793 |
} |
1794 |
} |
1795 |
|
1796 |
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
|
1797 |
JSObject* obj, |
1798 |
Object* length, |
1799 |
FixedArrayBase* parameter_map) { |
1800 |
// TODO(mstarzinger): This was never implemented but will be used once we
|
1801 |
// correctly implement [[DefineOwnProperty]] on arrays.
|
1802 |
UNIMPLEMENTED(); |
1803 |
return obj;
|
1804 |
} |
1805 |
|
1806 |
MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
|
1807 |
uint32_t key, |
1808 |
JSReceiver::DeleteMode mode) { |
1809 |
FixedArray* parameter_map = FixedArray::cast(obj->elements()); |
1810 |
Object* probe = GetParameterMapArg(obj, parameter_map, key); |
1811 |
if (!probe->IsTheHole()) {
|
1812 |
// TODO(kmillikin): We could check if this was the last aliased
|
1813 |
// parameter, and revert to normal elements in that case. That
|
1814 |
// would enable GC of the context.
|
1815 |
parameter_map->set_the_hole(key + 2);
|
1816 |
} else {
|
1817 |
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
|
1818 |
if (arguments->IsDictionary()) {
|
1819 |
return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
|
1820 |
} else {
|
1821 |
// It's difficult to access the version of DeleteCommon that is declared
|
1822 |
// in the templatized super class, call the concrete implementation in
|
1823 |
// the class for the most generalized ElementsKind subclass.
|
1824 |
return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
|
1825 |
} |
1826 |
} |
1827 |
return obj->GetHeap()->true_value();
|
1828 |
} |
1829 |
|
1830 |
MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
|
1831 |
uint32_t from_start, |
1832 |
FixedArrayBase* to, |
1833 |
ElementsKind from_kind, |
1834 |
uint32_t to_start, |
1835 |
int packed_size,
|
1836 |
int copy_size) {
|
1837 |
UNREACHABLE(); |
1838 |
return NULL; |
1839 |
} |
1840 |
|
1841 |
static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
|
1842 |
FixedArray* parameter_map = FixedArray::cast(backing_store); |
1843 |
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
|
1844 |
return Max(static_cast<uint32_t>(parameter_map->length() - 2), |
1845 |
ForArray(arguments)->GetCapacity(arguments)); |
1846 |
} |
1847 |
|
1848 |
static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
|
1849 |
uint32_t index) { |
1850 |
return index;
|
1851 |
} |
1852 |
|
1853 |
static bool HasElementImpl(Object* receiver, |
1854 |
JSObject* holder, |
1855 |
uint32_t key, |
1856 |
FixedArrayBase* parameters) { |
1857 |
FixedArray* parameter_map = FixedArray::cast(parameters); |
1858 |
Object* probe = GetParameterMapArg(holder, parameter_map, key); |
1859 |
if (!probe->IsTheHole()) {
|
1860 |
return true; |
1861 |
} else {
|
1862 |
FixedArrayBase* arguments = |
1863 |
FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1));
|
1864 |
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); |
1865 |
return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
|
1866 |
} |
1867 |
} |
1868 |
|
1869 |
private:
|
1870 |
static Object* GetParameterMapArg(JSObject* holder,
|
1871 |
FixedArray* parameter_map, |
1872 |
uint32_t key) { |
1873 |
uint32_t length = holder->IsJSArray() |
1874 |
? Smi::cast(JSArray::cast(holder)->length())->value() |
1875 |
: parameter_map->length(); |
1876 |
return key < (length - 2) |
1877 |
? parameter_map->get(key + 2)
|
1878 |
: parameter_map->GetHeap()->the_hole_value(); |
1879 |
} |
1880 |
}; |
1881 |
|
1882 |
|
1883 |
ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { |
1884 |
return elements_accessors_[ElementsKindForArray(array)];
|
1885 |
} |
1886 |
|
1887 |
|
1888 |
void ElementsAccessor::InitializeOncePerProcess() {
|
1889 |
static ElementsAccessor* accessor_array[] = {
|
1890 |
#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind), |
1891 |
ELEMENTS_LIST(ACCESSOR_ARRAY) |
1892 |
#undef ACCESSOR_ARRAY
|
1893 |
}; |
1894 |
|
1895 |
STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == |
1896 |
kElementsKindCount); |
1897 |
|
1898 |
elements_accessors_ = accessor_array; |
1899 |
} |
1900 |
|
1901 |
|
1902 |
void ElementsAccessor::TearDown() {
|
1903 |
#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; |
1904 |
ELEMENTS_LIST(ACCESSOR_DELETE) |
1905 |
#undef ACCESSOR_DELETE
|
1906 |
elements_accessors_ = NULL;
|
1907 |
} |
1908 |
|
1909 |
|
1910 |
template <typename ElementsAccessorSubclass, typename ElementsKindTraits> |
1911 |
MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, |
1912 |
ElementsKindTraits>:: |
1913 |
SetLengthImpl(JSObject* obj, |
1914 |
Object* length, |
1915 |
FixedArrayBase* backing_store) { |
1916 |
JSArray* array = JSArray::cast(obj); |
1917 |
|
1918 |
// Fast case: The new length fits into a Smi.
|
1919 |
MaybeObject* maybe_smi_length = length->ToSmi(); |
1920 |
Object* smi_length = Smi::FromInt(0);
|
1921 |
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
|
1922 |
const int value = Smi::cast(smi_length)->value(); |
1923 |
if (value >= 0) { |
1924 |
Object* new_length; |
1925 |
MaybeObject* result = ElementsAccessorSubclass:: |
1926 |
SetLengthWithoutNormalize(backing_store, array, smi_length, value); |
1927 |
if (!result->ToObject(&new_length)) return result; |
1928 |
ASSERT(new_length->IsSmi() || new_length->IsUndefined()); |
1929 |
if (new_length->IsSmi()) {
|
1930 |
array->set_length(Smi::cast(new_length)); |
1931 |
return array;
|
1932 |
} |
1933 |
} else {
|
1934 |
return ThrowArrayLengthRangeError(array->GetHeap());
|
1935 |
} |
1936 |
} |
1937 |
|
1938 |
// Slow case: The new length does not fit into a Smi or conversion
|
1939 |
// to slow elements is needed for other reasons.
|
1940 |
if (length->IsNumber()) {
|
1941 |
uint32_t value; |
1942 |
if (length->ToArrayIndex(&value)) {
|
1943 |
SeededNumberDictionary* dictionary; |
1944 |
MaybeObject* maybe_object = array->NormalizeElements(); |
1945 |
if (!maybe_object->To(&dictionary)) return maybe_object; |
1946 |
Object* new_length; |
1947 |
MaybeObject* result = DictionaryElementsAccessor:: |
1948 |
SetLengthWithoutNormalize(dictionary, array, length, value); |
1949 |
if (!result->ToObject(&new_length)) return result; |
1950 |
ASSERT(new_length->IsNumber()); |
1951 |
array->set_length(new_length); |
1952 |
return array;
|
1953 |
} else {
|
1954 |
return ThrowArrayLengthRangeError(array->GetHeap());
|
1955 |
} |
1956 |
} |
1957 |
|
1958 |
// Fall-back case: The new length is not a number so make the array
|
1959 |
// size one and set only element to length.
|
1960 |
FixedArray* new_backing_store; |
1961 |
MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
|
1962 |
if (!maybe_obj->To(&new_backing_store)) return maybe_obj; |
1963 |
new_backing_store->set(0, length);
|
1964 |
{ MaybeObject* result = array->SetContent(new_backing_store); |
1965 |
if (result->IsFailure()) return result; |
1966 |
} |
1967 |
return array;
|
1968 |
} |
1969 |
|
1970 |
|
1971 |
MUST_USE_RESULT MaybeObject* ArrayConstructInitializeElements( |
1972 |
JSArray* array, Arguments* args) { |
1973 |
Heap* heap = array->GetIsolate()->heap(); |
1974 |
|
1975 |
// Optimize the case where there is one argument and the argument is a
|
1976 |
// small smi.
|
1977 |
if (args->length() == 1) { |
1978 |
Object* obj = (*args)[0];
|
1979 |
if (obj->IsSmi()) {
|
1980 |
int len = Smi::cast(obj)->value();
|
1981 |
if (len > 0 && len < JSObject::kInitialMaxFastElementArray) { |
1982 |
ElementsKind elements_kind = array->GetElementsKind(); |
1983 |
MaybeObject* maybe_array = array->Initialize(len, len); |
1984 |
if (maybe_array->IsFailure()) return maybe_array; |
1985 |
|
1986 |
if (!IsFastHoleyElementsKind(elements_kind)) {
|
1987 |
elements_kind = GetHoleyElementsKind(elements_kind); |
1988 |
maybe_array = array->TransitionElementsKind(elements_kind); |
1989 |
if (maybe_array->IsFailure()) return maybe_array; |
1990 |
} |
1991 |
|
1992 |
return array;
|
1993 |
} else if (len == 0) { |
1994 |
return array->Initialize(JSArray::kPreallocatedArrayElements);
|
1995 |
} |
1996 |
} |
1997 |
|
1998 |
// Take the argument as the length.
|
1999 |
MaybeObject* maybe_obj = array->Initialize(0);
|
2000 |
if (!maybe_obj->To(&obj)) return maybe_obj; |
2001 |
|
2002 |
return array->SetElementsLength((*args)[0]); |
2003 |
} |
2004 |
|
2005 |
// Optimize the case where there are no parameters passed.
|
2006 |
if (args->length() == 0) { |
2007 |
return array->Initialize(JSArray::kPreallocatedArrayElements);
|
2008 |
} |
2009 |
|
2010 |
// Set length and elements on the array.
|
2011 |
int number_of_elements = args->length();
|
2012 |
MaybeObject* maybe_object = |
2013 |
array->EnsureCanContainElements(args, 0, number_of_elements,
|
2014 |
ALLOW_CONVERTED_DOUBLE_ELEMENTS); |
2015 |
if (maybe_object->IsFailure()) return maybe_object; |
2016 |
|
2017 |
// Allocate an appropriately typed elements array.
|
2018 |
MaybeObject* maybe_elms; |
2019 |
ElementsKind elements_kind = array->GetElementsKind(); |
2020 |
if (IsFastDoubleElementsKind(elements_kind)) {
|
2021 |
maybe_elms = heap->AllocateUninitializedFixedDoubleArray( |
2022 |
number_of_elements); |
2023 |
} else {
|
2024 |
maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements); |
2025 |
} |
2026 |
FixedArrayBase* elms; |
2027 |
if (!maybe_elms->To(&elms)) return maybe_elms; |
2028 |
|
2029 |
// Fill in the content
|
2030 |
switch (array->GetElementsKind()) {
|
2031 |
case FAST_HOLEY_SMI_ELEMENTS:
|
2032 |
case FAST_SMI_ELEMENTS: {
|
2033 |
FixedArray* smi_elms = FixedArray::cast(elms); |
2034 |
for (int index = 0; index < number_of_elements; index++) { |
2035 |
smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER); |
2036 |
} |
2037 |
break;
|
2038 |
} |
2039 |
case FAST_HOLEY_ELEMENTS:
|
2040 |
case FAST_ELEMENTS: {
|
2041 |
DisallowHeapAllocation no_gc; |
2042 |
WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); |
2043 |
FixedArray* object_elms = FixedArray::cast(elms); |
2044 |
for (int index = 0; index < number_of_elements; index++) { |
2045 |
object_elms->set(index, (*args)[index], mode); |
2046 |
} |
2047 |
break;
|
2048 |
} |
2049 |
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
2050 |
case FAST_DOUBLE_ELEMENTS: {
|
2051 |
FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms); |
2052 |
for (int index = 0; index < number_of_elements; index++) { |
2053 |
double_elms->set(index, (*args)[index]->Number()); |
2054 |
} |
2055 |
break;
|
2056 |
} |
2057 |
default:
|
2058 |
UNREACHABLE(); |
2059 |
break;
|
2060 |
} |
2061 |
|
2062 |
array->set_elements(elms); |
2063 |
array->set_length(Smi::FromInt(number_of_elements)); |
2064 |
return array;
|
2065 |
} |
2066 |
|
2067 |
} } // namespace v8::internal
|