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

Side by Side Diff: src/builtins.cc

Issue 223413002: Partial recover from performance degradation after handlification of ElementsAccessor::CopyElements… (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/elements.h » ('j') | src/factory.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 MUST_USE_RESULT 295 MUST_USE_RESULT
296 static inline Handle<FixedArrayBase> EnsureJSArrayWithWritableFastElements( 296 static inline Handle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
297 Isolate* isolate, 297 Isolate* isolate,
298 Handle<Object> receiver, 298 Handle<Object> receiver,
299 Arguments* args, 299 Arguments* args,
300 int first_added_arg) { 300 int first_added_arg) {
301 if (!receiver->IsJSArray()) return Handle<FixedArrayBase>::null(); 301 if (!receiver->IsJSArray()) return Handle<FixedArrayBase>::null();
302 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 302 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
303 if (array->map()->is_observed()) return Handle<FixedArrayBase>::null(); 303 if (array->map()->is_observed()) return Handle<FixedArrayBase>::null();
304 if (!array->map()->is_extensible()) return Handle<FixedArrayBase>::null(); 304 if (!array->map()->is_extensible()) return Handle<FixedArrayBase>::null();
305 Handle<FixedArrayBase> elms(array->elements()); 305 Handle<FixedArrayBase> elms(array->elements(), isolate);
306 Heap* heap = isolate->heap(); 306 Heap* heap = isolate->heap();
307 Map* map = elms->map(); 307 Map* map = elms->map();
308 if (map == heap->fixed_array_map()) { 308 if (map == heap->fixed_array_map()) {
309 if (args == NULL || array->HasFastObjectElements()) return elms; 309 if (args == NULL || array->HasFastObjectElements()) return elms;
310 } else if (map == heap->fixed_cow_array_map()) { 310 } else if (map == heap->fixed_cow_array_map()) {
311 elms = JSObject::EnsureWritableFastElements(array); 311 elms = JSObject::EnsureWritableFastElements(array);
312 if (args == NULL || array->HasFastObjectElements()) return elms; 312 if (args == NULL || array->HasFastObjectElements()) return elms;
313 } else if (map == heap->fixed_double_array_map()) { 313 } else if (map == heap->fixed_double_array_map()) {
314 if (args == NULL) return elms; 314 if (args == NULL) return elms;
315 } else { 315 } else {
316 return Handle<FixedArrayBase>::null(); 316 return Handle<FixedArrayBase>::null();
317 } 317 }
318 318
319 // Need to ensure that the arguments passed in args can be contained in 319 // Need to ensure that the arguments passed in args can be contained in
320 // the array. 320 // the array.
321 int args_length = args->length(); 321 int args_length = args->length();
322 if (first_added_arg >= args_length) return handle(array->elements()); 322 if (first_added_arg >= args_length) return handle(array->elements(), isolate);
323 323
324 ElementsKind origin_kind = array->map()->elements_kind(); 324 ElementsKind origin_kind = array->map()->elements_kind();
325 ASSERT(!IsFastObjectElementsKind(origin_kind)); 325 ASSERT(!IsFastObjectElementsKind(origin_kind));
326 ElementsKind target_kind = origin_kind; 326 ElementsKind target_kind = origin_kind;
327 int arg_count = args->length() - first_added_arg; 327 int arg_count = args->length() - first_added_arg;
328 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); 328 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
329 for (int i = 0; i < arg_count; i++) { 329 for (int i = 0; i < arg_count; i++) {
330 Object* arg = arguments[i]; 330 Object* arg = arguments[i];
331 if (arg->IsHeapObject()) { 331 if (arg->IsHeapObject()) {
332 if (arg->IsHeapNumber()) { 332 if (arg->IsHeapNumber()) {
333 target_kind = FAST_DOUBLE_ELEMENTS; 333 target_kind = FAST_DOUBLE_ELEMENTS;
334 } else { 334 } else {
335 target_kind = FAST_ELEMENTS; 335 target_kind = FAST_ELEMENTS;
336 break; 336 break;
337 } 337 }
338 } 338 }
339 } 339 }
340 if (target_kind != origin_kind) { 340 if (target_kind != origin_kind) {
341 JSObject::TransitionElementsKind(array, target_kind); 341 JSObject::TransitionElementsKind(array, target_kind);
342 return handle(array->elements()); 342 return handle(array->elements(), isolate);
343 } 343 }
344 return elms; 344 return elms;
345 } 345 }
346 346
347 347
348 // TODO(ishell): Handlify when all Array* builtins are handlified. 348 // TODO(ishell): Handlify when all Array* builtins are handlified.
349 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap, 349 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
350 JSArray* receiver) { 350 JSArray* receiver) {
351 if (!FLAG_clever_optimizations) return false; 351 if (!FLAG_clever_optimizations) return false;
352 Context* native_context = heap->isolate()->context()->native_context(); 352 Context* native_context = heap->isolate()->context()->native_context();
353 JSObject* array_proto = 353 JSObject* array_proto =
354 JSObject::cast(native_context->array_function()->prototype()); 354 JSObject::cast(native_context->array_function()->prototype());
355 return receiver->GetPrototype() == array_proto && 355 return receiver->GetPrototype() == array_proto &&
356 ArrayPrototypeHasNoElements(heap, native_context, array_proto); 356 ArrayPrototypeHasNoElements(heap, native_context, array_proto);
357 } 357 }
358 358
359 359
360 MUST_USE_RESULT static MaybeObject* CallJsBuiltin( 360 MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
361 Isolate* isolate, 361 Isolate* isolate,
362 const char* name, 362 const char* name,
363 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { 363 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
364 AllowHeapAllocation allow_allocation;
Yang 2014/04/03 08:10:43 Add a comment that the callees return immediately
Igor Sheludko 2014/04/03 09:01:00 As discussed offline, it is safer to put explicit
364 HandleScope handleScope(isolate); 365 HandleScope handleScope(isolate);
365 366
366 Handle<Object> js_builtin = 367 Handle<Object> js_builtin =
367 GetProperty(Handle<JSObject>(isolate->native_context()->builtins()), 368 GetProperty(Handle<JSObject>(isolate->native_context()->builtins()),
368 name); 369 name);
369 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin); 370 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
370 int argc = args.length() - 1; 371 int argc = args.length() - 1;
371 ScopedVector<Handle<Object> > argv(argc); 372 ScopedVector<Handle<Object> > argv(argc);
372 for (int i = 0; i < argc; ++i) { 373 for (int i = 0; i < argc; ++i) {
373 argv[i] = args.at<Object>(i + 1); 374 argv[i] = args.at<Object>(i + 1);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 int new_length = len + to_add; 412 int new_length = len + to_add;
412 413
413 if (new_length > elms->length()) { 414 if (new_length > elms->length()) {
414 // New backing storage is needed. 415 // New backing storage is needed.
415 int capacity = new_length + (new_length >> 1) + 16; 416 int capacity = new_length + (new_length >> 1) + 16;
416 Handle<FixedArray> new_elms = 417 Handle<FixedArray> new_elms =
417 isolate->factory()->NewUninitializedFixedArray(capacity); 418 isolate->factory()->NewUninitializedFixedArray(capacity);
418 419
419 ElementsAccessor* accessor = array->GetElementsAccessor(); 420 ElementsAccessor* accessor = array->GetElementsAccessor();
420 accessor->CopyElements( 421 accessor->CopyElements(
421 Handle<JSObject>::null(), 0, kind, new_elms, 0, 422 elms_obj, 0, kind, new_elms, 0,
422 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); 423 ElementsAccessor::kCopyToEndAndInitializeToHole);
423 424
424 elms = new_elms; 425 elms = new_elms;
425 } 426 }
426 427
427 // Add the provided values. 428 // Add the provided values.
428 DisallowHeapAllocation no_gc; 429 DisallowHeapAllocation no_gc;
429 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 430 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
430 for (int index = 0; index < to_add; index++) { 431 for (int index = 0; index < to_add; index++) {
431 elms->set(index + len, args[index + 1], mode); 432 elms->set(index + len, args[index + 1], mode);
432 } 433 }
(...skipping 21 matching lines...) Expand all
454 455
455 Handle<FixedDoubleArray> new_elms; 456 Handle<FixedDoubleArray> new_elms;
456 457
457 if (new_length > elms_len) { 458 if (new_length > elms_len) {
458 // New backing storage is needed. 459 // New backing storage is needed.
459 int capacity = new_length + (new_length >> 1) + 16; 460 int capacity = new_length + (new_length >> 1) + 16;
460 new_elms = isolate->factory()->NewFixedDoubleArray(capacity); 461 new_elms = isolate->factory()->NewFixedDoubleArray(capacity);
461 462
462 ElementsAccessor* accessor = array->GetElementsAccessor(); 463 ElementsAccessor* accessor = array->GetElementsAccessor();
463 accessor->CopyElements( 464 accessor->CopyElements(
464 Handle<JSObject>::null(), 0, kind, new_elms, 0, 465 elms_obj, 0, kind, new_elms, 0,
465 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj); 466 ElementsAccessor::kCopyToEndAndInitializeToHole);
466 467
467 } else { 468 } else {
468 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the 469 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
469 // empty_fixed_array. 470 // empty_fixed_array.
470 new_elms = Handle<FixedDoubleArray>::cast(elms_obj); 471 new_elms = Handle<FixedDoubleArray>::cast(elms_obj);
471 } 472 }
472 473
473 // Add the provided values. 474 // Add the provided values.
474 DisallowHeapAllocation no_gc; 475 DisallowHeapAllocation no_gc;
475 int index; 476 int index;
476 for (index = 0; index < to_add; index++) { 477 for (index = 0; index < to_add; index++) {
477 Object* arg = args[index + 1]; 478 Object* arg = args[index + 1];
478 new_elms->set(index + len, arg->Number()); 479 new_elms->set(index + len, arg->Number());
479 } 480 }
480 481
481 if (*new_elms != array->elements()) { 482 if (*new_elms != array->elements()) {
482 array->set_elements(*new_elms); 483 array->set_elements(*new_elms);
483 } 484 }
484 485
485 // Set the length. 486 // Set the length.
486 array->set_length(Smi::FromInt(new_length)); 487 array->set_length(Smi::FromInt(new_length));
487 return Smi::FromInt(new_length); 488 return Smi::FromInt(new_length);
488 } 489 }
489 } 490 }
490 491
491 492
492 // TODO(ishell): Temporary wrapper until handlified.
493 static bool ElementsAccessorHasElementWrapper(
494 ElementsAccessor* accessor,
495 Handle<Object> receiver,
496 Handle<JSObject> holder,
497 uint32_t key,
498 Handle<FixedArrayBase> backing_store = Handle<FixedArrayBase>::null()) {
499 return accessor->HasElement(*receiver, *holder, key,
500 backing_store.is_null() ? NULL : *backing_store);
501 }
502
503
504 BUILTIN(ArrayPop) { 493 BUILTIN(ArrayPop) {
505 HandleScope scope(isolate); 494 HandleScope scope(isolate);
506 Handle<Object> receiver = args.receiver(); 495 Handle<Object> receiver = args.receiver();
507 Handle<FixedArrayBase> elms_obj = 496 Handle<FixedArrayBase> elms_obj =
508 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); 497 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
509 if (elms_obj.is_null()) return CallJsBuiltin(isolate, "ArrayPop", args); 498 if (elms_obj.is_null()) return CallJsBuiltin(isolate, "ArrayPop", args);
510 499
511 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 500 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
512 ASSERT(!array->map()->is_observed()); 501 ASSERT(!array->map()->is_observed());
513 502
514 int len = Smi::cast(array->length())->value(); 503 int len = Smi::cast(array->length())->value();
515 if (len == 0) return isolate->heap()->undefined_value(); 504 if (len == 0) return isolate->heap()->undefined_value();
516 505
517 ElementsAccessor* accessor = array->GetElementsAccessor(); 506 ElementsAccessor* accessor = array->GetElementsAccessor();
518 int new_length = len - 1; 507 int new_length = len - 1;
519 Handle<Object> element; 508 Handle<Object> element;
520 if (ElementsAccessorHasElementWrapper( 509 if (accessor->HasElement(*array, *array, new_length, *elms_obj)) {
521 accessor, array, array, new_length, elms_obj)) {
522 element = accessor->Get( 510 element = accessor->Get(
523 array, array, new_length, elms_obj); 511 array, array, new_length, elms_obj);
524 } else { 512 } else {
525 Handle<Object> proto(array->GetPrototype(), isolate); 513 Handle<Object> proto(array->GetPrototype(), isolate);
526 element = Object::GetElement(isolate, proto, len - 1); 514 element = Object::GetElement(isolate, proto, len - 1);
527 } 515 }
528 RETURN_IF_EMPTY_HANDLE(isolate, element); 516 RETURN_IF_EMPTY_HANDLE(isolate, element);
529 RETURN_IF_EMPTY_HANDLE(isolate, 517 RETURN_IF_EMPTY_HANDLE(isolate,
530 accessor->SetLength( 518 accessor->SetLength(
531 array, handle(Smi::FromInt(new_length), isolate))); 519 array, handle(Smi::FromInt(new_length), isolate)));
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 599
612 if (new_length > elms->length()) { 600 if (new_length > elms->length()) {
613 // New backing storage is needed. 601 // New backing storage is needed.
614 int capacity = new_length + (new_length >> 1) + 16; 602 int capacity = new_length + (new_length >> 1) + 16;
615 Handle<FixedArray> new_elms = 603 Handle<FixedArray> new_elms =
616 isolate->factory()->NewUninitializedFixedArray(capacity); 604 isolate->factory()->NewUninitializedFixedArray(capacity);
617 605
618 ElementsKind kind = array->GetElementsKind(); 606 ElementsKind kind = array->GetElementsKind();
619 ElementsAccessor* accessor = array->GetElementsAccessor(); 607 ElementsAccessor* accessor = array->GetElementsAccessor();
620 accessor->CopyElements( 608 accessor->CopyElements(
621 Handle<JSObject>::null(), 0, kind, new_elms, to_add, 609 elms, 0, kind, new_elms, to_add,
622 ElementsAccessor::kCopyToEndAndInitializeToHole, elms); 610 ElementsAccessor::kCopyToEndAndInitializeToHole);
623 611
624 elms = new_elms; 612 elms = new_elms;
625 array->set_elements(*elms); 613 array->set_elements(*elms);
626 } else { 614 } else {
627 DisallowHeapAllocation no_gc; 615 DisallowHeapAllocation no_gc;
628 heap->MoveElements(*elms, to_add, 0, len); 616 heap->MoveElements(*elms, to_add, 0, len);
629 } 617 }
630 618
631 // Add the provided values. 619 // Add the provided values.
632 DisallowHeapAllocation no_gc; 620 DisallowHeapAllocation no_gc;
633 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc); 621 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
634 for (int i = 0; i < to_add; i++) { 622 for (int i = 0; i < to_add; i++) {
635 elms->set(i, args[i + 1], mode); 623 elms->set(i, args[i + 1], mode);
636 } 624 }
637 625
638 // Set the length. 626 // Set the length.
639 array->set_length(Smi::FromInt(new_length)); 627 array->set_length(Smi::FromInt(new_length));
640 return Smi::FromInt(new_length); 628 return Smi::FromInt(new_length);
641 } 629 }
642 630
643 631
644 BUILTIN(ArraySlice) { 632 BUILTIN(ArraySlice) {
645 HandleScope scope(isolate); 633 HandleScope scope(isolate);
646 Heap* heap = isolate->heap(); 634 Heap* heap = isolate->heap();
647 Handle<Object> receiver = args.receiver(); 635 Handle<Object> receiver = args.receiver();
648 Handle<FixedArrayBase> elms;
649 int len = -1; 636 int len = -1;
637 DisallowHeapAllocation no_allocations_before_creating_result;
Yang 2014/04/03 08:10:43 I would prefer if you still use scopes instead of
Igor Sheludko 2014/04/03 09:01:00 Done.
638
650 if (receiver->IsJSArray()) { 639 if (receiver->IsJSArray()) {
651 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 640 JSArray* array = JSArray::cast(*receiver);
652 if (!IsJSArrayFastElementMovingAllowed(heap, *array)) { 641 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
653 return CallJsBuiltin(isolate, "ArraySlice", args); 642 return CallJsBuiltin(isolate, "ArraySlice", args);
654 } 643 }
655 644
656 if (array->HasFastElements()) { 645 if (!array->HasFastElements()) {
657 elms = handle(array->elements());
658 } else {
659 return CallJsBuiltin(isolate, "ArraySlice", args); 646 return CallJsBuiltin(isolate, "ArraySlice", args);
660 } 647 }
661 648
662 len = Smi::cast(array->length())->value(); 649 len = Smi::cast(array->length())->value();
663 } else { 650 } else {
664 // Array.slice(arguments, ...) is quite a common idiom (notably more 651 // Array.slice(arguments, ...) is quite a common idiom (notably more
665 // than 50% of invocations in Web apps). Treat it in C++ as well. 652 // than 50% of invocations in Web apps). Treat it in C++ as well.
666 Handle<Map> arguments_map(isolate->context()->native_context()-> 653 Map* arguments_map = isolate->context()->native_context()->
667 sloppy_arguments_boilerplate()->map()); 654 sloppy_arguments_boilerplate()->map();
668 655
669 bool is_arguments_object_with_fast_elements = 656 bool is_arguments_object_with_fast_elements =
670 receiver->IsJSObject() && 657 receiver->IsJSObject() &&
671 Handle<JSObject>::cast(receiver)->map() == *arguments_map; 658 JSObject::cast(*receiver)->map() == arguments_map;
672 if (!is_arguments_object_with_fast_elements) { 659 if (!is_arguments_object_with_fast_elements) {
673 return CallJsBuiltin(isolate, "ArraySlice", args); 660 return CallJsBuiltin(isolate, "ArraySlice", args);
674 } 661 }
675 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 662 JSObject* object = JSObject::cast(*receiver);
676 663
677 if (object->HasFastElements()) { 664 if (!object->HasFastElements()) {
678 elms = handle(object->elements());
679 } else {
680 return CallJsBuiltin(isolate, "ArraySlice", args); 665 return CallJsBuiltin(isolate, "ArraySlice", args);
681 } 666 }
682 Handle<Object> len_obj( 667
683 object->InObjectPropertyAt(Heap::kArgumentsLengthIndex), isolate); 668 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
684 if (!len_obj->IsSmi()) { 669 if (!len_obj->IsSmi()) {
685 return CallJsBuiltin(isolate, "ArraySlice", args); 670 return CallJsBuiltin(isolate, "ArraySlice", args);
686 } 671 }
687 len = Handle<Smi>::cast(len_obj)->value(); 672 len = Smi::cast(len_obj)->value();
688 if (len > elms->length()) { 673 if (len > object->elements()->length()) {
689 return CallJsBuiltin(isolate, "ArraySlice", args); 674 return CallJsBuiltin(isolate, "ArraySlice", args);
690 } 675 }
691 } 676 }
692 677
693 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
694
695 ASSERT(len >= 0); 678 ASSERT(len >= 0);
696 int n_arguments = args.length() - 1; 679 int n_arguments = args.length() - 1;
697 680
698 // Note carefully choosen defaults---if argument is missing, 681 // Note carefully choosen defaults---if argument is missing,
699 // it's undefined which gets converted to 0 for relative_start 682 // it's undefined which gets converted to 0 for relative_start
700 // and to len for relative_end. 683 // and to len for relative_end.
701 int relative_start = 0; 684 int relative_start = 0;
702 int relative_end = len; 685 int relative_end = len;
703 if (n_arguments > 0) { 686 if (n_arguments > 0) {
704 Handle<Object> arg1 = args.at<Object>(1); 687 Object* arg1 = args[1];
705 if (arg1->IsSmi()) { 688 if (arg1->IsSmi()) {
706 relative_start = Handle<Smi>::cast(arg1)->value(); 689 relative_start = Smi::cast(arg1)->value();
707 } else if (arg1->IsHeapNumber()) { 690 } else if (arg1->IsHeapNumber()) {
708 double start = Handle<HeapNumber>::cast(arg1)->value(); 691 double start = HeapNumber::cast(arg1)->value();
709 if (start < kMinInt || start > kMaxInt) { 692 if (start < kMinInt || start > kMaxInt) {
710 return CallJsBuiltin(isolate, "ArraySlice", args); 693 return CallJsBuiltin(isolate, "ArraySlice", args);
711 } 694 }
712 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); 695 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
713 } else if (!arg1->IsUndefined()) { 696 } else if (!arg1->IsUndefined()) {
714 return CallJsBuiltin(isolate, "ArraySlice", args); 697 return CallJsBuiltin(isolate, "ArraySlice", args);
715 } 698 }
716 if (n_arguments > 1) { 699 if (n_arguments > 1) {
717 Handle<Object> arg2 = args.at<Object>(2); 700 Object* arg2 = args[2];
718 if (arg2->IsSmi()) { 701 if (arg2->IsSmi()) {
719 relative_end = Handle<Smi>::cast(arg2)->value(); 702 relative_end = Smi::cast(arg2)->value();
720 } else if (arg2->IsHeapNumber()) { 703 } else if (arg2->IsHeapNumber()) {
721 double end = Handle<HeapNumber>::cast(arg2)->value(); 704 double end = HeapNumber::cast(arg2)->value();
722 if (end < kMinInt || end > kMaxInt) { 705 if (end < kMinInt || end > kMaxInt) {
723 return CallJsBuiltin(isolate, "ArraySlice", args); 706 return CallJsBuiltin(isolate, "ArraySlice", args);
724 } 707 }
725 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); 708 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
726 } else if (!arg2->IsUndefined()) { 709 } else if (!arg2->IsUndefined()) {
727 return CallJsBuiltin(isolate, "ArraySlice", args); 710 return CallJsBuiltin(isolate, "ArraySlice", args);
728 } 711 }
729 } 712 }
730 } 713 }
731 714
732 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 715 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
733 int k = (relative_start < 0) ? Max(len + relative_start, 0) 716 int k = (relative_start < 0) ? Max(len + relative_start, 0)
734 : Min(relative_start, len); 717 : Min(relative_start, len);
735 718
736 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 719 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
737 int final = (relative_end < 0) ? Max(len + relative_end, 0) 720 int final = (relative_end < 0) ? Max(len + relative_end, 0)
738 : Min(relative_end, len); 721 : Min(relative_end, len);
739 722
740 // Calculate the length of result array. 723 // Calculate the length of result array.
741 int result_len = Max(final - k, 0); 724 int result_len = Max(final - k, 0);
742 725
726 Handle<JSObject> object = Handle<JSObject>::cast(receiver);
727 Handle<FixedArrayBase> elms(object->elements(), isolate);
728
743 ElementsKind kind = object->GetElementsKind(); 729 ElementsKind kind = object->GetElementsKind();
744 if (IsHoleyElementsKind(kind)) { 730 if (IsHoleyElementsKind(kind)) {
Yang 2014/04/03 08:10:43 Then add a DisallowHeapAllocation scope here.
Igor Sheludko 2014/04/03 09:01:00 Done.
745 bool packed = true; 731 bool packed = true;
746 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); 732 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
747 for (int i = k; i < final; i++) { 733 for (int i = k; i < final; i++) {
748 if (!ElementsAccessorHasElementWrapper( 734 if (!accessor->HasElement(*object, *object, i, *elms)) {
749 accessor, object, object, i, elms)) {
750 packed = false; 735 packed = false;
751 break; 736 break;
752 } 737 }
753 } 738 }
754 if (packed) { 739 if (packed) {
755 kind = GetPackedElementsKind(kind); 740 kind = GetPackedElementsKind(kind);
756 } else if (!receiver->IsJSArray()) { 741 } else if (!receiver->IsJSArray()) {
757 return CallJsBuiltin(isolate, "ArraySlice", args); 742 return CallJsBuiltin(isolate, "ArraySlice", args);
758 } 743 }
759 } 744 }
760 745
746 AllowHeapAllocation allow_allocation_to_create_a_result;
Yang 2014/04/03 08:10:43 This is now unnecessary.
Igor Sheludko 2014/04/03 09:01:00 Done.
761 Handle<JSArray> result_array = 747 Handle<JSArray> result_array =
762 isolate->factory()->NewJSArray(kind, result_len, result_len); 748 isolate->factory()->NewJSArray(kind, result_len, result_len);
763 749
764 DisallowHeapAllocation no_gc; 750 DisallowHeapAllocation no_more_allocations_allowed;
765 if (result_len == 0) return *result_array; 751 if (result_len == 0) return *result_array;
766 752
767 ElementsAccessor* accessor = object->GetElementsAccessor(); 753 ElementsAccessor* accessor = object->GetElementsAccessor();
768 accessor->CopyElements(Handle<JSObject>::null(), k, kind, 754 accessor->CopyElements(
769 handle(result_array->elements()), 0, result_len, elms); 755 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
770 return *result_array; 756 return *result_array;
771 } 757 }
772 758
773 759
774 BUILTIN(ArraySplice) { 760 BUILTIN(ArraySplice) {
775 HandleScope scope(isolate); 761 HandleScope scope(isolate);
776 Heap* heap = isolate->heap(); 762 Heap* heap = isolate->heap();
777 Handle<Object> receiver = args.receiver(); 763 Handle<Object> receiver = args.receiver();
778 Handle<FixedArrayBase> elms_obj = 764 Handle<FixedArrayBase> elms_obj =
779 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); 765 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
780 if (elms_obj.is_null() || 766 if (elms_obj.is_null() ||
781 !IsJSArrayFastElementMovingAllowed(heap, 767 !IsJSArrayFastElementMovingAllowed(heap,
782 *Handle<JSArray>::cast(receiver))) { 768 *Handle<JSArray>::cast(receiver))) {
783 return CallJsBuiltin(isolate, "ArraySplice", args); 769 return CallJsBuiltin(isolate, "ArraySplice", args);
784 } 770 }
785 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 771 Handle<JSArray> array = Handle<JSArray>::cast(receiver);
786 ASSERT(!array->map()->is_observed()); 772 ASSERT(!array->map()->is_observed());
787 773
788 int len = Smi::cast(array->length())->value(); 774 int len = Smi::cast(array->length())->value();
789 775
790 int n_arguments = args.length() - 1; 776 int n_arguments = args.length() - 1;
791 777
792 int relative_start = 0; 778 int relative_start = 0;
793 if (n_arguments > 0) { 779 if (n_arguments > 0) {
794 Handle<Object> arg1 = args.at<Object>(1); 780 Object* arg1 = args[1];
795 if (arg1->IsSmi()) { 781 if (arg1->IsSmi()) {
796 relative_start = Handle<Smi>::cast(arg1)->value(); 782 relative_start = Smi::cast(arg1)->value();
797 } else if (arg1->IsHeapNumber()) { 783 } else if (arg1->IsHeapNumber()) {
798 double start = Handle<HeapNumber>::cast(arg1)->value(); 784 double start = HeapNumber::cast(arg1)->value();
799 if (start < kMinInt || start > kMaxInt) { 785 if (start < kMinInt || start > kMaxInt) {
800 return CallJsBuiltin(isolate, "ArraySplice", args); 786 return CallJsBuiltin(isolate, "ArraySplice", args);
801 } 787 }
802 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); 788 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
803 } else if (!arg1->IsUndefined()) { 789 } else if (!arg1->IsUndefined()) {
804 return CallJsBuiltin(isolate, "ArraySplice", args); 790 return CallJsBuiltin(isolate, "ArraySplice", args);
805 } 791 }
806 } 792 }
807 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 793 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
808 : Min(relative_start, len); 794 : Min(relative_start, len);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 835
850 Handle<JSArray> result_array = 836 Handle<JSArray> result_array =
851 isolate->factory()->NewJSArray(elements_kind, 837 isolate->factory()->NewJSArray(elements_kind,
852 actual_delete_count, 838 actual_delete_count,
853 actual_delete_count); 839 actual_delete_count);
854 840
855 if (actual_delete_count > 0) { 841 if (actual_delete_count > 0) {
856 DisallowHeapAllocation no_gc; 842 DisallowHeapAllocation no_gc;
857 ElementsAccessor* accessor = array->GetElementsAccessor(); 843 ElementsAccessor* accessor = array->GetElementsAccessor();
858 accessor->CopyElements( 844 accessor->CopyElements(
859 Handle<JSObject>::null(), actual_start, elements_kind, 845 elms_obj, actual_start, elements_kind,
860 handle(result_array->elements()), 0, actual_delete_count, elms_obj); 846 handle(result_array->elements(), isolate), 0, actual_delete_count);
861 } 847 }
862 848
863 bool elms_changed = false; 849 bool elms_changed = false;
864 if (item_count < actual_delete_count) { 850 if (item_count < actual_delete_count) {
865 // Shrink the array. 851 // Shrink the array.
866 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) && 852 const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
867 ((actual_start + item_count) < 853 ((actual_start + item_count) <
868 (len - actual_delete_count - actual_start)); 854 (len - actual_delete_count - actual_start));
869 if (trim_array) { 855 if (trim_array) {
870 const int delta = actual_delete_count - item_count; 856 const int delta = actual_delete_count - item_count;
871 857
872 if (elms_obj->IsFixedDoubleArray()) { 858 if (elms_obj->IsFixedDoubleArray()) {
873 Handle<FixedDoubleArray> elms = 859 Handle<FixedDoubleArray> elms =
874 Handle<FixedDoubleArray>::cast(elms_obj); 860 Handle<FixedDoubleArray>::cast(elms_obj);
875 MoveDoubleElements(*elms, delta, *elms, 0, actual_start); 861 MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
876 } else { 862 } else {
877 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); 863 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
878 DisallowHeapAllocation no_gc; 864 DisallowHeapAllocation no_gc;
879 heap->MoveElements(*elms, delta, 0, actual_start); 865 heap->MoveElements(*elms, delta, 0, actual_start);
880 } 866 }
881 867
882 if (heap->CanMoveObjectStart(*elms_obj)) { 868 if (heap->CanMoveObjectStart(*elms_obj)) {
883 // On the fast path we move the start of the object in memory. 869 // On the fast path we move the start of the object in memory.
884 elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta)); 870 elms_obj = handle(LeftTrimFixedArray(heap, *elms_obj, delta), isolate);
885 } else { 871 } else {
886 // This is the slow path. We are going to move the elements to the left 872 // This is the slow path. We are going to move the elements to the left
887 // by copying them. For trimmed values we store the hole. 873 // by copying them. For trimmed values we store the hole.
888 if (elms_obj->IsFixedDoubleArray()) { 874 if (elms_obj->IsFixedDoubleArray()) {
889 Handle<FixedDoubleArray> elms = 875 Handle<FixedDoubleArray> elms =
890 Handle<FixedDoubleArray>::cast(elms_obj); 876 Handle<FixedDoubleArray>::cast(elms_obj);
891 MoveDoubleElements(*elms, 0, *elms, delta, len - delta); 877 MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
892 elms->FillWithHoles(len - delta, len); 878 elms->FillWithHoles(len - delta, len);
893 } else { 879 } else {
894 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); 880 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
928 Handle<FixedArray> new_elms = 914 Handle<FixedArray> new_elms =
929 isolate->factory()->NewUninitializedFixedArray(capacity); 915 isolate->factory()->NewUninitializedFixedArray(capacity);
930 916
931 DisallowHeapAllocation no_gc; 917 DisallowHeapAllocation no_gc;
932 918
933 ElementsKind kind = array->GetElementsKind(); 919 ElementsKind kind = array->GetElementsKind();
934 ElementsAccessor* accessor = array->GetElementsAccessor(); 920 ElementsAccessor* accessor = array->GetElementsAccessor();
935 if (actual_start > 0) { 921 if (actual_start > 0) {
936 // Copy the part before actual_start as is. 922 // Copy the part before actual_start as is.
937 accessor->CopyElements( 923 accessor->CopyElements(
938 Handle<JSObject>::null(), 0, kind, new_elms, 0, actual_start, elms); 924 elms, 0, kind, new_elms, 0, actual_start);
939 } 925 }
940 accessor->CopyElements( 926 accessor->CopyElements(
941 Handle<JSObject>::null(), actual_start + actual_delete_count, kind, 927 elms, actual_start + actual_delete_count, kind,
942 new_elms, actual_start + item_count, 928 new_elms, actual_start + item_count,
943 ElementsAccessor::kCopyToEndAndInitializeToHole, elms); 929 ElementsAccessor::kCopyToEndAndInitializeToHole);
944 930
945 elms_obj = new_elms; 931 elms_obj = new_elms;
946 elms_changed = true; 932 elms_changed = true;
947 } else { 933 } else {
948 DisallowHeapAllocation no_gc; 934 DisallowHeapAllocation no_gc;
949 heap->MoveElements(*elms, actual_start + item_count, 935 heap->MoveElements(*elms, actual_start + item_count,
950 actual_start + actual_delete_count, 936 actual_start + actual_delete_count,
951 (len - actual_delete_count - actual_start)); 937 (len - actual_delete_count - actual_start));
952 } 938 }
953 } 939 }
(...skipping 23 matching lines...) Expand all
977 // Set the length. 963 // Set the length.
978 array->set_length(Smi::FromInt(new_length)); 964 array->set_length(Smi::FromInt(new_length));
979 965
980 return *result_array; 966 return *result_array;
981 } 967 }
982 968
983 969
984 BUILTIN(ArrayConcat) { 970 BUILTIN(ArrayConcat) {
985 HandleScope scope(isolate); 971 HandleScope scope(isolate);
986 Heap* heap = isolate->heap(); 972 Heap* heap = isolate->heap();
987 Handle<Context> native_context(isolate->context()->native_context()); 973 Handle<Context> native_context(isolate->context()->native_context(), isolate);
988 Handle<JSObject> array_proto( 974 Handle<JSObject> array_proto(
989 JSObject::cast(native_context->array_function()->prototype())); 975 JSObject::cast(native_context->array_function()->prototype()), isolate);
990 if (!ArrayPrototypeHasNoElements(heap, *native_context, *array_proto)) { 976 if (!ArrayPrototypeHasNoElements(heap, *native_context, *array_proto)) {
991 return CallJsBuiltin(isolate, "ArrayConcat", args); 977 return CallJsBuiltin(isolate, "ArrayConcat", args);
992 } 978 }
993 979
994 // Iterate through all the arguments performing checks 980 // Iterate through all the arguments performing checks
995 // and calculating total length. 981 // and calculating total length.
996 int n_arguments = args.length(); 982 int n_arguments = args.length();
997 int result_len = 0; 983 int result_len = 0;
998 ElementsKind elements_kind = GetInitialFastElementsKind(); 984 ElementsKind elements_kind = GetInitialFastElementsKind();
999 bool has_double = false; 985 bool has_double = false;
1000 bool is_holey = false; 986 bool is_holey = false;
1001 for (int i = 0; i < n_arguments; i++) { 987 for (int i = 0; i < n_arguments; i++) {
1002 Handle<Object> arg = args.at<Object>(i); 988 DisallowHeapAllocation no_gc;
989 Object* arg = args[i];
1003 if (!arg->IsJSArray() || 990 if (!arg->IsJSArray() ||
1004 !Handle<JSArray>::cast(arg)->HasFastElements() || 991 !JSArray::cast(arg)->HasFastElements() ||
1005 Handle<JSArray>::cast(arg)->GetPrototype() != *array_proto) { 992 JSArray::cast(arg)->GetPrototype() != *array_proto) {
1006 return CallJsBuiltin(isolate, "ArrayConcat", args); 993 return CallJsBuiltin(isolate, "ArrayConcat", args);
1007 } 994 }
1008 int len = Smi::cast(Handle<JSArray>::cast(arg)->length())->value(); 995 int len = Smi::cast(JSArray::cast(arg)->length())->value();
1009 996
1010 // We shouldn't overflow when adding another len. 997 // We shouldn't overflow when adding another len.
1011 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 998 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1012 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 999 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1013 USE(kHalfOfMaxInt); 1000 USE(kHalfOfMaxInt);
1014 result_len += len; 1001 result_len += len;
1015 ASSERT(result_len >= 0); 1002 ASSERT(result_len >= 0);
1016 1003
1017 if (result_len > FixedDoubleArray::kMaxLength) { 1004 if (result_len > FixedDoubleArray::kMaxLength) {
1018 return CallJsBuiltin(isolate, "ArrayConcat", args); 1005 return CallJsBuiltin(isolate, "ArrayConcat", args);
1019 } 1006 }
1020 1007
1021 ElementsKind arg_kind = Handle<JSArray>::cast(arg)->map()->elements_kind(); 1008 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
1022 has_double = has_double || IsFastDoubleElementsKind(arg_kind); 1009 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
1023 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); 1010 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
1024 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { 1011 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
1025 elements_kind = arg_kind; 1012 elements_kind = arg_kind;
1026 } 1013 }
1027 } 1014 }
1028 1015
1029 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); 1016 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
1030 1017
1031 // If a double array is concatted into a fast elements array, the fast 1018 // If a double array is concatted into a fast elements array, the fast
1032 // elements array needs to be initialized to contain proper holes, since 1019 // elements array needs to be initialized to contain proper holes, since
1033 // boxing doubles may cause incremental marking. 1020 // boxing doubles may cause incremental marking.
1034 ArrayStorageAllocationMode mode = 1021 ArrayStorageAllocationMode mode =
1035 has_double && IsFastObjectElementsKind(elements_kind) 1022 has_double && IsFastObjectElementsKind(elements_kind)
1036 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS; 1023 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
1037 Handle<JSArray> result_array = 1024 Handle<JSArray> result_array =
1038 isolate->factory()->NewJSArray(elements_kind, 1025 isolate->factory()->NewJSArray(elements_kind,
1039 result_len, 1026 result_len,
1040 result_len, 1027 result_len,
1041 mode); 1028 mode);
1042 if (result_len == 0) return *result_array; 1029 if (result_len == 0) return *result_array;
1043 1030
1044 int j = 0; 1031 int j = 0;
1045 Handle<FixedArrayBase> storage(result_array->elements()); 1032 Handle<FixedArrayBase> storage(result_array->elements(), isolate);
1046 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); 1033 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
1047 for (int i = 0; i < n_arguments; i++) { 1034 for (int i = 0; i < n_arguments; i++) {
1048 Handle<JSArray> array = args.at<JSArray>(i); 1035 // It is crucial to keep |array| as a raw pointer to avoid performance
1036 // degradation.
1037 JSArray* array = JSArray::cast(args[i]);
1049 int len = Smi::cast(array->length())->value(); 1038 int len = Smi::cast(array->length())->value();
1050 ElementsKind from_kind = array->GetElementsKind(); 1039 ElementsKind from_kind = array->GetElementsKind();
1051 if (len > 0) { 1040 if (len > 0) {
1052 accessor->CopyElements(array, 0, from_kind, storage, j, len); 1041 accessor->CopyElements(array, 0, from_kind, storage, j, len);
1053 j += len; 1042 j += len;
1054 } 1043 }
1055 } 1044 }
1056 1045
1057 ASSERT(j == result_len); 1046 ASSERT(j == result_len);
1058 1047
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after
1719 } 1708 }
1720 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 1709 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1721 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 1710 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1722 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) 1711 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
1723 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 1712 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1724 #undef DEFINE_BUILTIN_ACCESSOR_C 1713 #undef DEFINE_BUILTIN_ACCESSOR_C
1725 #undef DEFINE_BUILTIN_ACCESSOR_A 1714 #undef DEFINE_BUILTIN_ACCESSOR_A
1726 1715
1727 1716
1728 } } // namespace v8::internal 1717 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/elements.h » ('j') | src/factory.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698