OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |