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