| 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 |