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

Side by Side Diff: src/builtins.cc

Issue 618002: Introduce Array.splice builtin. (Closed)
Patch Set: Proper restore Created 10 years, 10 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
« no previous file with comments | « src/builtins.h ('k') | test/mjsunit/array-splice.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 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 401 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 for (int i = 0; i < to_add; i++) { 412 for (int i = 0; i < to_add; i++) {
413 elms->set(i, args[i + 1], mode); 413 elms->set(i, args[i + 1], mode);
414 } 414 }
415 415
416 // Set the length. 416 // Set the length.
417 array->set_length(Smi::FromInt(new_length)); 417 array->set_length(Smi::FromInt(new_length));
418 return Smi::FromInt(new_length); 418 return Smi::FromInt(new_length);
419 } 419 }
420 420
421 421
422 static Object* SlowArraySlice(Handle<Object> receiver, 422 static Object* CallJsBuiltin(const char* name,
423 Object** arg0, 423 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
424 Object** arg1 = NULL) {
425 HandleScope handleScope; 424 HandleScope handleScope;
426 425
427 Handle<Object> slow_slice = 426 Handle<Object> js_builtin =
428 GetProperty(Handle<JSObject>(Top::global_context()->builtins()), 427 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
429 "ArraySlice"); 428 name);
430 ASSERT(slow_slice->IsJSFunction()); 429 ASSERT(js_builtin->IsJSFunction());
431 Handle<JSFunction> function(Handle<JSFunction>::cast(slow_slice)); 430 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
432 Object** args[] = { arg0, arg1 }; 431 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
432 int n_args = args.length() - 1;
433 for (int i = 0; i < n_args; i++) {
434 argv[i] = &args[i + 1];
435 }
433 bool pending_exception = false; 436 bool pending_exception = false;
434 Handle<Object> result = Execution::Call(function, 437 Handle<Object> result = Execution::Call(function,
435 receiver, 438 args.receiver(),
436 arg1 == NULL ? 1 : 2, 439 n_args,
437 args, 440 argv.start(),
438 &pending_exception); 441 &pending_exception);
439 if (pending_exception) return Failure::Exception(); 442 if (pending_exception) return Failure::Exception();
440 return *result; 443 return *result;
441 } 444 }
442 445
443 446
444 BUILTIN(ArraySlice) { 447 BUILTIN(ArraySlice) {
445 JSArray* array = JSArray::cast(*args.receiver()); 448 JSArray* array = JSArray::cast(*args.receiver());
446 ASSERT(array->HasFastElements()); 449 ASSERT(array->HasFastElements());
447 450
448 int len = Smi::cast(array->length())->value(); 451 int len = Smi::cast(array->length())->value();
449 452
450 int n_arguments = args.length() - 1; 453 int n_arguments = args.length() - 1;
451 454
452 // Note carefully choosen defaults---if argument is missing, 455 // Note carefully choosen defaults---if argument is missing,
453 // it's undefined which gets converted to 0 for relativeStart 456 // it's undefined which gets converted to 0 for relativeStart
454 // and to len for relativeEnd. 457 // and to len for relativeEnd.
455 int relativeStart = 0; 458 int relativeStart = 0;
456 int relativeEnd = len; 459 int relativeEnd = len;
457 if (n_arguments > 0) { 460 if (n_arguments > 0) {
458 Object* arg1 = args[1]; 461 Object* arg1 = args[1];
459 if (arg1->IsSmi()) { 462 if (arg1->IsSmi()) {
460 relativeStart = Smi::cast(arg1)->value(); 463 relativeStart = Smi::cast(arg1)->value();
461 } else if (!arg1->IsUndefined()) { 464 } else if (!arg1->IsUndefined()) {
462 if (n_arguments > 1) { 465 return CallJsBuiltin("ArraySlice", args);
463 return SlowArraySlice(args.receiver(), &args[1], &args[2]);
464 } else {
465 return SlowArraySlice(args.receiver(), &args[1]);
466 }
467 } 466 }
468 if (n_arguments > 1) { 467 if (n_arguments > 1) {
469 Object* arg2 = args[2]; 468 Object* arg2 = args[2];
470 if (arg2->IsSmi()) { 469 if (arg2->IsSmi()) {
471 relativeEnd = Smi::cast(arg2)->value(); 470 relativeEnd = Smi::cast(arg2)->value();
472 } else if (!arg2->IsUndefined()) { 471 } else if (!arg2->IsUndefined()) {
473 return SlowArraySlice(args.receiver(), &args[1], &args[2]); 472 return CallJsBuiltin("ArraySlice", args);
474 } 473 }
475 } 474 }
476 } 475 }
477 476
478 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 477 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
479 int k = (relativeStart < 0) ? Max(len + relativeStart, 0) 478 int k = (relativeStart < 0) ? Max(len + relativeStart, 0)
480 : Min(relativeStart, len); 479 : Min(relativeStart, len);
481 480
482 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 481 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
483 int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0) 482 int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 515
517 // Set elements. 516 // Set elements.
518 result_array->set_elements(result_elms); 517 result_array->set_elements(result_elms);
519 518
520 // Set the length. 519 // Set the length.
521 result_array->set_length(Smi::FromInt(result_len)); 520 result_array->set_length(Smi::FromInt(result_len));
522 return result_array; 521 return result_array;
523 } 522 }
524 523
525 524
525 BUILTIN(ArraySplice) {
526 JSArray* array = JSArray::cast(*args.receiver());
527 ASSERT(array->HasFastElements());
528
529 int len = Smi::cast(array->length())->value();
530
531 int n_arguments = args.length() - 1;
532
533 // SpiderMonkey and JSC return undefined in the case where no
534 // arguments are given instead of using the implicit undefined
535 // arguments. This does not follow ECMA-262, but we do the same for
536 // compatibility.
537 // TraceMonkey follows ECMA-262 though.
538 if (n_arguments == 0) {
539 return Heap::undefined_value();
540 }
541
542 int relativeStart = 0;
543 Object* arg1 = args[1];
544 if (arg1->IsSmi()) {
545 relativeStart = Smi::cast(arg1)->value();
546 } else if (!arg1->IsUndefined()) {
547 return CallJsBuiltin("ArraySplice", args);
548 }
549 int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0)
550 : Min(relativeStart, len);
551
552 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
553 // given differently from when an undefined delete count is given.
554 // This does not follow ECMA-262, but we do the same for
555 // compatibility.
556 int deleteCount = len;
557 if (n_arguments > 1) {
558 Object* arg2 = args[2];
559 if (arg2->IsSmi()) {
560 deleteCount = Smi::cast(arg2)->value();
561 } else {
562 return CallJsBuiltin("ArraySplice", args);
563 }
564 }
565 int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart);
566
567 JSFunction* array_function =
568 Top::context()->global_context()->array_function();
569
570 // Allocate result array.
571 Object* result = Heap::AllocateJSObject(array_function);
572 if (result->IsFailure()) return result;
573 JSArray* result_array = JSArray::cast(result);
574
575 result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount);
576 if (result->IsFailure()) return result;
577 FixedArray* result_elms = FixedArray::cast(result);
578
579 FixedArray* elms = FixedArray::cast(array->elements());
580
581 // Fetch the prototype.
582 JSObject* prototype = JSObject::cast(array_function->prototype());
583
584 AssertNoAllocation no_gc;
585 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
586
587 // Fill newly created array.
588 for (int k = 0; k < actualDeleteCount; k++) {
589 result_elms->set(k,
590 GetElementToMove(actualStart + k, elms, prototype),
591 mode);
592 }
593
594 // Set elements.
595 result_array->set_elements(result_elms);
596
597 // Set the length.
598 result_array->set_length(Smi::FromInt(actualDeleteCount));
599
600 int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0;
601
602 int new_length = len - actualDeleteCount + itemCount;
603
604 mode = elms->GetWriteBarrierMode(no_gc);
605 if (itemCount < actualDeleteCount) {
606 // Shrink the array.
607 for (int k = actualStart; k < (len - actualDeleteCount); k++) {
608 elms->set(k + itemCount,
609 GetElementToMove(k + actualDeleteCount, elms, prototype),
610 mode);
611 }
612
613 for (int k = len; k > new_length; k--) {
614 elms->set(k - 1, Heap::the_hole_value());
615 }
616 } else if (itemCount > actualDeleteCount) {
617 FixedArray* source_elms = elms;
618
619 // Check if array need to grow.
620 if (new_length > elms->length()) {
621 // New backing storage is needed.
622 int capacity = new_length + (new_length >> 1) + 16;
623 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
624 if (obj->IsFailure()) return obj;
625
626 FixedArray* new_elms = FixedArray::cast(obj);
627 mode = new_elms->GetWriteBarrierMode(no_gc);
628
629 // Copy the part before actualStart as is.
630 for (int k = 0; k < actualStart; k++) {
631 new_elms->set(k, elms->get(k), mode);
632 }
633
634 source_elms = elms;
635 elms = new_elms;
636 array->set_elements(elms);
637 }
638
639 for (int k = len - actualDeleteCount; k > actualStart; k--) {
640 elms->set(k + itemCount - 1,
641 GetElementToMove(k + actualDeleteCount - 1,
642 source_elms,
643 prototype),
644 mode);
645 }
646 }
647
648 for (int k = actualStart; k < actualStart + itemCount; k++) {
649 elms->set(k, args[3 + k - actualStart], mode);
650 }
651
652 // Set the length.
653 array->set_length(Smi::FromInt(new_length));
654
655 return result_array;
656 }
657
658
526 // ----------------------------------------------------------------------------- 659 // -----------------------------------------------------------------------------
527 // 660 //
528 661
529 662
530 // Returns the holder JSObject if the function can legally be called 663 // Returns the holder JSObject if the function can legally be called
531 // with this receiver. Returns Heap::null_value() if the call is 664 // with this receiver. Returns Heap::null_value() if the call is
532 // illegal. Any arguments that don't fit the expected type is 665 // illegal. Any arguments that don't fit the expected type is
533 // overwritten with undefined. Arguments that do fit the expected 666 // overwritten with undefined. Arguments that do fit the expected
534 // type is overwritten with the object in the prototype chain that 667 // type is overwritten with the object in the prototype chain that
535 // actually has that type. 668 // actually has that type.
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
1162 if (entry->contains(pc)) { 1295 if (entry->contains(pc)) {
1163 return names_[i]; 1296 return names_[i];
1164 } 1297 }
1165 } 1298 }
1166 } 1299 }
1167 return NULL; 1300 return NULL;
1168 } 1301 }
1169 1302
1170 1303
1171 } } // namespace v8::internal 1304 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/builtins.h ('k') | test/mjsunit/array-splice.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698