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
HasKey(FixedArray * array,Object * key)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
ThrowArrayLengthRangeError(Heap * heap)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
CopyObjectToObjectElements(FixedArrayBase * from_base,ElementsKind from_kind,uint32_t from_start,FixedArrayBase * to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)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
CopyDictionaryToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)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
CopyDoubleToObjectElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,ElementsKind to_kind,uint32_t to_start,int raw_copy_size)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
CopyDoubleToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)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
CopySmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)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
CopyPackedSmiToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int packed_size,int raw_copy_size)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
CopyObjectToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)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
CopyDictionaryToDoubleElements(FixedArrayBase * from_base,uint32_t from_start,FixedArrayBase * to_base,uint32_t to_start,int raw_copy_size)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
TraceTopFrame(Isolate * isolate)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
CheckArrayAbuse(JSObject * obj,const char * op,uint32_t key,bool allow_appending)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:
ElementsAccessorBase(const char * name)568 explicit ElementsAccessorBase(const char* name)
569 : ElementsAccessor(name) { }
570
571 typedef ElementsTraitsParam ElementsTraits;
572 typedef typename ElementsTraitsParam::BackingStore BackingStore;
573
kind() const574 virtual ElementsKind kind() const { return ElementsTraits::Kind; }
575
ValidateContents(JSObject * holder,int length)576 static void ValidateContents(JSObject* holder, int length) {
577 }
578
ValidateImpl(JSObject * holder)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
Validate(JSObject * holder)598 virtual void Validate(JSObject* holder) {
599 ElementsAccessorSubclass::ValidateImpl(holder);
600 }
601
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
HasElement(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
Get(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
GetImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetAttributes(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
GetAttributesImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetType(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
GetTypeImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetAccessorPair(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
GetAccessorPairImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
SetLength(JSArray * array,Object * length)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
SetCapacityAndLength(JSArray * array,int capacity,int length)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
SetFastElementsCapacityAndLength(JSObject * obj,int capacity,int length)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
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)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
CopyElements(JSObject * from_holder,uint32_t from_start,ElementsKind from_kind,FixedArrayBase * to,uint32_t to_start,int copy_size,FixedArrayBase * from)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
AddElementsToFixedArray(Object * receiver,JSObject * holder,FixedArray * to,FixedArrayBase * from)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:
GetCapacityImpl(FixedArrayBase * backing_store)867 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
868 return backing_store->length();
869 }
870
GetCapacity(FixedArrayBase * backing_store)871 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
872 return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
873 }
874
GetKeyForIndexImpl(FixedArrayBase * backing_store,uint32_t index)875 static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
876 uint32_t index) {
877 return index;
878 }
879
GetKeyForIndex(FixedArrayBase * backing_store,uint32_t index)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:
FastElementsAccessor(const char * name)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.
SetLengthWithoutNormalize(FixedArrayBase * backing_store,JSArray * array,Object * length_object,uint32_t length)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
DeleteCommon(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)1030 virtual MaybeObject* Delete(JSObject* obj,
1031 uint32_t key,
1032 JSReceiver::DeleteMode mode) {
1033 return DeleteCommon(obj, key, mode);
1034 }
1035
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
ValidateContents(JSObject * holder,int length)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
ElementsKindForArray(FixedArrayBase * array)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:
FastSmiOrObjectElementsAccessor(const char * name)1113 explicit FastSmiOrObjectElementsAccessor(const char* name)
1114 : FastElementsAccessor<FastElementsAccessorSubclass,
1115 KindTraits,
1116 kPointerSize>(name) {}
1117
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)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
SetFastElementsCapacityAndLength(JSObject * obj,uint32_t capacity,uint32_t length)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:
FastPackedSmiElementsAccessor(const char * name)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:
FastHoleySmiElementsAccessor(const char * name)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:
FastPackedObjectElementsAccessor(const char * name)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:
FastHoleyObjectElementsAccessor(const char * name)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:
FastDoubleElementsAccessor(const char * name)1236 explicit FastDoubleElementsAccessor(const char* name)
1237 : FastElementsAccessor<FastElementsAccessorSubclass,
1238 KindTraits,
1239 kDoubleSize>(name) {}
1240
SetFastElementsCapacityAndLength(JSObject * obj,uint32_t capacity,uint32_t length)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:
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)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> >;
FastPackedDoubleElementsAccessor(const char * name)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> >;
FastHoleyDoubleElementsAccessor(const char * name)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:
ExternalElementsAccessor(const char * name)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
GetImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetAttributesImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetTypeImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
SetLengthImpl(JSObject * obj,Object * length,FixedArrayBase * backing_store)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
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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:
ExternalByteElementsAccessor(const char * name)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:
ExternalUnsignedByteElementsAccessor(const char * name)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:
ExternalShortElementsAccessor(const char * name)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:
ExternalUnsignedShortElementsAccessor(const char * name)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:
ExternalIntElementsAccessor(const char * name)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:
ExternalUnsignedIntElementsAccessor(const char * name)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:
ExternalFloatElementsAccessor(const char * name)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:
ExternalDoubleElementsAccessor(const char * name)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:
PixelElementsAccessor(const char * name)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:
DictionaryElementsAccessor(const char * name)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.
SetLengthWithoutNormalize(FixedArrayBase * store,JSArray * array,Object * length_object,uint32_t length)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
DeleteCommon(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)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
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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
GetImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * store)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
GetAttributesImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetTypeImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * store)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
GetAccessorPairImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * store)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
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * backing_store)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
GetKeyForIndexImpl(FixedArrayBase * store,uint32_t index)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:
NonStrictArgumentsElementsAccessor(const char * name)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
GetImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * parameters)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
GetAttributesImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * backing_store)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
GetTypeImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * parameters)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
GetAccessorPairImpl(Object * receiver,JSObject * obj,uint32_t key,FixedArrayBase * parameters)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
SetLengthImpl(JSObject * obj,Object * length,FixedArrayBase * parameter_map)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
Delete(JSObject * obj,uint32_t key,JSReceiver::DeleteMode mode)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
CopyElementsImpl(FixedArrayBase * from,uint32_t from_start,FixedArrayBase * to,ElementsKind from_kind,uint32_t to_start,int packed_size,int copy_size)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
GetCapacityImpl(FixedArrayBase * backing_store)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
GetKeyForIndexImpl(FixedArrayBase * dict,uint32_t index)1848 static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
1849 uint32_t index) {
1850 return index;
1851 }
1852
HasElementImpl(Object * receiver,JSObject * holder,uint32_t key,FixedArrayBase * parameters)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:
GetParameterMapArg(JSObject * holder,FixedArray * parameter_map,uint32_t key)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
ForArray(FixedArrayBase * array)1883 ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
1884 return elements_accessors_[ElementsKindForArray(array)];
1885 }
1886
1887
InitializeOncePerProcess()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
TearDown()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>::
SetLengthImpl(JSObject * obj,Object * length,FixedArrayBase * backing_store)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
ArrayConstructInitializeElements(JSArray * array,Arguments * args)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
2068