blob: 89621cb3694ad63288f5b1f9556326da5e02dcc5 [file] [log] [blame]
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002// 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
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000030#include "arguments.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000031#include "objects.h"
32#include "elements.h"
rossberg@chromium.org28a37082011-08-22 11:03:23 +000033#include "utils.h"
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000034#include "v8conversions.h"
danno@chromium.orgc612e022011-11-10 11:38:15 +000035
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)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000043// - FastSmiOrObjectElementsAccessor
44// - FastPackedSmiElementsAccessor
45// - FastHoleySmiElementsAccessor
46// - FastPackedObjectElementsAccessor
47// - FastHoleyObjectElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +000048// - FastDoubleElementsAccessor
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000049// - FastPackedDoubleElementsAccessor
50// - FastHoleyDoubleElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +000051// - 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
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000065namespace v8 {
66namespace internal {
67
68
mmassi@chromium.org7028c052012-06-13 11:51:58 +000069static const int kPackedSizeNotKnown = -1;
70
71
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000072// 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) \
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000078 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) \
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000087 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
110template<ElementsKind Kind> class ElementsKindTraits {
111 public:
112 typedef FixedArrayBase BackingStore;
113};
114
115#define ELEMENTS_TRAITS(Class, KindParam, Store) \
116template<> class ElementsKindTraits<KindParam> { \
117 public: \
118 static const ElementsKind Kind = KindParam; \
119 typedef Store BackingStore; \
120};
121ELEMENTS_LIST(ELEMENTS_TRAITS)
122#undef ELEMENTS_TRAITS
123
124
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000125ElementsAccessor** ElementsAccessor::elements_accessors_;
126
127
danno@chromium.orgc612e022011-11-10 11:38:15 +0000128static bool HasKey(FixedArray* array, Object* key) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000129 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
danno@chromium.orgc612e022011-11-10 11:38:15 +0000142static 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
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000150static void CopyObjectToObjectElements(FixedArrayBase* from_base,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000151 ElementsKind from_kind,
152 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000153 FixedArrayBase* to_base,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000154 ElementsKind to_kind,
155 uint32_t to_start,
156 int raw_copy_size) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000157 ASSERT(to_base->map() !=
158 from_base->GetIsolate()->heap()->fixed_cow_array_map());
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000159 DisallowHeapAllocation no_allocation;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000160 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000164 copy_size = Min(from_base->length() - from_start,
165 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000166 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000167 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);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000173 }
174 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000175 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000176 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
177 (copy_size + static_cast<int>(from_start)) <= from_base->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000178 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000179 FixedArray* from = FixedArray::cast(from_base);
180 FixedArray* to = FixedArray::cast(to_base);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000181 ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
182 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000183 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,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000187 static_cast<size_t>(copy_size));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000188 if (IsFastObjectElementsKind(from_kind) &&
189 IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000190 Heap* heap = from->GetHeap();
191 if (!heap->InNewSpace(to)) {
192 heap->RecordWrites(to->address(),
193 to->OffsetOfElementAt(to_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000194 copy_size);
195 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000196 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000197 }
198}
199
200
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000201static void CopyDictionaryToObjectElements(FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000202 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000203 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000204 ElementsKind to_kind,
205 uint32_t to_start,
danno@chromium.orgc7406162012-03-26 09:46:02 +0000206 int raw_copy_size) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000207 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000208 DisallowHeapAllocation no_allocation;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000209 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;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000215 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000216 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);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000222 }
223 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000224 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000225 ASSERT(to_base != from_base);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000226 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000227 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000228 FixedArray* to = FixedArray::cast(to_base);
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000229 uint32_t to_length = to->length();
230 if (to_start + copy_size > to_length) {
231 copy_size = to_length - to_start;
232 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000233 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 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000243 if (IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000244 if (!heap->InNewSpace(to)) {
245 heap->RecordWrites(to->address(),
246 to->OffsetOfElementAt(to_start),
247 copy_size);
248 }
249 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000250 }
251}
252
253
254MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000255 FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000256 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000257 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000258 ElementsKind to_kind,
259 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000260 int raw_copy_size) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000261 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000262 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000266 copy_size = Min(from_base->length() - from_start,
267 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000268 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000269 // 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);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000278 }
279 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000280 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000281 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);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000286 for (int i = 0; i < copy_size; ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000287 if (IsFastSmiElementsKind(to_kind)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000288 UNIMPLEMENTED();
289 return Failure::Exception();
290 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000291 MaybeObject* maybe_value = from->get(i + from_start);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000292 Object* value;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000293 ASSERT(IsFastObjectElementsKind(to_kind));
294 // Because Double -> Object elements transitions allocate HeapObjects
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000295 // 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());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000301 Heap* heap = from->GetHeap();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000302 MaybeObject* maybe_value_object =
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000303 heap->AllocateHeapNumber(from->get_scalar(i + from_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000304 TENURED);
305 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
306 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000307 to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000308 }
309 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000310 return to;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000311}
312
313
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000314static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000315 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000316 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000317 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000318 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000323 copy_size = Min(from_base->length() - from_start,
324 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000325 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000326 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
327 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000328 }
329 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000330 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000331 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
332 (copy_size + static_cast<int>(from_start)) <= from_base->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000333 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000334 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
335 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000336 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;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000340 int words_per_double = (kDoubleSize / kPointerSize);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000341 CopyWords(reinterpret_cast<Object**>(to_address),
342 reinterpret_cast<Object**>(from_address),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000343 static_cast<size_t>(words_per_double * copy_size));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000344}
345
346
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000347static void CopySmiToDoubleElements(FixedArrayBase* from_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000348 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000349 FixedArrayBase* to_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000350 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000356 copy_size = from_base->length() - from_start;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000357 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000358 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
359 FixedDoubleArray::cast(to_base)->set_the_hole(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000360 }
361 }
362 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000363 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
364 (copy_size + static_cast<int>(from_start)) <= from_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000365 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000366 FixedArray* from = FixedArray::cast(from_base);
367 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000368 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
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000381static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000382 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000383 FixedArrayBase* to_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000384 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000392 copy_size = packed_size - from_start;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000393 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000394 to_end = to_base->length();
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000395 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000396 FixedDoubleArray::cast(to_base)->set_the_hole(i);
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000397 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000398 } 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 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000404 ASSERT(static_cast<int>(to_end) <= to_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000405 ASSERT(packed_size >= 0 && packed_size <= copy_size);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000406 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
407 (copy_size + static_cast<int>(from_start)) <= from_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000408 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000409 FixedArray* from = FixedArray::cast(from_base);
410 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000411 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 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000417}
418
419
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000420static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000421 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000422 FixedArrayBase* to_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000423 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);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000429 copy_size = from_base->length() - from_start;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000430 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000431 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
432 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000433 }
434 }
435 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000436 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
437 (copy_size + static_cast<int>(from_start)) <= from_base->length());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000438 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000439 FixedArray* from = FixedArray::cast(from_base);
440 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000441 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);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000447 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000448 to->set(to_start, hole_or_object->Number());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000449 }
450 }
451}
452
453
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000454static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000455 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000456 FixedArrayBase* to_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000457 uint32_t to_start,
458 int raw_copy_size) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000459 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000460 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) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000466 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
467 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000468 }
469 }
470 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000471 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000472 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000473 uint32_t to_length = to->length();
474 if (to_start + copy_size > to_length) {
475 copy_size = to_length - to_start;
476 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000477 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
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000488static void TraceTopFrame(Isolate* isolate) {
489 StackFrameIterator it(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000490 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()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000496 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 }
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000504 JavaScriptFrame::PrintTop(isolate, stdout, false, true);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000505}
506
507
508void 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));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000531 TraceTopFrame(obj->GetIsolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000532 PrintF("]\n");
533 }
534 } else {
535 PrintF("[%s elements length not integer value in ", elements_type);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000536 TraceTopFrame(obj->GetIsolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000537 PrintF("]\n");
538 }
539 } else {
540 PrintF("[%s elements length not a number in ", elements_type);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000541 TraceTopFrame(obj->GetIsolate());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000542 PrintF("]\n");
543 }
544}
545
546
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000547// 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).
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000564template <typename ElementsAccessorSubclass,
565 typename ElementsTraitsParam>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000566class ElementsAccessorBase : public ElementsAccessor {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000567 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000568 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; }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000575
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000576 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;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000584 // Arrays that have been shifted in place can't be verified.
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +0000585 if (fixed_array_base->IsFiller()) return;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000586 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
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000602 static bool HasElementImpl(Object* receiver,
603 JSObject* holder,
604 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000605 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000606 return ElementsAccessorSubclass::GetAttributesImpl(
607 receiver, holder, key, backing_store) != ABSENT;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000608 }
609
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000610 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(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000618 receiver, holder, key, backing_store);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000619 }
620
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000621 MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
622 JSObject* holder,
623 uint32_t key,
624 FixedArrayBase* backing_store) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000625 if (backing_store == NULL) {
626 backing_store = holder->elements();
627 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000628
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
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000639 return ElementsAccessorSubclass::GetImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000640 receiver, holder, key, backing_store);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000641 }
642
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000643 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
644 JSObject* obj,
645 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000646 FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000647 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000648 ? BackingStore::cast(backing_store)->get(key)
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000649 : backing_store->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000650 }
651
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000652 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(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000661 receiver, holder, key, backing_store);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000662 }
663
664 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
665 Object* receiver,
666 JSObject* obj,
667 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000668 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000669 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
670 return ABSENT;
671 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000672 return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000673 }
674
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000675 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(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000684 receiver, holder, key, backing_store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000685 }
686
687 MUST_USE_RESULT static PropertyType GetTypeImpl(
688 Object* receiver,
689 JSObject* obj,
690 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000691 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000692 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
693 return NONEXISTENT;
694 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000695 return BackingStore::cast(backing_store)->is_the_hole(key)
696 ? NONEXISTENT : FIELD;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000697 }
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(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000708 receiver, holder, key, backing_store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000709 }
710
711 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
712 Object* receiver,
713 JSObject* obj,
714 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000715 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000716 return NULL;
717 }
718
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000719 MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
720 Object* length) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000721 return ElementsAccessorSubclass::SetLengthImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000722 array, length, array->elements());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000723 }
724
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000725 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
726 JSObject* obj,
727 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000728 FixedArrayBase* backing_store);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000729
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000730 MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
731 JSArray* array,
732 int capacity,
733 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000734 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
735 array,
736 capacity,
737 length);
738 }
739
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000740 MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
741 JSObject* obj,
742 int capacity,
743 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000744 UNIMPLEMENTED();
745 return obj;
746 }
747
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000748 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
749 uint32_t key,
750 JSReceiver::DeleteMode mode) = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000751
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000752 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
753 uint32_t from_start,
754 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000755 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000756 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000757 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000758 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000759 UNREACHABLE();
760 return NULL;
761 }
762
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000763 MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder,
764 uint32_t from_start,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000765 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000766 FixedArrayBase* to,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000767 uint32_t to_start,
768 int copy_size,
769 FixedArrayBase* from) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000770 int packed_size = kPackedSizeNotKnown;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000771 if (from == NULL) {
772 from = from_holder->elements();
773 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000774
775 if (from_holder) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000776 bool is_packed = IsFastPackedElementsKind(from_kind) &&
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000777 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 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000785 return ElementsAccessorSubclass::CopyElementsImpl(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000786 from, from_start, to, from_kind, to_start, packed_size, copy_size);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000787 }
788
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000789 MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
790 Object* receiver,
791 JSObject* holder,
792 FixedArray* to,
793 FixedArrayBase* from) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000794 int len0 = to->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000795#ifdef DEBUG
796 if (FLAG_enable_slow_asserts) {
797 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000798 ASSERT(!to->get(i)->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000799 }
800 }
801#endif
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000802 if (from == NULL) {
803 from = holder->elements();
804 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805
806 // Optimize if 'other' is empty.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000807 // We cannot optimize if 'this' is empty, as other may have holes.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000808 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000809 if (len1 == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810
811 // Compute how many elements are not in other.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000812 uint32_t extra = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000813 for (uint32_t y = 0; y < len1; y++) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000814 uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000815 if (ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000816 receiver, holder, key, from)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000817 MaybeObject* maybe_value =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000818 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000819 Object* value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000820 if (!maybe_value->To(&value)) return maybe_value;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000821 ASSERT(!value->IsTheHole());
822 if (!HasKey(to, value)) {
823 extra++;
824 }
825 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000826 }
827
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000828 if (extra == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000829
830 // Allocate the result
831 FixedArray* result;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000832 MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra);
833 if (!maybe_obj->To(&result)) return maybe_obj;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834
835 // Fill in the content
836 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000837 DisallowHeapAllocation no_gc;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000838 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
839 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000840 Object* e = to->get(i);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000841 ASSERT(e->IsString() || e->IsNumber());
842 result->set(i, e, mode);
843 }
844 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000845 // Fill in the extra values.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000846 uint32_t index = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000847 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000848 uint32_t key =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000849 ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000850 if (ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000851 receiver, holder, key, from)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000852 MaybeObject* maybe_value =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000853 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000854 Object* value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000855 if (!maybe_value->To(&value)) return maybe_value;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000856 if (!value->IsTheHole() && !HasKey(to, value)) {
857 result->set(len0 + index, value);
858 index++;
859 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000860 }
861 }
862 ASSERT(extra == index);
863 return result;
864 }
865
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000866 protected:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000867 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000868 return backing_store->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000869 }
870
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000871 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000872 return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000873 }
874
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000875 static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000876 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000877 return index;
878 }
879
880 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000881 uint32_t index) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000882 return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000883 }
884
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000885 private:
886 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
887};
888
889
danno@chromium.orgc612e022011-11-10 11:38:15 +0000890// Super class for all fast element arrays.
891template<typename FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000892 typename KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000893 int ElementSize>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000894class FastElementsAccessor
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000895 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000896 public:
897 explicit FastElementsAccessor(const char* name)
898 : ElementsAccessorBase<FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000899 KindTraits>(name) {}
danno@chromium.orgc612e022011-11-10 11:38:15 +0000900 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000901 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000902 friend class NonStrictArgumentsElementsAccessor;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000903
904 typedef typename KindTraits::BackingStore BackingStore;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000905
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.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000908 static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000909 JSArray* array,
910 Object* length_object,
911 uint32_t length) {
912 uint32_t old_capacity = backing_store->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000913 Object* old_length = array->length();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000914 bool same_or_smaller_size = old_length->IsSmi() &&
915 static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000916 ElementsKind kind = array->GetElementsKind();
917
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000918 if (!same_or_smaller_size && IsFastElementsKind(kind) &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000919 !IsFastHoleyElementsKind(kind)) {
920 kind = GetHoleyElementsKind(kind);
921 MaybeObject* maybe_obj = array->TransitionElementsKind(kind);
922 if (maybe_obj->IsFailure()) return maybe_obj;
923 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000924
925 // Check whether the backing store should be shrunk.
926 if (length <= old_capacity) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000927 if (array->HasFastSmiOrObjectElements()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000928 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.
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +0000944 int old_length = FastD2IChecked(array->length()->Number());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000945 for (int i = length; i < old_length; i++) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000946 BackingStore::cast(backing_store)->set_the_hole(i);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000947 }
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;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000959 array->ValidateElements();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000960 return length_object;
961 }
962
963 // Request conversion to slow elements.
964 return array->GetHeap()->undefined_value();
965 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000966
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000967 static MaybeObject* DeleteCommon(JSObject* obj,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000968 uint32_t key,
969 JSReceiver::DeleteMode mode) {
970 ASSERT(obj->HasFastSmiOrObjectElements() ||
971 obj->HasFastDoubleElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000972 obj->HasFastArgumentsElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000973 Heap* heap = obj->GetHeap();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000974 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) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000983 backing_store = KindTraits::BackingStore::cast(
984 FixedArray::cast(backing_store)->get(1));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000985 }
986 uint32_t length = static_cast<uint32_t>(
987 obj->IsJSArray()
988 ? Smi::cast(JSArray::cast(obj)->length())->value()
989 : backing_store->length());
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000990 if (key < length) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000991 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 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001005 backing_store->set_the_hole(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001006 // 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.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001010 const int kMinLengthForSparsenessCheck = 64;
1011 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
1012 !heap->InNewSpace(backing_store) &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001013 ((key > 0 && backing_store->is_the_hole(key - 1)) ||
1014 (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001015 int num_used = 0;
1016 for (int i = 0; i < backing_store->length(); ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001017 if (!backing_store->is_the_hole(i)) ++num_used;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001018 // 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
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001030 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,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001040 FixedArrayBase* backing_store) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001041 if (key >= static_cast<uint32_t>(backing_store->length())) {
1042 return false;
1043 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001044 return !BackingStore::cast(backing_store)->is_the_hole(key);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001045 }
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
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001071static 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
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001106template<typename FastElementsAccessorSubclass,
1107 typename KindTraits>
1108class 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
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001118 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1119 uint32_t from_start,
1120 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001121 ElementsKind from_kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001122 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001123 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001124 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001125 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);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001151 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001152 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();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001162 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001163 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001164 }
1165
1166
danno@chromium.orgc612e022011-11-10 11:38:15 +00001167 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
1168 uint32_t capacity,
1169 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001170 JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
1171 obj->HasFastSmiElements()
1172 ? JSObject::kAllowSmiElements
1173 : JSObject::kDontAllowSmiElements;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001174 return obj->SetFastElementsCapacityAndLength(capacity,
1175 length,
1176 set_capacity_mode);
1177 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001178};
1179
1180
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001181class 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
1193class 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
1205class 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
1217class 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
1229template<typename FastElementsAccessorSubclass,
1230 typename KindTraits>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001231class FastDoubleElementsAccessor
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001232 : public FastElementsAccessor<FastElementsAccessorSubclass,
1233 KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001234 kDoubleSize> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001235 public:
1236 explicit FastDoubleElementsAccessor(const char* name)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001237 : FastElementsAccessor<FastElementsAccessorSubclass,
1238 KindTraits,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001239 kDoubleSize>(name) {}
1240
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001241 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
1242 uint32_t capacity,
1243 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001244 return obj->SetFastDoubleElementsCapacityAndLength(capacity,
1245 length);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001246 }
1247
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001248 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001249 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1250 uint32_t from_start,
1251 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001252 ElementsKind from_kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001253 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001254 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001255 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001256 switch (from_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001257 case FAST_SMI_ELEMENTS:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001258 CopyPackedSmiToDoubleElements(
1259 from, from_start, to, to_start, packed_size, copy_size);
1260 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001261 case FAST_HOLEY_SMI_ELEMENTS:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001262 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
1263 break;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001264 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001265 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001266 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001267 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:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001286 UNREACHABLE();
1287 }
1288 return to->GetHeap()->undefined_value();
1289 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001290};
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001291
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001292
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001293class 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
1307class 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) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001319};
1320
1321
1322// Super class for all external element arrays.
1323template<typename ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001324 ElementsKind Kind>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001325class ExternalElementsAccessor
1326 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001327 ElementsKindTraits<Kind> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001328 public:
1329 explicit ExternalElementsAccessor(const char* name)
1330 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001331 ElementsKindTraits<Kind> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001332
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001333 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001334 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
1335
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001336 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001337 ElementsKindTraits<Kind> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001338
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001339 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1340 JSObject* obj,
1341 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001342 FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001343 return
1344 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001345 ? BackingStore::cast(backing_store)->get(key)
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001346 : backing_store->GetHeap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001347 }
1348
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001349 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1350 Object* receiver,
1351 JSObject* obj,
1352 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001353 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001354 return
1355 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001356 ? NONE : ABSENT;
1357 }
1358
1359 MUST_USE_RESULT static PropertyType GetTypeImpl(
1360 Object* receiver,
1361 JSObject* obj,
1362 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001363 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001364 return
1365 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
1366 ? FIELD : NONEXISTENT;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001367 }
1368
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001369 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1370 JSObject* obj,
1371 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001372 FixedArrayBase* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001373 // External arrays do not support changing their length.
1374 UNREACHABLE();
1375 return obj;
1376 }
1377
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001378 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1379 uint32_t key,
1380 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001381 // External arrays always ignore deletes.
1382 return obj->GetHeap()->true_value();
1383 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001384
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001385 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001386 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001387 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001388 FixedArrayBase* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001389 uint32_t capacity =
1390 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
1391 return key < capacity;
1392 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001393};
1394
1395
1396class ExternalByteElementsAccessor
1397 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001398 EXTERNAL_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001399 public:
1400 explicit ExternalByteElementsAccessor(const char* name)
1401 : ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001402 EXTERNAL_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001403};
1404
1405
1406class ExternalUnsignedByteElementsAccessor
1407 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001408 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001409 public:
1410 explicit ExternalUnsignedByteElementsAccessor(const char* name)
1411 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001412 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001413};
1414
1415
1416class ExternalShortElementsAccessor
1417 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001418 EXTERNAL_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001419 public:
1420 explicit ExternalShortElementsAccessor(const char* name)
1421 : ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001422 EXTERNAL_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001423};
1424
1425
1426class ExternalUnsignedShortElementsAccessor
1427 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001428 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001429 public:
1430 explicit ExternalUnsignedShortElementsAccessor(const char* name)
1431 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001432 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001433};
1434
1435
1436class ExternalIntElementsAccessor
1437 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001438 EXTERNAL_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001439 public:
1440 explicit ExternalIntElementsAccessor(const char* name)
1441 : ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001442 EXTERNAL_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001443};
1444
1445
1446class ExternalUnsignedIntElementsAccessor
1447 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001448 EXTERNAL_UNSIGNED_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001449 public:
1450 explicit ExternalUnsignedIntElementsAccessor(const char* name)
1451 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001452 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001453};
1454
1455
1456class ExternalFloatElementsAccessor
1457 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001458 EXTERNAL_FLOAT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001459 public:
1460 explicit ExternalFloatElementsAccessor(const char* name)
1461 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001462 EXTERNAL_FLOAT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001463};
1464
1465
1466class ExternalDoubleElementsAccessor
1467 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001468 EXTERNAL_DOUBLE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001469 public:
1470 explicit ExternalDoubleElementsAccessor(const char* name)
1471 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001472 EXTERNAL_DOUBLE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001473};
1474
1475
1476class PixelElementsAccessor
1477 : public ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001478 EXTERNAL_PIXEL_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001479 public:
1480 explicit PixelElementsAccessor(const char* name)
1481 : ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001482 EXTERNAL_PIXEL_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001483};
1484
1485
1486class DictionaryElementsAccessor
1487 : public ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001488 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001489 public:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001490 explicit DictionaryElementsAccessor(const char* name)
1491 : ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001492 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001493
danno@chromium.orgc612e022011-11-10 11:38:15 +00001494 // Adjusts the length of the dictionary backing store and returns the new
1495 // length according to ES5 section 15.4.5.2 behavior.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001496 MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001497 FixedArrayBase* store,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001498 JSArray* array,
1499 Object* length_object,
1500 uint32_t length) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001501 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001502 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) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001526 // 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 {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001533 // 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++;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001543 }
1544 }
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001545 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001546
1547 // Update the number of elements.
1548 dict->ElementsRemoved(removed_entries);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001549 }
1550 return length_object;
1551 }
1552
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001553 MUST_USE_RESULT static MaybeObject* DeleteCommon(
1554 JSObject* obj,
1555 uint32_t key,
1556 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001557 Isolate* isolate = obj->GetIsolate();
1558 Heap* heap = isolate->heap();
1559 FixedArray* backing_store = FixedArray::cast(obj->elements());
1560 bool is_arguments =
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001561 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001562 if (is_arguments) {
1563 backing_store = FixedArray::cast(backing_store->get(1));
1564 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001565 SeededNumberDictionary* dictionary =
1566 SeededNumberDictionary::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001567 int entry = dictionary->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001568 if (entry != SeededNumberDictionary::kNotFound) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001569 Object* result = dictionary->DeleteProperty(entry, mode);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001570 if (result == heap->false_value()) {
1571 if (mode == JSObject::STRICT_DELETION) {
1572 // Deleting a non-configurable property in strict mode.
1573 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001574 Handle<Object> holder(obj, isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001575 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);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001581 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001582 return heap->false_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001583 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001584 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);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001593 }
1594 }
1595 return heap->true_value();
1596 }
1597
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001598 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1599 uint32_t from_start,
1600 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001601 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001602 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001603 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001604 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001605 UNREACHABLE();
1606 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001607 }
1608
1609
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001610 protected:
1611 friend class ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001612 ElementsKindTraits<DICTIONARY_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001613
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001614 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1615 uint32_t key,
1616 JSReceiver::DeleteMode mode) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001617 return DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001618 }
1619
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001620 MUST_USE_RESULT static MaybeObject* GetImpl(
1621 Object* receiver,
1622 JSObject* obj,
1623 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001624 FixedArrayBase* store) {
1625 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001626 int entry = backing_store->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001627 if (entry != SeededNumberDictionary::kNotFound) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001628 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 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001638 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001639 return obj->GetHeap()->the_hole_value();
1640 }
1641
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001642 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1643 Object* receiver,
1644 JSObject* obj,
1645 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001646 FixedArrayBase* backing_store) {
1647 SeededNumberDictionary* dictionary =
1648 SeededNumberDictionary::cast(backing_store);
1649 int entry = dictionary->FindEntry(key);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001650 if (entry != SeededNumberDictionary::kNotFound) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001651 return dictionary->DetailsAt(entry).attributes();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001652 }
1653 return ABSENT;
1654 }
1655
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001656 MUST_USE_RESULT static PropertyType GetTypeImpl(
1657 Object* receiver,
1658 JSObject* obj,
1659 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001660 FixedArrayBase* store) {
1661 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001662 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,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001673 FixedArrayBase* store) {
1674 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001675 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
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001684 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001685 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001686 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001687 FixedArrayBase* backing_store) {
1688 return SeededNumberDictionary::cast(backing_store)->FindEntry(key) !=
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001689 SeededNumberDictionary::kNotFound;
1690 }
1691
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001692 static uint32_t GetKeyForIndexImpl(FixedArrayBase* store,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001693 uint32_t index) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001694 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001695 Object* key = dict->KeyAt(index);
1696 return Smi::cast(key)->value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001697 }
1698};
1699
1700
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001701class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1702 NonStrictArgumentsElementsAccessor,
1703 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001704 public:
1705 explicit NonStrictArgumentsElementsAccessor(const char* name)
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001706 : ElementsAccessorBase<
1707 NonStrictArgumentsElementsAccessor,
1708 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001709 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001710 friend class ElementsAccessorBase<
1711 NonStrictArgumentsElementsAccessor,
1712 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001713
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001714 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1715 JSObject* obj,
1716 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001717 FixedArrayBase* parameters) {
1718 FixedArray* parameter_map = FixedArray::cast(parameters);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001719 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001720 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001721 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));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001728 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001729 receiver, obj, key, arguments);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001730 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 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001742 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001743 }
1744
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001745 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1746 Object* receiver,
1747 JSObject* obj,
1748 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001749 FixedArrayBase* backing_store) {
1750 FixedArray* parameter_map = FixedArray::cast(backing_store);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001751 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
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001762 MUST_USE_RESULT static PropertyType GetTypeImpl(
1763 Object* receiver,
1764 JSObject* obj,
1765 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001766 FixedArrayBase* parameters) {
1767 FixedArray* parameter_map = FixedArray::cast(parameters);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001768 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,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001783 FixedArrayBase* parameters) {
1784 FixedArray* parameter_map = FixedArray::cast(parameters);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001785 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
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001796 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1797 JSObject* obj,
1798 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001799 FixedArrayBase* parameter_map) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001800 // 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
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001806 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1807 uint32_t key,
1808 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001809 FixedArray* parameter_map = FixedArray::cast(obj->elements());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001810 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001811 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001812 // 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.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001815 parameter_map->set_the_hole(key + 2);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001816 } else {
1817 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1818 if (arguments->IsDictionary()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001819 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001820 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001821 // 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);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001825 }
1826 }
1827 return obj->GetHeap()->true_value();
1828 }
1829
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001830 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1831 uint32_t from_start,
1832 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001833 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001834 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001835 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001836 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001837 UNREACHABLE();
1838 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001839 }
1840
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001841 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
1842 FixedArray* parameter_map = FixedArray::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001843 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1844 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
1845 ForArray(arguments)->GetCapacity(arguments));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001846 }
1847
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001848 static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001849 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001850 return index;
1851 }
1852
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001853 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001854 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001855 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001856 FixedArrayBase* parameters) {
1857 FixedArray* parameter_map = FixedArray::cast(parameters);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001858 Object* probe = GetParameterMapArg(holder, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001859 if (!probe->IsTheHole()) {
1860 return true;
1861 } else {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001862 FixedArrayBase* arguments =
1863 FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001864 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001865 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001866 }
1867 }
1868
1869 private:
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001870 static Object* GetParameterMapArg(JSObject* holder,
1871 FixedArray* parameter_map,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001872 uint32_t key) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001873 uint32_t length = holder->IsJSArray()
1874 ? Smi::cast(JSArray::cast(holder)->length())->value()
1875 : parameter_map->length();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001876 return key < (length - 2)
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001877 ? parameter_map->get(key + 2)
1878 : parameter_map->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001879 }
1880};
1881
1882
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001883ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001884 return elements_accessors_[ElementsKindForArray(array)];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001885}
1886
1887
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001888void ElementsAccessor::InitializeOncePerProcess() {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001889 static ElementsAccessor* accessor_array[] = {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001890#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
erikcorry0ad885c2011-11-21 13:51:57 +00001891 ELEMENTS_LIST(ACCESSOR_ARRAY)
1892#undef ACCESSOR_ARRAY
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001893 };
1894
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001895 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
1896 kElementsKindCount);
1897
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001898 elements_accessors_ = accessor_array;
1899}
1900
1901
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001902void 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
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001910template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001911MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1912 ElementsKindTraits>::
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001913 SetLengthImpl(JSObject* obj,
1914 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001915 FixedArrayBase* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001916 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)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001943 SeededNumberDictionary* dictionary;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001944 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);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001964 { MaybeObject* result = array->SetContent(new_backing_store);
1965 if (result->IsFailure()) return result;
1966 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001967 return array;
1968}
1969
1970
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001971MUST_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: {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002041 DisallowHeapAllocation no_gc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002042 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
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002067} } // namespace v8::internal