blob: 04546446174b251599d1c30f9638589481dbb9ec [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdoch69a99ed2011-11-30 16:03:39 +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"
32#include "utils.h"
33
34namespace v8 {
35namespace internal {
36
37
38ElementsAccessor** ElementsAccessor::elements_accessors_;
39
40
Ben Murdoch85b71792012-04-11 18:30:58 +010041bool HasKey(FixedArray* array, Object* key) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000042 int len0 = array->length();
43 for (int i = 0; i < len0; i++) {
44 Object* element = array->get(i);
45 if (element->IsSmi() && element == key) return true;
46 if (element->IsString() &&
47 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
48 return true;
49 }
50 }
51 return false;
52}
53
54
55// Base class for element handler implementations. Contains the
56// the common logic for objects with different ElementsKinds.
57// Subclasses must specialize method for which the element
58// implementation differs from the base class implementation.
59//
60// This class is intended to be used in the following way:
61//
62// class SomeElementsAccessor :
63// public ElementsAccessorBase<SomeElementsAccessor,
64// BackingStoreClass> {
65// ...
66// }
67//
68// This is an example of the Curiously Recurring Template Pattern (see
69// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
70// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
71// specialization of SomeElementsAccessor methods).
Ben Murdoch85b71792012-04-11 18:30:58 +010072template <typename ElementsAccessorSubclass, typename BackingStoreClass>
Ben Murdoch69a99ed2011-11-30 16:03:39 +000073class ElementsAccessorBase : public ElementsAccessor {
74 protected:
Ben Murdoch85b71792012-04-11 18:30:58 +010075 ElementsAccessorBase() { }
76 virtual MaybeObject* Get(FixedArrayBase* backing_store,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010077 uint32_t key,
Ben Murdoch85b71792012-04-11 18:30:58 +010078 JSObject* obj,
79 Object* receiver) {
80 return ElementsAccessorSubclass::Get(
81 BackingStoreClass::cast(backing_store), key, obj, receiver);
82 }
83
84 static MaybeObject* Get(BackingStoreClass* backing_store,
85 uint32_t key,
86 JSObject* obj,
87 Object* receiver) {
88 if (key < ElementsAccessorSubclass::GetCapacity(backing_store)) {
89 return backing_store->get(key);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010090 }
Ben Murdoch85b71792012-04-11 18:30:58 +010091 return backing_store->GetHeap()->the_hole_value();
Ben Murdochc7cc0282012-03-05 14:35:55 +000092 }
93
Ben Murdoch69a99ed2011-11-30 16:03:39 +000094 virtual MaybeObject* Delete(JSObject* obj,
95 uint32_t key,
96 JSReceiver::DeleteMode mode) = 0;
97
Ben Murdoch85b71792012-04-11 18:30:58 +010098 virtual MaybeObject* AddElementsToFixedArray(FixedArrayBase* from,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010099 FixedArray* to,
Ben Murdoch85b71792012-04-11 18:30:58 +0100100 JSObject* holder,
101 Object* receiver) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000102 int len0 = to->length();
103#ifdef DEBUG
104 if (FLAG_enable_slow_asserts) {
105 for (int i = 0; i < len0; i++) {
106 ASSERT(!to->get(i)->IsTheHole());
107 }
108 }
109#endif
Ben Murdoch85b71792012-04-11 18:30:58 +0100110 BackingStoreClass* backing_store = BackingStoreClass::cast(from);
111 uint32_t len1 = ElementsAccessorSubclass::GetCapacity(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000112
113 // Optimize if 'other' is empty.
114 // We cannot optimize if 'this' is empty, as other may have holes.
115 if (len1 == 0) return to;
116
117 // Compute how many elements are not in other.
Ben Murdoch85b71792012-04-11 18:30:58 +0100118 int extra = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000119 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100120 if (ElementsAccessorSubclass::HasElementAtIndex(backing_store,
121 y,
122 holder,
123 receiver)) {
124 uint32_t key =
125 ElementsAccessorSubclass::GetKeyForIndex(backing_store, y);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000126 MaybeObject* maybe_value =
Ben Murdoch85b71792012-04-11 18:30:58 +0100127 ElementsAccessorSubclass::Get(backing_store, key, holder, receiver);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000128 Object* value;
129 if (!maybe_value->ToObject(&value)) return maybe_value;
130 ASSERT(!value->IsTheHole());
131 if (!HasKey(to, value)) {
132 extra++;
133 }
134 }
135 }
136
137 if (extra == 0) return to;
138
139 // Allocate the result
140 FixedArray* result;
141 MaybeObject* maybe_obj =
142 backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
143 if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
144
145 // Fill in the content
146 {
147 AssertNoAllocation no_gc;
148 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
149 for (int i = 0; i < len0; i++) {
150 Object* e = to->get(i);
151 ASSERT(e->IsString() || e->IsNumber());
152 result->set(i, e, mode);
153 }
154 }
155 // Fill in the extra values.
Ben Murdoch85b71792012-04-11 18:30:58 +0100156 int index = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000157 for (uint32_t y = 0; y < len1; y++) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100158 if (ElementsAccessorSubclass::HasElementAtIndex(backing_store,
159 y,
160 holder,
161 receiver)) {
162 uint32_t key =
163 ElementsAccessorSubclass::GetKeyForIndex(backing_store, y);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000164 MaybeObject* maybe_value =
Ben Murdoch85b71792012-04-11 18:30:58 +0100165 ElementsAccessorSubclass::Get(backing_store, key, holder, receiver);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000166 Object* value;
167 if (!maybe_value->ToObject(&value)) return maybe_value;
168 if (!value->IsTheHole() && !HasKey(to, value)) {
169 result->set(len0 + index, value);
170 index++;
171 }
172 }
173 }
174 ASSERT(extra == index);
175 return result;
176 }
177
178 protected:
Ben Murdoch85b71792012-04-11 18:30:58 +0100179 static uint32_t GetCapacity(BackingStoreClass* backing_store) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000180 return backing_store->length();
181 }
182
183 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100184 return ElementsAccessorSubclass::GetCapacity(
185 BackingStoreClass::cast(backing_store));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000186 }
187
Ben Murdoch85b71792012-04-11 18:30:58 +0100188 static bool HasElementAtIndex(BackingStoreClass* backing_store,
189 uint32_t index,
190 JSObject* holder,
191 Object* receiver) {
192 uint32_t key =
193 ElementsAccessorSubclass::GetKeyForIndex(backing_store, index);
194 MaybeObject* element = ElementsAccessorSubclass::Get(backing_store,
195 key,
196 holder,
197 receiver);
198 return !element->IsTheHole();
199 }
200
201 virtual bool HasElementAtIndex(FixedArrayBase* backing_store,
202 uint32_t index,
203 JSObject* holder,
204 Object* receiver) {
205 return ElementsAccessorSubclass::HasElementAtIndex(
206 BackingStoreClass::cast(backing_store), index, holder, receiver);
207 }
208
209 static uint32_t GetKeyForIndex(BackingStoreClass* backing_store,
210 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000211 return index;
212 }
213
214 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
Ben Murdoch85b71792012-04-11 18:30:58 +0100215 uint32_t index) {
216 return ElementsAccessorSubclass::GetKeyForIndex(
217 BackingStoreClass::cast(backing_store), index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000218 }
219
220 private:
221 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
222};
223
224
225class FastElementsAccessor
Ben Murdoch85b71792012-04-11 18:30:58 +0100226 : public ElementsAccessorBase<FastElementsAccessor, FixedArray> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100227 public:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000228 static MaybeObject* DeleteCommon(JSObject* obj,
229 uint32_t key) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100230 ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000231 Heap* heap = obj->GetHeap();
232 FixedArray* backing_store = FixedArray::cast(obj->elements());
233 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
234 backing_store = FixedArray::cast(backing_store->get(1));
235 } else {
236 Object* writable;
237 MaybeObject* maybe = obj->EnsureWritableFastElements();
238 if (!maybe->ToObject(&writable)) return maybe;
239 backing_store = FixedArray::cast(writable);
240 }
241 uint32_t length = static_cast<uint32_t>(
242 obj->IsJSArray()
243 ? Smi::cast(JSArray::cast(obj)->length())->value()
244 : backing_store->length());
245 if (key < length) {
246 backing_store->set_the_hole(key);
247 // If an old space backing store is larger than a certain size and
248 // has too few used values, normalize it.
249 // To avoid doing the check on every delete we require at least
250 // one adjacent hole to the value being deleted.
251 Object* hole = heap->the_hole_value();
252 const int kMinLengthForSparsenessCheck = 64;
253 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
254 !heap->InNewSpace(backing_store) &&
255 ((key > 0 && backing_store->get(key - 1) == hole) ||
256 (key + 1 < length && backing_store->get(key + 1) == hole))) {
257 int num_used = 0;
258 for (int i = 0; i < backing_store->length(); ++i) {
259 if (backing_store->get(i) != hole) ++num_used;
260 // Bail out early if more than 1/4 is used.
261 if (4 * num_used > backing_store->length()) break;
262 }
263 if (4 * num_used <= backing_store->length()) {
264 MaybeObject* result = obj->NormalizeElements();
265 if (result->IsFailure()) return result;
266 }
267 }
268 }
269 return heap->true_value();
270 }
271
Ben Murdochc7cc0282012-03-05 14:35:55 +0000272 protected:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000273 virtual MaybeObject* Delete(JSObject* obj,
274 uint32_t key,
275 JSReceiver::DeleteMode mode) {
276 return DeleteCommon(obj, key);
277 }
278};
279
280
281class FastDoubleElementsAccessor
Ben Murdoch85b71792012-04-11 18:30:58 +0100282 : public ElementsAccessorBase<FastDoubleElementsAccessor,
283 FixedDoubleArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000284 protected:
285 friend class ElementsAccessorBase<FastDoubleElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100286 FixedDoubleArray>;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100287
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000288 virtual MaybeObject* Delete(JSObject* obj,
289 uint32_t key,
290 JSReceiver::DeleteMode mode) {
291 int length = obj->IsJSArray()
292 ? Smi::cast(JSArray::cast(obj)->length())->value()
293 : FixedDoubleArray::cast(obj->elements())->length();
294 if (key < static_cast<uint32_t>(length)) {
295 FixedDoubleArray::cast(obj->elements())->set_the_hole(key);
296 }
297 return obj->GetHeap()->true_value();
298 }
299
Ben Murdoch85b71792012-04-11 18:30:58 +0100300 static bool HasElementAtIndex(FixedDoubleArray* backing_store,
301 uint32_t index,
302 JSObject* holder,
303 Object* receiver) {
304 return !backing_store->is_the_hole(index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000305 }
306};
307
308
309// Super class for all external element arrays.
310template<typename ExternalElementsAccessorSubclass,
Ben Murdoch85b71792012-04-11 18:30:58 +0100311 typename ExternalArray>
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000312class ExternalElementsAccessor
313 : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
Ben Murdoch85b71792012-04-11 18:30:58 +0100314 ExternalArray> {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100315 protected:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100316 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass,
Ben Murdoch85b71792012-04-11 18:30:58 +0100317 ExternalArray>;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100318
Ben Murdoch85b71792012-04-11 18:30:58 +0100319 static MaybeObject* Get(ExternalArray* backing_store,
320 uint32_t key,
321 JSObject* obj,
322 Object* receiver) {
323 if (key < ExternalElementsAccessorSubclass::GetCapacity(backing_store)) {
324 return backing_store->get(key);
325 } else {
326 return backing_store->GetHeap()->undefined_value();
327 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000328 }
329
330 virtual MaybeObject* Delete(JSObject* obj,
331 uint32_t key,
332 JSReceiver::DeleteMode mode) {
333 // External arrays always ignore deletes.
334 return obj->GetHeap()->true_value();
335 }
336};
337
338
339class ExternalByteElementsAccessor
340 : public ExternalElementsAccessor<ExternalByteElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100341 ExternalByteArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000342};
343
344
345class ExternalUnsignedByteElementsAccessor
346 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100347 ExternalUnsignedByteArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000348};
349
350
351class ExternalShortElementsAccessor
352 : public ExternalElementsAccessor<ExternalShortElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100353 ExternalShortArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000354};
355
356
357class ExternalUnsignedShortElementsAccessor
358 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100359 ExternalUnsignedShortArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000360};
361
362
363class ExternalIntElementsAccessor
364 : public ExternalElementsAccessor<ExternalIntElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100365 ExternalIntArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000366};
367
368
369class ExternalUnsignedIntElementsAccessor
370 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100371 ExternalUnsignedIntArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000372};
373
374
375class ExternalFloatElementsAccessor
376 : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100377 ExternalFloatArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000378};
379
380
381class ExternalDoubleElementsAccessor
382 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100383 ExternalDoubleArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000384};
385
386
387class PixelElementsAccessor
388 : public ExternalElementsAccessor<PixelElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100389 ExternalPixelArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000390};
391
392
393class DictionaryElementsAccessor
394 : public ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100395 SeededNumberDictionary> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000396 public:
397 static MaybeObject* DeleteCommon(JSObject* obj,
398 uint32_t key,
399 JSReceiver::DeleteMode mode) {
400 Isolate* isolate = obj->GetIsolate();
401 Heap* heap = isolate->heap();
402 FixedArray* backing_store = FixedArray::cast(obj->elements());
403 bool is_arguments =
Ben Murdoch589d6972011-11-30 16:04:58 +0000404 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000405 if (is_arguments) {
406 backing_store = FixedArray::cast(backing_store->get(1));
407 }
Ben Murdochc7cc0282012-03-05 14:35:55 +0000408 SeededNumberDictionary* dictionary =
409 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000410 int entry = dictionary->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000411 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000412 Object* result = dictionary->DeleteProperty(entry, mode);
413 if (result == heap->true_value()) {
414 MaybeObject* maybe_elements = dictionary->Shrink(key);
415 FixedArray* new_elements = NULL;
416 if (!maybe_elements->To(&new_elements)) {
417 return maybe_elements;
418 }
419 if (is_arguments) {
420 FixedArray::cast(obj->elements())->set(1, new_elements);
421 } else {
422 obj->set_elements(new_elements);
423 }
424 }
425 if (mode == JSObject::STRICT_DELETION &&
426 result == heap->false_value()) {
427 // In strict mode, attempting to delete a non-configurable property
428 // throws an exception.
429 HandleScope scope(isolate);
430 Handle<Object> holder(obj);
431 Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
432 Handle<Object> args[2] = { name, holder };
433 Handle<Object> error =
434 isolate->factory()->NewTypeError("strict_delete_property",
435 HandleVector(args, 2));
436 return isolate->Throw(*error);
437 }
438 }
439 return heap->true_value();
440 }
441
442 protected:
443 friend class ElementsAccessorBase<DictionaryElementsAccessor,
Ben Murdoch85b71792012-04-11 18:30:58 +0100444 SeededNumberDictionary>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000445
446 virtual MaybeObject* Delete(JSObject* obj,
447 uint32_t key,
448 JSReceiver::DeleteMode mode) {
449 return DeleteCommon(obj, key, mode);
450 }
451
Ben Murdoch85b71792012-04-11 18:30:58 +0100452 static MaybeObject* Get(SeededNumberDictionary* backing_store,
453 uint32_t key,
454 JSObject* obj,
455 Object* receiver) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000456 int entry = backing_store->FindEntry(key);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000457 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000458 Object* element = backing_store->ValueAt(entry);
459 PropertyDetails details = backing_store->DetailsAt(entry);
460 if (details.type() == CALLBACKS) {
461 return obj->GetElementWithCallback(receiver,
462 element,
463 key,
464 obj);
465 } else {
466 return element;
467 }
468 }
469 return obj->GetHeap()->the_hole_value();
470 }
471
Ben Murdoch85b71792012-04-11 18:30:58 +0100472 static uint32_t GetKeyForIndex(SeededNumberDictionary* dict,
473 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000474 Object* key = dict->KeyAt(index);
475 return Smi::cast(key)->value();
476 }
477};
478
479
Ben Murdoch85b71792012-04-11 18:30:58 +0100480class NonStrictArgumentsElementsAccessor
481 : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
482 FixedArray> {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000483 protected:
Ben Murdoch85b71792012-04-11 18:30:58 +0100484 friend class ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
485 FixedArray>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000486
Ben Murdoch85b71792012-04-11 18:30:58 +0100487 static MaybeObject* Get(FixedArray* parameter_map,
488 uint32_t key,
489 JSObject* obj,
490 Object* receiver) {
491 Object* probe = GetParameterMapArg(parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000492 if (!probe->IsTheHole()) {
493 Context* context = Context::cast(parameter_map->get(0));
494 int context_index = Smi::cast(probe)->value();
495 ASSERT(!context->get(context_index)->IsTheHole());
496 return context->get(context_index);
497 } else {
498 // Object is not mapped, defer to the arguments.
499 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdoch85b71792012-04-11 18:30:58 +0100500 return ElementsAccessor::ForArray(arguments)->Get(arguments,
501 key,
502 obj,
503 receiver);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000504 }
505 }
506
507 virtual MaybeObject* Delete(JSObject* obj,
Ben Murdoch85b71792012-04-11 18:30:58 +0100508 uint32_t key
509 ,
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000510 JSReceiver::DeleteMode mode) {
511 FixedArray* parameter_map = FixedArray::cast(obj->elements());
Ben Murdoch85b71792012-04-11 18:30:58 +0100512 Object* probe = GetParameterMapArg(parameter_map, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000513 if (!probe->IsTheHole()) {
514 // TODO(kmillikin): We could check if this was the last aliased
515 // parameter, and revert to normal elements in that case. That
516 // would enable GC of the context.
517 parameter_map->set_the_hole(key + 2);
518 } else {
519 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
520 if (arguments->IsDictionary()) {
521 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
522 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +0100523 return FastElementsAccessor::DeleteCommon(obj, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000524 }
525 }
526 return obj->GetHeap()->true_value();
527 }
528
Ben Murdoch85b71792012-04-11 18:30:58 +0100529 static uint32_t GetCapacity(FixedArray* parameter_map) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000530 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
531 return Max(static_cast<uint32_t>(parameter_map->length() - 2),
532 ForArray(arguments)->GetCapacity(arguments));
533 }
534
Ben Murdoch85b71792012-04-11 18:30:58 +0100535 static uint32_t GetKeyForIndex(FixedArray* dict,
536 uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000537 return index;
538 }
539
Ben Murdoch85b71792012-04-11 18:30:58 +0100540 static bool HasElementAtIndex(FixedArray* parameter_map,
541 uint32_t index,
542 JSObject* holder,
543 Object* receiver) {
544 Object* probe = GetParameterMapArg(parameter_map, index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000545 if (!probe->IsTheHole()) {
546 return true;
547 } else {
548 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
549 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
Ben Murdoch85b71792012-04-11 18:30:58 +0100550 return !accessor->Get(arguments, index, holder, receiver)->IsTheHole();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000551 }
552 }
553
554 private:
Ben Murdoch85b71792012-04-11 18:30:58 +0100555 static Object* GetParameterMapArg(FixedArray* parameter_map,
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000556 uint32_t key) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100557 uint32_t length = parameter_map->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000558 return key < (length - 2 )
559 ? parameter_map->get(key + 2)
560 : parameter_map->GetHeap()->the_hole_value();
561 }
562};
563
564
565ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) {
566 switch (array->map()->instance_type()) {
567 case FIXED_ARRAY_TYPE:
568 if (array->IsDictionary()) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000569 return elements_accessors_[DICTIONARY_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000570 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +0000571 return elements_accessors_[FAST_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000572 }
573 case EXTERNAL_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000574 return elements_accessors_[EXTERNAL_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000575 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000576 return elements_accessors_[EXTERNAL_UNSIGNED_BYTE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000577 case EXTERNAL_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000578 return elements_accessors_[EXTERNAL_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000579 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000580 return elements_accessors_[EXTERNAL_UNSIGNED_SHORT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000581 case EXTERNAL_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000582 return elements_accessors_[EXTERNAL_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000583 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000584 return elements_accessors_[EXTERNAL_UNSIGNED_INT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000585 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000586 return elements_accessors_[EXTERNAL_FLOAT_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000587 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000588 return elements_accessors_[EXTERNAL_DOUBLE_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000589 case EXTERNAL_PIXEL_ARRAY_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +0000590 return elements_accessors_[EXTERNAL_PIXEL_ELEMENTS];
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000591 default:
592 UNREACHABLE();
593 return NULL;
594 }
595}
596
597
598void ElementsAccessor::InitializeOncePerProcess() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000599 static struct ConcreteElementsAccessors {
Ben Murdoch85b71792012-04-11 18:30:58 +0100600 FastElementsAccessor fast_elements_handler;
601 FastDoubleElementsAccessor fast_double_elements_handler;
602 DictionaryElementsAccessor dictionary_elements_handler;
603 NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler;
604 ExternalByteElementsAccessor byte_elements_handler;
605 ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler;
606 ExternalShortElementsAccessor short_elements_handler;
607 ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler;
608 ExternalIntElementsAccessor int_elements_handler;
609 ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler;
610 ExternalFloatElementsAccessor float_elements_handler;
611 ExternalDoubleElementsAccessor double_elements_handler;
612 PixelElementsAccessor pixel_elements_handler;
613 } element_accessors;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000614
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000615 static ElementsAccessor* accessor_array[] = {
Ben Murdoch85b71792012-04-11 18:30:58 +0100616 &element_accessors.fast_elements_handler,
617 &element_accessors.fast_double_elements_handler,
618 &element_accessors.dictionary_elements_handler,
619 &element_accessors.non_strict_arguments_elements_handler,
620 &element_accessors.byte_elements_handler,
621 &element_accessors.unsigned_byte_elements_handler,
622 &element_accessors.short_elements_handler,
623 &element_accessors.unsigned_short_elements_handler,
624 &element_accessors.int_elements_handler,
625 &element_accessors.unsigned_int_elements_handler,
626 &element_accessors.float_elements_handler,
627 &element_accessors.double_elements_handler,
628 &element_accessors.pixel_elements_handler
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000629 };
630
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000631 elements_accessors_ = accessor_array;
632}
633
634
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000635} } // namespace v8::internal