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

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

Powered by Google App Engine
This is Rietveld 408576698