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.

Statistics
| Branch: | Revision:

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