Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: src/builtins.cc

Issue 11377132: Support all fast elements kinds in the major array operations. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments (and rebased) Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/elements.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 318
319 319
320 BUILTIN(ArrayCodeGeneric) { 320 BUILTIN(ArrayCodeGeneric) {
321 return ArrayCodeGenericCommon( 321 return ArrayCodeGenericCommon(
322 &args, 322 &args,
323 isolate, 323 isolate,
324 isolate->context()->native_context()->array_function()); 324 isolate->context()->native_context()->array_function());
325 } 325 }
326 326
327 327
328 static void MoveDoubleElements(FixedDoubleArray* dst,
329 int dst_index,
330 FixedDoubleArray* src,
331 int src_index,
332 int len) {
333 if (len == 0) return;
334 memmove(dst->data_start() + dst_index,
335 src->data_start() + src_index,
336 len * kDoubleSize);
337 }
338
339
328 static void MoveElements(Heap* heap, 340 static void MoveElements(Heap* heap,
329 AssertNoAllocation* no_gc, 341 AssertNoAllocation* no_gc,
330 FixedArray* dst, 342 FixedArray* dst,
331 int dst_index, 343 int dst_index,
332 FixedArray* src, 344 FixedArray* src,
333 int src_index, 345 int src_index,
334 int len) { 346 int len) {
335 if (len == 0) return; 347 if (len == 0) return;
336 ASSERT(dst->map() != HEAP->fixed_cow_array_map()); 348 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
337 memmove(dst->data_start() + dst_index, 349 memmove(dst->data_start() + dst_index,
338 src->data_start() + src_index, 350 src->data_start() + src_index,
339 len * kPointerSize); 351 len * kPointerSize);
340 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc); 352 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
341 if (mode == UPDATE_WRITE_BARRIER) { 353 if (mode == UPDATE_WRITE_BARRIER) {
342 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len); 354 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
343 } 355 }
344 heap->incremental_marking()->RecordWrites(dst); 356 heap->incremental_marking()->RecordWrites(dst);
345 } 357 }
346 358
347 359
348 static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) { 360 static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
349 ASSERT(dst->map() != heap->fixed_cow_array_map()); 361 ASSERT(dst->map() != heap->fixed_cow_array_map());
350 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from); 362 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
351 } 363 }
352 364
353 365
354 static FixedArray* LeftTrimFixedArray(Heap* heap, 366 static void FillWithHoles(FixedDoubleArray* dst, int from, int to) {
355 FixedArray* elms, 367 for (int i = from; i < to; i++) {
356 int to_trim) { 368 dst->set_the_hole(i);
369 }
370 }
371
372
373 static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
374 FixedArrayBase* elms,
375 int to_trim) {
376 Map* map = elms->map();
377 int entry_size;
378 if (elms->IsFixedArray()) {
379 entry_size = kPointerSize;
380 } else {
381 entry_size = kDoubleSize;
382 }
357 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); 383 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
358 // For now this trick is only applied to fixed arrays in new and paged space. 384 // For now this trick is only applied to fixed arrays in new and paged space.
359 // In large object space the object's start must coincide with chunk 385 // In large object space the object's start must coincide with chunk
360 // and thus the trick is just not applicable. 386 // and thus the trick is just not applicable.
361 ASSERT(!HEAP->lo_space()->Contains(elms)); 387 ASSERT(!HEAP->lo_space()->Contains(elms));
362 388
363 STATIC_ASSERT(FixedArray::kMapOffset == 0); 389 STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
364 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize); 390 STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
365 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize); 391 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
366 392
367 Object** former_start = HeapObject::RawField(elms, 0); 393 Object** former_start = HeapObject::RawField(elms, 0);
368 394
369 const int len = elms->length(); 395 const int len = elms->length();
370 396
371 if (to_trim > FixedArray::kHeaderSize / kPointerSize && 397 if (to_trim > FixedArrayBase::kHeaderSize / entry_size &&
398 elms->IsFixedArray() &&
372 !heap->new_space()->Contains(elms)) { 399 !heap->new_space()->Contains(elms)) {
373 // If we are doing a big trim in old space then we zap the space that was 400 // If we are doing a big trim in old space then we zap the space that was
374 // formerly part of the array so that the GC (aided by the card-based 401 // formerly part of the array so that the GC (aided by the card-based
375 // remembered set) won't find pointers to new-space there. 402 // remembered set) won't find pointers to new-space there.
376 Object** zap = reinterpret_cast<Object**>(elms->address()); 403 Object** zap = reinterpret_cast<Object**>(elms->address());
377 zap++; // Header of filler must be at least one word so skip that. 404 zap++; // Header of filler must be at least one word so skip that.
378 for (int i = 1; i < to_trim; i++) { 405 for (int i = 1; i < to_trim; i++) {
379 *zap++ = Smi::FromInt(0); 406 *zap++ = Smi::FromInt(0);
380 } 407 }
381 } 408 }
382 // Technically in new space this write might be omitted (except for 409 // Technically in new space this write might be omitted (except for
383 // debug mode which iterates through the heap), but to play safer 410 // debug mode which iterates through the heap), but to play safer
384 // we still do it. 411 // we still do it.
385 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize); 412 heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
386 413
387 former_start[to_trim] = heap->fixed_array_map(); 414 int new_start_index = to_trim * (entry_size / kPointerSize);
388 former_start[to_trim + 1] = Smi::FromInt(len - to_trim); 415 former_start[new_start_index] = map;
416 former_start[new_start_index + 1] = Smi::FromInt(len - to_trim);
389 417
390 // Maintain marking consistency for HeapObjectIterator and 418 // Maintain marking consistency for HeapObjectIterator and
391 // IncrementalMarking. 419 // IncrementalMarking.
392 int size_delta = to_trim * kPointerSize; 420 int size_delta = to_trim * entry_size;
393 if (heap->marking()->TransferMark(elms->address(), 421 if (heap->marking()->TransferMark(elms->address(),
394 elms->address() + size_delta)) { 422 elms->address() + size_delta)) {
395 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); 423 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
396 } 424 }
397 425
398 HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(), 426 HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
399 elms->address() + size_delta)); 427 elms->address() + size_delta));
400 return FixedArray::cast(HeapObject::FromAddress( 428 return FixedArrayBase::cast(HeapObject::FromAddress(
401 elms->address() + to_trim * kPointerSize)); 429 elms->address() + to_trim * entry_size));
402 } 430 }
403 431
404 432
405 static bool ArrayPrototypeHasNoElements(Heap* heap, 433 static bool ArrayPrototypeHasNoElements(Heap* heap,
406 Context* native_context, 434 Context* native_context,
407 JSObject* array_proto) { 435 JSObject* array_proto) {
408 // This method depends on non writability of Object and Array prototype 436 // This method depends on non writability of Object and Array prototype
409 // fields. 437 // fields.
410 if (array_proto->elements() != heap->empty_fixed_array()) return false; 438 if (array_proto->elements() != heap->empty_fixed_array()) return false;
411 // Object.prototype 439 // Object.prototype
412 Object* proto = array_proto->GetPrototype(); 440 Object* proto = array_proto->GetPrototype();
413 if (proto == heap->null_value()) return false; 441 if (proto == heap->null_value()) return false;
414 array_proto = JSObject::cast(proto); 442 array_proto = JSObject::cast(proto);
415 if (array_proto != native_context->initial_object_prototype()) return false; 443 if (array_proto != native_context->initial_object_prototype()) return false;
416 if (array_proto->elements() != heap->empty_fixed_array()) return false; 444 if (array_proto->elements() != heap->empty_fixed_array()) return false;
417 return array_proto->GetPrototype()->IsNull(); 445 return array_proto->GetPrototype()->IsNull();
418 } 446 }
419 447
420 448
421 MUST_USE_RESULT 449 MUST_USE_RESULT
422 static inline MaybeObject* EnsureJSArrayWithWritableFastElements( 450 static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
423 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) { 451 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
424 if (!receiver->IsJSArray()) return NULL; 452 if (!receiver->IsJSArray()) return NULL;
425 JSArray* array = JSArray::cast(receiver); 453 JSArray* array = JSArray::cast(receiver);
426 HeapObject* elms = array->elements(); 454 HeapObject* elms = array->elements();
427 Map* map = elms->map(); 455 Map* map = elms->map();
428 if (map == heap->fixed_array_map()) { 456 if (map == heap->fixed_array_map()) {
429 if (args == NULL || array->HasFastObjectElements()) return elms; 457 if (args == NULL || array->HasFastObjectElements()) return elms;
430 if (array->HasFastDoubleElements()) {
431 ASSERT(elms == heap->empty_fixed_array());
432 MaybeObject* maybe_transition =
433 array->TransitionElementsKind(FAST_ELEMENTS);
434 if (maybe_transition->IsFailure()) return maybe_transition;
435 return elms;
436 }
437 } else if (map == heap->fixed_cow_array_map()) { 458 } else if (map == heap->fixed_cow_array_map()) {
438 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements(); 459 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
439 if (args == NULL || array->HasFastObjectElements() || 460 if (args == NULL || array->HasFastObjectElements() ||
440 maybe_writable_result->IsFailure()) { 461 !maybe_writable_result->To(&elms)) {
441 return maybe_writable_result; 462 return maybe_writable_result;
442 } 463 }
464 } else if (map == heap->fixed_double_array_map()) {
465 if (args == NULL) return elms;
443 } else { 466 } else {
444 return NULL; 467 return NULL;
445 } 468 }
446 469
447 // Need to ensure that the arguments passed in args can be contained in 470 // Need to ensure that the arguments passed in args can be contained in
448 // the array. 471 // the array.
449 int args_length = args->length(); 472 int args_length = args->length();
450 if (first_added_arg >= args_length) return array->elements(); 473 if (first_added_arg >= args_length) return array->elements();
451 474
452 MaybeObject* maybe_array = array->EnsureCanContainElements( 475 ElementsKind origin_kind = array->map()->elements_kind();
453 args, 476 ASSERT(!IsFastObjectElementsKind(origin_kind));
454 first_added_arg, 477 ElementsKind target_kind = origin_kind;
455 args_length - first_added_arg, 478 int arg_count = args->length() - first_added_arg;
456 DONT_ALLOW_DOUBLE_ELEMENTS); 479 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
457 if (maybe_array->IsFailure()) return maybe_array; 480 for (int i = 0; i < arg_count; i++) {
458 return array->elements(); 481 Object* arg = arguments[i];
482 if (arg->IsHeapObject()) {
483 if (arg->IsHeapNumber()) {
484 target_kind = FAST_DOUBLE_ELEMENTS;
485 } else {
486 target_kind = FAST_ELEMENTS;
487 break;
488 }
489 }
490 }
491 if (target_kind != origin_kind) {
492 MaybeObject* maybe_failure = array->TransitionElementsKind(target_kind);
493 if (maybe_failure->IsFailure()) return maybe_failure;
494 return array->elements();
495 }
496 return elms;
459 } 497 }
460 498
461 499
462 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, 500 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
463 JSArray* receiver) { 501 JSArray* receiver) {
464 if (!FLAG_clever_optimizations) return false; 502 if (!FLAG_clever_optimizations) return false;
465 Context* native_context = heap->isolate()->context()->native_context(); 503 Context* native_context = heap->isolate()->context()->native_context();
466 JSObject* array_proto = 504 JSObject* array_proto =
467 JSObject::cast(native_context->array_function()->prototype()); 505 JSObject::cast(native_context->array_function()->prototype());
468 return receiver->GetPrototype() == array_proto && 506 return receiver->GetPrototype() == array_proto &&
(...skipping 23 matching lines...) Expand all
492 argv.start(), 530 argv.start(),
493 &pending_exception); 531 &pending_exception);
494 if (pending_exception) return Failure::Exception(); 532 if (pending_exception) return Failure::Exception();
495 return *result; 533 return *result;
496 } 534 }
497 535
498 536
499 BUILTIN(ArrayPush) { 537 BUILTIN(ArrayPush) {
500 Heap* heap = isolate->heap(); 538 Heap* heap = isolate->heap();
501 Object* receiver = *args.receiver(); 539 Object* receiver = *args.receiver();
502 Object* elms_obj; 540 FixedArrayBase* elms_obj;
503 { MaybeObject* maybe_elms_obj = 541 MaybeObject* maybe_elms_obj =
504 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1); 542 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
505 if (maybe_elms_obj == NULL) { 543 if (maybe_elms_obj == NULL) {
506 return CallJsBuiltin(isolate, "ArrayPush", args); 544 return CallJsBuiltin(isolate, "ArrayPush", args);
507 }
508 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
509 } 545 }
510 FixedArray* elms = FixedArray::cast(elms_obj); 546 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
511 JSArray* array = JSArray::cast(receiver);
512 547
513 if (FLAG_harmony_observation && array->map()->is_observed()) { 548 if (FLAG_harmony_observation &&
549 JSObject::cast(receiver)->map()->is_observed()) {
514 return CallJsBuiltin(isolate, "ArrayPush", args); 550 return CallJsBuiltin(isolate, "ArrayPush", args);
515 } 551 }
516 552
517 int len = Smi::cast(array->length())->value(); 553 JSArray* array = JSArray::cast(receiver);
518 int to_add = args.length() - 1; 554 ElementsKind kind = array->GetElementsKind();
519 if (to_add == 0) { 555
520 return Smi::FromInt(len); 556 if (IsFastSmiOrObjectElementsKind(kind)) {
557 FixedArray* elms = FixedArray::cast(elms_obj);
558
559 int len = Smi::cast(array->length())->value();
560 int to_add = args.length() - 1;
561 if (to_add == 0) {
562 return Smi::FromInt(len);
563 }
564 // Currently fixed arrays cannot grow too big, so
565 // we should never hit this case.
566 ASSERT(to_add <= (Smi::kMaxValue - len));
567
568 int new_length = len + to_add;
569
570 if (new_length > elms->length()) {
571 // New backing storage is needed.
572 int capacity = new_length + (new_length >> 1) + 16;
573 FixedArray* new_elms;
574 MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
575 if (!maybe_obj->To(&new_elms)) return maybe_obj;
576
577 ElementsAccessor* accessor = array->GetElementsAccessor();
578 MaybeObject* maybe_failure =
579 accessor->CopyElements(array, 0, new_elms, kind, 0, len, elms_obj);
580 ASSERT(!maybe_failure->IsFailure());
581 USE(maybe_failure);
582 FillWithHoles(heap, new_elms, new_length, capacity);
583
584 elms = new_elms;
585 }
586
587 // Add the provided values.
588 AssertNoAllocation no_gc;
589 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
590 for (int index = 0; index < to_add; index++) {
591 elms->set(index + len, args[index + 1], mode);
592 }
593
594 if (elms != array->elements()) {
595 array->set_elements(elms);
596 }
597
598 // Set the length.
599 array->set_length(Smi::FromInt(new_length));
600 return Smi::FromInt(new_length);
601 } else {
602 int len = Smi::cast(array->length())->value();
603 int elms_len = elms_obj->length();
604
605 int to_add = args.length() - 1;
606 if (to_add == 0) {
607 return Smi::FromInt(len);
608 }
609 // Currently fixed arrays cannot grow too big, so
610 // we should never hit this case.
611 ASSERT(to_add <= (Smi::kMaxValue - len));
612
613 int new_length = len + to_add;
614
615 FixedDoubleArray* new_elms;
616
617 if (new_length > elms_len) {
618 // New backing storage is needed.
619 int capacity = new_length + (new_length >> 1) + 16;
620 MaybeObject* maybe_obj =
621 heap->AllocateUninitializedFixedDoubleArray(capacity);
622 if (!maybe_obj->To(&new_elms)) return maybe_obj;
623
624 ElementsAccessor* accessor = array->GetElementsAccessor();
625 MaybeObject* maybe_failure =
626 accessor->CopyElements(array, 0, new_elms, kind, 0, len, elms_obj);
627 ASSERT(!maybe_failure->IsFailure());
628 USE(maybe_failure);
629
630 FillWithHoles(new_elms, len + to_add, new_elms->length());
631 } else {
632 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
633 // empty_fixed_array.
634 new_elms = FixedDoubleArray::cast(elms_obj);
635 }
636
637 // Add the provided values.
638 AssertNoAllocation no_gc;
639 int index;
640 for (index = 0; index < to_add; index++) {
641 Object* arg = args[index + 1];
642 new_elms->set(index + len, arg->Number());
643 }
644
645 if (new_elms != array->elements()) {
646 array->set_elements(new_elms);
647 }
648
649 // Set the length.
650 array->set_length(Smi::FromInt(new_length));
651 return Smi::FromInt(new_length);
521 } 652 }
522 // Currently fixed arrays cannot grow too big, so
523 // we should never hit this case.
524 ASSERT(to_add <= (Smi::kMaxValue - len));
525
526 int new_length = len + to_add;
527
528 if (new_length > elms->length()) {
529 // New backing storage is needed.
530 int capacity = new_length + (new_length >> 1) + 16;
531 Object* obj;
532 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
533 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
534 }
535 FixedArray* new_elms = FixedArray::cast(obj);
536
537 ElementsKind kind = array->GetElementsKind();
538 CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len);
539 FillWithHoles(heap, new_elms, new_length, capacity);
540
541 elms = new_elms;
542 }
543
544 // Add the provided values.
545 AssertNoAllocation no_gc;
546 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
547 for (int index = 0; index < to_add; index++) {
548 elms->set(index + len, args[index + 1], mode);
549 }
550
551 if (elms != array->elements()) {
552 array->set_elements(elms);
553 }
554
555 // Set the length.
556 array->set_length(Smi::FromInt(new_length));
557 return Smi::FromInt(new_length);
558 } 653 }
559 654
560 655
561 BUILTIN(ArrayPop) { 656 BUILTIN(ArrayPop) {
562 Heap* heap = isolate->heap(); 657 Heap* heap = isolate->heap();
563 Object* receiver = *args.receiver(); 658 Object* receiver = *args.receiver();
564 Object* elms_obj; 659 FixedArrayBase* elms_obj;
565 { MaybeObject* maybe_elms_obj = 660 MaybeObject* maybe_elms =
566 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); 661 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
567 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args); 662 if (maybe_elms == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
568 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 663 if (!maybe_elms->To(&elms_obj)) return maybe_elms;
569 } 664
570 FixedArray* elms = FixedArray::cast(elms_obj);
571 JSArray* array = JSArray::cast(receiver); 665 JSArray* array = JSArray::cast(receiver);
572 666
573 if (FLAG_harmony_observation && array->map()->is_observed()) { 667 if (FLAG_harmony_observation && array->map()->is_observed()) {
574 return CallJsBuiltin(isolate, "ArrayPop", args); 668 return CallJsBuiltin(isolate, "ArrayPop", args);
575 } 669 }
576 670
577 int len = Smi::cast(array->length())->value(); 671 int len = Smi::cast(array->length())->value();
578 if (len == 0) return heap->undefined_value(); 672 if (len == 0) return heap->undefined_value();
579 673
580 // Get top element 674 ElementsAccessor* accessor = array->GetElementsAccessor();
581 Object* top = elms->get(len - 1); 675 int new_length = len - 1;
582 676 Object* result;
583 // Set the length. 677 MaybeObject* maybe_result = accessor->Get(array, array, new_length);
584 array->set_length(Smi::FromInt(len - 1)); 678 if (!maybe_result->To(&result)) return maybe_result;
585 679 MaybeObject* maybe_failure =
586 if (!top->IsTheHole()) { 680 accessor->SetLength(array, Smi::FromInt(new_length));
587 // Delete the top element. 681 if (maybe_failure->IsFailure()) return maybe_failure;
588 elms->set_the_hole(len - 1); 682 if (!result->IsTheHole()) return result;
589 return top;
590 }
591
592 return array->GetPrototype()->GetElement(len - 1); 683 return array->GetPrototype()->GetElement(len - 1);
593 } 684 }
594 685
595 686
596 BUILTIN(ArrayShift) { 687 BUILTIN(ArrayShift) {
597 Heap* heap = isolate->heap(); 688 Heap* heap = isolate->heap();
598 Object* receiver = *args.receiver(); 689 Object* receiver = *args.receiver();
599 Object* elms_obj; 690 FixedArrayBase* elms_obj;
600 { MaybeObject* maybe_elms_obj = 691 MaybeObject* maybe_elms_obj =
601 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); 692 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
602 if (maybe_elms_obj == NULL) 693 if (maybe_elms_obj == NULL)
603 return CallJsBuiltin(isolate, "ArrayShift", args); 694 return CallJsBuiltin(isolate, "ArrayShift", args);
604 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 695 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
605 } 696
606 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 697 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
607 return CallJsBuiltin(isolate, "ArrayShift", args); 698 return CallJsBuiltin(isolate, "ArrayShift", args);
608 } 699 }
609 FixedArray* elms = FixedArray::cast(elms_obj);
610 JSArray* array = JSArray::cast(receiver); 700 JSArray* array = JSArray::cast(receiver);
611 ASSERT(array->HasFastSmiOrObjectElements());
612 701
613 if (FLAG_harmony_observation && array->map()->is_observed()) { 702 if (FLAG_harmony_observation && array->map()->is_observed()) {
614 return CallJsBuiltin(isolate, "ArrayShift", args); 703 return CallJsBuiltin(isolate, "ArrayShift", args);
615 } 704 }
616 705
617 int len = Smi::cast(array->length())->value(); 706 int len = Smi::cast(array->length())->value();
618 if (len == 0) return heap->undefined_value(); 707 if (len == 0) return heap->undefined_value();
619 708
620 // Get first element 709 // Get first element
621 Object* first = elms->get(0); 710 ElementsAccessor* accessor = array->GetElementsAccessor();
622 if (first->IsTheHole()) { 711 Object* first;
623 first = heap->undefined_value(); 712 MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj);
624 } 713 if (!maybe_first->To(&first)) return maybe_first;
625 714
626 if (!heap->lo_space()->Contains(elms)) { 715 if (!heap->lo_space()->Contains(elms_obj)) {
627 array->set_elements(LeftTrimFixedArray(heap, elms, 1)); 716 array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1));
628 } else { 717 } else {
629 // Shift the elements. 718 // Shift the elements.
630 AssertNoAllocation no_gc; 719 if (elms_obj->IsFixedArray()) {
631 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1); 720 FixedArray* elms = FixedArray::cast(elms_obj);
632 elms->set(len - 1, heap->the_hole_value()); 721 AssertNoAllocation no_gc;
722 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
723 elms->set(len - 1, heap->the_hole_value());
724 } else {
725 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
726 MoveDoubleElements(elms, 0, elms, 1, len - 1);
727 elms->set_the_hole(len - 1);
728 }
633 } 729 }
634 730
635 // Set the length. 731 // Set the length.
636 array->set_length(Smi::FromInt(len - 1)); 732 array->set_length(Smi::FromInt(len - 1));
637 733
638 return first; 734 return first;
639 } 735 }
640 736
641 737
642 BUILTIN(ArrayUnshift) { 738 BUILTIN(ArrayUnshift) {
643 Heap* heap = isolate->heap(); 739 Heap* heap = isolate->heap();
644 Object* receiver = *args.receiver(); 740 Object* receiver = *args.receiver();
645 Object* elms_obj; 741 FixedArrayBase* elms_obj;
646 { MaybeObject* maybe_elms_obj = 742 MaybeObject* maybe_elms_obj =
647 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); 743 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
648 if (maybe_elms_obj == NULL) 744 if (maybe_elms_obj == NULL)
649 return CallJsBuiltin(isolate, "ArrayUnshift", args); 745 return CallJsBuiltin(isolate, "ArrayUnshift", args);
650 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 746 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
651 } 747
652 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 748 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
653 return CallJsBuiltin(isolate, "ArrayUnshift", args); 749 return CallJsBuiltin(isolate, "ArrayUnshift", args);
654 } 750 }
751 JSArray* array = JSArray::cast(receiver);
752 if (!array->HasFastSmiOrObjectElements()) {
753 return CallJsBuiltin(isolate, "ArrayUnshift", args);
754 }
655 FixedArray* elms = FixedArray::cast(elms_obj); 755 FixedArray* elms = FixedArray::cast(elms_obj);
656 JSArray* array = JSArray::cast(receiver);
657 ASSERT(array->HasFastSmiOrObjectElements());
658 756
659 if (FLAG_harmony_observation && array->map()->is_observed()) { 757 if (FLAG_harmony_observation && array->map()->is_observed()) {
660 return CallJsBuiltin(isolate, "ArrayUnshift", args); 758 return CallJsBuiltin(isolate, "ArrayUnshift", args);
661 } 759 }
662 760
663 int len = Smi::cast(array->length())->value(); 761 int len = Smi::cast(array->length())->value();
664 int to_add = args.length() - 1; 762 int to_add = args.length() - 1;
665 int new_length = len + to_add; 763 int new_length = len + to_add;
666 // Currently fixed arrays cannot grow too big, so 764 // Currently fixed arrays cannot grow too big, so
667 // we should never hit this case. 765 // we should never hit this case.
668 ASSERT(to_add <= (Smi::kMaxValue - len)); 766 ASSERT(to_add <= (Smi::kMaxValue - len));
669 767
670 MaybeObject* maybe_object = 768 MaybeObject* maybe_object =
671 array->EnsureCanContainElements(&args, 1, to_add, 769 array->EnsureCanContainElements(&args, 1, to_add,
672 DONT_ALLOW_DOUBLE_ELEMENTS); 770 DONT_ALLOW_DOUBLE_ELEMENTS);
673 if (maybe_object->IsFailure()) return maybe_object; 771 if (maybe_object->IsFailure()) return maybe_object;
674 772
675 if (new_length > elms->length()) { 773 if (new_length > elms->length()) {
676 // New backing storage is needed. 774 // New backing storage is needed.
677 int capacity = new_length + (new_length >> 1) + 16; 775 int capacity = new_length + (new_length >> 1) + 16;
678 Object* obj; 776 FixedArray* new_elms;
679 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); 777 MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
680 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 778 if (!maybe_elms->To(&new_elms)) return maybe_elms;
681 } 779
682 FixedArray* new_elms = FixedArray::cast(obj);
683 ElementsKind kind = array->GetElementsKind(); 780 ElementsKind kind = array->GetElementsKind();
684 CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len); 781 ElementsAccessor* accessor = array->GetElementsAccessor();
782 MaybeObject* maybe_failure =
783 accessor->CopyElements(array, 0, new_elms, kind, to_add, len, elms);
784 ASSERT(!maybe_failure->IsFailure());
785 USE(maybe_failure);
786
685 FillWithHoles(heap, new_elms, new_length, capacity); 787 FillWithHoles(heap, new_elms, new_length, capacity);
686 elms = new_elms; 788 elms = new_elms;
687 array->set_elements(elms); 789 array->set_elements(elms);
688 } else { 790 } else {
689 AssertNoAllocation no_gc; 791 AssertNoAllocation no_gc;
690 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len); 792 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
691 } 793 }
692 794
693 // Add the provided values. 795 // Add the provided values.
694 AssertNoAllocation no_gc; 796 AssertNoAllocation no_gc;
695 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 797 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
696 for (int i = 0; i < to_add; i++) { 798 for (int i = 0; i < to_add; i++) {
697 elms->set(i, args[i + 1], mode); 799 elms->set(i, args[i + 1], mode);
698 } 800 }
699 801
700 // Set the length. 802 // Set the length.
701 array->set_length(Smi::FromInt(new_length)); 803 array->set_length(Smi::FromInt(new_length));
702 return Smi::FromInt(new_length); 804 return Smi::FromInt(new_length);
703 } 805 }
704 806
705 807
706 BUILTIN(ArraySlice) { 808 BUILTIN(ArraySlice) {
707 Heap* heap = isolate->heap(); 809 Heap* heap = isolate->heap();
708 Object* receiver = *args.receiver(); 810 Object* receiver = *args.receiver();
709 FixedArray* elms; 811 FixedArrayBase* elms;
710 int len = -1; 812 int len = -1;
711 if (receiver->IsJSArray()) { 813 if (receiver->IsJSArray()) {
712 JSArray* array = JSArray::cast(receiver); 814 JSArray* array = JSArray::cast(receiver);
713 if (!array->HasFastSmiOrObjectElements() || 815 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
714 !IsJSArrayFastElementMovingAllowed(heap, array)) {
715 return CallJsBuiltin(isolate, "ArraySlice", args); 816 return CallJsBuiltin(isolate, "ArraySlice", args);
716 } 817 }
717 818
718 elms = FixedArray::cast(array->elements()); 819 if (array->HasFastElements()) {
820 elms = array->elements();
821 } else {
822 return CallJsBuiltin(isolate, "ArraySlice", args);
823 }
824
719 len = Smi::cast(array->length())->value(); 825 len = Smi::cast(array->length())->value();
720 } else { 826 } else {
721 // Array.slice(arguments, ...) is quite a common idiom (notably more 827 // Array.slice(arguments, ...) is quite a common idiom (notably more
722 // than 50% of invocations in Web apps). Treat it in C++ as well. 828 // than 50% of invocations in Web apps). Treat it in C++ as well.
723 Map* arguments_map = 829 Map* arguments_map =
724 isolate->context()->native_context()->arguments_boilerplate()->map(); 830 isolate->context()->native_context()->arguments_boilerplate()->map();
725 831
726 bool is_arguments_object_with_fast_elements = 832 bool is_arguments_object_with_fast_elements =
727 receiver->IsJSObject() 833 receiver->IsJSObject() &&
728 && JSObject::cast(receiver)->map() == arguments_map 834 JSObject::cast(receiver)->map() == arguments_map;
729 && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
730 if (!is_arguments_object_with_fast_elements) { 835 if (!is_arguments_object_with_fast_elements) {
731 return CallJsBuiltin(isolate, "ArraySlice", args); 836 return CallJsBuiltin(isolate, "ArraySlice", args);
732 } 837 }
733 elms = FixedArray::cast(JSObject::cast(receiver)->elements()); 838 JSObject* object = JSObject::cast(receiver);
734 Object* len_obj = JSObject::cast(receiver) 839
735 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex); 840 if (object->HasFastElements()) {
841 elms = object->elements();
842 } else {
843 return CallJsBuiltin(isolate, "ArraySlice", args);
844 }
845 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
736 if (!len_obj->IsSmi()) { 846 if (!len_obj->IsSmi()) {
737 return CallJsBuiltin(isolate, "ArraySlice", args); 847 return CallJsBuiltin(isolate, "ArraySlice", args);
738 } 848 }
739 len = Smi::cast(len_obj)->value(); 849 len = Smi::cast(len_obj)->value();
740 if (len > elms->length()) { 850 if (len > elms->length()) {
741 return CallJsBuiltin(isolate, "ArraySlice", args); 851 return CallJsBuiltin(isolate, "ArraySlice", args);
742 } 852 }
853 }
854
855 JSObject* object = JSObject::cast(receiver);
856 ElementsKind kind = object->GetElementsKind();
857
858 if (IsHoleyElementsKind(kind)) {
859 bool packed = true;
860 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
743 for (int i = 0; i < len; i++) { 861 for (int i = 0; i < len; i++) {
744 if (elms->get(i) == heap->the_hole_value()) { 862 if (!accessor->HasElement(object, object, i, elms)) {
745 return CallJsBuiltin(isolate, "ArraySlice", args); 863 packed = false;
864 break;
746 } 865 }
747 } 866 }
867 if (packed) {
868 kind = GetPackedElementsKind(kind);
869 } else if (!receiver->IsJSArray()) {
870 return CallJsBuiltin(isolate, "ArraySlice", args);
871 }
748 } 872 }
873
749 ASSERT(len >= 0); 874 ASSERT(len >= 0);
750 int n_arguments = args.length() - 1; 875 int n_arguments = args.length() - 1;
751 876
752 // Note carefully choosen defaults---if argument is missing, 877 // Note carefully choosen defaults---if argument is missing,
753 // it's undefined which gets converted to 0 for relative_start 878 // it's undefined which gets converted to 0 for relative_start
754 // and to len for relative_end. 879 // and to len for relative_end.
755 int relative_start = 0; 880 int relative_start = 0;
756 int relative_end = len; 881 int relative_end = len;
757 if (n_arguments > 0) { 882 if (n_arguments > 0) {
758 Object* arg1 = args[1]; 883 Object* arg1 = args[1];
759 if (arg1->IsSmi()) { 884 if (arg1->IsSmi()) {
760 relative_start = Smi::cast(arg1)->value(); 885 relative_start = Smi::cast(arg1)->value();
886 } else if (arg1->IsHeapNumber()) {
887 double start = HeapNumber::cast(arg1)->value();
888 if (start < kMinInt || start > kMaxInt) {
889 return CallJsBuiltin(isolate, "ArraySlice", args);
890 }
891 relative_start = static_cast<int>(start);
761 } else if (!arg1->IsUndefined()) { 892 } else if (!arg1->IsUndefined()) {
762 return CallJsBuiltin(isolate, "ArraySlice", args); 893 return CallJsBuiltin(isolate, "ArraySlice", args);
763 } 894 }
764 if (n_arguments > 1) { 895 if (n_arguments > 1) {
765 Object* arg2 = args[2]; 896 Object* arg2 = args[2];
766 if (arg2->IsSmi()) { 897 if (arg2->IsSmi()) {
767 relative_end = Smi::cast(arg2)->value(); 898 relative_end = Smi::cast(arg2)->value();
899 } else if (arg2->IsHeapNumber()) {
900 double end = HeapNumber::cast(arg2)->value();
901 if (end < kMinInt || end > kMaxInt) {
902 return CallJsBuiltin(isolate, "ArraySlice", args);
903 }
904 relative_end = static_cast<int>(end);
768 } else if (!arg2->IsUndefined()) { 905 } else if (!arg2->IsUndefined()) {
769 return CallJsBuiltin(isolate, "ArraySlice", args); 906 return CallJsBuiltin(isolate, "ArraySlice", args);
770 } 907 }
771 } 908 }
772 } 909 }
773 910
774 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 911 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
775 int k = (relative_start < 0) ? Max(len + relative_start, 0) 912 int k = (relative_start < 0) ? Max(len + relative_start, 0)
776 : Min(relative_start, len); 913 : Min(relative_start, len);
777 914
778 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 915 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
779 int final = (relative_end < 0) ? Max(len + relative_end, 0) 916 int final = (relative_end < 0) ? Max(len + relative_end, 0)
780 : Min(relative_end, len); 917 : Min(relative_end, len);
781 918
782 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
783
784 // Calculate the length of result array. 919 // Calculate the length of result array.
785 int result_len = Max(final - k, 0); 920 int result_len = Max(final - k, 0);
786 921
787 MaybeObject* maybe_array =
788 heap->AllocateJSArrayAndStorage(elements_kind,
789 result_len,
790 result_len);
791 JSArray* result_array; 922 JSArray* result_array;
923 MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind,
924 result_len,
925 result_len);
792 if (!maybe_array->To(&result_array)) return maybe_array; 926 if (!maybe_array->To(&result_array)) return maybe_array;
793 927
794 CopyObjectToObjectElements(elms, elements_kind, k, 928 ElementsAccessor* accessor = object->GetElementsAccessor();
795 FixedArray::cast(result_array->elements()), 929 MaybeObject* maybe_failure =
796 elements_kind, 0, result_len); 930 accessor->CopyElements(object, k, result_array->elements(),
931 kind, 0, result_len, elms);
932 ASSERT(!maybe_failure->IsFailure());
933 USE(maybe_failure);
797 934
798 return result_array; 935 return result_array;
799 } 936 }
800 937
801 938
802 BUILTIN(ArraySplice) { 939 BUILTIN(ArraySplice) {
803 Heap* heap = isolate->heap(); 940 Heap* heap = isolate->heap();
804 Object* receiver = *args.receiver(); 941 Object* receiver = *args.receiver();
805 Object* elms_obj; 942 FixedArrayBase* elms_obj;
806 { MaybeObject* maybe_elms_obj = 943 MaybeObject* maybe_elms =
807 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); 944 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
808 if (maybe_elms_obj == NULL) 945 if (maybe_elms == NULL) {
809 return CallJsBuiltin(isolate, "ArraySplice", args); 946 return CallJsBuiltin(isolate, "ArraySplice", args);
810 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
811 } 947 }
948 if (!maybe_elms->To(&elms_obj)) return maybe_elms;
949
812 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 950 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
813 return CallJsBuiltin(isolate, "ArraySplice", args); 951 return CallJsBuiltin(isolate, "ArraySplice", args);
814 } 952 }
815 FixedArray* elms = FixedArray::cast(elms_obj);
816 JSArray* array = JSArray::cast(receiver); 953 JSArray* array = JSArray::cast(receiver);
817 ASSERT(array->HasFastSmiOrObjectElements());
818 954
819 if (FLAG_harmony_observation && array->map()->is_observed()) { 955 if (FLAG_harmony_observation && array->map()->is_observed()) {
820 return CallJsBuiltin(isolate, "ArraySplice", args); 956 return CallJsBuiltin(isolate, "ArraySplice", args);
821 } 957 }
822 958
823 int len = Smi::cast(array->length())->value(); 959 int len = Smi::cast(array->length())->value();
824 960
825 int n_arguments = args.length() - 1; 961 int n_arguments = args.length() - 1;
826 962
827 int relative_start = 0; 963 int relative_start = 0;
828 if (n_arguments > 0) { 964 if (n_arguments > 0) {
829 Object* arg1 = args[1]; 965 Object* arg1 = args[1];
830 if (arg1->IsSmi()) { 966 if (arg1->IsSmi()) {
831 relative_start = Smi::cast(arg1)->value(); 967 relative_start = Smi::cast(arg1)->value();
968 } else if (arg1->IsHeapNumber()) {
969 double start = HeapNumber::cast(arg1)->value();
970 if (start < kMinInt || start > kMaxInt) {
971 return CallJsBuiltin(isolate, "ArraySplice", args);
972 }
973 relative_start = static_cast<int>(start);
832 } else if (!arg1->IsUndefined()) { 974 } else if (!arg1->IsUndefined()) {
833 return CallJsBuiltin(isolate, "ArraySplice", args); 975 return CallJsBuiltin(isolate, "ArraySplice", args);
834 } 976 }
835 } 977 }
836 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 978 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
837 : Min(relative_start, len); 979 : Min(relative_start, len);
838 980
839 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 981 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
840 // given as a request to delete all the elements from the start. 982 // given as a request to delete all the elements from the start.
841 // And it differs from the case of undefined delete count. 983 // And it differs from the case of undefined delete count.
842 // This does not follow ECMA-262, but we do the same for 984 // This does not follow ECMA-262, but we do the same for
843 // compatibility. 985 // compatibility.
844 int actual_delete_count; 986 int actual_delete_count;
845 if (n_arguments == 1) { 987 if (n_arguments == 1) {
846 ASSERT(len - actual_start >= 0); 988 ASSERT(len - actual_start >= 0);
847 actual_delete_count = len - actual_start; 989 actual_delete_count = len - actual_start;
848 } else { 990 } else {
849 int value = 0; // ToInteger(undefined) == 0 991 int value = 0; // ToInteger(undefined) == 0
850 if (n_arguments > 1) { 992 if (n_arguments > 1) {
851 Object* arg2 = args[2]; 993 Object* arg2 = args[2];
852 if (arg2->IsSmi()) { 994 if (arg2->IsSmi()) {
853 value = Smi::cast(arg2)->value(); 995 value = Smi::cast(arg2)->value();
854 } else { 996 } else {
855 return CallJsBuiltin(isolate, "ArraySplice", args); 997 return CallJsBuiltin(isolate, "ArraySplice", args);
856 } 998 }
857 } 999 }
858 actual_delete_count = Min(Max(value, 0), len - actual_start); 1000 actual_delete_count = Min(Max(value, 0), len - actual_start);
859 } 1001 }
860 1002
1003 ElementsKind elements_kind = array->GetElementsKind();
1004
1005 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
1006 int new_length = len - actual_delete_count + item_count;
1007
1008 // For double mode we do not support changing the length.
1009 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
1010 return CallJsBuiltin(isolate, "ArraySplice", args);
1011 }
1012
1013 if (new_length == 0) {
1014 MaybeObject* maybe_array = heap->AllocateJSArrayWithElements(
1015 elms_obj, elements_kind, actual_delete_count);
1016 if (maybe_array->IsFailure()) return maybe_array;
1017 array->set_elements(heap->empty_fixed_array());
1018 array->set_length(Smi::FromInt(0));
1019 return maybe_array;
1020 }
1021
861 JSArray* result_array = NULL; 1022 JSArray* result_array = NULL;
862 ElementsKind elements_kind =
863 JSObject::cast(receiver)->GetElementsKind();
864 MaybeObject* maybe_array = 1023 MaybeObject* maybe_array =
865 heap->AllocateJSArrayAndStorage(elements_kind, 1024 heap->AllocateJSArrayAndStorage(elements_kind,
866 actual_delete_count, 1025 actual_delete_count,
867 actual_delete_count); 1026 actual_delete_count);
868 if (!maybe_array->To(&result_array)) return maybe_array; 1027 if (!maybe_array->To(&result_array)) return maybe_array;
869 1028
870 { 1029 if (actual_delete_count > 0) {
871 // Fill newly created array. 1030 ElementsAccessor* accessor = array->GetElementsAccessor();
872 CopyObjectToObjectElements(elms, elements_kind, actual_start, 1031 MaybeObject* maybe_failure =
873 FixedArray::cast(result_array->elements()), 1032 accessor->CopyElements(array, actual_start, result_array->elements(),
874 elements_kind, 0, actual_delete_count); 1033 elements_kind, 0, actual_delete_count, elms_obj);
1034 // Cannot fail since the origin and target array are of the same elements
1035 // kind.
1036 ASSERT(!maybe_failure->IsFailure());
1037 USE(maybe_failure);
875 } 1038 }
876 1039
877 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
878 int new_length = len - actual_delete_count + item_count;
879
880 bool elms_changed = false; 1040 bool elms_changed = false;
881 if (item_count < actual_delete_count) { 1041 if (item_count < actual_delete_count) {
882 // Shrink the array. 1042 // Shrink the array.
883 const bool trim_array = !heap->lo_space()->Contains(elms) && 1043 const bool trim_array = !heap->lo_space()->Contains(elms_obj) &&
884 ((actual_start + item_count) < 1044 ((actual_start + item_count) <
885 (len - actual_delete_count - actual_start)); 1045 (len - actual_delete_count - actual_start));
886 if (trim_array) { 1046 if (trim_array) {
887 const int delta = actual_delete_count - item_count; 1047 const int delta = actual_delete_count - item_count;
888 1048
889 { 1049 if (elms_obj->IsFixedDoubleArray()) {
1050 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
1051 MoveDoubleElements(elms, delta, elms, 0, actual_start);
1052 } else {
1053 FixedArray* elms = FixedArray::cast(elms_obj);
890 AssertNoAllocation no_gc; 1054 AssertNoAllocation no_gc;
891 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); 1055 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
892 } 1056 }
893 1057
894 elms = LeftTrimFixedArray(heap, elms, delta); 1058 elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
895 1059
896 elms_changed = true; 1060 elms_changed = true;
897 } else { 1061 } else {
898 AssertNoAllocation no_gc; 1062 if (elms_obj->IsFixedDoubleArray()) {
899 MoveElements(heap, &no_gc, 1063 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
900 elms, actual_start + item_count, 1064 MoveDoubleElements(elms, actual_start + item_count,
901 elms, actual_start + actual_delete_count, 1065 elms, actual_start + actual_delete_count,
902 (len - actual_delete_count - actual_start)); 1066 (len - actual_delete_count - actual_start));
903 FillWithHoles(heap, elms, new_length, len); 1067 FillWithHoles(elms, new_length, len);
1068 } else {
1069 FixedArray* elms = FixedArray::cast(elms_obj);
1070 AssertNoAllocation no_gc;
1071 MoveElements(heap, &no_gc,
1072 elms, actual_start + item_count,
1073 elms, actual_start + actual_delete_count,
1074 (len - actual_delete_count - actual_start));
1075 FillWithHoles(heap, elms, new_length, len);
1076 }
904 } 1077 }
905 } else if (item_count > actual_delete_count) { 1078 } else if (item_count > actual_delete_count) {
1079 FixedArray* elms = FixedArray::cast(elms_obj);
906 // Currently fixed arrays cannot grow too big, so 1080 // Currently fixed arrays cannot grow too big, so
907 // we should never hit this case. 1081 // we should never hit this case.
908 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); 1082 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
909 1083
910 // Check if array need to grow. 1084 // Check if array need to grow.
911 if (new_length > elms->length()) { 1085 if (new_length > elms->length()) {
912 // New backing storage is needed. 1086 // New backing storage is needed.
913 int capacity = new_length + (new_length >> 1) + 16; 1087 int capacity = new_length + (new_length >> 1) + 16;
914 Object* obj; 1088 FixedArray* new_elms;
915 { MaybeObject* maybe_obj = 1089 MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
916 heap->AllocateUninitializedFixedArray(capacity); 1090 if (!maybe_obj->To(&new_elms)) return maybe_obj;
917 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
918 }
919 FixedArray* new_elms = FixedArray::cast(obj);
920 1091
921 { 1092 // Copy the part before actual_start as is.
922 // Copy the part before actual_start as is. 1093 ElementsKind kind = array->GetElementsKind();
923 ElementsKind kind = array->GetElementsKind(); 1094 ElementsAccessor* accessor = array->GetElementsAccessor();
924 CopyObjectToObjectElements(elms, kind, 0, 1095 MaybeObject* maybe_failure = accessor->CopyElements(
925 new_elms, kind, 0, actual_start); 1096 array, 0, new_elms, kind, 0, actual_start, elms);
926 const int to_copy = len - actual_delete_count - actual_start; 1097 ASSERT(!maybe_failure->IsFailure());
927 CopyObjectToObjectElements(elms, kind, 1098 USE(maybe_failure);
928 actual_start + actual_delete_count, 1099 const int to_copy = len - actual_delete_count - actual_start;
929 new_elms, kind, 1100 maybe_failure = accessor->CopyElements(
930 actual_start + item_count, to_copy); 1101 array, actual_start + actual_delete_count, new_elms, kind,
931 } 1102 actual_start + item_count, to_copy, elms);
1103 ASSERT(!maybe_failure->IsFailure());
1104 USE(maybe_failure);
932 1105
933 FillWithHoles(heap, new_elms, new_length, capacity); 1106 FillWithHoles(heap, new_elms, new_length, capacity);
934 1107
935 elms = new_elms; 1108 elms_obj = new_elms;
936 elms_changed = true; 1109 elms_changed = true;
937 } else { 1110 } else {
938 AssertNoAllocation no_gc; 1111 AssertNoAllocation no_gc;
939 MoveElements(heap, &no_gc, 1112 MoveElements(heap, &no_gc,
940 elms, actual_start + item_count, 1113 elms, actual_start + item_count,
941 elms, actual_start + actual_delete_count, 1114 elms, actual_start + actual_delete_count,
942 (len - actual_delete_count - actual_start)); 1115 (len - actual_delete_count - actual_start));
943 } 1116 }
944 } 1117 }
945 1118
946 AssertNoAllocation no_gc; 1119 if (IsFastDoubleElementsKind(elements_kind)) {
947 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 1120 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
948 for (int k = actual_start; k < actual_start + item_count; k++) { 1121 for (int k = actual_start; k < actual_start + item_count; k++) {
949 elms->set(k, args[3 + k - actual_start], mode); 1122 Object* arg = args[3 + k - actual_start];
1123 if (arg->IsSmi()) {
1124 elms->set(k, Smi::cast(arg)->value());
1125 } else {
1126 elms->set(k, HeapNumber::cast(arg)->value());
1127 }
1128 }
1129 } else {
1130 FixedArray* elms = FixedArray::cast(elms_obj);
1131 AssertNoAllocation no_gc;
1132 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
1133 for (int k = actual_start; k < actual_start + item_count; k++) {
1134 elms->set(k, args[3 + k - actual_start], mode);
1135 }
950 } 1136 }
951 1137
952 if (elms_changed) { 1138 if (elms_changed) {
953 array->set_elements(elms); 1139 array->set_elements(elms_obj);
954 } 1140 }
955
956 // Set the length. 1141 // Set the length.
957 array->set_length(Smi::FromInt(new_length)); 1142 array->set_length(Smi::FromInt(new_length));
958 1143
959 return result_array; 1144 return result_array;
960 } 1145 }
961 1146
962 1147
963 BUILTIN(ArrayConcat) { 1148 BUILTIN(ArrayConcat) {
964 Heap* heap = isolate->heap(); 1149 Heap* heap = isolate->heap();
965 Context* native_context = isolate->context()->native_context(); 1150 Context* native_context = isolate->context()->native_context();
966 JSObject* array_proto = 1151 JSObject* array_proto =
967 JSObject::cast(native_context->array_function()->prototype()); 1152 JSObject::cast(native_context->array_function()->prototype());
968 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) { 1153 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) {
969 return CallJsBuiltin(isolate, "ArrayConcat", args); 1154 return CallJsBuiltin(isolate, "ArrayConcat", args);
970 } 1155 }
971 1156
972 // Iterate through all the arguments performing checks 1157 // Iterate through all the arguments performing checks
973 // and calculating total length. 1158 // and calculating total length.
974 int n_arguments = args.length(); 1159 int n_arguments = args.length();
975 int result_len = 0; 1160 int result_len = 0;
976 ElementsKind elements_kind = GetInitialFastElementsKind(); 1161 ElementsKind elements_kind = GetInitialFastElementsKind();
977 for (int i = 0; i < n_arguments; i++) { 1162 for (int i = 0; i < n_arguments; i++) {
978 Object* arg = args[i]; 1163 Object* arg = args[i];
979 if (!arg->IsJSArray() || 1164 if (!arg->IsJSArray() ||
980 !JSArray::cast(arg)->HasFastSmiOrObjectElements() || 1165 !JSArray::cast(arg)->HasFastElements() ||
981 JSArray::cast(arg)->GetPrototype() != array_proto) { 1166 JSArray::cast(arg)->GetPrototype() != array_proto) {
982 return CallJsBuiltin(isolate, "ArrayConcat", args); 1167 return CallJsBuiltin(isolate, "ArrayConcat", args);
983 } 1168 }
984
985 int len = Smi::cast(JSArray::cast(arg)->length())->value(); 1169 int len = Smi::cast(JSArray::cast(arg)->length())->value();
986 1170
987 // We shouldn't overflow when adding another len. 1171 // We shouldn't overflow when adding another len.
988 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 1172 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
989 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 1173 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
990 USE(kHalfOfMaxInt); 1174 USE(kHalfOfMaxInt);
991 result_len += len; 1175 result_len += len;
992 ASSERT(result_len >= 0); 1176 ASSERT(result_len >= 0);
993 1177
994 if (result_len > FixedArray::kMaxLength) { 1178 if (result_len > FixedDoubleArray::kMaxLength) {
995 return CallJsBuiltin(isolate, "ArrayConcat", args); 1179 return CallJsBuiltin(isolate, "ArrayConcat", args);
996 } 1180 }
997 1181
998 if (!JSArray::cast(arg)->HasFastSmiElements()) { 1182 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
999 if (IsFastSmiElementsKind(elements_kind)) { 1183 ElementsKind packed_kind = GetPackedElementsKind(arg_kind);
1000 if (IsFastHoleyElementsKind(elements_kind)) { 1184 if (IsMoreGeneralElementsKindTransition(
1001 elements_kind = FAST_HOLEY_ELEMENTS; 1185 GetPackedElementsKind(elements_kind), packed_kind)) {
1002 } else { 1186 if (IsFastHoleyElementsKind(elements_kind)) {
1003 elements_kind = FAST_ELEMENTS; 1187 elements_kind = GetHoleyElementsKind(arg_kind);
1004 } 1188 } else {
1189 elements_kind = arg_kind;
1005 } 1190 }
1006 } 1191 }
1007
1008 if (JSArray::cast(arg)->HasFastHoleyElements()) {
1009 elements_kind = GetHoleyElementsKind(elements_kind);
1010 }
1011 } 1192 }
1012 1193
1194 JSArray* result_array;
1013 // Allocate result. 1195 // Allocate result.
1014 JSArray* result_array;
1015 MaybeObject* maybe_array = 1196 MaybeObject* maybe_array =
1016 heap->AllocateJSArrayAndStorage(elements_kind, 1197 heap->AllocateJSArrayAndStorage(elements_kind,
1017 result_len, 1198 result_len,
1018 result_len); 1199 result_len);
1019 if (!maybe_array->To(&result_array)) return maybe_array; 1200 if (!maybe_array->To(&result_array)) return maybe_array;
1020 if (result_len == 0) return result_array; 1201 if (result_len == 0) return result_array;
1021 1202
1022 // Copy data. 1203 int j = 0;
1023 int start_pos = 0; 1204 FixedArrayBase* storage = result_array->elements();
1024 FixedArray* result_elms(FixedArray::cast(result_array->elements()));
1025 for (int i = 0; i < n_arguments; i++) { 1205 for (int i = 0; i < n_arguments; i++) {
1026 JSArray* array = JSArray::cast(args[i]); 1206 JSArray* array = JSArray::cast(args[i]);
1207 ElementsAccessor* accessor = array->GetElementsAccessor();
1027 int len = Smi::cast(array->length())->value(); 1208 int len = Smi::cast(array->length())->value();
1028 FixedArray* elms = FixedArray::cast(array->elements()); 1209 MaybeObject* maybe_failure =
1029 CopyObjectToObjectElements(elms, elements_kind, 0, 1210 accessor->CopyElements(array, 0, storage, elements_kind, j, len);
1030 result_elms, elements_kind, 1211 if (maybe_failure->IsFailure()) return maybe_failure;
1031 start_pos, len); 1212 j += len;
1032 start_pos += len;
1033 } 1213 }
1034 ASSERT(start_pos == result_len); 1214
1215 ASSERT(j == result_len);
1035 1216
1036 return result_array; 1217 return result_array;
1037 } 1218 }
1038 1219
1039 1220
1040 // ----------------------------------------------------------------------------- 1221 // -----------------------------------------------------------------------------
1041 // Strict mode poison pills 1222 // Strict mode poison pills
1042 1223
1043 1224
1044 BUILTIN(StrictModePoisonPill) { 1225 BUILTIN(StrictModePoisonPill) {
(...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after
1734 return Handle<Code>(code_address); \ 1915 return Handle<Code>(code_address); \
1735 } 1916 }
1736 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 1917 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1737 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 1918 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1738 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 1919 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1739 #undef DEFINE_BUILTIN_ACCESSOR_C 1920 #undef DEFINE_BUILTIN_ACCESSOR_C
1740 #undef DEFINE_BUILTIN_ACCESSOR_A 1921 #undef DEFINE_BUILTIN_ACCESSOR_A
1741 1922
1742 1923
1743 } } // namespace v8::internal 1924 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/elements.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698