1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "arguments.h" 31 #include "objects.h" 32 #include "elements.h" 33 #include "utils.h" 34 #include "v8conversions.h" 35 36 // Each concrete ElementsAccessor can handle exactly one ElementsKind, 37 // several abstract ElementsAccessor classes are used to allow sharing 38 // common code. 39 // 40 // Inheritance hierarchy: 41 // - ElementsAccessorBase (abstract) 42 // - FastElementsAccessor (abstract) 43 // - FastSmiOrObjectElementsAccessor 44 // - FastPackedSmiElementsAccessor 45 // - FastHoleySmiElementsAccessor 46 // - FastPackedObjectElementsAccessor 47 // - FastHoleyObjectElementsAccessor 48 // - FastDoubleElementsAccessor 49 // - FastPackedDoubleElementsAccessor 50 // - FastHoleyDoubleElementsAccessor 51 // - ExternalElementsAccessor (abstract) 52 // - ExternalByteElementsAccessor 53 // - ExternalUnsignedByteElementsAccessor 54 // - ExternalShortElementsAccessor 55 // - ExternalUnsignedShortElementsAccessor 56 // - ExternalIntElementsAccessor 57 // - ExternalUnsignedIntElementsAccessor 58 // - ExternalFloatElementsAccessor 59 // - ExternalDoubleElementsAccessor 60 // - PixelElementsAccessor 61 // - DictionaryElementsAccessor 62 // - NonStrictArgumentsElementsAccessor 63 64 65 namespace v8 { 66 namespace internal { 67 68 69 static const int kPackedSizeNotKnown = -1; 70 71 72 // First argument in list is the accessor class, the second argument is the 73 // accessor ElementsKind, and the third is the backing store class. Use the 74 // fast element handler for smi-only arrays. The implementation is currently 75 // identical. Note that the order must match that of the ElementsKind enum for 76 // the |accessor_array[]| below to work. 77 #define ELEMENTS_LIST(V) \ 78 V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \ 79 V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \ 80 FixedArray) \ 81 V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \ 82 V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \ 83 V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \ 84 FixedDoubleArray) \ 85 V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \ 86 FixedDoubleArray) \ 87 V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \ 88 SeededNumberDictionary) \ 89 V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \ 90 FixedArray) \ 91 V(ExternalByteElementsAccessor, EXTERNAL_BYTE_ELEMENTS, \ 92 ExternalByteArray) \ 93 V(ExternalUnsignedByteElementsAccessor, \ 94 EXTERNAL_UNSIGNED_BYTE_ELEMENTS, ExternalUnsignedByteArray) \ 95 V(ExternalShortElementsAccessor, EXTERNAL_SHORT_ELEMENTS, \ 96 ExternalShortArray) \ 97 V(ExternalUnsignedShortElementsAccessor, \ 98 EXTERNAL_UNSIGNED_SHORT_ELEMENTS, ExternalUnsignedShortArray) \ 99 V(ExternalIntElementsAccessor, EXTERNAL_INT_ELEMENTS, \ 100 ExternalIntArray) \ 101 V(ExternalUnsignedIntElementsAccessor, \ 102 EXTERNAL_UNSIGNED_INT_ELEMENTS, ExternalUnsignedIntArray) \ 103 V(ExternalFloatElementsAccessor, \ 104 EXTERNAL_FLOAT_ELEMENTS, ExternalFloatArray) \ 105 V(ExternalDoubleElementsAccessor, \ 106 EXTERNAL_DOUBLE_ELEMENTS, ExternalDoubleArray) \ 107 V(PixelElementsAccessor, EXTERNAL_PIXEL_ELEMENTS, ExternalPixelArray) 108 109 110 template<ElementsKind Kind> class ElementsKindTraits { 111 public: 112 typedef FixedArrayBase BackingStore; 113 }; 114 115 #define ELEMENTS_TRAITS(Class, KindParam, Store) \ 116 template<> class ElementsKindTraits<KindParam> { \ 117 public: \ 118 static const ElementsKind Kind = KindParam; \ 119 typedef Store BackingStore; \ 120 }; 121 ELEMENTS_LIST(ELEMENTS_TRAITS) 122 #undef ELEMENTS_TRAITS 123 124 125 ElementsAccessor** ElementsAccessor::elements_accessors_; 126 127 128 static bool HasKey(FixedArray* array, Object* key) { 129 int len0 = array->length(); 130 for (int i = 0; i < len0; i++) { 131 Object* element = array->get(i); 132 if (element->IsSmi() && element == key) return true; 133 if (element->IsString() && 134 key->IsString() && String::cast(element)->Equals(String::cast(key))) { 135 return true; 136 } 137 } 138 return false; 139 } 140 141 142 static Failure* ThrowArrayLengthRangeError(Heap* heap) { 143 HandleScope scope(heap->isolate()); 144 return heap->isolate()->Throw( 145 *heap->isolate()->factory()->NewRangeError("invalid_array_length", 146 HandleVector<Object>(NULL, 0))); 147 } 148 149 150 static void CopyObjectToObjectElements(FixedArrayBase* from_base, 151 ElementsKind from_kind, 152 uint32_t from_start, 153 FixedArrayBase* to_base, 154 ElementsKind to_kind, 155 uint32_t to_start, 156 int raw_copy_size) { 157 ASSERT(to_base->map() != 158 from_base->GetIsolate()->heap()->fixed_cow_array_map()); 159 DisallowHeapAllocation no_allocation; 160 int copy_size = raw_copy_size; 161 if (raw_copy_size < 0) { 162 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 163 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 164 copy_size = Min(from_base->length() - from_start, 165 to_base->length() - to_start); 166 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 167 int start = to_start + copy_size; 168 int length = to_base->length() - start; 169 if (length > 0) { 170 Heap* heap = from_base->GetHeap(); 171 MemsetPointer(FixedArray::cast(to_base)->data_start() + start, 172 heap->the_hole_value(), length); 173 } 174 } 175 } 176 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 177 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 178 if (copy_size == 0) return; 179 FixedArray* from = FixedArray::cast(from_base); 180 FixedArray* to = FixedArray::cast(to_base); 181 ASSERT(IsFastSmiOrObjectElementsKind(from_kind)); 182 ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); 183 Address to_address = to->address() + FixedArray::kHeaderSize; 184 Address from_address = from->address() + FixedArray::kHeaderSize; 185 CopyWords(reinterpret_cast<Object**>(to_address) + to_start, 186 reinterpret_cast<Object**>(from_address) + from_start, 187 static_cast<size_t>(copy_size)); 188 if (IsFastObjectElementsKind(from_kind) && 189 IsFastObjectElementsKind(to_kind)) { 190 Heap* heap = from->GetHeap(); 191 if (!heap->InNewSpace(to)) { 192 heap->RecordWrites(to->address(), 193 to->OffsetOfElementAt(to_start), 194 copy_size); 195 } 196 heap->incremental_marking()->RecordWrites(to); 197 } 198 } 199 200 201 static void CopyDictionaryToObjectElements(FixedArrayBase* from_base, 202 uint32_t from_start, 203 FixedArrayBase* to_base, 204 ElementsKind to_kind, 205 uint32_t to_start, 206 int raw_copy_size) { 207 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); 208 DisallowHeapAllocation no_allocation; 209 int copy_size = raw_copy_size; 210 Heap* heap = from->GetHeap(); 211 if (raw_copy_size < 0) { 212 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 213 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 214 copy_size = from->max_number_key() + 1 - from_start; 215 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 216 int start = to_start + copy_size; 217 int length = to_base->length() - start; 218 if (length > 0) { 219 Heap* heap = from->GetHeap(); 220 MemsetPointer(FixedArray::cast(to_base)->data_start() + start, 221 heap->the_hole_value(), length); 222 } 223 } 224 } 225 ASSERT(to_base != from_base); 226 ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); 227 if (copy_size == 0) return; 228 FixedArray* to = FixedArray::cast(to_base); 229 uint32_t to_length = to->length(); 230 if (to_start + copy_size > to_length) { 231 copy_size = to_length - to_start; 232 } 233 for (int i = 0; i < copy_size; i++) { 234 int entry = from->FindEntry(i + from_start); 235 if (entry != SeededNumberDictionary::kNotFound) { 236 Object* value = from->ValueAt(entry); 237 ASSERT(!value->IsTheHole()); 238 to->set(i + to_start, value, SKIP_WRITE_BARRIER); 239 } else { 240 to->set_the_hole(i + to_start); 241 } 242 } 243 if (IsFastObjectElementsKind(to_kind)) { 244 if (!heap->InNewSpace(to)) { 245 heap->RecordWrites(to->address(), 246 to->OffsetOfElementAt(to_start), 247 copy_size); 248 } 249 heap->incremental_marking()->RecordWrites(to); 250 } 251 } 252 253 254 MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( 255 FixedArrayBase* from_base, 256 uint32_t from_start, 257 FixedArrayBase* to_base, 258 ElementsKind to_kind, 259 uint32_t to_start, 260 int raw_copy_size) { 261 ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); 262 int copy_size = raw_copy_size; 263 if (raw_copy_size < 0) { 264 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 265 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 266 copy_size = Min(from_base->length() - from_start, 267 to_base->length() - to_start); 268 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 269 // Also initialize the area that will be copied over since HeapNumber 270 // allocation below can cause an incremental marking step, requiring all 271 // existing heap objects to be propertly initialized. 272 int start = to_start; 273 int length = to_base->length() - start; 274 if (length > 0) { 275 Heap* heap = from_base->GetHeap(); 276 MemsetPointer(FixedArray::cast(to_base)->data_start() + start, 277 heap->the_hole_value(), length); 278 } 279 } 280 } 281 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 282 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 283 if (copy_size == 0) return from_base; 284 FixedDoubleArray* from = FixedDoubleArray::cast(from_base); 285 FixedArray* to = FixedArray::cast(to_base); 286 for (int i = 0; i < copy_size; ++i) { 287 if (IsFastSmiElementsKind(to_kind)) { 288 UNIMPLEMENTED(); 289 return Failure::Exception(); 290 } else { 291 MaybeObject* maybe_value = from->get(i + from_start); 292 Object* value; 293 ASSERT(IsFastObjectElementsKind(to_kind)); 294 // Because Double -> Object elements transitions allocate HeapObjects 295 // iteratively, the allocate must succeed within a single GC cycle, 296 // otherwise the retry after the GC will also fail. In order to ensure 297 // that no GC is triggered, allocate HeapNumbers from old space if they 298 // can't be taken from new space. 299 if (!maybe_value->ToObject(&value)) { 300 ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory()); 301 Heap* heap = from->GetHeap(); 302 MaybeObject* maybe_value_object = 303 heap->AllocateHeapNumber(from->get_scalar(i + from_start), 304 TENURED); 305 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; 306 } 307 to->set(i + to_start, value, UPDATE_WRITE_BARRIER); 308 } 309 } 310 return to; 311 } 312 313 314 static void CopyDoubleToDoubleElements(FixedArrayBase* from_base, 315 uint32_t from_start, 316 FixedArrayBase* to_base, 317 uint32_t to_start, 318 int raw_copy_size) { 319 int copy_size = raw_copy_size; 320 if (raw_copy_size < 0) { 321 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 322 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 323 copy_size = Min(from_base->length() - from_start, 324 to_base->length() - to_start); 325 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 326 for (int i = to_start + copy_size; i < to_base->length(); ++i) { 327 FixedDoubleArray::cast(to_base)->set_the_hole(i); 328 } 329 } 330 } 331 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 332 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 333 if (copy_size == 0) return; 334 FixedDoubleArray* from = FixedDoubleArray::cast(from_base); 335 FixedDoubleArray* to = FixedDoubleArray::cast(to_base); 336 Address to_address = to->address() + FixedDoubleArray::kHeaderSize; 337 Address from_address = from->address() + FixedDoubleArray::kHeaderSize; 338 to_address += kDoubleSize * to_start; 339 from_address += kDoubleSize * from_start; 340 int words_per_double = (kDoubleSize / kPointerSize); 341 CopyWords(reinterpret_cast<Object**>(to_address), 342 reinterpret_cast<Object**>(from_address), 343 static_cast<size_t>(words_per_double * copy_size)); 344 } 345 346 347 static void CopySmiToDoubleElements(FixedArrayBase* from_base, 348 uint32_t from_start, 349 FixedArrayBase* to_base, 350 uint32_t to_start, 351 int raw_copy_size) { 352 int copy_size = raw_copy_size; 353 if (raw_copy_size < 0) { 354 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 355 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 356 copy_size = from_base->length() - from_start; 357 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 358 for (int i = to_start + copy_size; i < to_base->length(); ++i) { 359 FixedDoubleArray::cast(to_base)->set_the_hole(i); 360 } 361 } 362 } 363 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 364 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 365 if (copy_size == 0) return; 366 FixedArray* from = FixedArray::cast(from_base); 367 FixedDoubleArray* to = FixedDoubleArray::cast(to_base); 368 Object* the_hole = from->GetHeap()->the_hole_value(); 369 for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size); 370 from_start < from_end; from_start++, to_start++) { 371 Object* hole_or_smi = from->get(from_start); 372 if (hole_or_smi == the_hole) { 373 to->set_the_hole(to_start); 374 } else { 375 to->set(to_start, Smi::cast(hole_or_smi)->value()); 376 } 377 } 378 } 379 380 381 static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base, 382 uint32_t from_start, 383 FixedArrayBase* to_base, 384 uint32_t to_start, 385 int packed_size, 386 int raw_copy_size) { 387 int copy_size = raw_copy_size; 388 uint32_t to_end; 389 if (raw_copy_size < 0) { 390 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 391 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 392 copy_size = packed_size - from_start; 393 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 394 to_end = to_base->length(); 395 for (uint32_t i = to_start + copy_size; i < to_end; ++i) { 396 FixedDoubleArray::cast(to_base)->set_the_hole(i); 397 } 398 } else { 399 to_end = to_start + static_cast<uint32_t>(copy_size); 400 } 401 } else { 402 to_end = to_start + static_cast<uint32_t>(copy_size); 403 } 404 ASSERT(static_cast<int>(to_end) <= to_base->length()); 405 ASSERT(packed_size >= 0 && packed_size <= copy_size); 406 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 407 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 408 if (copy_size == 0) return; 409 FixedArray* from = FixedArray::cast(from_base); 410 FixedDoubleArray* to = FixedDoubleArray::cast(to_base); 411 for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size); 412 from_start < from_end; from_start++, to_start++) { 413 Object* smi = from->get(from_start); 414 ASSERT(!smi->IsTheHole()); 415 to->set(to_start, Smi::cast(smi)->value()); 416 } 417 } 418 419 420 static void CopyObjectToDoubleElements(FixedArrayBase* from_base, 421 uint32_t from_start, 422 FixedArrayBase* to_base, 423 uint32_t to_start, 424 int raw_copy_size) { 425 int copy_size = raw_copy_size; 426 if (raw_copy_size < 0) { 427 ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || 428 raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 429 copy_size = from_base->length() - from_start; 430 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 431 for (int i = to_start + copy_size; i < to_base->length(); ++i) { 432 FixedDoubleArray::cast(to_base)->set_the_hole(i); 433 } 434 } 435 } 436 ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() && 437 (copy_size + static_cast<int>(from_start)) <= from_base->length()); 438 if (copy_size == 0) return; 439 FixedArray* from = FixedArray::cast(from_base); 440 FixedDoubleArray* to = FixedDoubleArray::cast(to_base); 441 Object* the_hole = from->GetHeap()->the_hole_value(); 442 for (uint32_t from_end = from_start + copy_size; 443 from_start < from_end; from_start++, to_start++) { 444 Object* hole_or_object = from->get(from_start); 445 if (hole_or_object == the_hole) { 446 to->set_the_hole(to_start); 447 } else { 448 to->set(to_start, hole_or_object->Number()); 449 } 450 } 451 } 452 453 454 static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, 455 uint32_t from_start, 456 FixedArrayBase* to_base, 457 uint32_t to_start, 458 int raw_copy_size) { 459 SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base); 460 int copy_size = raw_copy_size; 461 if (copy_size < 0) { 462 ASSERT(copy_size == ElementsAccessor::kCopyToEnd || 463 copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); 464 copy_size = from->max_number_key() + 1 - from_start; 465 if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { 466 for (int i = to_start + copy_size; i < to_base->length(); ++i) { 467 FixedDoubleArray::cast(to_base)->set_the_hole(i); 468 } 469 } 470 } 471 if (copy_size == 0) return; 472 FixedDoubleArray* to = FixedDoubleArray::cast(to_base); 473 uint32_t to_length = to->length(); 474 if (to_start + copy_size > to_length) { 475 copy_size = to_length - to_start; 476 } 477 for (int i = 0; i < copy_size; i++) { 478 int entry = from->FindEntry(i + from_start); 479 if (entry != SeededNumberDictionary::kNotFound) { 480 to->set(i + to_start, from->ValueAt(entry)->Number()); 481 } else { 482 to->set_the_hole(i + to_start); 483 } 484 } 485 } 486 487 488 static void TraceTopFrame(Isolate* isolate) { 489 StackFrameIterator it(isolate); 490 if (it.done()) { 491 PrintF("unknown location (no JavaScript frames present)"); 492 return; 493 } 494 StackFrame* raw_frame = it.frame(); 495 if (raw_frame->is_internal()) { 496 Code* apply_builtin = isolate->builtins()->builtin( 497 Builtins::kFunctionApply); 498 if (raw_frame->unchecked_code() == apply_builtin) { 499 PrintF("apply from "); 500 it.Advance(); 501 raw_frame = it.frame(); 502 } 503 } 504 JavaScriptFrame::PrintTop(isolate, stdout, false, true); 505 } 506 507 508 void CheckArrayAbuse(JSObject* obj, const char* op, uint32_t key, 509 bool allow_appending) { 510 Object* raw_length = NULL; 511 const char* elements_type = "array"; 512 if (obj->IsJSArray()) { 513 JSArray* array = JSArray::cast(obj); 514 raw_length = array->length(); 515 } else { 516 raw_length = Smi::FromInt(obj->elements()->length()); 517 elements_type = "object"; 518 } 519 520 if (raw_length->IsNumber()) { 521 double n = raw_length->Number(); 522 if (FastI2D(FastD2UI(n)) == n) { 523 int32_t int32_length = DoubleToInt32(n); 524 uint32_t compare_length = static_cast<uint32_t>(int32_length); 525 if (allow_appending) compare_length++; 526 if (key >= compare_length) { 527 PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ", 528 elements_type, op, elements_type, 529 static_cast<int>(int32_length), 530 static_cast<int>(key)); 531 TraceTopFrame(obj->GetIsolate()); 532 PrintF("]\n"); 533 } 534 } else { 535 PrintF("[%s elements length not integer value in ", elements_type); 536 TraceTopFrame(obj->GetIsolate()); 537 PrintF("]\n"); 538 } 539 } else { 540 PrintF("[%s elements length not a number in ", elements_type); 541 TraceTopFrame(obj->GetIsolate()); 542 PrintF("]\n"); 543 } 544 } 545 546 547 // Base class for element handler implementations. Contains the 548 // the common logic for objects with different ElementsKinds. 549 // Subclasses must specialize method for which the element 550 // implementation differs from the base class implementation. 551 // 552 // This class is intended to be used in the following way: 553 // 554 // class SomeElementsAccessor : 555 // public ElementsAccessorBase<SomeElementsAccessor, 556 // BackingStoreClass> { 557 // ... 558 // } 559 // 560 // This is an example of the Curiously Recurring Template Pattern (see 561 // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use 562 // CRTP to guarantee aggressive compile time optimizations (i.e. inlining and 563 // specialization of SomeElementsAccessor methods). 564 template <typename ElementsAccessorSubclass, 565 typename ElementsTraitsParam> 566 class ElementsAccessorBase : public ElementsAccessor { 567 protected: 568 explicit ElementsAccessorBase(const char* name) 569 : ElementsAccessor(name) { } 570 571 typedef ElementsTraitsParam ElementsTraits; 572 typedef typename ElementsTraitsParam::BackingStore BackingStore; 573 574 virtual ElementsKind kind() const { return ElementsTraits::Kind; } 575 576 static void ValidateContents(JSObject* holder, int length) { 577 } 578 579 static void ValidateImpl(JSObject* holder) { 580 FixedArrayBase* fixed_array_base = holder->elements(); 581 // When objects are first allocated, its elements are Failures. 582 if (fixed_array_base->IsFailure()) return; 583 if (!fixed_array_base->IsHeapObject()) return; 584 // Arrays that have been shifted in place can't be verified. 585 if (fixed_array_base->IsFiller()) return; 586 int length = 0; 587 if (holder->IsJSArray()) { 588 Object* length_obj = JSArray::cast(holder)->length(); 589 if (length_obj->IsSmi()) { 590 length = Smi::cast(length_obj)->value(); 591 } 592 } else { 593 length = fixed_array_base->length(); 594 } 595 ElementsAccessorSubclass::ValidateContents(holder, length); 596 } 597 598 virtual void Validate(JSObject* holder) { 599 ElementsAccessorSubclass::ValidateImpl(holder); 600 } 601 602 static bool HasElementImpl(Object* receiver, 603 JSObject* holder, 604 uint32_t key, 605 FixedArrayBase* backing_store) { 606 return ElementsAccessorSubclass::GetAttributesImpl( 607 receiver, holder, key, backing_store) != ABSENT; 608 } 609 610 virtual bool HasElement(Object* receiver, 611 JSObject* holder, 612 uint32_t key, 613 FixedArrayBase* backing_store) { 614 if (backing_store == NULL) { 615 backing_store = holder->elements(); 616 } 617 return ElementsAccessorSubclass::HasElementImpl( 618 receiver, holder, key, backing_store); 619 } 620 621 MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver, 622 JSObject* holder, 623 uint32_t key, 624 FixedArrayBase* backing_store) { 625 if (backing_store == NULL) { 626 backing_store = holder->elements(); 627 } 628 629 if (!IsExternalArrayElementsKind(ElementsTraits::Kind) && 630 FLAG_trace_js_array_abuse) { 631 CheckArrayAbuse(holder, "elements read", key); 632 } 633 634 if (IsExternalArrayElementsKind(ElementsTraits::Kind) && 635 FLAG_trace_external_array_abuse) { 636 CheckArrayAbuse(holder, "external elements read", key); 637 } 638 639 return ElementsAccessorSubclass::GetImpl( 640 receiver, holder, key, backing_store); 641 } 642 643 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, 644 JSObject* obj, 645 uint32_t key, 646 FixedArrayBase* backing_store) { 647 return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) 648 ? BackingStore::cast(backing_store)->get(key) 649 : backing_store->GetHeap()->the_hole_value(); 650 } 651 652 MUST_USE_RESULT virtual PropertyAttributes GetAttributes( 653 Object* receiver, 654 JSObject* holder, 655 uint32_t key, 656 FixedArrayBase* backing_store) { 657 if (backing_store == NULL) { 658 backing_store = holder->elements(); 659 } 660 return ElementsAccessorSubclass::GetAttributesImpl( 661 receiver, holder, key, backing_store); 662 } 663 664 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( 665 Object* receiver, 666 JSObject* obj, 667 uint32_t key, 668 FixedArrayBase* backing_store) { 669 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { 670 return ABSENT; 671 } 672 return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE; 673 } 674 675 MUST_USE_RESULT virtual PropertyType GetType( 676 Object* receiver, 677 JSObject* holder, 678 uint32_t key, 679 FixedArrayBase* backing_store) { 680 if (backing_store == NULL) { 681 backing_store = holder->elements(); 682 } 683 return ElementsAccessorSubclass::GetTypeImpl( 684 receiver, holder, key, backing_store); 685 } 686 687 MUST_USE_RESULT static PropertyType GetTypeImpl( 688 Object* receiver, 689 JSObject* obj, 690 uint32_t key, 691 FixedArrayBase* backing_store) { 692 if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { 693 return NONEXISTENT; 694 } 695 return BackingStore::cast(backing_store)->is_the_hole(key) 696 ? NONEXISTENT : FIELD; 697 } 698 699 MUST_USE_RESULT virtual AccessorPair* GetAccessorPair( 700 Object* receiver, 701 JSObject* holder, 702 uint32_t key, 703 FixedArrayBase* backing_store) { 704 if (backing_store == NULL) { 705 backing_store = holder->elements(); 706 } 707 return ElementsAccessorSubclass::GetAccessorPairImpl( 708 receiver, holder, key, backing_store); 709 } 710 711 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( 712 Object* receiver, 713 JSObject* obj, 714 uint32_t key, 715 FixedArrayBase* backing_store) { 716 return NULL; 717 } 718 719 MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array, 720 Object* length) { 721 return ElementsAccessorSubclass::SetLengthImpl( 722 array, length, array->elements()); 723 } 724 725 MUST_USE_RESULT static MaybeObject* SetLengthImpl( 726 JSObject* obj, 727 Object* length, 728 FixedArrayBase* backing_store); 729 730 MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength( 731 JSArray* array, 732 int capacity, 733 int length) { 734 return ElementsAccessorSubclass::SetFastElementsCapacityAndLength( 735 array, 736 capacity, 737 length); 738 } 739 740 MUST_USE_RESULT static MaybeObject* SetFastElementsCapacityAndLength( 741 JSObject* obj, 742 int capacity, 743 int length) { 744 UNIMPLEMENTED(); 745 return obj; 746 } 747 748 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, 749 uint32_t key, 750 JSReceiver::DeleteMode mode) = 0; 751 752 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, 753 uint32_t from_start, 754 FixedArrayBase* to, 755 ElementsKind from_kind, 756 uint32_t to_start, 757 int packed_size, 758 int copy_size) { 759 UNREACHABLE(); 760 return NULL; 761 } 762 763 MUST_USE_RESULT virtual MaybeObject* CopyElements(JSObject* from_holder, 764 uint32_t from_start, 765 ElementsKind from_kind, 766 FixedArrayBase* to, 767 uint32_t to_start, 768 int copy_size, 769 FixedArrayBase* from) { 770 int packed_size = kPackedSizeNotKnown; 771 if (from == NULL) { 772 from = from_holder->elements(); 773 } 774 775 if (from_holder) { 776 bool is_packed = IsFastPackedElementsKind(from_kind) && 777 from_holder->IsJSArray(); 778 if (is_packed) { 779 packed_size = Smi::cast(JSArray::cast(from_holder)->length())->value(); 780 if (copy_size >= 0 && packed_size > copy_size) { 781 packed_size = copy_size; 782 } 783 } 784 } 785 return ElementsAccessorSubclass::CopyElementsImpl( 786 from, from_start, to, from_kind, to_start, packed_size, copy_size); 787 } 788 789 MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray( 790 Object* receiver, 791 JSObject* holder, 792 FixedArray* to, 793 FixedArrayBase* from) { 794 int len0 = to->length(); 795 #ifdef ENABLE_SLOW_ASSERTS 796 if (FLAG_enable_slow_asserts) { 797 for (int i = 0; i < len0; i++) { 798 ASSERT(!to->get(i)->IsTheHole()); 799 } 800 } 801 #endif 802 if (from == NULL) { 803 from = holder->elements(); 804 } 805 806 // Optimize if 'other' is empty. 807 // We cannot optimize if 'this' is empty, as other may have holes. 808 uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from); 809 if (len1 == 0) return to; 810 811 // Compute how many elements are not in other. 812 uint32_t extra = 0; 813 for (uint32_t y = 0; y < len1; y++) { 814 uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); 815 if (ElementsAccessorSubclass::HasElementImpl( 816 receiver, holder, key, from)) { 817 MaybeObject* maybe_value = 818 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); 819 Object* value; 820 if (!maybe_value->To(&value)) return maybe_value; 821 ASSERT(!value->IsTheHole()); 822 if (!HasKey(to, value)) { 823 extra++; 824 } 825 } 826 } 827 828 if (extra == 0) return to; 829 830 // Allocate the result 831 FixedArray* result; 832 MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra); 833 if (!maybe_obj->To(&result)) return maybe_obj; 834 835 // Fill in the content 836 { 837 DisallowHeapAllocation no_gc; 838 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); 839 for (int i = 0; i < len0; i++) { 840 Object* e = to->get(i); 841 ASSERT(e->IsString() || e->IsNumber()); 842 result->set(i, e, mode); 843 } 844 } 845 // Fill in the extra values. 846 uint32_t index = 0; 847 for (uint32_t y = 0; y < len1; y++) { 848 uint32_t key = 849 ElementsAccessorSubclass::GetKeyForIndexImpl(from, y); 850 if (ElementsAccessorSubclass::HasElementImpl( 851 receiver, holder, key, from)) { 852 MaybeObject* maybe_value = 853 ElementsAccessorSubclass::GetImpl(receiver, holder, key, from); 854 Object* value; 855 if (!maybe_value->To(&value)) return maybe_value; 856 if (!value->IsTheHole() && !HasKey(to, value)) { 857 result->set(len0 + index, value); 858 index++; 859 } 860 } 861 } 862 ASSERT(extra == index); 863 return result; 864 } 865 866 protected: 867 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) { 868 return backing_store->length(); 869 } 870 871 virtual uint32_t GetCapacity(FixedArrayBase* backing_store) { 872 return ElementsAccessorSubclass::GetCapacityImpl(backing_store); 873 } 874 875 static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store, 876 uint32_t index) { 877 return index; 878 } 879 880 virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store, 881 uint32_t index) { 882 return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index); 883 } 884 885 private: 886 DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase); 887 }; 888 889 890 // Super class for all fast element arrays. 891 template<typename FastElementsAccessorSubclass, 892 typename KindTraits, 893 int ElementSize> 894 class FastElementsAccessor 895 : public ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits> { 896 public: 897 explicit FastElementsAccessor(const char* name) 898 : ElementsAccessorBase<FastElementsAccessorSubclass, 899 KindTraits>(name) {} 900 protected: 901 friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>; 902 friend class NonStrictArgumentsElementsAccessor; 903 904 typedef typename KindTraits::BackingStore BackingStore; 905 906 // Adjusts the length of the fast backing store or returns the new length or 907 // undefined in case conversion to a slow backing store should be performed. 908 static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store, 909 JSArray* array, 910 Object* length_object, 911 uint32_t length) { 912 uint32_t old_capacity = backing_store->length(); 913 Object* old_length = array->length(); 914 bool same_or_smaller_size = old_length->IsSmi() && 915 static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length; 916 ElementsKind kind = array->GetElementsKind(); 917 918 if (!same_or_smaller_size && IsFastElementsKind(kind) && 919 !IsFastHoleyElementsKind(kind)) { 920 kind = GetHoleyElementsKind(kind); 921 MaybeObject* maybe_obj = array->TransitionElementsKind(kind); 922 if (maybe_obj->IsFailure()) return maybe_obj; 923 } 924 925 // Check whether the backing store should be shrunk. 926 if (length <= old_capacity) { 927 if (array->HasFastSmiOrObjectElements()) { 928 MaybeObject* maybe_obj = array->EnsureWritableFastElements(); 929 if (!maybe_obj->To(&backing_store)) return maybe_obj; 930 } 931 if (2 * length <= old_capacity) { 932 // If more than half the elements won't be used, trim the array. 933 if (length == 0) { 934 array->initialize_elements(); 935 } else { 936 backing_store->set_length(length); 937 Address filler_start = backing_store->address() + 938 BackingStore::OffsetOfElementAt(length); 939 int filler_size = (old_capacity - length) * ElementSize; 940 array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size); 941 } 942 } else { 943 // Otherwise, fill the unused tail with holes. 944 int old_length = FastD2IChecked(array->length()->Number()); 945 for (int i = length; i < old_length; i++) { 946 BackingStore::cast(backing_store)->set_the_hole(i); 947 } 948 } 949 return length_object; 950 } 951 952 // Check whether the backing store should be expanded. 953 uint32_t min = JSObject::NewElementsCapacity(old_capacity); 954 uint32_t new_capacity = length > min ? length : min; 955 if (!array->ShouldConvertToSlowElements(new_capacity)) { 956 MaybeObject* result = FastElementsAccessorSubclass:: 957 SetFastElementsCapacityAndLength(array, new_capacity, length); 958 if (result->IsFailure()) return result; 959 array->ValidateElements(); 960 return length_object; 961 } 962 963 // Request conversion to slow elements. 964 return array->GetHeap()->undefined_value(); 965 } 966 967 static MaybeObject* DeleteCommon(JSObject* obj, 968 uint32_t key, 969 JSReceiver::DeleteMode mode) { 970 ASSERT(obj->HasFastSmiOrObjectElements() || 971 obj->HasFastDoubleElements() || 972 obj->HasFastArgumentsElements()); 973 Heap* heap = obj->GetHeap(); 974 Object* elements = obj->elements(); 975 if (elements == heap->empty_fixed_array()) { 976 return heap->true_value(); 977 } 978 typename KindTraits::BackingStore* backing_store = 979 KindTraits::BackingStore::cast(elements); 980 bool is_non_strict_arguments_elements_map = 981 backing_store->map() == heap->non_strict_arguments_elements_map(); 982 if (is_non_strict_arguments_elements_map) { 983 backing_store = KindTraits::BackingStore::cast( 984 FixedArray::cast(backing_store)->get(1)); 985 } 986 uint32_t length = static_cast<uint32_t>( 987 obj->IsJSArray() 988 ? Smi::cast(JSArray::cast(obj)->length())->value() 989 : backing_store->length()); 990 if (key < length) { 991 if (!is_non_strict_arguments_elements_map) { 992 ElementsKind kind = KindTraits::Kind; 993 if (IsFastPackedElementsKind(kind)) { 994 MaybeObject* transitioned = 995 obj->TransitionElementsKind(GetHoleyElementsKind(kind)); 996 if (transitioned->IsFailure()) return transitioned; 997 } 998 if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { 999 Object* writable; 1000 MaybeObject* maybe = obj->EnsureWritableFastElements(); 1001 if (!maybe->ToObject(&writable)) return maybe; 1002 backing_store = KindTraits::BackingStore::cast(writable); 1003 } 1004 } 1005 backing_store->set_the_hole(key); 1006 // If an old space backing store is larger than a certain size and 1007 // has too few used values, normalize it. 1008 // To avoid doing the check on every delete we require at least 1009 // one adjacent hole to the value being deleted. 1010 const int kMinLengthForSparsenessCheck = 64; 1011 if (backing_store->length() >= kMinLengthForSparsenessCheck && 1012 !heap->InNewSpace(backing_store) && 1013 ((key > 0 && backing_store->is_the_hole(key - 1)) || 1014 (key + 1 < length && backing_store->is_the_hole(key + 1)))) { 1015 int num_used = 0; 1016 for (int i = 0; i < backing_store->length(); ++i) { 1017 if (!backing_store->is_the_hole(i)) ++num_used; 1018 // Bail out early if more than 1/4 is used. 1019 if (4 * num_used > backing_store->length()) break; 1020 } 1021 if (4 * num_used <= backing_store->length()) { 1022 MaybeObject* result = obj->NormalizeElements(); 1023 if (result->IsFailure()) return result; 1024 } 1025 } 1026 } 1027 return heap->true_value(); 1028 } 1029 1030 virtual MaybeObject* Delete(JSObject* obj, 1031 uint32_t key, 1032 JSReceiver::DeleteMode mode) { 1033 return DeleteCommon(obj, key, mode); 1034 } 1035 1036 static bool HasElementImpl( 1037 Object* receiver, 1038 JSObject* holder, 1039 uint32_t key, 1040 FixedArrayBase* backing_store) { 1041 if (key >= static_cast<uint32_t>(backing_store->length())) { 1042 return false; 1043 } 1044 return !BackingStore::cast(backing_store)->is_the_hole(key); 1045 } 1046 1047 static void ValidateContents(JSObject* holder, int length) { 1048 #if DEBUG 1049 FixedArrayBase* elements = holder->elements(); 1050 Heap* heap = elements->GetHeap(); 1051 Map* map = elements->map(); 1052 ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) && 1053 (map == heap->fixed_array_map() || 1054 map == heap->fixed_cow_array_map())) || 1055 (IsFastDoubleElementsKind(KindTraits::Kind) == 1056 ((map == heap->fixed_array_map() && length == 0) || 1057 map == heap->fixed_double_array_map()))); 1058 for (int i = 0; i < length; i++) { 1059 typename KindTraits::BackingStore* backing_store = 1060 KindTraits::BackingStore::cast(elements); 1061 ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) || 1062 static_cast<Object*>(backing_store->get(i))->IsSmi()) || 1063 (IsFastHoleyElementsKind(KindTraits::Kind) == 1064 backing_store->is_the_hole(i))); 1065 } 1066 #endif 1067 } 1068 }; 1069 1070 1071 static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) { 1072 switch (array->map()->instance_type()) { 1073 case FIXED_ARRAY_TYPE: 1074 if (array->IsDictionary()) { 1075 return DICTIONARY_ELEMENTS; 1076 } else { 1077 return FAST_HOLEY_ELEMENTS; 1078 } 1079 case FIXED_DOUBLE_ARRAY_TYPE: 1080 return FAST_HOLEY_DOUBLE_ELEMENTS; 1081 case EXTERNAL_BYTE_ARRAY_TYPE: 1082 return EXTERNAL_BYTE_ELEMENTS; 1083 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: 1084 return EXTERNAL_UNSIGNED_BYTE_ELEMENTS; 1085 case EXTERNAL_SHORT_ARRAY_TYPE: 1086 return EXTERNAL_SHORT_ELEMENTS; 1087 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: 1088 return EXTERNAL_UNSIGNED_SHORT_ELEMENTS; 1089 case EXTERNAL_INT_ARRAY_TYPE: 1090 return EXTERNAL_INT_ELEMENTS; 1091 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: 1092 return EXTERNAL_UNSIGNED_INT_ELEMENTS; 1093 case EXTERNAL_FLOAT_ARRAY_TYPE: 1094 return EXTERNAL_FLOAT_ELEMENTS; 1095 case EXTERNAL_DOUBLE_ARRAY_TYPE: 1096 return EXTERNAL_DOUBLE_ELEMENTS; 1097 case EXTERNAL_PIXEL_ARRAY_TYPE: 1098 return EXTERNAL_PIXEL_ELEMENTS; 1099 default: 1100 UNREACHABLE(); 1101 } 1102 return FAST_HOLEY_ELEMENTS; 1103 } 1104 1105 1106 template<typename FastElementsAccessorSubclass, 1107 typename KindTraits> 1108 class FastSmiOrObjectElementsAccessor 1109 : public FastElementsAccessor<FastElementsAccessorSubclass, 1110 KindTraits, 1111 kPointerSize> { 1112 public: 1113 explicit FastSmiOrObjectElementsAccessor(const char* name) 1114 : FastElementsAccessor<FastElementsAccessorSubclass, 1115 KindTraits, 1116 kPointerSize>(name) {} 1117 1118 static MaybeObject* CopyElementsImpl(FixedArrayBase* from, 1119 uint32_t from_start, 1120 FixedArrayBase* to, 1121 ElementsKind from_kind, 1122 uint32_t to_start, 1123 int packed_size, 1124 int copy_size) { 1125 ElementsKind to_kind = KindTraits::Kind; 1126 switch (from_kind) { 1127 case FAST_SMI_ELEMENTS: 1128 case FAST_HOLEY_SMI_ELEMENTS: 1129 case FAST_ELEMENTS: 1130 case FAST_HOLEY_ELEMENTS: 1131 CopyObjectToObjectElements( 1132 from, from_kind, from_start, to, to_kind, to_start, copy_size); 1133 return to->GetHeap()->undefined_value(); 1134 case FAST_DOUBLE_ELEMENTS: 1135 case FAST_HOLEY_DOUBLE_ELEMENTS: 1136 return CopyDoubleToObjectElements( 1137 from, from_start, to, to_kind, to_start, copy_size); 1138 case DICTIONARY_ELEMENTS: 1139 CopyDictionaryToObjectElements( 1140 from, from_start, to, to_kind, to_start, copy_size); 1141 return to->GetHeap()->undefined_value(); 1142 case NON_STRICT_ARGUMENTS_ELEMENTS: { 1143 // TODO(verwaest): This is a temporary hack to support extending 1144 // NON_STRICT_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength. 1145 // This case should be UNREACHABLE(). 1146 FixedArray* parameter_map = FixedArray::cast(from); 1147 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); 1148 ElementsKind from_kind = ElementsKindForArray(arguments); 1149 return CopyElementsImpl(arguments, from_start, to, from_kind, 1150 to_start, packed_size, copy_size); 1151 } 1152 case EXTERNAL_BYTE_ELEMENTS: 1153 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 1154 case EXTERNAL_SHORT_ELEMENTS: 1155 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 1156 case EXTERNAL_INT_ELEMENTS: 1157 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 1158 case EXTERNAL_FLOAT_ELEMENTS: 1159 case EXTERNAL_DOUBLE_ELEMENTS: 1160 case EXTERNAL_PIXEL_ELEMENTS: 1161 UNREACHABLE(); 1162 } 1163 return NULL; 1164 } 1165 1166 1167 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, 1168 uint32_t capacity, 1169 uint32_t length) { 1170 JSObject::SetFastElementsCapacitySmiMode set_capacity_mode = 1171 obj->HasFastSmiElements() 1172 ? JSObject::kAllowSmiElements 1173 : JSObject::kDontAllowSmiElements; 1174 return obj->SetFastElementsCapacityAndLength(capacity, 1175 length, 1176 set_capacity_mode); 1177 } 1178 }; 1179 1180 1181 class FastPackedSmiElementsAccessor 1182 : public FastSmiOrObjectElementsAccessor< 1183 FastPackedSmiElementsAccessor, 1184 ElementsKindTraits<FAST_SMI_ELEMENTS> > { 1185 public: 1186 explicit FastPackedSmiElementsAccessor(const char* name) 1187 : FastSmiOrObjectElementsAccessor< 1188 FastPackedSmiElementsAccessor, 1189 ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {} 1190 }; 1191 1192 1193 class FastHoleySmiElementsAccessor 1194 : public FastSmiOrObjectElementsAccessor< 1195 FastHoleySmiElementsAccessor, 1196 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > { 1197 public: 1198 explicit FastHoleySmiElementsAccessor(const char* name) 1199 : FastSmiOrObjectElementsAccessor< 1200 FastHoleySmiElementsAccessor, 1201 ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {} 1202 }; 1203 1204 1205 class FastPackedObjectElementsAccessor 1206 : public FastSmiOrObjectElementsAccessor< 1207 FastPackedObjectElementsAccessor, 1208 ElementsKindTraits<FAST_ELEMENTS> > { 1209 public: 1210 explicit FastPackedObjectElementsAccessor(const char* name) 1211 : FastSmiOrObjectElementsAccessor< 1212 FastPackedObjectElementsAccessor, 1213 ElementsKindTraits<FAST_ELEMENTS> >(name) {} 1214 }; 1215 1216 1217 class FastHoleyObjectElementsAccessor 1218 : public FastSmiOrObjectElementsAccessor< 1219 FastHoleyObjectElementsAccessor, 1220 ElementsKindTraits<FAST_HOLEY_ELEMENTS> > { 1221 public: 1222 explicit FastHoleyObjectElementsAccessor(const char* name) 1223 : FastSmiOrObjectElementsAccessor< 1224 FastHoleyObjectElementsAccessor, 1225 ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {} 1226 }; 1227 1228 1229 template<typename FastElementsAccessorSubclass, 1230 typename KindTraits> 1231 class FastDoubleElementsAccessor 1232 : public FastElementsAccessor<FastElementsAccessorSubclass, 1233 KindTraits, 1234 kDoubleSize> { 1235 public: 1236 explicit FastDoubleElementsAccessor(const char* name) 1237 : FastElementsAccessor<FastElementsAccessorSubclass, 1238 KindTraits, 1239 kDoubleSize>(name) {} 1240 1241 static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, 1242 uint32_t capacity, 1243 uint32_t length) { 1244 return obj->SetFastDoubleElementsCapacityAndLength(capacity, 1245 length); 1246 } 1247 1248 protected: 1249 static MaybeObject* CopyElementsImpl(FixedArrayBase* from, 1250 uint32_t from_start, 1251 FixedArrayBase* to, 1252 ElementsKind from_kind, 1253 uint32_t to_start, 1254 int packed_size, 1255 int copy_size) { 1256 switch (from_kind) { 1257 case FAST_SMI_ELEMENTS: 1258 CopyPackedSmiToDoubleElements( 1259 from, from_start, to, to_start, packed_size, copy_size); 1260 break; 1261 case FAST_HOLEY_SMI_ELEMENTS: 1262 CopySmiToDoubleElements(from, from_start, to, to_start, copy_size); 1263 break; 1264 case FAST_DOUBLE_ELEMENTS: 1265 case FAST_HOLEY_DOUBLE_ELEMENTS: 1266 CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size); 1267 break; 1268 case FAST_ELEMENTS: 1269 case FAST_HOLEY_ELEMENTS: 1270 CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size); 1271 break; 1272 case DICTIONARY_ELEMENTS: 1273 CopyDictionaryToDoubleElements( 1274 from, from_start, to, to_start, copy_size); 1275 break; 1276 case NON_STRICT_ARGUMENTS_ELEMENTS: 1277 case EXTERNAL_BYTE_ELEMENTS: 1278 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 1279 case EXTERNAL_SHORT_ELEMENTS: 1280 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 1281 case EXTERNAL_INT_ELEMENTS: 1282 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 1283 case EXTERNAL_FLOAT_ELEMENTS: 1284 case EXTERNAL_DOUBLE_ELEMENTS: 1285 case EXTERNAL_PIXEL_ELEMENTS: 1286 UNREACHABLE(); 1287 } 1288 return to->GetHeap()->undefined_value(); 1289 } 1290 }; 1291 1292 1293 class FastPackedDoubleElementsAccessor 1294 : public FastDoubleElementsAccessor< 1295 FastPackedDoubleElementsAccessor, 1296 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > { 1297 public: 1298 friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor, 1299 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >; 1300 explicit FastPackedDoubleElementsAccessor(const char* name) 1301 : FastDoubleElementsAccessor< 1302 FastPackedDoubleElementsAccessor, 1303 ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {} 1304 }; 1305 1306 1307 class FastHoleyDoubleElementsAccessor 1308 : public FastDoubleElementsAccessor< 1309 FastHoleyDoubleElementsAccessor, 1310 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > { 1311 public: 1312 friend class ElementsAccessorBase< 1313 FastHoleyDoubleElementsAccessor, 1314 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >; 1315 explicit FastHoleyDoubleElementsAccessor(const char* name) 1316 : FastDoubleElementsAccessor< 1317 FastHoleyDoubleElementsAccessor, 1318 ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {} 1319 }; 1320 1321 1322 // Super class for all external element arrays. 1323 template<typename ExternalElementsAccessorSubclass, 1324 ElementsKind Kind> 1325 class ExternalElementsAccessor 1326 : public ElementsAccessorBase<ExternalElementsAccessorSubclass, 1327 ElementsKindTraits<Kind> > { 1328 public: 1329 explicit ExternalElementsAccessor(const char* name) 1330 : ElementsAccessorBase<ExternalElementsAccessorSubclass, 1331 ElementsKindTraits<Kind> >(name) {} 1332 1333 protected: 1334 typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore; 1335 1336 friend class ElementsAccessorBase<ExternalElementsAccessorSubclass, 1337 ElementsKindTraits<Kind> >; 1338 1339 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, 1340 JSObject* obj, 1341 uint32_t key, 1342 FixedArrayBase* backing_store) { 1343 return 1344 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) 1345 ? BackingStore::cast(backing_store)->get(key) 1346 : backing_store->GetHeap()->undefined_value(); 1347 } 1348 1349 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( 1350 Object* receiver, 1351 JSObject* obj, 1352 uint32_t key, 1353 FixedArrayBase* backing_store) { 1354 return 1355 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) 1356 ? NONE : ABSENT; 1357 } 1358 1359 MUST_USE_RESULT static PropertyType GetTypeImpl( 1360 Object* receiver, 1361 JSObject* obj, 1362 uint32_t key, 1363 FixedArrayBase* backing_store) { 1364 return 1365 key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) 1366 ? FIELD : NONEXISTENT; 1367 } 1368 1369 MUST_USE_RESULT static MaybeObject* SetLengthImpl( 1370 JSObject* obj, 1371 Object* length, 1372 FixedArrayBase* backing_store) { 1373 // External arrays do not support changing their length. 1374 UNREACHABLE(); 1375 return obj; 1376 } 1377 1378 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, 1379 uint32_t key, 1380 JSReceiver::DeleteMode mode) { 1381 // External arrays always ignore deletes. 1382 return obj->GetHeap()->true_value(); 1383 } 1384 1385 static bool HasElementImpl(Object* receiver, 1386 JSObject* holder, 1387 uint32_t key, 1388 FixedArrayBase* backing_store) { 1389 uint32_t capacity = 1390 ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store); 1391 return key < capacity; 1392 } 1393 }; 1394 1395 1396 class ExternalByteElementsAccessor 1397 : public ExternalElementsAccessor<ExternalByteElementsAccessor, 1398 EXTERNAL_BYTE_ELEMENTS> { 1399 public: 1400 explicit ExternalByteElementsAccessor(const char* name) 1401 : ExternalElementsAccessor<ExternalByteElementsAccessor, 1402 EXTERNAL_BYTE_ELEMENTS>(name) {} 1403 }; 1404 1405 1406 class ExternalUnsignedByteElementsAccessor 1407 : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, 1408 EXTERNAL_UNSIGNED_BYTE_ELEMENTS> { 1409 public: 1410 explicit ExternalUnsignedByteElementsAccessor(const char* name) 1411 : ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor, 1412 EXTERNAL_UNSIGNED_BYTE_ELEMENTS>(name) {} 1413 }; 1414 1415 1416 class ExternalShortElementsAccessor 1417 : public ExternalElementsAccessor<ExternalShortElementsAccessor, 1418 EXTERNAL_SHORT_ELEMENTS> { 1419 public: 1420 explicit ExternalShortElementsAccessor(const char* name) 1421 : ExternalElementsAccessor<ExternalShortElementsAccessor, 1422 EXTERNAL_SHORT_ELEMENTS>(name) {} 1423 }; 1424 1425 1426 class ExternalUnsignedShortElementsAccessor 1427 : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, 1428 EXTERNAL_UNSIGNED_SHORT_ELEMENTS> { 1429 public: 1430 explicit ExternalUnsignedShortElementsAccessor(const char* name) 1431 : ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor, 1432 EXTERNAL_UNSIGNED_SHORT_ELEMENTS>(name) {} 1433 }; 1434 1435 1436 class ExternalIntElementsAccessor 1437 : public ExternalElementsAccessor<ExternalIntElementsAccessor, 1438 EXTERNAL_INT_ELEMENTS> { 1439 public: 1440 explicit ExternalIntElementsAccessor(const char* name) 1441 : ExternalElementsAccessor<ExternalIntElementsAccessor, 1442 EXTERNAL_INT_ELEMENTS>(name) {} 1443 }; 1444 1445 1446 class ExternalUnsignedIntElementsAccessor 1447 : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, 1448 EXTERNAL_UNSIGNED_INT_ELEMENTS> { 1449 public: 1450 explicit ExternalUnsignedIntElementsAccessor(const char* name) 1451 : ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor, 1452 EXTERNAL_UNSIGNED_INT_ELEMENTS>(name) {} 1453 }; 1454 1455 1456 class ExternalFloatElementsAccessor 1457 : public ExternalElementsAccessor<ExternalFloatElementsAccessor, 1458 EXTERNAL_FLOAT_ELEMENTS> { 1459 public: 1460 explicit ExternalFloatElementsAccessor(const char* name) 1461 : ExternalElementsAccessor<ExternalFloatElementsAccessor, 1462 EXTERNAL_FLOAT_ELEMENTS>(name) {} 1463 }; 1464 1465 1466 class ExternalDoubleElementsAccessor 1467 : public ExternalElementsAccessor<ExternalDoubleElementsAccessor, 1468 EXTERNAL_DOUBLE_ELEMENTS> { 1469 public: 1470 explicit ExternalDoubleElementsAccessor(const char* name) 1471 : ExternalElementsAccessor<ExternalDoubleElementsAccessor, 1472 EXTERNAL_DOUBLE_ELEMENTS>(name) {} 1473 }; 1474 1475 1476 class PixelElementsAccessor 1477 : public ExternalElementsAccessor<PixelElementsAccessor, 1478 EXTERNAL_PIXEL_ELEMENTS> { 1479 public: 1480 explicit PixelElementsAccessor(const char* name) 1481 : ExternalElementsAccessor<PixelElementsAccessor, 1482 EXTERNAL_PIXEL_ELEMENTS>(name) {} 1483 }; 1484 1485 1486 class DictionaryElementsAccessor 1487 : public ElementsAccessorBase<DictionaryElementsAccessor, 1488 ElementsKindTraits<DICTIONARY_ELEMENTS> > { 1489 public: 1490 explicit DictionaryElementsAccessor(const char* name) 1491 : ElementsAccessorBase<DictionaryElementsAccessor, 1492 ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {} 1493 1494 // Adjusts the length of the dictionary backing store and returns the new 1495 // length according to ES5 section 15.4.5.2 behavior. 1496 MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize( 1497 FixedArrayBase* store, 1498 JSArray* array, 1499 Object* length_object, 1500 uint32_t length) { 1501 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); 1502 Heap* heap = array->GetHeap(); 1503 int capacity = dict->Capacity(); 1504 uint32_t new_length = length; 1505 uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); 1506 if (new_length < old_length) { 1507 // Find last non-deletable element in range of elements to be 1508 // deleted and adjust range accordingly. 1509 for (int i = 0; i < capacity; i++) { 1510 Object* key = dict->KeyAt(i); 1511 if (key->IsNumber()) { 1512 uint32_t number = static_cast<uint32_t>(key->Number()); 1513 if (new_length <= number && number < old_length) { 1514 PropertyDetails details = dict->DetailsAt(i); 1515 if (details.IsDontDelete()) new_length = number + 1; 1516 } 1517 } 1518 } 1519 if (new_length != length) { 1520 MaybeObject* maybe_object = heap->NumberFromUint32(new_length); 1521 if (!maybe_object->To(&length_object)) return maybe_object; 1522 } 1523 } 1524 1525 if (new_length == 0) { 1526 // If the length of a slow array is reset to zero, we clear 1527 // the array and flush backing storage. This has the added 1528 // benefit that the array returns to fast mode. 1529 Object* obj; 1530 MaybeObject* maybe_obj = array->ResetElements(); 1531 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1532 } else { 1533 // Remove elements that should be deleted. 1534 int removed_entries = 0; 1535 Object* the_hole_value = heap->the_hole_value(); 1536 for (int i = 0; i < capacity; i++) { 1537 Object* key = dict->KeyAt(i); 1538 if (key->IsNumber()) { 1539 uint32_t number = static_cast<uint32_t>(key->Number()); 1540 if (new_length <= number && number < old_length) { 1541 dict->SetEntry(i, the_hole_value, the_hole_value); 1542 removed_entries++; 1543 } 1544 } 1545 } 1546 1547 // Update the number of elements. 1548 dict->ElementsRemoved(removed_entries); 1549 } 1550 return length_object; 1551 } 1552 1553 MUST_USE_RESULT static MaybeObject* DeleteCommon( 1554 JSObject* obj, 1555 uint32_t key, 1556 JSReceiver::DeleteMode mode) { 1557 Isolate* isolate = obj->GetIsolate(); 1558 Heap* heap = isolate->heap(); 1559 FixedArray* backing_store = FixedArray::cast(obj->elements()); 1560 bool is_arguments = 1561 (obj->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS); 1562 if (is_arguments) { 1563 backing_store = FixedArray::cast(backing_store->get(1)); 1564 } 1565 SeededNumberDictionary* dictionary = 1566 SeededNumberDictionary::cast(backing_store); 1567 int entry = dictionary->FindEntry(key); 1568 if (entry != SeededNumberDictionary::kNotFound) { 1569 Object* result = dictionary->DeleteProperty(entry, mode); 1570 if (result == heap->false_value()) { 1571 if (mode == JSObject::STRICT_DELETION) { 1572 // Deleting a non-configurable property in strict mode. 1573 HandleScope scope(isolate); 1574 Handle<Object> holder(obj, isolate); 1575 Handle<Object> name = isolate->factory()->NewNumberFromUint(key); 1576 Handle<Object> args[2] = { name, holder }; 1577 Handle<Object> error = 1578 isolate->factory()->NewTypeError("strict_delete_property", 1579 HandleVector(args, 2)); 1580 return isolate->Throw(*error); 1581 } 1582 return heap->false_value(); 1583 } 1584 MaybeObject* maybe_elements = dictionary->Shrink(key); 1585 FixedArray* new_elements = NULL; 1586 if (!maybe_elements->To(&new_elements)) { 1587 return maybe_elements; 1588 } 1589 if (is_arguments) { 1590 FixedArray::cast(obj->elements())->set(1, new_elements); 1591 } else { 1592 obj->set_elements(new_elements); 1593 } 1594 } 1595 return heap->true_value(); 1596 } 1597 1598 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, 1599 uint32_t from_start, 1600 FixedArrayBase* to, 1601 ElementsKind from_kind, 1602 uint32_t to_start, 1603 int packed_size, 1604 int copy_size) { 1605 UNREACHABLE(); 1606 return NULL; 1607 } 1608 1609 1610 protected: 1611 friend class ElementsAccessorBase<DictionaryElementsAccessor, 1612 ElementsKindTraits<DICTIONARY_ELEMENTS> >; 1613 1614 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, 1615 uint32_t key, 1616 JSReceiver::DeleteMode mode) { 1617 return DeleteCommon(obj, key, mode); 1618 } 1619 1620 MUST_USE_RESULT static MaybeObject* GetImpl( 1621 Object* receiver, 1622 JSObject* obj, 1623 uint32_t key, 1624 FixedArrayBase* store) { 1625 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); 1626 int entry = backing_store->FindEntry(key); 1627 if (entry != SeededNumberDictionary::kNotFound) { 1628 Object* element = backing_store->ValueAt(entry); 1629 PropertyDetails details = backing_store->DetailsAt(entry); 1630 if (details.type() == CALLBACKS) { 1631 return obj->GetElementWithCallback(receiver, 1632 element, 1633 key, 1634 obj); 1635 } else { 1636 return element; 1637 } 1638 } 1639 return obj->GetHeap()->the_hole_value(); 1640 } 1641 1642 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( 1643 Object* receiver, 1644 JSObject* obj, 1645 uint32_t key, 1646 FixedArrayBase* backing_store) { 1647 SeededNumberDictionary* dictionary = 1648 SeededNumberDictionary::cast(backing_store); 1649 int entry = dictionary->FindEntry(key); 1650 if (entry != SeededNumberDictionary::kNotFound) { 1651 return dictionary->DetailsAt(entry).attributes(); 1652 } 1653 return ABSENT; 1654 } 1655 1656 MUST_USE_RESULT static PropertyType GetTypeImpl( 1657 Object* receiver, 1658 JSObject* obj, 1659 uint32_t key, 1660 FixedArrayBase* store) { 1661 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); 1662 int entry = backing_store->FindEntry(key); 1663 if (entry != SeededNumberDictionary::kNotFound) { 1664 return backing_store->DetailsAt(entry).type(); 1665 } 1666 return NONEXISTENT; 1667 } 1668 1669 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( 1670 Object* receiver, 1671 JSObject* obj, 1672 uint32_t key, 1673 FixedArrayBase* store) { 1674 SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store); 1675 int entry = backing_store->FindEntry(key); 1676 if (entry != SeededNumberDictionary::kNotFound && 1677 backing_store->DetailsAt(entry).type() == CALLBACKS && 1678 backing_store->ValueAt(entry)->IsAccessorPair()) { 1679 return AccessorPair::cast(backing_store->ValueAt(entry)); 1680 } 1681 return NULL; 1682 } 1683 1684 static bool HasElementImpl(Object* receiver, 1685 JSObject* holder, 1686 uint32_t key, 1687 FixedArrayBase* backing_store) { 1688 return SeededNumberDictionary::cast(backing_store)->FindEntry(key) != 1689 SeededNumberDictionary::kNotFound; 1690 } 1691 1692 static uint32_t GetKeyForIndexImpl(FixedArrayBase* store, 1693 uint32_t index) { 1694 SeededNumberDictionary* dict = SeededNumberDictionary::cast(store); 1695 Object* key = dict->KeyAt(index); 1696 return Smi::cast(key)->value(); 1697 } 1698 }; 1699 1700 1701 class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< 1702 NonStrictArgumentsElementsAccessor, 1703 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> > { 1704 public: 1705 explicit NonStrictArgumentsElementsAccessor(const char* name) 1706 : ElementsAccessorBase< 1707 NonStrictArgumentsElementsAccessor, 1708 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >(name) {} 1709 protected: 1710 friend class ElementsAccessorBase< 1711 NonStrictArgumentsElementsAccessor, 1712 ElementsKindTraits<NON_STRICT_ARGUMENTS_ELEMENTS> >; 1713 1714 MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver, 1715 JSObject* obj, 1716 uint32_t key, 1717 FixedArrayBase* parameters) { 1718 FixedArray* parameter_map = FixedArray::cast(parameters); 1719 Object* probe = GetParameterMapArg(obj, parameter_map, key); 1720 if (!probe->IsTheHole()) { 1721 Context* context = Context::cast(parameter_map->get(0)); 1722 int context_index = Smi::cast(probe)->value(); 1723 ASSERT(!context->get(context_index)->IsTheHole()); 1724 return context->get(context_index); 1725 } else { 1726 // Object is not mapped, defer to the arguments. 1727 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 1728 MaybeObject* maybe_result = ElementsAccessor::ForArray(arguments)->Get( 1729 receiver, obj, key, arguments); 1730 Object* result; 1731 if (!maybe_result->ToObject(&result)) return maybe_result; 1732 // Elements of the arguments object in slow mode might be slow aliases. 1733 if (result->IsAliasedArgumentsEntry()) { 1734 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(result); 1735 Context* context = Context::cast(parameter_map->get(0)); 1736 int context_index = entry->aliased_context_slot(); 1737 ASSERT(!context->get(context_index)->IsTheHole()); 1738 return context->get(context_index); 1739 } else { 1740 return result; 1741 } 1742 } 1743 } 1744 1745 MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( 1746 Object* receiver, 1747 JSObject* obj, 1748 uint32_t key, 1749 FixedArrayBase* backing_store) { 1750 FixedArray* parameter_map = FixedArray::cast(backing_store); 1751 Object* probe = GetParameterMapArg(obj, parameter_map, key); 1752 if (!probe->IsTheHole()) { 1753 return NONE; 1754 } else { 1755 // If not aliased, check the arguments. 1756 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 1757 return ElementsAccessor::ForArray(arguments)->GetAttributes( 1758 receiver, obj, key, arguments); 1759 } 1760 } 1761 1762 MUST_USE_RESULT static PropertyType GetTypeImpl( 1763 Object* receiver, 1764 JSObject* obj, 1765 uint32_t key, 1766 FixedArrayBase* parameters) { 1767 FixedArray* parameter_map = FixedArray::cast(parameters); 1768 Object* probe = GetParameterMapArg(obj, parameter_map, key); 1769 if (!probe->IsTheHole()) { 1770 return FIELD; 1771 } else { 1772 // If not aliased, check the arguments. 1773 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 1774 return ElementsAccessor::ForArray(arguments)->GetType( 1775 receiver, obj, key, arguments); 1776 } 1777 } 1778 1779 MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl( 1780 Object* receiver, 1781 JSObject* obj, 1782 uint32_t key, 1783 FixedArrayBase* parameters) { 1784 FixedArray* parameter_map = FixedArray::cast(parameters); 1785 Object* probe = GetParameterMapArg(obj, parameter_map, key); 1786 if (!probe->IsTheHole()) { 1787 return NULL; 1788 } else { 1789 // If not aliased, check the arguments. 1790 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 1791 return ElementsAccessor::ForArray(arguments)->GetAccessorPair( 1792 receiver, obj, key, arguments); 1793 } 1794 } 1795 1796 MUST_USE_RESULT static MaybeObject* SetLengthImpl( 1797 JSObject* obj, 1798 Object* length, 1799 FixedArrayBase* parameter_map) { 1800 // TODO(mstarzinger): This was never implemented but will be used once we 1801 // correctly implement [[DefineOwnProperty]] on arrays. 1802 UNIMPLEMENTED(); 1803 return obj; 1804 } 1805 1806 MUST_USE_RESULT virtual MaybeObject* Delete(JSObject* obj, 1807 uint32_t key, 1808 JSReceiver::DeleteMode mode) { 1809 FixedArray* parameter_map = FixedArray::cast(obj->elements()); 1810 Object* probe = GetParameterMapArg(obj, parameter_map, key); 1811 if (!probe->IsTheHole()) { 1812 // TODO(kmillikin): We could check if this was the last aliased 1813 // parameter, and revert to normal elements in that case. That 1814 // would enable GC of the context. 1815 parameter_map->set_the_hole(key + 2); 1816 } else { 1817 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); 1818 if (arguments->IsDictionary()) { 1819 return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); 1820 } else { 1821 // It's difficult to access the version of DeleteCommon that is declared 1822 // in the templatized super class, call the concrete implementation in 1823 // the class for the most generalized ElementsKind subclass. 1824 return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode); 1825 } 1826 } 1827 return obj->GetHeap()->true_value(); 1828 } 1829 1830 MUST_USE_RESULT static MaybeObject* CopyElementsImpl(FixedArrayBase* from, 1831 uint32_t from_start, 1832 FixedArrayBase* to, 1833 ElementsKind from_kind, 1834 uint32_t to_start, 1835 int packed_size, 1836 int copy_size) { 1837 UNREACHABLE(); 1838 return NULL; 1839 } 1840 1841 static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) { 1842 FixedArray* parameter_map = FixedArray::cast(backing_store); 1843 FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1)); 1844 return Max(static_cast<uint32_t>(parameter_map->length() - 2), 1845 ForArray(arguments)->GetCapacity(arguments)); 1846 } 1847 1848 static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict, 1849 uint32_t index) { 1850 return index; 1851 } 1852 1853 static bool HasElementImpl(Object* receiver, 1854 JSObject* holder, 1855 uint32_t key, 1856 FixedArrayBase* parameters) { 1857 FixedArray* parameter_map = FixedArray::cast(parameters); 1858 Object* probe = GetParameterMapArg(holder, parameter_map, key); 1859 if (!probe->IsTheHole()) { 1860 return true; 1861 } else { 1862 FixedArrayBase* arguments = 1863 FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1)); 1864 ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments); 1865 return !accessor->Get(receiver, holder, key, arguments)->IsTheHole(); 1866 } 1867 } 1868 1869 private: 1870 static Object* GetParameterMapArg(JSObject* holder, 1871 FixedArray* parameter_map, 1872 uint32_t key) { 1873 uint32_t length = holder->IsJSArray() 1874 ? Smi::cast(JSArray::cast(holder)->length())->value() 1875 : parameter_map->length(); 1876 return key < (length - 2) 1877 ? parameter_map->get(key + 2) 1878 : parameter_map->GetHeap()->the_hole_value(); 1879 } 1880 }; 1881 1882 1883 ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { 1884 return elements_accessors_[ElementsKindForArray(array)]; 1885 } 1886 1887 1888 void ElementsAccessor::InitializeOncePerProcess() { 1889 static ElementsAccessor* accessor_array[] = { 1890 #define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind), 1891 ELEMENTS_LIST(ACCESSOR_ARRAY) 1892 #undef ACCESSOR_ARRAY 1893 }; 1894 1895 STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) == 1896 kElementsKindCount); 1897 1898 elements_accessors_ = accessor_array; 1899 } 1900 1901 1902 void ElementsAccessor::TearDown() { 1903 #define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind]; 1904 ELEMENTS_LIST(ACCESSOR_DELETE) 1905 #undef ACCESSOR_DELETE 1906 elements_accessors_ = NULL; 1907 } 1908 1909 1910 template <typename ElementsAccessorSubclass, typename ElementsKindTraits> 1911 MUST_USE_RESULT MaybeObject* ElementsAccessorBase<ElementsAccessorSubclass, 1912 ElementsKindTraits>:: 1913 SetLengthImpl(JSObject* obj, 1914 Object* length, 1915 FixedArrayBase* backing_store) { 1916 JSArray* array = JSArray::cast(obj); 1917 1918 // Fast case: The new length fits into a Smi. 1919 MaybeObject* maybe_smi_length = length->ToSmi(); 1920 Object* smi_length = Smi::FromInt(0); 1921 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { 1922 const int value = Smi::cast(smi_length)->value(); 1923 if (value >= 0) { 1924 Object* new_length; 1925 MaybeObject* result = ElementsAccessorSubclass:: 1926 SetLengthWithoutNormalize(backing_store, array, smi_length, value); 1927 if (!result->ToObject(&new_length)) return result; 1928 ASSERT(new_length->IsSmi() || new_length->IsUndefined()); 1929 if (new_length->IsSmi()) { 1930 array->set_length(Smi::cast(new_length)); 1931 return array; 1932 } 1933 } else { 1934 return ThrowArrayLengthRangeError(array->GetHeap()); 1935 } 1936 } 1937 1938 // Slow case: The new length does not fit into a Smi or conversion 1939 // to slow elements is needed for other reasons. 1940 if (length->IsNumber()) { 1941 uint32_t value; 1942 if (length->ToArrayIndex(&value)) { 1943 SeededNumberDictionary* dictionary; 1944 MaybeObject* maybe_object = array->NormalizeElements(); 1945 if (!maybe_object->To(&dictionary)) return maybe_object; 1946 Object* new_length; 1947 MaybeObject* result = DictionaryElementsAccessor:: 1948 SetLengthWithoutNormalize(dictionary, array, length, value); 1949 if (!result->ToObject(&new_length)) return result; 1950 ASSERT(new_length->IsNumber()); 1951 array->set_length(new_length); 1952 return array; 1953 } else { 1954 return ThrowArrayLengthRangeError(array->GetHeap()); 1955 } 1956 } 1957 1958 // Fall-back case: The new length is not a number so make the array 1959 // size one and set only element to length. 1960 FixedArray* new_backing_store; 1961 MaybeObject* maybe_obj = array->GetHeap()->AllocateFixedArray(1); 1962 if (!maybe_obj->To(&new_backing_store)) return maybe_obj; 1963 new_backing_store->set(0, length); 1964 { MaybeObject* result = array->SetContent(new_backing_store); 1965 if (result->IsFailure()) return result; 1966 } 1967 return array; 1968 } 1969 1970 1971 MUST_USE_RESULT MaybeObject* ArrayConstructInitializeElements( 1972 JSArray* array, Arguments* args) { 1973 Heap* heap = array->GetIsolate()->heap(); 1974 1975 // Optimize the case where there is one argument and the argument is a 1976 // small smi. 1977 if (args->length() == 1) { 1978 Object* obj = (*args)[0]; 1979 if (obj->IsSmi()) { 1980 int len = Smi::cast(obj)->value(); 1981 if (len > 0 && len < JSObject::kInitialMaxFastElementArray) { 1982 ElementsKind elements_kind = array->GetElementsKind(); 1983 MaybeObject* maybe_array = array->Initialize(len, len); 1984 if (maybe_array->IsFailure()) return maybe_array; 1985 1986 if (!IsFastHoleyElementsKind(elements_kind)) { 1987 elements_kind = GetHoleyElementsKind(elements_kind); 1988 maybe_array = array->TransitionElementsKind(elements_kind); 1989 if (maybe_array->IsFailure()) return maybe_array; 1990 } 1991 1992 return array; 1993 } else if (len == 0) { 1994 return array->Initialize(JSArray::kPreallocatedArrayElements); 1995 } 1996 } 1997 1998 // Take the argument as the length. 1999 MaybeObject* maybe_obj = array->Initialize(0); 2000 if (!maybe_obj->To(&obj)) return maybe_obj; 2001 2002 return array->SetElementsLength((*args)[0]); 2003 } 2004 2005 // Optimize the case where there are no parameters passed. 2006 if (args->length() == 0) { 2007 return array->Initialize(JSArray::kPreallocatedArrayElements); 2008 } 2009 2010 // Set length and elements on the array. 2011 int number_of_elements = args->length(); 2012 MaybeObject* maybe_object = 2013 array->EnsureCanContainElements(args, 0, number_of_elements, 2014 ALLOW_CONVERTED_DOUBLE_ELEMENTS); 2015 if (maybe_object->IsFailure()) return maybe_object; 2016 2017 // Allocate an appropriately typed elements array. 2018 MaybeObject* maybe_elms; 2019 ElementsKind elements_kind = array->GetElementsKind(); 2020 if (IsFastDoubleElementsKind(elements_kind)) { 2021 maybe_elms = heap->AllocateUninitializedFixedDoubleArray( 2022 number_of_elements); 2023 } else { 2024 maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements); 2025 } 2026 FixedArrayBase* elms; 2027 if (!maybe_elms->To(&elms)) return maybe_elms; 2028 2029 // Fill in the content 2030 switch (array->GetElementsKind()) { 2031 case FAST_HOLEY_SMI_ELEMENTS: 2032 case FAST_SMI_ELEMENTS: { 2033 FixedArray* smi_elms = FixedArray::cast(elms); 2034 for (int index = 0; index < number_of_elements; index++) { 2035 smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER); 2036 } 2037 break; 2038 } 2039 case FAST_HOLEY_ELEMENTS: 2040 case FAST_ELEMENTS: { 2041 DisallowHeapAllocation no_gc; 2042 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 2043 FixedArray* object_elms = FixedArray::cast(elms); 2044 for (int index = 0; index < number_of_elements; index++) { 2045 object_elms->set(index, (*args)[index], mode); 2046 } 2047 break; 2048 } 2049 case FAST_HOLEY_DOUBLE_ELEMENTS: 2050 case FAST_DOUBLE_ELEMENTS: { 2051 FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms); 2052 for (int index = 0; index < number_of_elements; index++) { 2053 double_elms->set(index, (*args)[index]->Number()); 2054 } 2055 break; 2056 } 2057 default: 2058 UNREACHABLE(); 2059 break; 2060 } 2061 2062 array->set_elements(elms); 2063 array->set_length(Smi::FromInt(number_of_elements)); 2064 return array; 2065 } 2066 2067 } } // namespace v8::internal 2068