blob: e1be677072bc67e58c368b1d275c8e333993005a [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
30#include "objects.h"
31#include "elements.h"
rossberg@chromium.org28a37082011-08-22 11:03:23 +000032#include "utils.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000033
danno@chromium.orgc612e022011-11-10 11:38:15 +000034
35// Each concrete ElementsAccessor can handle exactly one ElementsKind,
36// several abstract ElementsAccessor classes are used to allow sharing
37// common code.
38//
39// Inheritance hierarchy:
40// - ElementsAccessorBase (abstract)
41// - FastElementsAccessor (abstract)
42// - FastObjectElementsAccessor
43// - FastDoubleElementsAccessor
44// - ExternalElementsAccessor (abstract)
45// - ExternalByteElementsAccessor
46// - ExternalUnsignedByteElementsAccessor
47// - ExternalShortElementsAccessor
48// - ExternalUnsignedShortElementsAccessor
49// - ExternalIntElementsAccessor
50// - ExternalUnsignedIntElementsAccessor
51// - ExternalFloatElementsAccessor
52// - ExternalDoubleElementsAccessor
53// - PixelElementsAccessor
54// - DictionaryElementsAccessor
55// - NonStrictArgumentsElementsAccessor
56
57
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000058namespace v8 {
59namespace internal {
60
61
62ElementsAccessor** ElementsAccessor::elements_accessors_;
63
64
danno@chromium.orgc612e022011-11-10 11:38:15 +000065static bool HasKey(FixedArray* array, Object* key) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000066 int len0 = array->length();
67 for (int i = 0; i < len0; i++) {
68 Object* element = array->get(i);
69 if (element->IsSmi() && element == key) return true;
70 if (element->IsString() &&
71 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
72 return true;
73 }
74 }
75 return false;
76}
77
78
danno@chromium.orgc612e022011-11-10 11:38:15 +000079static Failure* ThrowArrayLengthRangeError(Heap* heap) {
80 HandleScope scope(heap->isolate());
81 return heap->isolate()->Throw(
82 *heap->isolate()->factory()->NewRangeError("invalid_array_length",
83 HandleVector<Object>(NULL, 0)));
84}
85
86
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000087// Base class for element handler implementations. Contains the
88// the common logic for objects with different ElementsKinds.
89// Subclasses must specialize method for which the element
90// implementation differs from the base class implementation.
91//
92// This class is intended to be used in the following way:
93//
94// class SomeElementsAccessor :
95// public ElementsAccessorBase<SomeElementsAccessor,
96// BackingStoreClass> {
97// ...
98// }
99//
100// This is an example of the Curiously Recurring Template Pattern (see
101// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
102// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
103// specialization of SomeElementsAccessor methods).
104template <typename ElementsAccessorSubclass, typename BackingStoreClass>
105class ElementsAccessorBase : public ElementsAccessor {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000106 protected:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000107 explicit ElementsAccessorBase(const char* name) : ElementsAccessor(name) { }
108
109 static bool HasElementImpl(Object* receiver,
110 JSObject* holder,
111 uint32_t key,
112 BackingStoreClass* backing_store) {
113 MaybeObject* element =
114 ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store);
115 return !element->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000116 }
117
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000118 virtual bool HasElement(Object* receiver,
119 JSObject* holder,
120 uint32_t key,
121 FixedArrayBase* backing_store) {
122 if (backing_store == NULL) {
123 backing_store = holder->elements();
124 }
125 return ElementsAccessorSubclass::HasElementImpl(
126 receiver, holder, key, BackingStoreClass::cast(backing_store));
127 }
128
129 virtual MaybeObject* Get(Object* receiver,
130 JSObject* holder,
131 uint32_t key,
132 FixedArrayBase* backing_store) {
133 if (backing_store == NULL) {
134 backing_store = holder->elements();
135 }
136 return ElementsAccessorSubclass::GetImpl(
137 receiver, holder, key, BackingStoreClass::cast(backing_store));
138 }
139
140 static MaybeObject* GetImpl(Object* receiver,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000141 JSObject* obj,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000142 uint32_t key,
143 BackingStoreClass* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000144 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
145 ? backing_store->get(key)
146 : backing_store->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000147 }
148
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000149 virtual MaybeObject* SetLength(JSArray* array,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000150 Object* length) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000151 return ElementsAccessorSubclass::SetLengthImpl(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000152 array, length, BackingStoreClass::cast(array->elements()));
danno@chromium.orgc612e022011-11-10 11:38:15 +0000153 }
154
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000155 static MaybeObject* SetLengthImpl(JSObject* obj,
156 Object* length,
157 BackingStoreClass* backing_store);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000158
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000159 virtual MaybeObject* SetCapacityAndLength(JSArray* array,
160 int capacity,
161 int length) {
162 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength(
163 array,
164 capacity,
165 length);
166 }
167
168 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
169 int capacity,
170 int length) {
171 UNIMPLEMENTED();
172 return obj;
173 }
174
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000175 virtual MaybeObject* Delete(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000176 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000177 JSReceiver::DeleteMode mode) = 0;
178
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000179 virtual MaybeObject* AddElementsToFixedArray(Object* receiver,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000180 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000181 FixedArray* to,
182 FixedArrayBase* from) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000183 int len0 = to->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000184#ifdef DEBUG
185 if (FLAG_enable_slow_asserts) {
186 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000187 ASSERT(!to->get(i)->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000188 }
189 }
190#endif
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000191 if (from == NULL) {
192 from = holder->elements();
193 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000194 BackingStoreClass* backing_store = BackingStoreClass::cast(from);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000195 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000196
197 // Optimize if 'other' is empty.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000198 // We cannot optimize if 'this' is empty, as other may have holes.
199 if (len1 == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000200
201 // Compute how many elements are not in other.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000202 uint32_t extra = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000203 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000204 uint32_t key =
205 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
206 if (ElementsAccessorSubclass::HasElementImpl(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000207 receiver, holder, key, backing_store)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000208 MaybeObject* maybe_value =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000209 ElementsAccessorSubclass::GetImpl(receiver, holder,
210 key, backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000211 Object* value;
212 if (!maybe_value->ToObject(&value)) return maybe_value;
213 ASSERT(!value->IsTheHole());
214 if (!HasKey(to, value)) {
215 extra++;
216 }
217 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000218 }
219
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000220 if (extra == 0) return to;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000221
222 // Allocate the result
223 FixedArray* result;
224 MaybeObject* maybe_obj =
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000225 backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000226 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
227
228 // Fill in the content
229 {
230 AssertNoAllocation no_gc;
231 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
232 for (int i = 0; i < len0; i++) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000233 Object* e = to->get(i);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000234 ASSERT(e->IsString() || e->IsNumber());
235 result->set(i, e, mode);
236 }
237 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000238 // Fill in the extra values.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000239 uint32_t index = 0;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000240 for (uint32_t y = 0; y < len1; y++) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000241 uint32_t key =
242 ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
243 if (ElementsAccessorSubclass::HasElementImpl(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000244 receiver, holder, key, backing_store)) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000245 MaybeObject* maybe_value =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000246 ElementsAccessorSubclass::GetImpl(receiver, holder,
247 key, backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000248 Object* value;
249 if (!maybe_value->ToObject(&value)) return maybe_value;
250 if (!value->IsTheHole() && !HasKey(to, value)) {
251 result->set(len0 + index, value);
252 index++;
253 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000254 }
255 }
256 ASSERT(extra == index);
257 return result;
258 }
259
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000260 protected:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000261 static uint32_t GetCapacityImpl(BackingStoreClass* backing_store) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000262 return backing_store->length();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000263 }
264
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000265 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000266 return ElementsAccessorSubclass::GetCapacityImpl(
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000267 BackingStoreClass::cast(backing_store));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000268 }
269
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000270 static uint32_t GetKeyForIndexImpl(BackingStoreClass* backing_store,
271 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000272 return index;
273 }
274
275 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000276 uint32_t index) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000277 return ElementsAccessorSubclass::GetKeyForIndexImpl(
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000278 BackingStoreClass::cast(backing_store), index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000279 }
280
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000281 private:
282 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
283};
284
285
danno@chromium.orgc612e022011-11-10 11:38:15 +0000286// Super class for all fast element arrays.
287template<typename FastElementsAccessorSubclass,
288 typename BackingStore,
289 int ElementSize>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000290class FastElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +0000291 : public ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000292 public:
293 explicit FastElementsAccessor(const char* name)
294 : ElementsAccessorBase<FastElementsAccessorSubclass,
295 BackingStore>(name) {}
danno@chromium.orgc612e022011-11-10 11:38:15 +0000296 protected:
297 friend class ElementsAccessorBase<FastElementsAccessorSubclass, BackingStore>;
298
299 // Adjusts the length of the fast backing store or returns the new length or
300 // undefined in case conversion to a slow backing store should be performed.
301 static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
302 JSArray* array,
303 Object* length_object,
304 uint32_t length) {
305 uint32_t old_capacity = backing_store->length();
306
307 // Check whether the backing store should be shrunk.
308 if (length <= old_capacity) {
309 if (array->HasFastTypeElements()) {
310 MaybeObject* maybe_obj = array->EnsureWritableFastElements();
311 if (!maybe_obj->To(&backing_store)) return maybe_obj;
312 }
313 if (2 * length <= old_capacity) {
314 // If more than half the elements won't be used, trim the array.
315 if (length == 0) {
316 array->initialize_elements();
317 } else {
318 backing_store->set_length(length);
319 Address filler_start = backing_store->address() +
320 BackingStore::OffsetOfElementAt(length);
321 int filler_size = (old_capacity - length) * ElementSize;
322 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
323 }
324 } else {
325 // Otherwise, fill the unused tail with holes.
326 int old_length = FastD2I(array->length()->Number());
327 for (int i = length; i < old_length; i++) {
328 backing_store->set_the_hole(i);
329 }
330 }
331 return length_object;
332 }
333
334 // Check whether the backing store should be expanded.
335 uint32_t min = JSObject::NewElementsCapacity(old_capacity);
336 uint32_t new_capacity = length > min ? length : min;
337 if (!array->ShouldConvertToSlowElements(new_capacity)) {
338 MaybeObject* result = FastElementsAccessorSubclass::
339 SetFastElementsCapacityAndLength(array, new_capacity, length);
340 if (result->IsFailure()) return result;
341 return length_object;
342 }
343
344 // Request conversion to slow elements.
345 return array->GetHeap()->undefined_value();
346 }
347};
348
349
350class FastObjectElementsAccessor
351 : public FastElementsAccessor<FastObjectElementsAccessor,
352 FixedArray,
353 kPointerSize> {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000354 public:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000355 explicit FastObjectElementsAccessor(const char* name)
356 : FastElementsAccessor<FastObjectElementsAccessor,
357 FixedArray,
358 kPointerSize>(name) {}
359
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000360 static MaybeObject* DeleteCommon(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000361 uint32_t key) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000362 ASSERT(obj->HasFastElements() ||
363 obj->HasFastSmiOnlyElements() ||
364 obj->HasFastArgumentsElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000365 Heap* heap = obj->GetHeap();
366 FixedArray* backing_store = FixedArray::cast(obj->elements());
367 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
368 backing_store = FixedArray::cast(backing_store->get(1));
369 } else {
370 Object* writable;
371 MaybeObject* maybe = obj->EnsureWritableFastElements();
372 if (!maybe->ToObject(&writable)) return maybe;
373 backing_store = FixedArray::cast(writable);
374 }
375 uint32_t length = static_cast<uint32_t>(
376 obj->IsJSArray()
377 ? Smi::cast(JSArray::cast(obj)->length())->value()
378 : backing_store->length());
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000379 if (key < length) {
380 backing_store->set_the_hole(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000381 // If an old space backing store is larger than a certain size and
382 // has too few used values, normalize it.
383 // To avoid doing the check on every delete we require at least
384 // one adjacent hole to the value being deleted.
385 Object* hole = heap->the_hole_value();
386 const int kMinLengthForSparsenessCheck = 64;
387 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
388 !heap->InNewSpace(backing_store) &&
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000389 ((key > 0 && backing_store->get(key - 1) == hole) ||
390 (key + 1 < length && backing_store->get(key + 1) == hole))) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000391 int num_used = 0;
392 for (int i = 0; i < backing_store->length(); ++i) {
393 if (backing_store->get(i) != hole) ++num_used;
394 // Bail out early if more than 1/4 is used.
395 if (4 * num_used > backing_store->length()) break;
396 }
397 if (4 * num_used <= backing_store->length()) {
398 MaybeObject* result = obj->NormalizeElements();
399 if (result->IsFailure()) return result;
400 }
401 }
402 }
403 return heap->true_value();
404 }
405
danno@chromium.orgc612e022011-11-10 11:38:15 +0000406 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
407 uint32_t capacity,
408 uint32_t length) {
409 JSObject::SetFastElementsCapacityMode set_capacity_mode =
410 obj->HasFastSmiOnlyElements()
411 ? JSObject::kAllowSmiOnlyElements
412 : JSObject::kDontAllowSmiOnlyElements;
413 return obj->SetFastElementsCapacityAndLength(capacity,
414 length,
415 set_capacity_mode);
416 }
417
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000418 protected:
419 friend class FastElementsAccessor<FastObjectElementsAccessor,
420 FixedArray,
421 kPointerSize>;
422
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000423 virtual MaybeObject* Delete(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000424 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000425 JSReceiver::DeleteMode mode) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000426 return DeleteCommon(obj, key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000427 }
428};
429
430
431class FastDoubleElementsAccessor
danno@chromium.orgc612e022011-11-10 11:38:15 +0000432 : public FastElementsAccessor<FastDoubleElementsAccessor,
433 FixedDoubleArray,
434 kDoubleSize> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000435 public:
436 explicit FastDoubleElementsAccessor(const char* name)
437 : FastElementsAccessor<FastDoubleElementsAccessor,
438 FixedDoubleArray,
439 kDoubleSize>(name) {}
440
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000441 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj,
442 uint32_t capacity,
443 uint32_t length) {
444 return obj->SetFastDoubleElementsCapacityAndLength(capacity, length);
445 }
446
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000447 protected:
448 friend class ElementsAccessorBase<FastDoubleElementsAccessor,
449 FixedDoubleArray>;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000450 friend class FastElementsAccessor<FastDoubleElementsAccessor,
451 FixedDoubleArray,
452 kDoubleSize>;
453
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000454 virtual MaybeObject* Delete(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000455 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000456 JSReceiver::DeleteMode mode) {
457 int length = obj->IsJSArray()
458 ? Smi::cast(JSArray::cast(obj)->length())->value()
459 : FixedDoubleArray::cast(obj->elements())->length();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000460 if (key < static_cast<uint32_t>(length)) {
461 FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000462 }
463 return obj->GetHeap()->true_value();
464 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000465
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000466 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000467 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000468 uint32_t key,
469 FixedDoubleArray* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000470 return !backing_store->is_the_hole(key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000471 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000472};
473
474
475// Super class for all external element arrays.
476template<typename ExternalElementsAccessorSubclass,
477 typename ExternalArray>
478class ExternalElementsAccessor
479 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
480 ExternalArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000481 public:
482 explicit ExternalElementsAccessor(const char* name)
483 : ElementsAccessorBase<ExternalElementsAccessorSubclass,
484 ExternalArray>(name) {}
485
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000486 protected:
487 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
488 ExternalArray>;
489
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000490 static MaybeObject* GetImpl(Object* receiver,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000491 JSObject* obj,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000492 uint32_t key,
493 ExternalArray* backing_store) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000494 return
495 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
496 ? backing_store->get(key)
497 : backing_store->GetHeap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000498 }
499
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000500 static MaybeObject* SetLengthImpl(JSObject* obj,
501 Object* length,
502 ExternalArray* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000503 // External arrays do not support changing their length.
504 UNREACHABLE();
505 return obj;
506 }
507
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000508 virtual MaybeObject* Delete(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000509 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000510 JSReceiver::DeleteMode mode) {
511 // External arrays always ignore deletes.
512 return obj->GetHeap()->true_value();
513 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000514
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000515 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000516 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000517 uint32_t key,
518 ExternalArray* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000519 uint32_t capacity =
520 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
521 return key < capacity;
522 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000523};
524
525
526class ExternalByteElementsAccessor
527 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
528 ExternalByteArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000529 public:
530 explicit ExternalByteElementsAccessor(const char* name)
531 : ExternalElementsAccessor<ExternalByteElementsAccessor,
532 ExternalByteArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000533};
534
535
536class ExternalUnsignedByteElementsAccessor
537 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
538 ExternalUnsignedByteArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000539 public:
540 explicit ExternalUnsignedByteElementsAccessor(const char* name)
541 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
542 ExternalUnsignedByteArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000543};
544
545
546class ExternalShortElementsAccessor
547 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
548 ExternalShortArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000549 public:
550 explicit ExternalShortElementsAccessor(const char* name)
551 : ExternalElementsAccessor<ExternalShortElementsAccessor,
552 ExternalShortArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000553};
554
555
556class ExternalUnsignedShortElementsAccessor
557 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
558 ExternalUnsignedShortArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000559 public:
560 explicit ExternalUnsignedShortElementsAccessor(const char* name)
561 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
562 ExternalUnsignedShortArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000563};
564
565
566class ExternalIntElementsAccessor
567 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
568 ExternalIntArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000569 public:
570 explicit ExternalIntElementsAccessor(const char* name)
571 : ExternalElementsAccessor<ExternalIntElementsAccessor,
572 ExternalIntArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000573};
574
575
576class ExternalUnsignedIntElementsAccessor
577 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
578 ExternalUnsignedIntArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000579 public:
580 explicit ExternalUnsignedIntElementsAccessor(const char* name)
581 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
582 ExternalUnsignedIntArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000583};
584
585
586class ExternalFloatElementsAccessor
587 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
588 ExternalFloatArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000589 public:
590 explicit ExternalFloatElementsAccessor(const char* name)
591 : ExternalElementsAccessor<ExternalFloatElementsAccessor,
592 ExternalFloatArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000593};
594
595
596class ExternalDoubleElementsAccessor
597 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
598 ExternalDoubleArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000599 public:
600 explicit ExternalDoubleElementsAccessor(const char* name)
601 : ExternalElementsAccessor<ExternalDoubleElementsAccessor,
602 ExternalDoubleArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000603};
604
605
606class PixelElementsAccessor
607 : public ExternalElementsAccessor<PixelElementsAccessor,
608 ExternalPixelArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000609 public:
610 explicit PixelElementsAccessor(const char* name)
611 : ExternalElementsAccessor<PixelElementsAccessor,
612 ExternalPixelArray>(name) {}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000613};
614
615
616class DictionaryElementsAccessor
617 : public ElementsAccessorBase<DictionaryElementsAccessor,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000618 SeededNumberDictionary> {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619 public:
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000620 explicit DictionaryElementsAccessor(const char* name)
621 : ElementsAccessorBase<DictionaryElementsAccessor,
622 SeededNumberDictionary>(name) {}
623
danno@chromium.orgc612e022011-11-10 11:38:15 +0000624 // Adjusts the length of the dictionary backing store and returns the new
625 // length according to ES5 section 15.4.5.2 behavior.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000626 static MaybeObject* SetLengthWithoutNormalize(SeededNumberDictionary* dict,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000627 JSArray* array,
628 Object* length_object,
629 uint32_t length) {
630 if (length == 0) {
631 // If the length of a slow array is reset to zero, we clear
632 // the array and flush backing storage. This has the added
633 // benefit that the array returns to fast mode.
634 Object* obj;
635 MaybeObject* maybe_obj = array->ResetElements();
636 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
637 } else {
638 uint32_t new_length = length;
639 uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
640 if (new_length < old_length) {
641 // Find last non-deletable element in range of elements to be
642 // deleted and adjust range accordingly.
643 Heap* heap = array->GetHeap();
644 int capacity = dict->Capacity();
645 for (int i = 0; i < capacity; i++) {
646 Object* key = dict->KeyAt(i);
647 if (key->IsNumber()) {
648 uint32_t number = static_cast<uint32_t>(key->Number());
649 if (new_length <= number && number < old_length) {
650 PropertyDetails details = dict->DetailsAt(i);
651 if (details.IsDontDelete()) new_length = number + 1;
652 }
653 }
654 }
655 if (new_length != length) {
656 MaybeObject* maybe_object = heap->NumberFromUint32(new_length);
657 if (!maybe_object->To(&length_object)) return maybe_object;
658 }
659
660 // Remove elements that should be deleted.
661 int removed_entries = 0;
662 Object* the_hole_value = heap->the_hole_value();
663 for (int i = 0; i < capacity; i++) {
664 Object* key = dict->KeyAt(i);
665 if (key->IsNumber()) {
666 uint32_t number = static_cast<uint32_t>(key->Number());
667 if (new_length <= number && number < old_length) {
668 dict->SetEntry(i, the_hole_value, the_hole_value);
669 removed_entries++;
670 }
671 }
672 }
673
674 // Update the number of elements.
675 dict->ElementsRemoved(removed_entries);
676 }
677 }
678 return length_object;
679 }
680
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000681 static MaybeObject* DeleteCommon(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000682 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000683 JSReceiver::DeleteMode mode) {
684 Isolate* isolate = obj->GetIsolate();
685 Heap* heap = isolate->heap();
686 FixedArray* backing_store = FixedArray::cast(obj->elements());
687 bool is_arguments =
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000688 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 if (is_arguments) {
690 backing_store = FixedArray::cast(backing_store->get(1));
691 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000692 SeededNumberDictionary* dictionary =
693 SeededNumberDictionary::cast(backing_store);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000694 int entry = dictionary->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000695 if (entry != SeededNumberDictionary::kNotFound) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000696 Object* result = dictionary->DeleteProperty(entry, mode);
697 if (result == heap->true_value()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000698 MaybeObject* maybe_elements = dictionary->Shrink(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000699 FixedArray* new_elements = NULL;
700 if (!maybe_elements->To(&new_elements)) {
701 return maybe_elements;
702 }
703 if (is_arguments) {
704 FixedArray::cast(obj->elements())->set(1, new_elements);
705 } else {
706 obj->set_elements(new_elements);
707 }
708 }
709 if (mode == JSObject::STRICT_DELETION &&
710 result == heap->false_value()) {
711 // In strict mode, attempting to delete a non-configurable property
712 // throws an exception.
713 HandleScope scope(isolate);
714 Handle<Object> holder(obj);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000715 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000716 Handle<Object> args[2] = { name, holder };
717 Handle<Object> error =
718 isolate->factory()->NewTypeError("strict_delete_property",
719 HandleVector(args, 2));
720 return isolate->Throw(*error);
721 }
722 }
723 return heap->true_value();
724 }
725
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000726 protected:
727 friend class ElementsAccessorBase<DictionaryElementsAccessor,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000728 SeededNumberDictionary>;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000729
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000730 virtual MaybeObject* Delete(JSObject* obj,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000731 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000732 JSReceiver::DeleteMode mode) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000733 return DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000734 }
735
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000736 static MaybeObject* GetImpl(Object* receiver,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000737 JSObject* obj,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000738 uint32_t key,
739 SeededNumberDictionary* backing_store) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000740 int entry = backing_store->FindEntry(key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000741 if (entry != SeededNumberDictionary::kNotFound) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000742 Object* element = backing_store->ValueAt(entry);
743 PropertyDetails details = backing_store->DetailsAt(entry);
744 if (details.type() == CALLBACKS) {
745 return obj->GetElementWithCallback(receiver,
746 element,
747 key,
748 obj);
749 } else {
750 return element;
751 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000752 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000753 return obj->GetHeap()->the_hole_value();
754 }
755
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000756 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000757 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000758 uint32_t key,
759 SeededNumberDictionary* backing_store) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000760 return backing_store->FindEntry(key) !=
761 SeededNumberDictionary::kNotFound;
762 }
763
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
765 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000766 Object* key = dict->KeyAt(index);
767 return Smi::cast(key)->value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000768 }
769};
770
771
772class NonStrictArgumentsElementsAccessor
773 : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
774 FixedArray> {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000775 public:
776 explicit NonStrictArgumentsElementsAccessor(const char* name)
777 : ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
778 FixedArray>(name) {}
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000779 protected:
780 friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
781 FixedArray>;
782
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000783 static MaybeObject* GetImpl(Object* receiver,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000784 JSObject* obj,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000785 uint32_t key,
786 FixedArray* parameter_map) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000787 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000788 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000789 Context* context = Context::cast(parameter_map->get(0));
790 int context_index = Smi::cast(probe)->value();
791 ASSERT(!context->get(context_index)->IsTheHole());
792 return context->get(context_index);
793 } else {
794 // Object is not mapped, defer to the arguments.
795 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000796 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000797 receiver, obj, key, arguments);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000798 Object* result;
799 if (!maybe_result->ToObject(&result)) return maybe_result;
800 // Elements of the arguments object in slow mode might be slow aliases.
801 if (result->IsAliasedArgumentsEntry()) {
802 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result);
803 Context* context = Context::cast(parameter_map->get(0));
804 int context_index = entry->aliased_context_slot();
805 ASSERT(!context->get(context_index)->IsTheHole());
806 return context->get(context_index);
807 } else {
808 return result;
809 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000811 }
812
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000813 static MaybeObject* SetLengthImpl(JSObject* obj,
814 Object* length,
815 FixedArray* parameter_map) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000816 // TODO(mstarzinger): This was never implemented but will be used once we
817 // correctly implement [[DefineOwnProperty]] on arrays.
818 UNIMPLEMENTED();
819 return obj;
820 }
821
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000822 virtual MaybeObject* Delete(JSObject* obj,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000823 uint32_t key,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824 JSReceiver::DeleteMode mode) {
825 FixedArray* parameter_map = FixedArray::cast(obj->elements());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000826 Object* probe = GetParameterMapArg(obj, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000827 if (!probe->IsTheHole()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000828 // TODO(kmillikin): We could check if this was the last aliased
829 // parameter, and revert to normal elements in that case. That
830 // would enable GC of the context.
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000831 parameter_map->set_the_hole(key + 2);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 } else {
833 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
834 if (arguments->IsDictionary()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000835 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000836 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000837 return FastObjectElementsAccessor::DeleteCommon(obj, key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000838 }
839 }
840 return obj->GetHeap()->true_value();
841 }
842
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000843 static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000844 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
845 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
846 ForArray(arguments)->GetCapacity(arguments));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000847 }
848
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000849 static uint32_t GetKeyForIndexImpl(FixedArray* dict,
850 uint32_t index) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000851 return index;
852 }
853
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000854 static bool HasElementImpl(Object* receiver,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000855 JSObject* holder,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000856 uint32_t key,
857 FixedArray* parameter_map) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000858 Object* probe = GetParameterMapArg(holder, parameter_map, key);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000859 if (!probe->IsTheHole()) {
860 return true;
861 } else {
862 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
863 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000864 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000865 }
866 }
867
868 private:
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000869 static Object* GetParameterMapArg(JSObject* holder,
870 FixedArray* parameter_map,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000871 uint32_t key) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000872 uint32_t length = holder->IsJSArray()
873 ? Smi::cast(JSArray::cast(holder)->length())->value()
874 : parameter_map->length();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000875 return key < (length - 2 )
876 ? parameter_map->get(key + 2)
877 : parameter_map->GetHeap()->the_hole_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000878 }
879};
880
881
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000882ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
883 switch (array->map()->instance_type()) {
884 case FIXED_ARRAY_TYPE:
885 if (array->IsDictionary()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000886 return elements_accessors_[DICTIONARY_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000887 } else {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000888 return elements_accessors_[FAST_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000889 }
890 case EXTERNAL_BYTE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000891 return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000892 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000893 return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000894 case EXTERNAL_SHORT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000895 return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000896 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000897 return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000898 case EXTERNAL_INT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000899 return elements_accessors_[EXTERNAL_INT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000900 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000901 return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000902 case EXTERNAL_FLOAT_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000903 return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000904 case EXTERNAL_DOUBLE_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000905 return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000906 case EXTERNAL_PIXEL_ARRAY_TYPE:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000907 return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000908 default:
909 UNREACHABLE();
910 return NULL;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000911 }
912}
913
914
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000915void ElementsAccessor::InitializeOncePerProcess() {
erikcorry0ad885c2011-11-21 13:51:57 +0000916 // First argument in list is the accessor class, the second argument is can
917 // be any arbitrary unique identifier, in this case chosen to be the
918 // corresponding enum. Use the fast element handler for smi-only arrays.
919 // The implementation is currently identical. Note that the order must match
920 // that of the ElementsKind enum for the |accessor_array[]| below to work.
921#define ELEMENTS_LIST(V) \
922 V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS) \
923 V(FastObjectElementsAccessor, FAST_ELEMENTS) \
924 V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS) \
925 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS) \
926 V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS) \
927 V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS) \
928 V(ExternalUnsignedByteElementsAccessor, EXTERNAL_UNSIGNED_BYTE_ELEMENTS) \
929 V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS) \
930 V(ExternalUnsignedShortElementsAccessor, EXTERNAL_UNSIGNED_SHORT_ELEMENTS) \
931 V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS) \
932 V(ExternalUnsignedIntElementsAccessor, EXTERNAL_UNSIGNED_INT_ELEMENTS) \
933 V(ExternalFloatElementsAccessor, EXTERNAL_FLOAT_ELEMENTS) \
934 V(ExternalDoubleElementsAccessor, EXTERNAL_DOUBLE_ELEMENTS) \
935 V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS)
936
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000937 static struct ConcreteElementsAccessors {
erikcorry0ad885c2011-11-21 13:51:57 +0000938#define ACCESSOR_STRUCT(Class, Name) Class* Name##_handler;
939 ELEMENTS_LIST(ACCESSOR_STRUCT)
940#undef ACCESSOR_STRUCT
941 } element_accessors = {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000942#define ACCESSOR_INIT(Class, Name) new Class(#Name),
erikcorry0ad885c2011-11-21 13:51:57 +0000943 ELEMENTS_LIST(ACCESSOR_INIT)
944#undef ACCESSOR_INIT
945 };
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000946
947 static ElementsAccessor* accessor_array[] = {
erikcorry0ad885c2011-11-21 13:51:57 +0000948#define ACCESSOR_ARRAY(Class, Name) element_accessors.Name##_handler,
949 ELEMENTS_LIST(ACCESSOR_ARRAY)
950#undef ACCESSOR_ARRAY
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000951 };
952
erikcorry0ad885c2011-11-21 13:51:57 +0000953#undef ELEMENTS_LIST
954
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000955 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
956 kElementsKindCount);
957
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000958 elements_accessors_ = accessor_array;
959}
960
961
danno@chromium.orgc612e022011-11-10 11:38:15 +0000962template <typename ElementsAccessorSubclass, typename BackingStoreClass>
963MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, BackingStoreClass>::
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000964 SetLengthImpl(JSObject* obj,
965 Object* length,
966 BackingStoreClass* backing_store) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000967 JSArray* array = JSArray::cast(obj);
968
969 // Fast case: The new length fits into a Smi.
970 MaybeObject* maybe_smi_length = length->ToSmi();
971 Object* smi_length = Smi::FromInt(0);
972 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
973 const int value = Smi::cast(smi_length)->value();
974 if (value >= 0) {
975 Object* new_length;
976 MaybeObject* result = ElementsAccessorSubclass::
977 SetLengthWithoutNormalize(backing_store, array, smi_length, value);
978 if (!result->ToObject(&new_length)) return result;
979 ASSERT(new_length->IsSmi() || new_length->IsUndefined());
980 if (new_length->IsSmi()) {
981 array->set_length(Smi::cast(new_length));
982 return array;
983 }
984 } else {
985 return ThrowArrayLengthRangeError(array->GetHeap());
986 }
987 }
988
989 // Slow case: The new length does not fit into a Smi or conversion
990 // to slow elements is needed for other reasons.
991 if (length->IsNumber()) {
992 uint32_t value;
993 if (length->ToArrayIndex(&value)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000994 SeededNumberDictionary* dictionary;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000995 MaybeObject* maybe_object = array->NormalizeElements();
996 if (!maybe_object->To(&dictionary)) return maybe_object;
997 Object* new_length;
998 MaybeObject* result = DictionaryElementsAccessor::
999 SetLengthWithoutNormalize(dictionary, array, length, value);
1000 if (!result->ToObject(&new_length)) return result;
1001 ASSERT(new_length->IsNumber());
1002 array->set_length(new_length);
1003 return array;
1004 } else {
1005 return ThrowArrayLengthRangeError(array->GetHeap());
1006 }
1007 }
1008
1009 // Fall-back case: The new length is not a number so make the array
1010 // size one and set only element to length.
1011 FixedArray* new_backing_store;
1012 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1);
1013 if (!maybe_obj->To(&new_backing_store)) return maybe_obj;
1014 new_backing_store->set(0, length);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001015 { MaybeObject* result = array->SetContent(new_backing_store);
1016 if (result->IsFailure()) return result;
1017 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001018 return array;
1019}
1020
1021
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001022} } // namespace v8::internal