blob: 77abf4e42b871b848f91a6cbe00df15545b42252 [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) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000157 ASSERT(to_base->map() != HEAP->fixed_cow_array_map());
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000158 DisallowHeapAllocation no_allocation;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000159 int copy_size = raw_copy_size;
160 if (raw_copy_size < 0) {
161 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
162 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000163 copy_size = Min(from_base->length() - from_start,
164 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000165 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000166 int start = to_start + copy_size;
167 int length = to_base->length() - start;
168 if (length > 0) {
169 Heap* heap = from_base->GetHeap();
170 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
171 heap->the_hole_value(), length);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000172 }
173 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000174 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000175 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
176 (copy_size + static_cast<int>(from_start)) <= from_base->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000177 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000178 FixedArray* from = FixedArray::cast(from_base);
179 FixedArray* to = FixedArray::cast(to_base);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000180 ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
181 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000182 Address to_address = to->address() + FixedArray::kHeaderSize;
183 Address from_address = from->address() + FixedArray::kHeaderSize;
184 CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
185 reinterpret_cast<Object**>(from_address) + from_start,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000186 static_cast<size_t>(copy_size));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000187 if (IsFastObjectElementsKind(from_kind) &&
188 IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000189 Heap* heap = from->GetHeap();
190 if (!heap->InNewSpace(to)) {
191 heap->RecordWrites(to->address(),
192 to->OffsetOfElementAt(to_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000193 copy_size);
194 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000195 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000196 }
197}
198
199
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000200static void CopyDictionaryToObjectElements(FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000201 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000202 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000203 ElementsKind to_kind,
204 uint32_t to_start,
danno@chromium.orgc7406162012-03-26 09:46:02 +0000205 int raw_copy_size) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000206 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000207 DisallowHeapAllocation no_allocation;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000208 int copy_size = raw_copy_size;
209 Heap* heap = from->GetHeap();
210 if (raw_copy_size < 0) {
211 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
212 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
213 copy_size = from->max_number_key() + 1 - from_start;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000214 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000215 int start = to_start + copy_size;
216 int length = to_base->length() - start;
217 if (length > 0) {
218 Heap* heap = from->GetHeap();
219 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
220 heap->the_hole_value(), length);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000221 }
222 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000223 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000224 ASSERT(to_base != from_base);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000225 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000226 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000227 FixedArray* to = FixedArray::cast(to_base);
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000228 uint32_t to_length = to->length();
229 if (to_start + copy_size > to_length) {
230 copy_size = to_length - to_start;
231 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000232 for (int i = 0; i < copy_size; i++) {
233 int entry = from->FindEntry(i + from_start);
234 if (entry != SeededNumberDictionary::kNotFound) {
235 Object* value = from->ValueAt(entry);
236 ASSERT(!value->IsTheHole());
237 to->set(i + to_start, value, SKIP_WRITE_BARRIER);
238 } else {
239 to->set_the_hole(i + to_start);
240 }
241 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000242 if (IsFastObjectElementsKind(to_kind)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000243 if (!heap->InNewSpace(to)) {
244 heap->RecordWrites(to->address(),
245 to->OffsetOfElementAt(to_start),
246 copy_size);
247 }
248 heap->incremental_marking()->RecordWrites(to);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000249 }
250}
251
252
253MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000254 FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000255 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000256 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000257 ElementsKind to_kind,
258 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000259 int raw_copy_size) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000260 ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000261 int copy_size = raw_copy_size;
262 if (raw_copy_size < 0) {
263 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
264 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000265 copy_size = Min(from_base->length() - from_start,
266 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000267 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000268 // Also initialize the area that will be copied over since HeapNumber
269 // allocation below can cause an incremental marking step, requiring all
270 // existing heap objects to be propertly initialized.
271 int start = to_start;
272 int length = to_base->length() - start;
273 if (length > 0) {
274 Heap* heap = from_base->GetHeap();
275 MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
276 heap->the_hole_value(), length);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000277 }
278 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000279 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000280 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
281 (copy_size + static_cast<int>(from_start)) <= from_base->length());
282 if (copy_size == 0) return from_base;
283 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
284 FixedArray* to = FixedArray::cast(to_base);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000285 for (int i = 0; i < copy_size; ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000286 if (IsFastSmiElementsKind(to_kind)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000287 UNIMPLEMENTED();
288 return Failure::Exception();
289 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000290 MaybeObject* maybe_value = from->get(i + from_start);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000291 Object* value;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000292 ASSERT(IsFastObjectElementsKind(to_kind));
293 // Because Double -> Object elements transitions allocate HeapObjects
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000294 // iteratively, the allocate must succeed within a single GC cycle,
295 // otherwise the retry after the GC will also fail. In order to ensure
296 // that no GC is triggered, allocate HeapNumbers from old space if they
297 // can't be taken from new space.
298 if (!maybe_value->ToObject(&value)) {
299 ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000300 Heap* heap = from->GetHeap();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000301 MaybeObject* maybe_value_object =
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000302 heap->AllocateHeapNumber(from->get_scalar(i + from_start),
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000303 TENURED);
304 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
305 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000306 to->set(i + to_start, value, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000307 }
308 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000309 return to;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000310}
311
312
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000313static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000314 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000315 FixedArrayBase* to_base,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000316 uint32_t to_start,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000317 int raw_copy_size) {
318 int copy_size = raw_copy_size;
319 if (raw_copy_size < 0) {
320 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
321 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000322 copy_size = Min(from_base->length() - from_start,
323 to_base->length() - to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000324 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000325 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
326 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000327 }
328 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000329 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000330 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
331 (copy_size + static_cast<int>(from_start)) <= from_base->length());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000332 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000333 FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
334 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000335 Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
336 Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
337 to_address += kDoubleSize * to_start;
338 from_address += kDoubleSize * from_start;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000339 int words_per_double = (kDoubleSize / kPointerSize);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000340 CopyWords(reinterpret_cast<Object**>(to_address),
341 reinterpret_cast<Object**>(from_address),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000342 static_cast<size_t>(words_per_double * copy_size));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000343}
344
345
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000346static void CopySmiToDoubleElements(FixedArrayBase* from_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000347 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000348 FixedArrayBase* to_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000349 uint32_t to_start,
350 int raw_copy_size) {
351 int copy_size = raw_copy_size;
352 if (raw_copy_size < 0) {
353 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
354 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000355 copy_size = from_base->length() - from_start;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000356 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000357 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
358 FixedDoubleArray::cast(to_base)->set_the_hole(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000359 }
360 }
361 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000362 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
363 (copy_size + static_cast<int>(from_start)) <= from_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000364 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000365 FixedArray* from = FixedArray::cast(from_base);
366 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000367 Object* the_hole = from->GetHeap()->the_hole_value();
368 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
369 from_start < from_end; from_start++, to_start++) {
370 Object* hole_or_smi = from->get(from_start);
371 if (hole_or_smi == the_hole) {
372 to->set_the_hole(to_start);
373 } else {
374 to->set(to_start, Smi::cast(hole_or_smi)->value());
375 }
376 }
377}
378
379
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000380static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000381 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000382 FixedArrayBase* to_base,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000383 uint32_t to_start,
384 int packed_size,
385 int raw_copy_size) {
386 int copy_size = raw_copy_size;
387 uint32_t to_end;
388 if (raw_copy_size < 0) {
389 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
390 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000391 copy_size = packed_size - from_start;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000392 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000393 to_end = to_base->length();
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000394 for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000395 FixedDoubleArray::cast(to_base)->set_the_hole(i);
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000396 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000397 } else {
398 to_end = to_start + static_cast<uint32_t>(copy_size);
399 }
400 } else {
401 to_end = to_start + static_cast<uint32_t>(copy_size);
402 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000403 ASSERT(static_cast<int>(to_end) <= to_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000404 ASSERT(packed_size >= 0 && packed_size <= copy_size);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000405 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
406 (copy_size + static_cast<int>(from_start)) <= from_base->length());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000407 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000408 FixedArray* from = FixedArray::cast(from_base);
409 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000410 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
411 from_start < from_end; from_start++, to_start++) {
412 Object* smi = from->get(from_start);
413 ASSERT(!smi->IsTheHole());
414 to->set(to_start, Smi::cast(smi)->value());
415 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000416}
417
418
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000419static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000420 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000421 FixedArrayBase* to_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000422 uint32_t to_start,
423 int raw_copy_size) {
424 int copy_size = raw_copy_size;
425 if (raw_copy_size < 0) {
426 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
427 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000428 copy_size = from_base->length() - from_start;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000429 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000430 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
431 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000432 }
433 }
434 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000435 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
436 (copy_size + static_cast<int>(from_start)) <= from_base->length());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000437 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000438 FixedArray* from = FixedArray::cast(from_base);
439 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000440 Object* the_hole = from->GetHeap()->the_hole_value();
441 for (uint32_t from_end = from_start + copy_size;
442 from_start < from_end; from_start++, to_start++) {
443 Object* hole_or_object = from->get(from_start);
444 if (hole_or_object == the_hole) {
445 to->set_the_hole(to_start);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000446 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000447 to->set(to_start, hole_or_object->Number());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000448 }
449 }
450}
451
452
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000453static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000454 uint32_t from_start,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000455 FixedArrayBase* to_base,
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000456 uint32_t to_start,
457 int raw_copy_size) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000458 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000459 int copy_size = raw_copy_size;
460 if (copy_size < 0) {
461 ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
462 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
463 copy_size = from->max_number_key() + 1 - from_start;
464 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000465 for (int i = to_start + copy_size; i < to_base->length(); ++i) {
466 FixedDoubleArray::cast(to_base)->set_the_hole(i);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000467 }
468 }
469 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000470 if (copy_size == 0) return;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000471 FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
danno@chromium.org8c0a43f2012-04-03 08:37:53 +0000472 uint32_t to_length = to->length();
473 if (to_start + copy_size > to_length) {
474 copy_size = to_length - to_start;
475 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000476 for (int i = 0; i < copy_size; i++) {
477 int entry = from->FindEntry(i + from_start);
478 if (entry != SeededNumberDictionary::kNotFound) {
479 to->set(i + to_start, from->ValueAt(entry)->Number());
480 } else {
481 to->set_the_hole(i + to_start);
482 }
483 }
484}
485
486
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000487static void TraceTopFrame(Isolate* isolate) {
488 StackFrameIterator it(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000489 if (it.done()) {
490 PrintF("unknown location (no JavaScript frames present)");
491 return;
492 }
493 StackFrame* raw_frame = it.frame();
494 if (raw_frame->is_internal()) {
495 Isolate* isolate = Isolate::Current();
496 Code* apply_builtin = isolate->builtins()->builtin(
497 Builtins::kFunctionApply);
498 if (raw_frame->unchecked_code() == apply_builtin) {
499 PrintF("apply from ");
500 it.Advance();
501 raw_frame = it.frame();
502 }
503 }
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;
584 Map* map = fixed_array_base->map();
585 // Arrays that have been shifted in place can't be verified.
586 Heap* heap = holder->GetHeap();
danno@chromium.org72204d52012-10-31 10:02:10 +0000587 if (map == heap->one_pointer_filler_map() ||
588 map == heap->two_pointer_filler_map() ||
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000589 map == heap->free_space_map()) {
590 return;
591 }
592 int length = 0;
593 if (holder->IsJSArray()) {
594 Object* length_obj = JSArray::cast(holder)->length();
595 if (length_obj->IsSmi()) {
596 length = Smi::cast(length_obj)->value();
597 }
598 } else {
599 length = fixed_array_base->length();
600 }
601 ElementsAccessorSubclass::ValidateContents(holder, length);
602 }
603
604 virtual void Validate(JSObject* holder) {
605 ElementsAccessorSubclass::ValidateImpl(holder);
606 }
607
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000608 static bool HasElementImpl(Object* receiver,
609 JSObject* holder,
610 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000611 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000612 return ElementsAccessorSubclass::GetAttributesImpl(
613 receiver, holder, key, backing_store) != ABSENT;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000614 }
615
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000616 virtual bool HasElement(Object* receiver,
617 JSObject* holder,
618 uint32_t key,
619 FixedArrayBase* backing_store) {
620 if (backing_store == NULL) {
621 backing_store = holder->elements();
622 }
623 return ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000624 receiver, holder, key, backing_store);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000625 }
626
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000627 MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
628 JSObject* holder,
629 uint32_t key,
630 FixedArrayBase* backing_store) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000631 if (backing_store == NULL) {
632 backing_store = holder->elements();
633 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000634
635 if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
636 FLAG_trace_js_array_abuse) {
637 CheckArrayAbuse(holder, "elements read", key);
638 }
639
640 if (IsExternalArrayElementsKind(ElementsTraits::Kind) &&
641 FLAG_trace_external_array_abuse) {
642 CheckArrayAbuse(holder, "external elements read", key);
643 }
644
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000645 return ElementsAccessorSubclass::GetImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000646 receiver, holder, key, backing_store);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000647 }
648
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000649 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
650 JSObject* obj,
651 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000652 FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000653 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000654 ? BackingStore::cast(backing_store)->get(key)
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000655 : backing_store->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000656 }
657
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000658 MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
659 Object* receiver,
660 JSObject* holder,
661 uint32_t key,
662 FixedArrayBase* backing_store) {
663 if (backing_store == NULL) {
664 backing_store = holder->elements();
665 }
666 return ElementsAccessorSubclass::GetAttributesImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000667 receiver, holder, key, backing_store);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000668 }
669
670 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
671 Object* receiver,
672 JSObject* obj,
673 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000674 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000675 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
676 return ABSENT;
677 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000678 return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000679 }
680
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000681 MUST_USE_RESULT virtual PropertyType GetType(
682 Object* receiver,
683 JSObject* holder,
684 uint32_t key,
685 FixedArrayBase* backing_store) {
686 if (backing_store == NULL) {
687 backing_store = holder->elements();
688 }
689 return ElementsAccessorSubclass::GetTypeImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000690 receiver, holder, key, backing_store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000691 }
692
693 MUST_USE_RESULT static PropertyType GetTypeImpl(
694 Object* receiver,
695 JSObject* obj,
696 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000697 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000698 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
699 return NONEXISTENT;
700 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000701 return BackingStore::cast(backing_store)->is_the_hole(key)
702 ? NONEXISTENT : FIELD;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000703 }
704
705 MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
706 Object* receiver,
707 JSObject* holder,
708 uint32_t key,
709 FixedArrayBase* backing_store) {
710 if (backing_store == NULL) {
711 backing_store = holder->elements();
712 }
713 return ElementsAccessorSubclass::GetAccessorPairImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000714 receiver, holder, key, backing_store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000715 }
716
717 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
718 Object* receiver,
719 JSObject* obj,
720 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000721 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000722 return NULL;
723 }
724
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000725 MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
726 Object* length) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000727 return ElementsAccessorSubclass::SetLengthImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000728 array, length, array->elements());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000729 }
730
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000731 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
732 JSObject* obj,
733 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000734 FixedArrayBase* backing_store);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000735
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000736 MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
737 JSArray* array,
738 int capacity,
739 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000740 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
741 array,
742 capacity,
743 length);
744 }
745
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000746 MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength(
747 JSObject* obj,
748 int capacity,
749 int length) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000750 UNIMPLEMENTED();
751 return obj;
752 }
753
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000754 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
755 uint32_t key,
756 JSReceiver::DeleteMode mode) = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000757
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000758 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
759 uint32_t from_start,
760 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000761 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000762 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000763 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000764 int copy_size) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000765 UNREACHABLE();
766 return NULL;
767 }
768
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000769 MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder,
770 uint32_t from_start,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000771 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000772 FixedArrayBase* to,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000773 uint32_t to_start,
774 int copy_size,
775 FixedArrayBase* from) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000776 int packed_size = kPackedSizeNotKnown;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000777 if (from == NULL) {
778 from = from_holder->elements();
779 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000780
781 if (from_holder) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000782 bool is_packed = IsFastPackedElementsKind(from_kind) &&
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000783 from_holder->IsJSArray();
784 if (is_packed) {
785 packed_size = Smi::cast(JSArray::cast(from_holder)->length())->value();
786 if (copy_size >= 0 && packed_size > copy_size) {
787 packed_size = copy_size;
788 }
789 }
790 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000791 return ElementsAccessorSubclass::CopyElementsImpl(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000792 from, from_start, to, from_kind, to_start, packed_size, copy_size);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000793 }
794
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000795 MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray(
796 Object* receiver,
797 JSObject* holder,
798 FixedArray* to,
799 FixedArrayBase* from) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000800 int len0 = to->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000801#ifdef DEBUG
802 if (FLAG_enable_slow_asserts) {
803 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000804 ASSERT(!to->get(i)->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805 }
806 }
807#endif
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000808 if (from == NULL) {
809 from = holder->elements();
810 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000811
812 // Optimize if 'other' is empty.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000813 // We cannot optimize if 'this' is empty, as other may have holes.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000814 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000815 if (len1 == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000816
817 // Compute how many elements are not in other.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000818 uint32_t extra = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000819 for (uint32_t y = 0; y < len1; y++) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000820 uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000821 if (ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000822 receiver, holder, key, from)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000823 MaybeObject* maybe_value =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000824 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000825 Object* value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000826 if (!maybe_value->To(&value)) return maybe_value;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000827 ASSERT(!value->IsTheHole());
828 if (!HasKey(to, value)) {
829 extra++;
830 }
831 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 }
833
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000834 if (extra == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000835
836 // Allocate the result
837 FixedArray* result;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000838 MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra);
839 if (!maybe_obj->To(&result)) return maybe_obj;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000840
841 // Fill in the content
842 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000843 DisallowHeapAllocation no_gc;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000844 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
845 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000846 Object* e = to->get(i);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000847 ASSERT(e->IsString() || e->IsNumber());
848 result->set(i, e, mode);
849 }
850 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000851 // Fill in the extra values.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000852 uint32_t index = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000853 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000854 uint32_t key =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000855 ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000856 if (ElementsAccessorSubclass::HasElementImpl(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000857 receiver, holder, key, from)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000858 MaybeObject* maybe_value =
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000859 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000860 Object* value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000861 if (!maybe_value->To(&value)) return maybe_value;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000862 if (!value->IsTheHole() && !HasKey(to, value)) {
863 result->set(len0 + index, value);
864 index++;
865 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000866 }
867 }
868 ASSERT(extra == index);
869 return result;
870 }
871
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000872 protected:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000873 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000874 return backing_store->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000875 }
876
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000877 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000878 return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000879 }
880
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000881 static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000882 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000883 return index;
884 }
885
886 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000887 uint32_t index) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000888 return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000889 }
890
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000891 private:
892 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
893};
894
895
danno@chromium.orgc612e022011-11-10 11:38:15 +0000896// Super class for all fast element arrays.
897template<typename FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000898 typename KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000899 int ElementSize>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000900class FastElementsAccessor
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000901 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000902 public:
903 explicit FastElementsAccessor(const char* name)
904 : ElementsAccessorBase<FastElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000905 KindTraits>(name) {}
danno@chromium.orgc612e022011-11-10 11:38:15 +0000906 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000907 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000908 friend class NonStrictArgumentsElementsAccessor;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000909
910 typedef typename KindTraits::BackingStore BackingStore;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000911
912 // Adjusts the length of the fast backing store or returns the new length or
913 // undefined in case conversion to a slow backing store should be performed.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000914 static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000915 JSArray* array,
916 Object* length_object,
917 uint32_t length) {
918 uint32_t old_capacity = backing_store->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000919 Object* old_length = array->length();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000920 bool same_or_smaller_size = old_length->IsSmi() &&
921 static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000922 ElementsKind kind = array->GetElementsKind();
923
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000924 if (!same_or_smaller_size && IsFastElementsKind(kind) &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000925 !IsFastHoleyElementsKind(kind)) {
926 kind = GetHoleyElementsKind(kind);
927 MaybeObject* maybe_obj = array->TransitionElementsKind(kind);
928 if (maybe_obj->IsFailure()) return maybe_obj;
929 }
danno@chromium.orgc612e022011-11-10 11:38:15 +0000930
931 // Check whether the backing store should be shrunk.
932 if (length <= old_capacity) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000933 if (array->HasFastSmiOrObjectElements()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000934 MaybeObject* maybe_obj = array->EnsureWritableFastElements();
935 if (!maybe_obj->To(&backing_store)) return maybe_obj;
936 }
937 if (2 * length <= old_capacity) {
938 // If more than half the elements won't be used, trim the array.
939 if (length == 0) {
940 array->initialize_elements();
941 } else {
942 backing_store->set_length(length);
943 Address filler_start = backing_store->address() +
944 BackingStore::OffsetOfElementAt(length);
945 int filler_size = (old_capacity - length) * ElementSize;
946 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
947 }
948 } else {
949 // Otherwise, fill the unused tail with holes.
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +0000950 int old_length = FastD2IChecked(array->length()->Number());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000951 for (int i = length; i < old_length; i++) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000952 BackingStore::cast(backing_store)->set_the_hole(i);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000953 }
954 }
955 return length_object;
956 }
957
958 // Check whether the backing store should be expanded.
959 uint32_t min = JSObject::NewElementsCapacity(old_capacity);
960 uint32_t new_capacity = length > min ? length : min;
961 if (!array->ShouldConvertToSlowElements(new_capacity)) {
962 MaybeObject* result = FastElementsAccessorSubclass::
963 SetFastElementsCapacityAndLength(array, new_capacity, length);
964 if (result->IsFailure()) return result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000965 array->ValidateElements();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000966 return length_object;
967 }
968
969 // Request conversion to slow elements.
970 return array->GetHeap()->undefined_value();
971 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000972
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000973 static MaybeObject* DeleteCommon(JSObject* obj,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000974 uint32_t key,
975 JSReceiver::DeleteMode mode) {
976 ASSERT(obj->HasFastSmiOrObjectElements() ||
977 obj->HasFastDoubleElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000978 obj->HasFastArgumentsElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000979 Heap* heap = obj->GetHeap();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000980 Object* elements = obj->elements();
981 if (elements == heap->empty_fixed_array()) {
982 return heap->true_value();
983 }
984 typename KindTraits::BackingStore* backing_store =
985 KindTraits::BackingStore::cast(elements);
986 bool is_non_strict_arguments_elements_map =
987 backing_store->map() == heap->non_strict_arguments_elements_map();
988 if (is_non_strict_arguments_elements_map) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000989 backing_store = KindTraits::BackingStore::cast(
990 FixedArray::cast(backing_store)->get(1));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000991 }
992 uint32_t length = static_cast<uint32_t>(
993 obj->IsJSArray()
994 ? Smi::cast(JSArray::cast(obj)->length())->value()
995 : backing_store->length());
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000996 if (key < length) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000997 if (!is_non_strict_arguments_elements_map) {
998 ElementsKind kind = KindTraits::Kind;
999 if (IsFastPackedElementsKind(kind)) {
1000 MaybeObject* transitioned =
1001 obj->TransitionElementsKind(GetHoleyElementsKind(kind));
1002 if (transitioned->IsFailure()) return transitioned;
1003 }
1004 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
1005 Object* writable;
1006 MaybeObject* maybe = obj->EnsureWritableFastElements();
1007 if (!maybe->ToObject(&writable)) return maybe;
1008 backing_store = KindTraits::BackingStore::cast(writable);
1009 }
1010 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001011 backing_store->set_the_hole(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001012 // If an old space backing store is larger than a certain size and
1013 // has too few used values, normalize it.
1014 // To avoid doing the check on every delete we require at least
1015 // one adjacent hole to the value being deleted.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001016 const int kMinLengthForSparsenessCheck = 64;
1017 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
1018 !heap->InNewSpace(backing_store) &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001019 ((key > 0 && backing_store->is_the_hole(key - 1)) ||
1020 (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001021 int num_used = 0;
1022 for (int i = 0; i < backing_store->length(); ++i) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001023 if (!backing_store->is_the_hole(i)) ++num_used;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001024 // Bail out early if more than 1/4 is used.
1025 if (4 * num_used > backing_store->length()) break;
1026 }
1027 if (4 * num_used <= backing_store->length()) {
1028 MaybeObject* result = obj->NormalizeElements();
1029 if (result->IsFailure()) return result;
1030 }
1031 }
1032 }
1033 return heap->true_value();
1034 }
1035
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001036 virtual MaybeObject* Delete(JSObject* obj,
1037 uint32_t key,
1038 JSReceiver::DeleteMode mode) {
1039 return DeleteCommon(obj, key, mode);
1040 }
1041
1042 static bool HasElementImpl(
1043 Object* receiver,
1044 JSObject* holder,
1045 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001046 FixedArrayBase* backing_store) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001047 if (key >= static_cast<uint32_t>(backing_store->length())) {
1048 return false;
1049 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001050 return !BackingStore::cast(backing_store)->is_the_hole(key);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001051 }
1052
1053 static void ValidateContents(JSObject* holder, int length) {
1054#if DEBUG
1055 FixedArrayBase* elements = holder->elements();
1056 Heap* heap = elements->GetHeap();
1057 Map* map = elements->map();
1058 ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) &&
1059 (map == heap->fixed_array_map() ||
1060 map == heap->fixed_cow_array_map())) ||
1061 (IsFastDoubleElementsKind(KindTraits::Kind) ==
1062 ((map == heap->fixed_array_map() && length == 0) ||
1063 map == heap->fixed_double_array_map())));
1064 for (int i = 0; i < length; i++) {
1065 typename KindTraits::BackingStore* backing_store =
1066 KindTraits::BackingStore::cast(elements);
1067 ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) ||
1068 static_cast<Object*>(backing_store->get(i))->IsSmi()) ||
1069 (IsFastHoleyElementsKind(KindTraits::Kind) ==
1070 backing_store->is_the_hole(i)));
1071 }
1072#endif
1073 }
1074};
1075
1076
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001077static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) {
1078 switch (array->map()->instance_type()) {
1079 case FIXED_ARRAY_TYPE:
1080 if (array->IsDictionary()) {
1081 return DICTIONARY_ELEMENTS;
1082 } else {
1083 return FAST_HOLEY_ELEMENTS;
1084 }
1085 case FIXED_DOUBLE_ARRAY_TYPE:
1086 return FAST_HOLEY_DOUBLE_ELEMENTS;
1087 case EXTERNAL_BYTE_ARRAY_TYPE:
1088 return EXTERNAL_BYTE_ELEMENTS;
1089 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1090 return EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
1091 case EXTERNAL_SHORT_ARRAY_TYPE:
1092 return EXTERNAL_SHORT_ELEMENTS;
1093 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1094 return EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
1095 case EXTERNAL_INT_ARRAY_TYPE:
1096 return EXTERNAL_INT_ELEMENTS;
1097 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1098 return EXTERNAL_UNSIGNED_INT_ELEMENTS;
1099 case EXTERNAL_FLOAT_ARRAY_TYPE:
1100 return EXTERNAL_FLOAT_ELEMENTS;
1101 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1102 return EXTERNAL_DOUBLE_ELEMENTS;
1103 case EXTERNAL_PIXEL_ARRAY_TYPE:
1104 return EXTERNAL_PIXEL_ELEMENTS;
1105 default:
1106 UNREACHABLE();
1107 }
1108 return FAST_HOLEY_ELEMENTS;
1109}
1110
1111
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001112template<typename FastElementsAccessorSubclass,
1113 typename KindTraits>
1114class FastSmiOrObjectElementsAccessor
1115 : public FastElementsAccessor<FastElementsAccessorSubclass,
1116 KindTraits,
1117 kPointerSize> {
1118 public:
1119 explicit FastSmiOrObjectElementsAccessor(const char* name)
1120 : FastElementsAccessor<FastElementsAccessorSubclass,
1121 KindTraits,
1122 kPointerSize>(name) {}
1123
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001124 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1125 uint32_t from_start,
1126 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001127 ElementsKind from_kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001128 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001129 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001130 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001131 ElementsKind to_kind = KindTraits::Kind;
1132 switch (from_kind) {
1133 case FAST_SMI_ELEMENTS:
1134 case FAST_HOLEY_SMI_ELEMENTS:
1135 case FAST_ELEMENTS:
1136 case FAST_HOLEY_ELEMENTS:
1137 CopyObjectToObjectElements(
1138 from, from_kind, from_start, to, to_kind, to_start, copy_size);
1139 return to->GetHeap()->undefined_value();
1140 case FAST_DOUBLE_ELEMENTS:
1141 case FAST_HOLEY_DOUBLE_ELEMENTS:
1142 return CopyDoubleToObjectElements(
1143 from, from_start, to, to_kind, to_start, copy_size);
1144 case DICTIONARY_ELEMENTS:
1145 CopyDictionaryToObjectElements(
1146 from, from_start, to, to_kind, to_start, copy_size);
1147 return to->GetHeap()->undefined_value();
1148 case NON_STRICT_ARGUMENTS_ELEMENTS: {
1149 // TODO(verwaest): This is a temporary hack to support extending
1150 // NON_STRICT_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
1151 // This case should be UNREACHABLE().
1152 FixedArray* parameter_map = FixedArray::cast(from);
1153 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1154 ElementsKind from_kind = ElementsKindForArray(arguments);
1155 return CopyElementsImpl(arguments, from_start, to, from_kind,
1156 to_start, packed_size, copy_size);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001157 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001158 case EXTERNAL_BYTE_ELEMENTS:
1159 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
1160 case EXTERNAL_SHORT_ELEMENTS:
1161 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
1162 case EXTERNAL_INT_ELEMENTS:
1163 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
1164 case EXTERNAL_FLOAT_ELEMENTS:
1165 case EXTERNAL_DOUBLE_ELEMENTS:
1166 case EXTERNAL_PIXEL_ELEMENTS:
1167 UNREACHABLE();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001168 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001169 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001170 }
1171
1172
danno@chromium.orgc612e022011-11-10 11:38:15 +00001173 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
1174 uint32_t capacity,
1175 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001176 JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
1177 obj->HasFastSmiElements()
1178 ? JSObject::kAllowSmiElements
1179 : JSObject::kDontAllowSmiElements;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001180 return obj->SetFastElementsCapacityAndLength(capacity,
1181 length,
1182 set_capacity_mode);
1183 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001184};
1185
1186
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001187class FastPackedSmiElementsAccessor
1188 : public FastSmiOrObjectElementsAccessor<
1189 FastPackedSmiElementsAccessor,
1190 ElementsKindTraits<FAST_SMI_ELEMENTS> > {
1191 public:
1192 explicit FastPackedSmiElementsAccessor(const char* name)
1193 : FastSmiOrObjectElementsAccessor<
1194 FastPackedSmiElementsAccessor,
1195 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {}
1196};
1197
1198
1199class FastHoleySmiElementsAccessor
1200 : public FastSmiOrObjectElementsAccessor<
1201 FastHoleySmiElementsAccessor,
1202 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > {
1203 public:
1204 explicit FastHoleySmiElementsAccessor(const char* name)
1205 : FastSmiOrObjectElementsAccessor<
1206 FastHoleySmiElementsAccessor,
1207 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {}
1208};
1209
1210
1211class FastPackedObjectElementsAccessor
1212 : public FastSmiOrObjectElementsAccessor<
1213 FastPackedObjectElementsAccessor,
1214 ElementsKindTraits<FAST_ELEMENTS> > {
1215 public:
1216 explicit FastPackedObjectElementsAccessor(const char* name)
1217 : FastSmiOrObjectElementsAccessor<
1218 FastPackedObjectElementsAccessor,
1219 ElementsKindTraits<FAST_ELEMENTS> >(name) {}
1220};
1221
1222
1223class FastHoleyObjectElementsAccessor
1224 : public FastSmiOrObjectElementsAccessor<
1225 FastHoleyObjectElementsAccessor,
1226 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > {
1227 public:
1228 explicit FastHoleyObjectElementsAccessor(const char* name)
1229 : FastSmiOrObjectElementsAccessor<
1230 FastHoleyObjectElementsAccessor,
1231 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {}
1232};
1233
1234
1235template<typename FastElementsAccessorSubclass,
1236 typename KindTraits>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237class FastDoubleElementsAccessor
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001238 : public FastElementsAccessor<FastElementsAccessorSubclass,
1239 KindTraits,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001240 kDoubleSize> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001241 public:
1242 explicit FastDoubleElementsAccessor(const char* name)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001243 : FastElementsAccessor<FastElementsAccessorSubclass,
1244 KindTraits,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001245 kDoubleSize>(name) {}
1246
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001247 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
1248 uint32_t capacity,
1249 uint32_t length) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001250 return obj->SetFastDoubleElementsCapacityAndLength(capacity,
1251 length);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001252 }
1253
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001254 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001255 static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1256 uint32_t from_start,
1257 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001258 ElementsKind from_kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001259 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001260 int packed_size,
danno@chromium.orgc7406162012-03-26 09:46:02 +00001261 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001262 switch (from_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001263 case FAST_SMI_ELEMENTS:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001264 CopyPackedSmiToDoubleElements(
1265 from, from_start, to, to_start, packed_size, copy_size);
1266 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001267 case FAST_HOLEY_SMI_ELEMENTS:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001268 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
1269 break;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001270 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001271 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001272 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001273 break;
1274 case FAST_ELEMENTS:
1275 case FAST_HOLEY_ELEMENTS:
1276 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
1277 break;
1278 case DICTIONARY_ELEMENTS:
1279 CopyDictionaryToDoubleElements(
1280 from, from_start, to, to_start, copy_size);
1281 break;
1282 case NON_STRICT_ARGUMENTS_ELEMENTS:
1283 case EXTERNAL_BYTE_ELEMENTS:
1284 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
1285 case EXTERNAL_SHORT_ELEMENTS:
1286 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
1287 case EXTERNAL_INT_ELEMENTS:
1288 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
1289 case EXTERNAL_FLOAT_ELEMENTS:
1290 case EXTERNAL_DOUBLE_ELEMENTS:
1291 case EXTERNAL_PIXEL_ELEMENTS:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001292 UNREACHABLE();
1293 }
1294 return to->GetHeap()->undefined_value();
1295 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001296};
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001297
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001298
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001299class FastPackedDoubleElementsAccessor
1300 : public FastDoubleElementsAccessor<
1301 FastPackedDoubleElementsAccessor,
1302 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
1303 public:
1304 friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
1305 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
1306 explicit FastPackedDoubleElementsAccessor(const char* name)
1307 : FastDoubleElementsAccessor<
1308 FastPackedDoubleElementsAccessor,
1309 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {}
1310};
1311
1312
1313class FastHoleyDoubleElementsAccessor
1314 : public FastDoubleElementsAccessor<
1315 FastHoleyDoubleElementsAccessor,
1316 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
1317 public:
1318 friend class ElementsAccessorBase<
1319 FastHoleyDoubleElementsAccessor,
1320 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
1321 explicit FastHoleyDoubleElementsAccessor(const char* name)
1322 : FastDoubleElementsAccessor<
1323 FastHoleyDoubleElementsAccessor,
1324 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001325};
1326
1327
1328// Super class for all external element arrays.
1329template<typename ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001330 ElementsKind Kind>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001331class ExternalElementsAccessor
1332 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001333 ElementsKindTraits<Kind> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001334 public:
1335 explicit ExternalElementsAccessor(const char* name)
1336 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001337 ElementsKindTraits<Kind> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001338
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001339 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001340 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
1341
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001342 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001343 ElementsKindTraits<Kind> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001344
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001345 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1346 JSObject* obj,
1347 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001348 FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001349 return
1350 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001351 ? BackingStore::cast(backing_store)->get(key)
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001352 : backing_store->GetHeap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001353 }
1354
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001355 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1356 Object* receiver,
1357 JSObject* obj,
1358 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001359 FixedArrayBase* backing_store) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001360 return
1361 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001362 ? NONE : ABSENT;
1363 }
1364
1365 MUST_USE_RESULT static PropertyType GetTypeImpl(
1366 Object* receiver,
1367 JSObject* obj,
1368 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001369 FixedArrayBase* backing_store) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001370 return
1371 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
1372 ? FIELD : NONEXISTENT;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001373 }
1374
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001375 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1376 JSObject* obj,
1377 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001378 FixedArrayBase* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001379 // External arrays do not support changing their length.
1380 UNREACHABLE();
1381 return obj;
1382 }
1383
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001384 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1385 uint32_t key,
1386 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001387 // External arrays always ignore deletes.
1388 return obj->GetHeap()->true_value();
1389 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001390
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001391 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001392 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001393 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001394 FixedArrayBase* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001395 uint32_t capacity =
1396 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
1397 return key < capacity;
1398 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001399};
1400
1401
1402class ExternalByteElementsAccessor
1403 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001404 EXTERNAL_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001405 public:
1406 explicit ExternalByteElementsAccessor(const char* name)
1407 : ExternalElementsAccessor<ExternalByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001408 EXTERNAL_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001409};
1410
1411
1412class ExternalUnsignedByteElementsAccessor
1413 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001414 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001415 public:
1416 explicit ExternalUnsignedByteElementsAccessor(const char* name)
1417 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001418 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001419};
1420
1421
1422class ExternalShortElementsAccessor
1423 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001424 EXTERNAL_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001425 public:
1426 explicit ExternalShortElementsAccessor(const char* name)
1427 : ExternalElementsAccessor<ExternalShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001428 EXTERNAL_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001429};
1430
1431
1432class ExternalUnsignedShortElementsAccessor
1433 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001434 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001435 public:
1436 explicit ExternalUnsignedShortElementsAccessor(const char* name)
1437 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001438 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001439};
1440
1441
1442class ExternalIntElementsAccessor
1443 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001444 EXTERNAL_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001445 public:
1446 explicit ExternalIntElementsAccessor(const char* name)
1447 : ExternalElementsAccessor<ExternalIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001448 EXTERNAL_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001449};
1450
1451
1452class ExternalUnsignedIntElementsAccessor
1453 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001454 EXTERNAL_UNSIGNED_INT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001455 public:
1456 explicit ExternalUnsignedIntElementsAccessor(const char* name)
1457 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001458 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001459};
1460
1461
1462class ExternalFloatElementsAccessor
1463 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001464 EXTERNAL_FLOAT_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001465 public:
1466 explicit ExternalFloatElementsAccessor(const char* name)
1467 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001468 EXTERNAL_FLOAT_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001469};
1470
1471
1472class ExternalDoubleElementsAccessor
1473 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001474 EXTERNAL_DOUBLE_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001475 public:
1476 explicit ExternalDoubleElementsAccessor(const char* name)
1477 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001478 EXTERNAL_DOUBLE_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001479};
1480
1481
1482class PixelElementsAccessor
1483 : public ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001484 EXTERNAL_PIXEL_ELEMENTS> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001485 public:
1486 explicit PixelElementsAccessor(const char* name)
1487 : ExternalElementsAccessor<PixelElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001488 EXTERNAL_PIXEL_ELEMENTS>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001489};
1490
1491
1492class DictionaryElementsAccessor
1493 : public ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001494 ElementsKindTraits<DICTIONARY_ELEMENTS> > {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001495 public:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001496 explicit DictionaryElementsAccessor(const char* name)
1497 : ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001498 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001499
danno@chromium.orgc612e022011-11-10 11:38:15 +00001500 // Adjusts the length of the dictionary backing store and returns the new
1501 // length according to ES5 section 15.4.5.2 behavior.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001502 MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001503 FixedArrayBase* store,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001504 JSArray* array,
1505 Object* length_object,
1506 uint32_t length) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001507 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001508 Heap* heap = array->GetHeap();
1509 int capacity = dict->Capacity();
1510 uint32_t new_length = length;
1511 uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
1512 if (new_length < old_length) {
1513 // Find last non-deletable element in range of elements to be
1514 // deleted and adjust range accordingly.
1515 for (int i = 0; i < capacity; i++) {
1516 Object* key = dict->KeyAt(i);
1517 if (key->IsNumber()) {
1518 uint32_t number = static_cast<uint32_t>(key->Number());
1519 if (new_length <= number && number < old_length) {
1520 PropertyDetails details = dict->DetailsAt(i);
1521 if (details.IsDontDelete()) new_length = number + 1;
1522 }
1523 }
1524 }
1525 if (new_length != length) {
1526 MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
1527 if (!maybe_object->To(&length_object)) return maybe_object;
1528 }
1529 }
1530
1531 if (new_length == 0) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001532 // If the length of a slow array is reset to zero, we clear
1533 // the array and flush backing storage. This has the added
1534 // benefit that the array returns to fast mode.
1535 Object* obj;
1536 MaybeObject* maybe_obj = array->ResetElements();
1537 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1538 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001539 // Remove elements that should be deleted.
1540 int removed_entries = 0;
1541 Object* the_hole_value = heap->the_hole_value();
1542 for (int i = 0; i < capacity; i++) {
1543 Object* key = dict->KeyAt(i);
1544 if (key->IsNumber()) {
1545 uint32_t number = static_cast<uint32_t>(key->Number());
1546 if (new_length <= number && number < old_length) {
1547 dict->SetEntry(i, the_hole_value, the_hole_value);
1548 removed_entries++;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001549 }
1550 }
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001551 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001552
1553 // Update the number of elements.
1554 dict->ElementsRemoved(removed_entries);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001555 }
1556 return length_object;
1557 }
1558
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001559 MUST_USE_RESULT static MaybeObject* DeleteCommon(
1560 JSObject* obj,
1561 uint32_t key,
1562 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001563 Isolate* isolate = obj->GetIsolate();
1564 Heap* heap = isolate->heap();
1565 FixedArray* backing_store = FixedArray::cast(obj->elements());
1566 bool is_arguments =
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001567 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001568 if (is_arguments) {
1569 backing_store = FixedArray::cast(backing_store->get(1));
1570 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001571 SeededNumberDictionary* dictionary =
1572 SeededNumberDictionary::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001573 int entry = dictionary->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001574 if (entry != SeededNumberDictionary::kNotFound) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001575 Object* result = dictionary->DeleteProperty(entry, mode);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001576 if (result == heap->false_value()) {
1577 if (mode == JSObject::STRICT_DELETION) {
1578 // Deleting a non-configurable property in strict mode.
1579 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001580 Handle<Object> holder(obj, isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001581 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
1582 Handle<Object> args[2] = { name, holder };
1583 Handle<Object> error =
1584 isolate->factory()->NewTypeError("strict_delete_property",
1585 HandleVector(args, 2));
1586 return isolate->Throw(*error);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001587 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001588 return heap->false_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001589 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001590 MaybeObject* maybe_elements = dictionary->Shrink(key);
1591 FixedArray* new_elements = NULL;
1592 if (!maybe_elements->To(&new_elements)) {
1593 return maybe_elements;
1594 }
1595 if (is_arguments) {
1596 FixedArray::cast(obj->elements())->set(1, new_elements);
1597 } else {
1598 obj->set_elements(new_elements);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001599 }
1600 }
1601 return heap->true_value();
1602 }
1603
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001604 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1605 uint32_t from_start,
1606 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001607 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001608 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001609 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001610 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001611 UNREACHABLE();
1612 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001613 }
1614
1615
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001616 protected:
1617 friend class ElementsAccessorBase<DictionaryElementsAccessor,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001618 ElementsKindTraits<DICTIONARY_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001619
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001620 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1621 uint32_t key,
1622 JSReceiver::DeleteMode mode) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001623 return DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001624 }
1625
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001626 MUST_USE_RESULT static MaybeObject* GetImpl(
1627 Object* receiver,
1628 JSObject* obj,
1629 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001630 FixedArrayBase* store) {
1631 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001632 int entry = backing_store->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001633 if (entry != SeededNumberDictionary::kNotFound) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001634 Object* element = backing_store->ValueAt(entry);
1635 PropertyDetails details = backing_store->DetailsAt(entry);
1636 if (details.type() == CALLBACKS) {
1637 return obj->GetElementWithCallback(receiver,
1638 element,
1639 key,
1640 obj);
1641 } else {
1642 return element;
1643 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001644 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001645 return obj->GetHeap()->the_hole_value();
1646 }
1647
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001648 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1649 Object* receiver,
1650 JSObject* obj,
1651 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001652 FixedArrayBase* backing_store) {
1653 SeededNumberDictionary* dictionary =
1654 SeededNumberDictionary::cast(backing_store);
1655 int entry = dictionary->FindEntry(key);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001656 if (entry != SeededNumberDictionary::kNotFound) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001657 return dictionary->DetailsAt(entry).attributes();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001658 }
1659 return ABSENT;
1660 }
1661
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001662 MUST_USE_RESULT static PropertyType GetTypeImpl(
1663 Object* receiver,
1664 JSObject* obj,
1665 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001666 FixedArrayBase* store) {
1667 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001668 int entry = backing_store->FindEntry(key);
1669 if (entry != SeededNumberDictionary::kNotFound) {
1670 return backing_store->DetailsAt(entry).type();
1671 }
1672 return NONEXISTENT;
1673 }
1674
1675 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
1676 Object* receiver,
1677 JSObject* obj,
1678 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001679 FixedArrayBase* store) {
1680 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001681 int entry = backing_store->FindEntry(key);
1682 if (entry != SeededNumberDictionary::kNotFound &&
1683 backing_store->DetailsAt(entry).type() == CALLBACKS &&
1684 backing_store->ValueAt(entry)->IsAccessorPair()) {
1685 return AccessorPair::cast(backing_store->ValueAt(entry));
1686 }
1687 return NULL;
1688 }
1689
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001690 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001691 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001692 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001693 FixedArrayBase* backing_store) {
1694 return SeededNumberDictionary::cast(backing_store)->FindEntry(key) !=
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001695 SeededNumberDictionary::kNotFound;
1696 }
1697
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001698 static uint32_t GetKeyForIndexImpl(FixedArrayBase* store,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001699 uint32_t index) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001700 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001701 Object* key = dict->KeyAt(index);
1702 return Smi::cast(key)->value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001703 }
1704};
1705
1706
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001707class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase<
1708 NonStrictArgumentsElementsAccessor,
1709 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001710 public:
1711 explicit NonStrictArgumentsElementsAccessor(const char* name)
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001712 : ElementsAccessorBase<
1713 NonStrictArgumentsElementsAccessor,
1714 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001715 protected:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001716 friend class ElementsAccessorBase<
1717 NonStrictArgumentsElementsAccessor,
1718 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001719
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001720 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
1721 JSObject* obj,
1722 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001723 FixedArrayBase* parameters) {
1724 FixedArray* parameter_map = FixedArray::cast(parameters);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001725 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001726 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001727 Context* context = Context::cast(parameter_map->get(0));
1728 int context_index = Smi::cast(probe)->value();
1729 ASSERT(!context->get(context_index)->IsTheHole());
1730 return context->get(context_index);
1731 } else {
1732 // Object is not mapped, defer to the arguments.
1733 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001734 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001735 receiver, obj, key, arguments);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001736 Object* result;
1737 if (!maybe_result->ToObject(&result)) return maybe_result;
1738 // Elements of the arguments object in slow mode might be slow aliases.
1739 if (result->IsAliasedArgumentsEntry()) {
1740 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
1741 Context* context = Context::cast(parameter_map->get(0));
1742 int context_index = entry->aliased_context_slot();
1743 ASSERT(!context->get(context_index)->IsTheHole());
1744 return context->get(context_index);
1745 } else {
1746 return result;
1747 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001748 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001749 }
1750
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001751 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
1752 Object* receiver,
1753 JSObject* obj,
1754 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001755 FixedArrayBase* backing_store) {
1756 FixedArray* parameter_map = FixedArray::cast(backing_store);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001757 Object* probe = GetParameterMapArg(obj, parameter_map, key);
1758 if (!probe->IsTheHole()) {
1759 return NONE;
1760 } else {
1761 // If not aliased, check the arguments.
1762 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1763 return ElementsAccessor::ForArray(arguments)->GetAttributes(
1764 receiver, obj, key, arguments);
1765 }
1766 }
1767
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001768 MUST_USE_RESULT static PropertyType GetTypeImpl(
1769 Object* receiver,
1770 JSObject* obj,
1771 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001772 FixedArrayBase* parameters) {
1773 FixedArray* parameter_map = FixedArray::cast(parameters);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001774 Object* probe = GetParameterMapArg(obj, parameter_map, key);
1775 if (!probe->IsTheHole()) {
1776 return FIELD;
1777 } else {
1778 // If not aliased, check the arguments.
1779 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1780 return ElementsAccessor::ForArray(arguments)->GetType(
1781 receiver, obj, key, arguments);
1782 }
1783 }
1784
1785 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
1786 Object* receiver,
1787 JSObject* obj,
1788 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001789 FixedArrayBase* parameters) {
1790 FixedArray* parameter_map = FixedArray::cast(parameters);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001791 Object* probe = GetParameterMapArg(obj, parameter_map, key);
1792 if (!probe->IsTheHole()) {
1793 return NULL;
1794 } else {
1795 // If not aliased, check the arguments.
1796 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1797 return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
1798 receiver, obj, key, arguments);
1799 }
1800 }
1801
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001802 MUST_USE_RESULT static MaybeObject* SetLengthImpl(
1803 JSObject* obj,
1804 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001805 FixedArrayBase* parameter_map) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001806 // TODO(mstarzinger): This was never implemented but will be used once we
1807 // correctly implement [[DefineOwnProperty]] on arrays.
1808 UNIMPLEMENTED();
1809 return obj;
1810 }
1811
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001812 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj,
1813 uint32_t key,
1814 JSReceiver::DeleteMode mode) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001815 FixedArray* parameter_map = FixedArray::cast(obj->elements());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001816 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001817 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001818 // TODO(kmillikin): We could check if this was the last aliased
1819 // parameter, and revert to normal elements in that case. That
1820 // would enable GC of the context.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001821 parameter_map->set_the_hole(key + 2);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001822 } else {
1823 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
1824 if (arguments->IsDictionary()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001825 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001826 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001827 // It's difficult to access the version of DeleteCommon that is declared
1828 // in the templatized super class, call the concrete implementation in
1829 // the class for the most generalized ElementsKind subclass.
1830 return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001831 }
1832 }
1833 return obj->GetHeap()->true_value();
1834 }
1835
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001836 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from,
1837 uint32_t from_start,
1838 FixedArrayBase* to,
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001839 ElementsKind from_kind,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001840 uint32_t to_start,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001841 int packed_size,
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001842 int copy_size) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001843 UNREACHABLE();
1844 return NULL;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001845 }
1846
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001847 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
1848 FixedArray* parameter_map = FixedArray::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001849 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
1850 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
1851 ForArray(arguments)->GetCapacity(arguments));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001852 }
1853
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001854 static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001855 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001856 return index;
1857 }
1858
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001859 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001860 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001861 uint32_t key,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001862 FixedArrayBase* parameters) {
1863 FixedArray* parameter_map = FixedArray::cast(parameters);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001864 Object* probe = GetParameterMapArg(holder, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001865 if (!probe->IsTheHole()) {
1866 return true;
1867 } else {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001868 FixedArrayBase* arguments =
1869 FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1));
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001870 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001871 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001872 }
1873 }
1874
1875 private:
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001876 static Object* GetParameterMapArg(JSObject* holder,
1877 FixedArray* parameter_map,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001878 uint32_t key) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001879 uint32_t length = holder->IsJSArray()
1880 ? Smi::cast(JSArray::cast(holder)->length())->value()
1881 : parameter_map->length();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001882 return key < (length - 2)
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001883 ? parameter_map->get(key + 2)
1884 : parameter_map->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001885 }
1886};
1887
1888
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001889ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001890 return elements_accessors_[ElementsKindForArray(array)];
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001891}
1892
1893
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001894void ElementsAccessor::InitializeOncePerProcess() {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001895 static ElementsAccessor* accessor_array[] = {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001896#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
erikcorry0ad885c2011-11-21 13:51:57 +00001897 ELEMENTS_LIST(ACCESSOR_ARRAY)
1898#undef ACCESSOR_ARRAY
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001899 };
1900
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001901 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
1902 kElementsKindCount);
1903
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001904 elements_accessors_ = accessor_array;
1905}
1906
1907
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001908void ElementsAccessor::TearDown() {
1909#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
1910 ELEMENTS_LIST(ACCESSOR_DELETE)
1911#undef ACCESSOR_DELETE
1912 elements_accessors_ = NULL;
1913}
1914
1915
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001916template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001917MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass,
1918 ElementsKindTraits>::
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001919 SetLengthImpl(JSObject* obj,
1920 Object* length,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001921 FixedArrayBase* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001922 JSArray* array = JSArray::cast(obj);
1923
1924 // Fast case: The new length fits into a Smi.
1925 MaybeObject* maybe_smi_length = length->ToSmi();
1926 Object* smi_length = Smi::FromInt(0);
1927 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
1928 const int value = Smi::cast(smi_length)->value();
1929 if (value >= 0) {
1930 Object* new_length;
1931 MaybeObject* result = ElementsAccessorSubclass::
1932 SetLengthWithoutNormalize(backing_store, array, smi_length, value);
1933 if (!result->ToObject(&new_length)) return result;
1934 ASSERT(new_length->IsSmi() || new_length->IsUndefined());
1935 if (new_length->IsSmi()) {
1936 array->set_length(Smi::cast(new_length));
1937 return array;
1938 }
1939 } else {
1940 return ThrowArrayLengthRangeError(array->GetHeap());
1941 }
1942 }
1943
1944 // Slow case: The new length does not fit into a Smi or conversion
1945 // to slow elements is needed for other reasons.
1946 if (length->IsNumber()) {
1947 uint32_t value;
1948 if (length->ToArrayIndex(&value)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001949 SeededNumberDictionary* dictionary;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001950 MaybeObject* maybe_object = array->NormalizeElements();
1951 if (!maybe_object->To(&dictionary)) return maybe_object;
1952 Object* new_length;
1953 MaybeObject* result = DictionaryElementsAccessor::
1954 SetLengthWithoutNormalize(dictionary, array, length, value);
1955 if (!result->ToObject(&new_length)) return result;
1956 ASSERT(new_length->IsNumber());
1957 array->set_length(new_length);
1958 return array;
1959 } else {
1960 return ThrowArrayLengthRangeError(array->GetHeap());
1961 }
1962 }
1963
1964 // Fall-back case: The new length is not a number so make the array
1965 // size one and set only element to length.
1966 FixedArray* new_backing_store;
1967 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
1968 if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
1969 new_backing_store->set(0, length);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 { MaybeObject* result = array->SetContent(new_backing_store);
1971 if (result->IsFailure()) return result;
1972 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001973 return array;
1974}
1975
1976
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001977MUST_USE_RESULT MaybeObject* ArrayConstructInitializeElements(
1978 JSArray* array, Arguments* args) {
1979 Heap* heap = array->GetIsolate()->heap();
1980
1981 // Optimize the case where there is one argument and the argument is a
1982 // small smi.
1983 if (args->length() == 1) {
1984 Object* obj = (*args)[0];
1985 if (obj->IsSmi()) {
1986 int len = Smi::cast(obj)->value();
1987 if (len > 0 && len < JSObject::kInitialMaxFastElementArray) {
1988 ElementsKind elements_kind = array->GetElementsKind();
1989 MaybeObject* maybe_array = array->Initialize(len, len);
1990 if (maybe_array->IsFailure()) return maybe_array;
1991
1992 if (!IsFastHoleyElementsKind(elements_kind)) {
1993 elements_kind = GetHoleyElementsKind(elements_kind);
1994 maybe_array = array->TransitionElementsKind(elements_kind);
1995 if (maybe_array->IsFailure()) return maybe_array;
1996 }
1997
1998 return array;
1999 } else if (len == 0) {
2000 return array->Initialize(JSArray::kPreallocatedArrayElements);
2001 }
2002 }
2003
2004 // Take the argument as the length.
2005 MaybeObject* maybe_obj = array->Initialize(0);
2006 if (!maybe_obj->To(&obj)) return maybe_obj;
2007
2008 return array->SetElementsLength((*args)[0]);
2009 }
2010
2011 // Optimize the case where there are no parameters passed.
2012 if (args->length() == 0) {
2013 return array->Initialize(JSArray::kPreallocatedArrayElements);
2014 }
2015
2016 // Set length and elements on the array.
2017 int number_of_elements = args->length();
2018 MaybeObject* maybe_object =
2019 array->EnsureCanContainElements(args, 0, number_of_elements,
2020 ALLOW_CONVERTED_DOUBLE_ELEMENTS);
2021 if (maybe_object->IsFailure()) return maybe_object;
2022
2023 // Allocate an appropriately typed elements array.
2024 MaybeObject* maybe_elms;
2025 ElementsKind elements_kind = array->GetElementsKind();
2026 if (IsFastDoubleElementsKind(elements_kind)) {
2027 maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
2028 number_of_elements);
2029 } else {
2030 maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
2031 }
2032 FixedArrayBase* elms;
2033 if (!maybe_elms->To(&elms)) return maybe_elms;
2034
2035 // Fill in the content
2036 switch (array->GetElementsKind()) {
2037 case FAST_HOLEY_SMI_ELEMENTS:
2038 case FAST_SMI_ELEMENTS: {
2039 FixedArray* smi_elms = FixedArray::cast(elms);
2040 for (int index = 0; index < number_of_elements; index++) {
2041 smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER);
2042 }
2043 break;
2044 }
2045 case FAST_HOLEY_ELEMENTS:
2046 case FAST_ELEMENTS: {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002047 DisallowHeapAllocation no_gc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002048 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
2049 FixedArray* object_elms = FixedArray::cast(elms);
2050 for (int index = 0; index < number_of_elements; index++) {
2051 object_elms->set(index, (*args)[index], mode);
2052 }
2053 break;
2054 }
2055 case FAST_HOLEY_DOUBLE_ELEMENTS:
2056 case FAST_DOUBLE_ELEMENTS: {
2057 FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
2058 for (int index = 0; index < number_of_elements; index++) {
2059 double_elms->set(index, (*args)[index]->Number());
2060 }
2061 break;
2062 }
2063 default:
2064 UNREACHABLE();
2065 break;
2066 }
2067
2068 array->set_elements(elms);
2069 array->set_length(Smi::FromInt(number_of_elements));
2070 return array;
2071}
2072
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002073} } // namespace v8::internal