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

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: Fixed slicing of holey arguments 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
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_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 // Get top element
danno 2012/11/15 10:34:28 Simplify both cases to (if performance allows) El
581 Object* top = elms->get(len - 1); 675 if (elms_obj->IsFixedArray()) {
582 676 FixedArray* elms = FixedArray::cast(elms_obj);
677 MaybeObject* top = elms->get(len - 1);
678 if (!top->IsTheHole()) {
679 // Delete the top element.
680 elms->set_the_hole(len - 1);
681 // Set the length.
682 array->set_length(Smi::FromInt(len - 1));
683 return top;
684 }
685 } else {
686 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
687 if (!elms->is_the_hole(len - 1)) {
688 MaybeObject* top = heap->AllocateHeapNumber(elms->get_scalar(len - 1));
689 if (top->IsFailure()) return top;
690 elms->set_the_hole(len - 1);
691 // Set the length.
692 array->set_length(Smi::FromInt(len - 1));
693 return top;
694 }
695 }
583 // Set the length. 696 // Set the length.
584 array->set_length(Smi::FromInt(len - 1)); 697 array->set_length(Smi::FromInt(len - 1));
585
586 if (!top->IsTheHole()) {
587 // Delete the top element.
588 elms->set_the_hole(len - 1);
589 return top;
590 }
591
592 return array->GetPrototype()->GetElement(len - 1); 698 return array->GetPrototype()->GetElement(len - 1);
593 } 699 }
594 700
595 701
596 BUILTIN(ArrayShift) { 702 BUILTIN(ArrayShift) {
597 Heap* heap = isolate->heap(); 703 Heap* heap = isolate->heap();
598 Object* receiver = *args.receiver(); 704 Object* receiver = *args.receiver();
599 Object* elms_obj; 705 FixedArrayBase* elms_obj;
600 { MaybeObject* maybe_elms_obj = 706 MaybeObject* maybe_elms_obj =
601 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); 707 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
602 if (maybe_elms_obj == NULL) 708 if (maybe_elms_obj == NULL)
603 return CallJsBuiltin(isolate, "ArrayShift", args); 709 return CallJsBuiltin(isolate, "ArrayShift", args);
604 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 710 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
605 } 711
606 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 712 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
607 return CallJsBuiltin(isolate, "ArrayShift", args); 713 return CallJsBuiltin(isolate, "ArrayShift", args);
608 } 714 }
609 FixedArray* elms = FixedArray::cast(elms_obj);
610 JSArray* array = JSArray::cast(receiver); 715 JSArray* array = JSArray::cast(receiver);
611 ASSERT(array->HasFastSmiOrObjectElements());
612 716
613 if (FLAG_harmony_observation && array->map()->is_observed()) { 717 if (FLAG_harmony_observation && array->map()->is_observed()) {
614 return CallJsBuiltin(isolate, "ArrayShift", args); 718 return CallJsBuiltin(isolate, "ArrayShift", args);
615 } 719 }
616 720
617 int len = Smi::cast(array->length())->value(); 721 int len = Smi::cast(array->length())->value();
618 if (len == 0) return heap->undefined_value(); 722 if (len == 0) return heap->undefined_value();
619 723
620 // Get first element 724 // Get first element
621 Object* first = elms->get(0); 725 ElementsAccessor* accessor = array->GetElementsAccessor();
622 if (first->IsTheHole()) { 726 Object* first;
623 first = heap->undefined_value(); 727 MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj);
624 } 728 if (!maybe_first->To(&first)) return maybe_first;
625 729
626 if (!heap->lo_space()->Contains(elms)) { 730 if (!heap->lo_space()->Contains(elms_obj)) {
627 array->set_elements(LeftTrimFixedArray(heap, elms, 1)); 731 array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1));
628 } else { 732 } else {
629 // Shift the elements. 733 // Shift the elements.
630 AssertNoAllocation no_gc; 734 if (elms_obj->IsFixedArray()) {
631 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1); 735 FixedArray* elms = FixedArray::cast(elms_obj);
632 elms->set(len - 1, heap->the_hole_value()); 736 AssertNoAllocation no_gc;
737 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
738 elms->set(len - 1, heap->the_hole_value());
739 } else {
740 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
741 MoveDoubleElements(elms, 0, elms, 1, len - 1);
742 elms->set_the_hole(len - 1);
743 }
633 } 744 }
634 745
635 // Set the length. 746 // Set the length.
636 array->set_length(Smi::FromInt(len - 1)); 747 array->set_length(Smi::FromInt(len - 1));
637 748
638 return first; 749 return first;
639 } 750 }
640 751
641 752
642 BUILTIN(ArrayUnshift) { 753 BUILTIN(ArrayUnshift) {
643 Heap* heap = isolate->heap(); 754 Heap* heap = isolate->heap();
644 Object* receiver = *args.receiver(); 755 Object* receiver = *args.receiver();
645 Object* elms_obj; 756 FixedArrayBase* elms_obj;
646 { MaybeObject* maybe_elms_obj = 757 MaybeObject* maybe_elms_obj =
647 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0); 758 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
648 if (maybe_elms_obj == NULL) 759 if (maybe_elms_obj == NULL)
649 return CallJsBuiltin(isolate, "ArrayUnshift", args); 760 return CallJsBuiltin(isolate, "ArrayUnshift", args);
650 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; 761 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
651 } 762
652 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 763 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
653 return CallJsBuiltin(isolate, "ArrayUnshift", args); 764 return CallJsBuiltin(isolate, "ArrayUnshift", args);
654 } 765 }
766 JSArray* array = JSArray::cast(receiver);
767 if (!array->HasFastSmiOrObjectElements()) {
768 return CallJsBuiltin(isolate, "ArrayUnshift", args);
769 }
655 FixedArray* elms = FixedArray::cast(elms_obj); 770 FixedArray* elms = FixedArray::cast(elms_obj);
656 JSArray* array = JSArray::cast(receiver);
657 ASSERT(array->HasFastSmiOrObjectElements());
658 771
659 if (FLAG_harmony_observation && array->map()->is_observed()) { 772 if (FLAG_harmony_observation && array->map()->is_observed()) {
660 return CallJsBuiltin(isolate, "ArrayUnshift", args); 773 return CallJsBuiltin(isolate, "ArrayUnshift", args);
661 } 774 }
662 775
663 int len = Smi::cast(array->length())->value(); 776 int len = Smi::cast(array->length())->value();
664 int to_add = args.length() - 1; 777 int to_add = args.length() - 1;
665 int new_length = len + to_add; 778 int new_length = len + to_add;
666 // Currently fixed arrays cannot grow too big, so 779 // Currently fixed arrays cannot grow too big, so
667 // we should never hit this case. 780 // we should never hit this case.
668 ASSERT(to_add <= (Smi::kMaxValue - len)); 781 ASSERT(to_add <= (Smi::kMaxValue - len));
669 782
670 MaybeObject* maybe_object = 783 MaybeObject* maybe_object =
671 array->EnsureCanContainElements(&args, 1, to_add, 784 array->EnsureCanContainElements(&args, 1, to_add,
672 DONT_ALLOW_DOUBLE_ELEMENTS); 785 DONT_ALLOW_DOUBLE_ELEMENTS);
673 if (maybe_object->IsFailure()) return maybe_object; 786 if (maybe_object->IsFailure()) return maybe_object;
674 787
675 if (new_length > elms->length()) { 788 if (new_length > elms->length()) {
676 // New backing storage is needed. 789 // New backing storage is needed.
677 int capacity = new_length + (new_length >> 1) + 16; 790 int capacity = new_length + (new_length >> 1) + 16;
678 Object* obj; 791 FixedArray* new_elms;
679 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity); 792 MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
680 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 793 if (!maybe_elms->To(&new_elms)) return maybe_elms;
681 } 794
682 FixedArray* new_elms = FixedArray::cast(obj);
683 ElementsKind kind = array->GetElementsKind(); 795 ElementsKind kind = array->GetElementsKind();
684 CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len); 796 ElementsAccessor* accessor = array->GetElementsAccessor();
797 MaybeObject* maybe_failure =
798 accessor->CopyElements(array, 0, new_elms, kind, to_add, len, elms);
799 ASSERT(!maybe_failure->IsFailure());
800 USE(maybe_failure);
801
685 FillWithHoles(heap, new_elms, new_length, capacity); 802 FillWithHoles(heap, new_elms, new_length, capacity);
686 elms = new_elms; 803 elms = new_elms;
687 array->set_elements(elms); 804 array->set_elements(elms);
688 } else { 805 } else {
689 AssertNoAllocation no_gc; 806 AssertNoAllocation no_gc;
690 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len); 807 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
691 } 808 }
692 809
693 // Add the provided values. 810 // Add the provided values.
694 AssertNoAllocation no_gc; 811 AssertNoAllocation no_gc;
695 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 812 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
696 for (int i = 0; i < to_add; i++) { 813 for (int i = 0; i < to_add; i++) {
697 elms->set(i, args[i + 1], mode); 814 elms->set(i, args[i + 1], mode);
698 } 815 }
699 816
700 // Set the length. 817 // Set the length.
701 array->set_length(Smi::FromInt(new_length)); 818 array->set_length(Smi::FromInt(new_length));
702 return Smi::FromInt(new_length); 819 return Smi::FromInt(new_length);
703 } 820 }
704 821
705 822
706 BUILTIN(ArraySlice) { 823 BUILTIN(ArraySlice) {
707 Heap* heap = isolate->heap(); 824 Heap* heap = isolate->heap();
708 Object* receiver = *args.receiver(); 825 Object* receiver = *args.receiver();
709 FixedArray* elms; 826 FixedArrayBase* elms;
710 int len = -1; 827 int len = -1;
711 if (receiver->IsJSArray()) { 828 if (receiver->IsJSArray()) {
712 JSArray* array = JSArray::cast(receiver); 829 JSArray* array = JSArray::cast(receiver);
713 if (!array->HasFastSmiOrObjectElements() || 830 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
714 !IsJSArrayFastElementMovingAllowed(heap, array)) {
715 return CallJsBuiltin(isolate, "ArraySlice", args); 831 return CallJsBuiltin(isolate, "ArraySlice", args);
716 } 832 }
717 833
718 elms = FixedArray::cast(array->elements()); 834 if (array->HasFastElements()) {
835 elms = array->elements();
836 } else {
837 return CallJsBuiltin(isolate, "ArraySlice", args);
838 }
839
719 len = Smi::cast(array->length())->value(); 840 len = Smi::cast(array->length())->value();
841
720 } else { 842 } else {
721 // Array.slice(arguments, ...) is quite a common idiom (notably more 843 // Array.slice(arguments, ...) is quite a common idiom (notably more
722 // than 50% of invocations in Web apps). Treat it in C++ as well. 844 // than 50% of invocations in Web apps). Treat it in C++ as well.
723 Map* arguments_map = 845 Map* arguments_map =
724 isolate->context()->native_context()->arguments_boilerplate()->map(); 846 isolate->context()->native_context()->arguments_boilerplate()->map();
725 847
726 bool is_arguments_object_with_fast_elements = 848 bool is_arguments_object_with_fast_elements =
727 receiver->IsJSObject() 849 receiver->IsJSObject() &&
728 && JSObject::cast(receiver)->map() == arguments_map 850 JSObject::cast(receiver)->map() == arguments_map;
729 && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
730 if (!is_arguments_object_with_fast_elements) { 851 if (!is_arguments_object_with_fast_elements) {
731 return CallJsBuiltin(isolate, "ArraySlice", args); 852 return CallJsBuiltin(isolate, "ArraySlice", args);
732 } 853 }
733 elms = FixedArray::cast(JSObject::cast(receiver)->elements()); 854 JSObject* object = JSObject::cast(receiver);
734 Object* len_obj = JSObject::cast(receiver) 855
735 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex); 856 if (object->HasFastElements()) {
857 elms = object->elements();
858 } else {
859 return CallJsBuiltin(isolate, "ArraySlice", args);
860 }
861 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
736 if (!len_obj->IsSmi()) { 862 if (!len_obj->IsSmi()) {
737 return CallJsBuiltin(isolate, "ArraySlice", args); 863 return CallJsBuiltin(isolate, "ArraySlice", args);
738 } 864 }
739 len = Smi::cast(len_obj)->value(); 865 len = Smi::cast(len_obj)->value();
740 if (len > elms->length()) { 866 if (len > elms->length()) {
741 return CallJsBuiltin(isolate, "ArraySlice", args); 867 return CallJsBuiltin(isolate, "ArraySlice", args);
742 } 868 }
869 }
870
871 JSObject* object = JSObject::cast(receiver);
872 ElementsKind kind = object->GetElementsKind();
873
874 if (IsHoleyElementsKind(kind)) {
875 bool packed = true;
876 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
743 for (int i = 0; i < len; i++) { 877 for (int i = 0; i < len; i++) {
744 if (elms->get(i) == heap->the_hole_value()) { 878 if (!accessor->HasElement(object, object, i, elms)) {
745 return CallJsBuiltin(isolate, "ArraySlice", args); 879 packed = false;
880 break;
746 } 881 }
747 } 882 }
883 if (packed) {
884 kind = GetPackedElementsKind(kind);
885 } else if (!receiver->IsJSArray()) {
886 return CallJsBuiltin(isolate, "ArraySlice", args);
887 }
748 } 888 }
889
749 ASSERT(len >= 0); 890 ASSERT(len >= 0);
750 int n_arguments = args.length() - 1; 891 int n_arguments = args.length() - 1;
751 892
752 // Note carefully choosen defaults---if argument is missing, 893 // Note carefully choosen defaults---if argument is missing,
753 // it's undefined which gets converted to 0 for relative_start 894 // it's undefined which gets converted to 0 for relative_start
754 // and to len for relative_end. 895 // and to len for relative_end.
755 int relative_start = 0; 896 int relative_start = 0;
756 int relative_end = len; 897 int relative_end = len;
757 if (n_arguments > 0) { 898 if (n_arguments > 0) {
758 Object* arg1 = args[1]; 899 Object* arg1 = args[1];
759 if (arg1->IsSmi()) { 900 if (arg1->IsSmi()) {
760 relative_start = Smi::cast(arg1)->value(); 901 relative_start = Smi::cast(arg1)->value();
902 } else if (arg1->IsHeapNumber()) {
903 double start = HeapNumber::cast(arg1)->value();
904 if (start < kMinInt || start > kMaxInt) {
905 return CallJsBuiltin(isolate, "ArraySlice", args);
906 }
907 relative_start = static_cast<int>(start);
761 } else if (!arg1->IsUndefined()) { 908 } else if (!arg1->IsUndefined()) {
762 return CallJsBuiltin(isolate, "ArraySlice", args); 909 return CallJsBuiltin(isolate, "ArraySlice", args);
763 } 910 }
764 if (n_arguments > 1) { 911 if (n_arguments > 1) {
765 Object* arg2 = args[2]; 912 Object* arg2 = args[2];
766 if (arg2->IsSmi()) { 913 if (arg2->IsSmi()) {
767 relative_end = Smi::cast(arg2)->value(); 914 relative_end = Smi::cast(arg2)->value();
915 } else if (arg2->IsHeapNumber()) {
916 double end = HeapNumber::cast(arg2)->value();
917 if (end < kMinInt || end > kMaxInt) {
918 return CallJsBuiltin(isolate, "ArraySlice", args);
919 }
920 relative_end = static_cast<int>(end);
768 } else if (!arg2->IsUndefined()) { 921 } else if (!arg2->IsUndefined()) {
769 return CallJsBuiltin(isolate, "ArraySlice", args); 922 return CallJsBuiltin(isolate, "ArraySlice", args);
770 } 923 }
771 } 924 }
772 } 925 }
773 926
774 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 927 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
775 int k = (relative_start < 0) ? Max(len + relative_start, 0) 928 int k = (relative_start < 0) ? Max(len + relative_start, 0)
776 : Min(relative_start, len); 929 : Min(relative_start, len);
777 930
778 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 931 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
779 int final = (relative_end < 0) ? Max(len + relative_end, 0) 932 int final = (relative_end < 0) ? Max(len + relative_end, 0)
780 : Min(relative_end, len); 933 : Min(relative_end, len);
781 934
782 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
783
784 // Calculate the length of result array. 935 // Calculate the length of result array.
785 int result_len = Max(final - k, 0); 936 int result_len = Max(final - k, 0);
786 937
787 MaybeObject* maybe_array =
788 heap->AllocateJSArrayAndStorage(elements_kind,
789 result_len,
790 result_len);
791 JSArray* result_array; 938 JSArray* result_array;
939 MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind,
940 result_len,
941 result_len);
792 if (!maybe_array->To(&result_array)) return maybe_array; 942 if (!maybe_array->To(&result_array)) return maybe_array;
793 943
794 CopyObjectToObjectElements(elms, elements_kind, k, 944 ElementsAccessor* accessor = object->GetElementsAccessor();
795 FixedArray::cast(result_array->elements()), 945 MaybeObject* maybe_failure =
796 elements_kind, 0, result_len); 946 accessor->CopyElements(object, k, result_array->elements(),
947 kind, 0, result_len, elms);
948 ASSERT(!maybe_failure->IsFailure());
949 USE(maybe_failure);
797 950
798 return result_array; 951 return result_array;
799 } 952 }
800 953
801 954
802 BUILTIN(ArraySplice) { 955 BUILTIN(ArraySplice) {
803 Heap* heap = isolate->heap(); 956 Heap* heap = isolate->heap();
804 Object* receiver = *args.receiver(); 957 Object* receiver = *args.receiver();
805 Object* elms_obj; 958 FixedArrayBase* elms_obj;
806 { MaybeObject* maybe_elms_obj = 959 MaybeObject* maybe_elms =
807 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3); 960 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
808 if (maybe_elms_obj == NULL) 961 if (maybe_elms == NULL) {
809 return CallJsBuiltin(isolate, "ArraySplice", args); 962 return CallJsBuiltin(isolate, "ArraySplice", args);
810 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
811 } 963 }
964 if (!maybe_elms->To(&elms_obj)) return maybe_elms;
965
812 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) { 966 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
813 return CallJsBuiltin(isolate, "ArraySplice", args); 967 return CallJsBuiltin(isolate, "ArraySplice", args);
814 } 968 }
815 FixedArray* elms = FixedArray::cast(elms_obj);
816 JSArray* array = JSArray::cast(receiver); 969 JSArray* array = JSArray::cast(receiver);
817 ASSERT(array->HasFastSmiOrObjectElements());
818 970
819 if (FLAG_harmony_observation && array->map()->is_observed()) { 971 if (FLAG_harmony_observation && array->map()->is_observed()) {
820 return CallJsBuiltin(isolate, "ArraySplice", args); 972 return CallJsBuiltin(isolate, "ArraySplice", args);
821 } 973 }
822 974
823 int len = Smi::cast(array->length())->value(); 975 int len = Smi::cast(array->length())->value();
824 976
825 int n_arguments = args.length() - 1; 977 int n_arguments = args.length() - 1;
826 978
827 int relative_start = 0; 979 int relative_start = 0;
828 if (n_arguments > 0) { 980 if (n_arguments > 0) {
829 Object* arg1 = args[1]; 981 Object* arg1 = args[1];
830 if (arg1->IsSmi()) { 982 if (arg1->IsSmi()) {
831 relative_start = Smi::cast(arg1)->value(); 983 relative_start = Smi::cast(arg1)->value();
984 } else if (arg1->IsHeapNumber()) {
985 double start = HeapNumber::cast(arg1)->value();
986 if (start < kMinInt || start > kMaxInt) {
987 return CallJsBuiltin(isolate, "ArraySlice", args);
988 }
989 relative_start = static_cast<int>(start);
832 } else if (!arg1->IsUndefined()) { 990 } else if (!arg1->IsUndefined()) {
833 return CallJsBuiltin(isolate, "ArraySplice", args); 991 return CallJsBuiltin(isolate, "ArraySplice", args);
834 } 992 }
835 } 993 }
836 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 994 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
837 : Min(relative_start, len); 995 : Min(relative_start, len);
838 996
839 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 997 // 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. 998 // given as a request to delete all the elements from the start.
841 // And it differs from the case of undefined delete count. 999 // And it differs from the case of undefined delete count.
842 // This does not follow ECMA-262, but we do the same for 1000 // This does not follow ECMA-262, but we do the same for
843 // compatibility. 1001 // compatibility.
844 int actual_delete_count; 1002 int actual_delete_count;
845 if (n_arguments == 1) { 1003 if (n_arguments == 1) {
846 ASSERT(len - actual_start >= 0); 1004 ASSERT(len - actual_start >= 0);
847 actual_delete_count = len - actual_start; 1005 actual_delete_count = len - actual_start;
848 } else { 1006 } else {
849 int value = 0; // ToInteger(undefined) == 0 1007 int value = 0; // ToInteger(undefined) == 0
850 if (n_arguments > 1) { 1008 if (n_arguments > 1) {
851 Object* arg2 = args[2]; 1009 Object* arg2 = args[2];
852 if (arg2->IsSmi()) { 1010 if (arg2->IsSmi()) {
853 value = Smi::cast(arg2)->value(); 1011 value = Smi::cast(arg2)->value();
854 } else { 1012 } else {
855 return CallJsBuiltin(isolate, "ArraySplice", args); 1013 return CallJsBuiltin(isolate, "ArraySplice", args);
856 } 1014 }
857 } 1015 }
858 actual_delete_count = Min(Max(value, 0), len - actual_start); 1016 actual_delete_count = Min(Max(value, 0), len - actual_start);
859 } 1017 }
860 1018
1019 ElementsKind elements_kind = array->GetElementsKind();
1020
1021 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
1022 int new_length = len - actual_delete_count + item_count;
1023
1024 // For double mode we do not support changing the length.
1025 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
1026 return CallJsBuiltin(isolate, "ArraySplice", args);
1027 }
1028
1029 if (new_length == 0) {
1030 MaybeObject* maybe_array = heap->AllocateJSArrayWithElements(
1031 elms_obj, elements_kind, actual_delete_count);
1032 if (maybe_array->IsFailure()) return maybe_array;
1033 array->set_elements(heap->empty_fixed_array());
1034 array->set_length(Smi::FromInt(0));
1035 return maybe_array;
1036 }
1037
861 JSArray* result_array = NULL; 1038 JSArray* result_array = NULL;
862 ElementsKind elements_kind =
863 JSObject::cast(receiver)->GetElementsKind();
864 MaybeObject* maybe_array = 1039 MaybeObject* maybe_array =
865 heap->AllocateJSArrayAndStorage(elements_kind, 1040 heap->AllocateJSArrayAndStorage(elements_kind,
866 actual_delete_count, 1041 actual_delete_count,
867 actual_delete_count); 1042 actual_delete_count);
868 if (!maybe_array->To(&result_array)) return maybe_array; 1043 if (!maybe_array->To(&result_array)) return maybe_array;
869 1044
870 { 1045 if (actual_delete_count > 0) {
871 // Fill newly created array. 1046 ElementsAccessor* accessor = array->GetElementsAccessor();
872 CopyObjectToObjectElements(elms, elements_kind, actual_start, 1047 MaybeObject* maybe_failure =
873 FixedArray::cast(result_array->elements()), 1048 accessor->CopyElements(array, actual_start, result_array->elements(),
874 elements_kind, 0, actual_delete_count); 1049 elements_kind, 0, actual_delete_count, elms_obj);
1050 // Cannot fail since the origin and target array are of the same elements
1051 // kind.
1052 ASSERT(!maybe_failure->IsFailure());
1053 USE(maybe_failure);
875 } 1054 }
876 1055
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; 1056 bool elms_changed = false;
881 if (item_count < actual_delete_count) { 1057 if (item_count < actual_delete_count) {
882 // Shrink the array. 1058 // Shrink the array.
883 const bool trim_array = !heap->lo_space()->Contains(elms) && 1059 const bool trim_array = !heap->lo_space()->Contains(elms_obj) &&
884 ((actual_start + item_count) < 1060 ((actual_start + item_count) <
885 (len - actual_delete_count - actual_start)); 1061 (len - actual_delete_count - actual_start));
886 if (trim_array) { 1062 if (trim_array) {
887 const int delta = actual_delete_count - item_count; 1063 const int delta = actual_delete_count - item_count;
888 1064
889 { 1065 if (elms_obj->IsFixedDoubleArray()) {
1066 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
1067 MoveDoubleElements(elms, delta, elms, 0, actual_start);
1068 } else {
1069 FixedArray* elms = FixedArray::cast(elms_obj);
890 AssertNoAllocation no_gc; 1070 AssertNoAllocation no_gc;
891 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start); 1071 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
892 } 1072 }
893 1073
894 elms = LeftTrimFixedArray(heap, elms, delta); 1074 elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
895 1075
896 elms_changed = true; 1076 elms_changed = true;
897 } else { 1077 } else {
898 AssertNoAllocation no_gc; 1078 if (elms_obj->IsFixedDoubleArray()) {
899 MoveElements(heap, &no_gc, 1079 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
900 elms, actual_start + item_count, 1080 MoveDoubleElements(elms, actual_start + item_count,
901 elms, actual_start + actual_delete_count, 1081 elms, actual_start + actual_delete_count,
902 (len - actual_delete_count - actual_start)); 1082 (len - actual_delete_count - actual_start));
903 FillWithHoles(heap, elms, new_length, len); 1083 FillWithHoles(elms, new_length, len);
1084 } else {
1085 FixedArray* elms = FixedArray::cast(elms_obj);
1086 AssertNoAllocation no_gc;
1087 MoveElements(heap, &no_gc,
1088 elms, actual_start + item_count,
1089 elms, actual_start + actual_delete_count,
1090 (len - actual_delete_count - actual_start));
1091 FillWithHoles(heap, elms, new_length, len);
1092 }
904 } 1093 }
905 } else if (item_count > actual_delete_count) { 1094 } else if (item_count > actual_delete_count) {
1095 FixedArray* elms = FixedArray::cast(elms_obj);
906 // Currently fixed arrays cannot grow too big, so 1096 // Currently fixed arrays cannot grow too big, so
907 // we should never hit this case. 1097 // we should never hit this case.
908 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len)); 1098 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
909 1099
910 // Check if array need to grow. 1100 // Check if array need to grow.
911 if (new_length > elms->length()) { 1101 if (new_length > elms->length()) {
912 // New backing storage is needed. 1102 // New backing storage is needed.
913 int capacity = new_length + (new_length >> 1) + 16; 1103 int capacity = new_length + (new_length >> 1) + 16;
914 Object* obj; 1104 FixedArray* new_elms;
915 { MaybeObject* maybe_obj = 1105 MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
916 heap->AllocateUninitializedFixedArray(capacity); 1106 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 1107
921 { 1108 // Copy the part before actual_start as is.
922 // Copy the part before actual_start as is. 1109 ElementsKind kind = array->GetElementsKind();
923 ElementsKind kind = array->GetElementsKind(); 1110 ElementsAccessor* accessor = array->GetElementsAccessor();
924 CopyObjectToObjectElements(elms, kind, 0, 1111 MaybeObject* maybe_failure = accessor->CopyElements(
925 new_elms, kind, 0, actual_start); 1112 array, 0, new_elms, kind, 0, actual_start, elms);
926 const int to_copy = len - actual_delete_count - actual_start; 1113 ASSERT(!maybe_failure->IsFailure());
927 CopyObjectToObjectElements(elms, kind, 1114 USE(maybe_failure);
928 actual_start + actual_delete_count, 1115 const int to_copy = len - actual_delete_count - actual_start;
929 new_elms, kind, 1116 maybe_failure = accessor->CopyElements(
930 actual_start + item_count, to_copy); 1117 array, actual_start + actual_delete_count, new_elms, kind,
931 } 1118 actual_start + item_count, to_copy, elms);
1119 ASSERT(!maybe_failure->IsFailure());
1120 USE(maybe_failure);
932 1121
933 FillWithHoles(heap, new_elms, new_length, capacity); 1122 FillWithHoles(heap, new_elms, new_length, capacity);
934 1123
935 elms = new_elms; 1124 elms_obj = new_elms;
936 elms_changed = true; 1125 elms_changed = true;
937 } else { 1126 } else {
938 AssertNoAllocation no_gc; 1127 AssertNoAllocation no_gc;
939 MoveElements(heap, &no_gc, 1128 MoveElements(heap, &no_gc,
940 elms, actual_start + item_count, 1129 elms, actual_start + item_count,
941 elms, actual_start + actual_delete_count, 1130 elms, actual_start + actual_delete_count,
942 (len - actual_delete_count - actual_start)); 1131 (len - actual_delete_count - actual_start));
943 } 1132 }
944 } 1133 }
945 1134
946 AssertNoAllocation no_gc; 1135 if (IsFastDoubleElementsKind(elements_kind)) {
947 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 1136 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
948 for (int k = actual_start; k < actual_start + item_count; k++) { 1137 for (int k = actual_start; k < actual_start + item_count; k++) {
949 elms->set(k, args[3 + k - actual_start], mode); 1138 Object* arg = args[3 + k - actual_start];
1139 if (arg->IsSmi()) {
1140 elms->set(k, Smi::cast(arg)->value());
1141 } else {
1142 elms->set(k, HeapNumber::cast(arg)->value());
1143 }
1144 }
1145 } else {
1146 FixedArray* elms = FixedArray::cast(elms_obj);
1147 AssertNoAllocation no_gc;
1148 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
1149 for (int k = actual_start; k < actual_start + item_count; k++) {
1150 elms->set(k, args[3 + k - actual_start], mode);
1151 }
950 } 1152 }
951 1153
952 if (elms_changed) { 1154 if (elms_changed) {
953 array->set_elements(elms); 1155 array->set_elements(elms_obj);
954 } 1156 }
955
956 // Set the length. 1157 // Set the length.
957 array->set_length(Smi::FromInt(new_length)); 1158 array->set_length(Smi::FromInt(new_length));
958 1159
959 return result_array; 1160 return result_array;
960 } 1161 }
961 1162
962 1163
963 BUILTIN(ArrayConcat) { 1164 BUILTIN(ArrayConcat) {
964 Heap* heap = isolate->heap(); 1165 Heap* heap = isolate->heap();
965 Context* native_context = isolate->context()->native_context(); 1166 Context* native_context = isolate->context()->native_context();
966 JSObject* array_proto = 1167 JSObject* array_proto =
967 JSObject::cast(native_context->array_function()->prototype()); 1168 JSObject::cast(native_context->array_function()->prototype());
968 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) { 1169 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) {
969 return CallJsBuiltin(isolate, "ArrayConcat", args); 1170 return CallJsBuiltin(isolate, "ArrayConcat", args);
970 } 1171 }
971 1172
972 // Iterate through all the arguments performing checks 1173 // Iterate through all the arguments performing checks
973 // and calculating total length. 1174 // and calculating total length.
974 int n_arguments = args.length(); 1175 int n_arguments = args.length();
975 int result_len = 0; 1176 int result_len = 0;
976 ElementsKind elements_kind = GetInitialFastElementsKind(); 1177 ElementsKind elements_kind = GetInitialFastElementsKind();
977 for (int i = 0; i < n_arguments; i++) { 1178 for (int i = 0; i < n_arguments; i++) {
978 Object* arg = args[i]; 1179 Object* arg = args[i];
979 if (!arg->IsJSArray() || 1180 if (!arg->IsJSArray() ||
980 !JSArray::cast(arg)->HasFastSmiOrObjectElements() || 1181 !JSArray::cast(arg)->HasFastElements() ||
981 JSArray::cast(arg)->GetPrototype() != array_proto) { 1182 JSArray::cast(arg)->GetPrototype() != array_proto) {
982 return CallJsBuiltin(isolate, "ArrayConcat", args); 1183 return CallJsBuiltin(isolate, "ArrayConcat", args);
983 } 1184 }
984
985 int len = Smi::cast(JSArray::cast(arg)->length())->value(); 1185 int len = Smi::cast(JSArray::cast(arg)->length())->value();
986 1186
987 // We shouldn't overflow when adding another len. 1187 // We shouldn't overflow when adding another len.
988 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 1188 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
989 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 1189 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
990 USE(kHalfOfMaxInt); 1190 USE(kHalfOfMaxInt);
991 result_len += len; 1191 result_len += len;
992 ASSERT(result_len >= 0); 1192 ASSERT(result_len >= 0);
993 1193
994 if (result_len > FixedArray::kMaxLength) { 1194 if (result_len > FixedDoubleArray::kMaxLength) {
995 return CallJsBuiltin(isolate, "ArrayConcat", args); 1195 return CallJsBuiltin(isolate, "ArrayConcat", args);
996 } 1196 }
997 1197
998 if (!JSArray::cast(arg)->HasFastSmiElements()) { 1198 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
999 if (IsFastSmiElementsKind(elements_kind)) { 1199 ElementsKind packed_kind = GetPackedElementsKind(arg_kind);
1000 if (IsFastHoleyElementsKind(elements_kind)) { 1200 if (IsMoreGeneralElementsKindTransition(
1001 elements_kind = FAST_HOLEY_ELEMENTS; 1201 GetPackedElementsKind(elements_kind), packed_kind)) {
1002 } else { 1202 if (IsFastHoleyElementsKind(elements_kind)) {
1003 elements_kind = FAST_ELEMENTS; 1203 elements_kind = GetHoleyElementsKind(arg_kind);
1004 } 1204 } else {
1205 elements_kind = arg_kind;
1005 } 1206 }
1006 } 1207 }
1007
1008 if (JSArray::cast(arg)->HasFastHoleyElements()) {
1009 elements_kind = GetHoleyElementsKind(elements_kind);
1010 }
1011 } 1208 }
1012 1209
1210 JSArray* result_array;
1013 // Allocate result. 1211 // Allocate result.
1014 JSArray* result_array;
1015 MaybeObject* maybe_array = 1212 MaybeObject* maybe_array =
1016 heap->AllocateJSArrayAndStorage(elements_kind, 1213 heap->AllocateJSArrayAndStorage(elements_kind,
1017 result_len, 1214 result_len,
1018 result_len); 1215 result_len);
1019 if (!maybe_array->To(&result_array)) return maybe_array; 1216 if (!maybe_array->To(&result_array)) return maybe_array;
1020 if (result_len == 0) return result_array; 1217 if (result_len == 0) return result_array;
1021 1218
1022 // Copy data. 1219 int j = 0;
1023 int start_pos = 0; 1220 FixedArrayBase* storage = result_array->elements();
1024 FixedArray* result_elms(FixedArray::cast(result_array->elements()));
1025 for (int i = 0; i < n_arguments; i++) { 1221 for (int i = 0; i < n_arguments; i++) {
1026 JSArray* array = JSArray::cast(args[i]); 1222 JSArray* array = JSArray::cast(args[i]);
1223 ElementsAccessor* accessor = array->GetElementsAccessor();
1027 int len = Smi::cast(array->length())->value(); 1224 int len = Smi::cast(array->length())->value();
1028 FixedArray* elms = FixedArray::cast(array->elements()); 1225 MaybeObject* maybe_failure =
1029 CopyObjectToObjectElements(elms, elements_kind, 0, 1226 accessor->CopyElements(array, 0, storage, elements_kind, j, len);
1030 result_elms, elements_kind, 1227 if (maybe_failure->IsFailure()) return maybe_failure;
1031 start_pos, len); 1228 j += len;
1032 start_pos += len;
1033 } 1229 }
1034 ASSERT(start_pos == result_len); 1230
1231 ASSERT(j == result_len);
1035 1232
1036 return result_array; 1233 return result_array;
1037 } 1234 }
1038 1235
1039 1236
1040 // ----------------------------------------------------------------------------- 1237 // -----------------------------------------------------------------------------
1041 // Strict mode poison pills 1238 // Strict mode poison pills
1042 1239
1043 1240
1044 BUILTIN(StrictModePoisonPill) { 1241 BUILTIN(StrictModePoisonPill) {
(...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after
1734 return Handle<Code>(code_address); \ 1931 return Handle<Code>(code_address); \
1735 } 1932 }
1736 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 1933 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1737 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 1934 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1738 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 1935 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1739 #undef DEFINE_BUILTIN_ACCESSOR_C 1936 #undef DEFINE_BUILTIN_ACCESSOR_C
1740 #undef DEFINE_BUILTIN_ACCESSOR_A 1937 #undef DEFINE_BUILTIN_ACCESSOR_A
1741 1938
1742 1939
1743 } } // namespace v8::internal 1940 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/elements.h » ('j') | src/heap.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698