| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 4 // |
| 5 // The intrinsic code below is executed before a method has built its frame. | 5 // The intrinsic code below is executed before a method has built its frame. |
| 6 // The return address is on the stack and the arguments below it. | 6 // The return address is on the stack and the arguments below it. |
| 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. | 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. |
| 8 // Each intrinsification method returns true if the corresponding | 8 // Each intrinsification method returns true if the corresponding |
| 9 // Dart method was intrinsified. | 9 // Dart method was intrinsified. |
| 10 | 10 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 ECX); | 242 ECX); |
| 243 // Caller is responsible of preserving the value if necessary. | 243 // Caller is responsible of preserving the value if necessary. |
| 244 __ ret(); | 244 __ ret(); |
| 245 __ Bind(&fall_through); | 245 __ Bind(&fall_through); |
| 246 return false; | 246 return false; |
| 247 } | 247 } |
| 248 | 248 |
| 249 | 249 |
| 250 // Allocate a GrowableObjectArray using the backing array specified. | 250 // Allocate a GrowableObjectArray using the backing array specified. |
| 251 // On stack: type argument (+2), data (+1), return-address (+0). | 251 // On stack: type argument (+2), data (+1), return-address (+0). |
| 252 bool Intrinsifier::GArray_Allocate(Assembler* assembler) { | 252 bool Intrinsifier::GrowableArray_Allocate(Assembler* assembler) { |
| 253 // This snippet of inlined code uses the following registers: | 253 // This snippet of inlined code uses the following registers: |
| 254 // EAX, EBX | 254 // EAX, EBX |
| 255 // and the newly allocated object is returned in EAX. | 255 // and the newly allocated object is returned in EAX. |
| 256 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; | 256 const intptr_t kTypeArgumentsOffset = 2 * kWordSize; |
| 257 const intptr_t kArrayOffset = 1 * kWordSize; | 257 const intptr_t kArrayOffset = 1 * kWordSize; |
| 258 Label fall_through; | 258 Label fall_through; |
| 259 | 259 |
| 260 // Compute the size to be allocated, it is based on the array length | 260 // Compute the size to be allocated, it is based on the array length |
| 261 // and is computed as: | 261 // and is computed as: |
| 262 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + | 262 // RoundedAllocationSize(sizeof(RawGrowableObjectArray)) + |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 | 461 |
| 462 // Gets the length of a ByteArray. | 462 // Gets the length of a ByteArray. |
| 463 bool Intrinsifier::ByteArrayBase_getLength(Assembler* assembler) { | 463 bool Intrinsifier::ByteArrayBase_getLength(Assembler* assembler) { |
| 464 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 464 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 465 __ movl(EAX, FieldAddress(EAX, ByteArray::length_offset())); | 465 __ movl(EAX, FieldAddress(EAX, ByteArray::length_offset())); |
| 466 __ ret(); | 466 __ ret(); |
| 467 return true; | 467 return true; |
| 468 } | 468 } |
| 469 | 469 |
| 470 | 470 |
| 471 // Tests if index is a valid length (Smi and within valid index range), | |
| 472 // jumps to fall_through if it is not. | |
| 473 // Returns index in EBX, array in EAX. | |
| 474 // This should be used only on getIndexed intrinsics. | |
| 475 static void TestByteArrayGetIndex(Assembler* assembler, Label* fall_through) { | |
| 476 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Array. | |
| 477 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Index. | |
| 478 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 479 __ j(NOT_ZERO, fall_through, Assembler::kNearJump); // Non-smi index. | |
| 480 // Range check. | |
| 481 __ cmpl(EBX, FieldAddress(EAX, ByteArray::length_offset())); | |
| 482 // Runtime throws exception. | |
| 483 __ j(ABOVE_EQUAL, fall_through, Assembler::kNearJump); | |
| 484 } | |
| 485 | |
| 486 | |
| 487 // Tests if index is a valid length (Smi and within valid index range), | |
| 488 // jumps to fall_through if it is not. | |
| 489 // Returns index in EBX, array in EAX. | |
| 490 // This should be used only for setIndexed intrinsics. | |
| 491 static void TestByteArraySetIndex(Assembler* assembler, Label* fall_through) { | |
| 492 __ movl(EAX, Address(ESP, + 3 * kWordSize)); // Array. | |
| 493 __ movl(EBX, Address(ESP, + 2 * kWordSize)); // Index. | |
| 494 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 495 __ j(NOT_ZERO, fall_through, Assembler::kNearJump); // Non-smi index. | |
| 496 // Range check. | |
| 497 __ cmpl(EBX, FieldAddress(EAX, ByteArray::length_offset())); | |
| 498 // Runtime throws exception. | |
| 499 __ j(ABOVE_EQUAL, fall_through, Assembler::kNearJump); | |
| 500 } | |
| 501 | |
| 502 | |
| 503 bool Intrinsifier::Int8Array_getIndexed(Assembler* assembler) { | |
| 504 Label fall_through; | |
| 505 TestByteArrayGetIndex(assembler, &fall_through); | |
| 506 // EBX: index as Smi. | |
| 507 // EAX: array. | |
| 508 __ SmiUntag(EBX); | |
| 509 __ movsxb(EAX, FieldAddress(EAX, | |
| 510 EBX, | |
| 511 TIMES_1, | |
| 512 Int8Array::data_offset())); | |
| 513 __ SmiTag(EAX); | |
| 514 __ ret(); | |
| 515 __ Bind(&fall_through); | |
| 516 return false; | |
| 517 } | |
| 518 | |
| 519 | |
| 520 bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) { | |
| 521 Label fall_through; | |
| 522 TestByteArraySetIndex(assembler, &fall_through); | |
| 523 // EBX: index as Smi. | |
| 524 // EAX: array. | |
| 525 __ SmiUntag(EBX); | |
| 526 // Free EBX for the value since we want a byte register. | |
| 527 __ movl(EDI, EBX); | |
| 528 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 529 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 530 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | |
| 531 __ SmiUntag(EBX); | |
| 532 // Check that the value is a byte. Add 128 to EBX to bring it into | |
| 533 // the range 0..FF. | |
| 534 __ addl(EBX, Immediate(128)); | |
| 535 __ cmpl(EBX, Immediate(0xFF)); | |
| 536 __ j(ABOVE, &fall_through, Assembler::kNearJump); | |
| 537 // Undo addition. | |
| 538 __ subl(EBX, Immediate(128)); | |
| 539 __ movb(FieldAddress(EAX, EDI, TIMES_1, Int8Array::data_offset()), BL); | |
| 540 __ ret(); | |
| 541 __ Bind(&fall_through); | |
| 542 return false; | |
| 543 } | |
| 544 | |
| 545 | |
| 546 #define TYPED_ARRAY_ALLOCATION(type_name, scale_factor) \ | 471 #define TYPED_ARRAY_ALLOCATION(type_name, scale_factor) \ |
| 547 Label fall_through; \ | 472 Label fall_through; \ |
| 548 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ | 473 const intptr_t kArrayLengthStackOffset = 1 * kWordSize; \ |
| 549 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ | 474 __ movl(EDI, Address(ESP, kArrayLengthStackOffset)); /* Array length. */ \ |
| 550 /* Check that length is a positive Smi. */ \ | 475 /* Check that length is a positive Smi. */ \ |
| 551 /* EDI: requested array length argument. */ \ | 476 /* EDI: requested array length argument. */ \ |
| 552 __ testl(EDI, Immediate(kSmiTagSize)); \ | 477 __ testl(EDI, Immediate(kSmiTagSize)); \ |
| 553 __ j(NOT_ZERO, &fall_through); \ | 478 __ j(NOT_ZERO, &fall_through); \ |
| 554 __ cmpl(EDI, Immediate(0)); \ | 479 __ cmpl(EDI, Immediate(0)); \ |
| 555 __ j(LESS, &fall_through); \ | 480 __ j(LESS, &fall_through); \ |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 __ ret(); \ | 553 __ ret(); \ |
| 629 __ Bind(&fall_through); \ | 554 __ Bind(&fall_through); \ |
| 630 | 555 |
| 631 | 556 |
| 632 bool Intrinsifier::Int8Array_new(Assembler* assembler) { | 557 bool Intrinsifier::Int8Array_new(Assembler* assembler) { |
| 633 TYPED_ARRAY_ALLOCATION(Int8Array, TIMES_1); | 558 TYPED_ARRAY_ALLOCATION(Int8Array, TIMES_1); |
| 634 return false; | 559 return false; |
| 635 } | 560 } |
| 636 | 561 |
| 637 | 562 |
| 638 bool Intrinsifier::Uint8Array_getIndexed(Assembler* assembler) { | |
| 639 Label fall_through; | |
| 640 TestByteArrayGetIndex(assembler, &fall_through); | |
| 641 // EBX: index as Smi. | |
| 642 // EAX: array. | |
| 643 __ SmiUntag(EBX); | |
| 644 __ movzxb(EAX, FieldAddress(EAX, | |
| 645 EBX, | |
| 646 TIMES_1, | |
| 647 Uint8Array::data_offset())); | |
| 648 __ SmiTag(EAX); | |
| 649 __ ret(); | |
| 650 __ Bind(&fall_through); | |
| 651 return false; | |
| 652 } | |
| 653 | |
| 654 | |
| 655 bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) { | |
| 656 Label fall_through; | |
| 657 TestByteArraySetIndex(assembler, &fall_through); | |
| 658 // EBX: index as Smi. | |
| 659 // EAX: array. | |
| 660 __ SmiUntag(EBX); | |
| 661 // Free EBX for the value since we want a byte register. | |
| 662 __ movl(EDI, EBX); | |
| 663 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 664 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 665 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | |
| 666 __ SmiUntag(EBX); | |
| 667 // Check that the value is a byte. | |
| 668 __ cmpl(EBX, Immediate(0xFF)); | |
| 669 __ j(ABOVE, &fall_through, Assembler::kNearJump); | |
| 670 __ movb(FieldAddress(EAX, EDI, TIMES_1, Uint8Array::data_offset()), BL); | |
| 671 __ ret(); | |
| 672 __ Bind(&fall_through); | |
| 673 return false; | |
| 674 } | |
| 675 | |
| 676 | |
| 677 bool Intrinsifier::Uint8Array_new(Assembler* assembler) { | 563 bool Intrinsifier::Uint8Array_new(Assembler* assembler) { |
| 678 TYPED_ARRAY_ALLOCATION(Uint8Array, TIMES_1); | 564 TYPED_ARRAY_ALLOCATION(Uint8Array, TIMES_1); |
| 679 return false; | 565 return false; |
| 680 } | 566 } |
| 681 | 567 |
| 682 | 568 |
| 683 bool Intrinsifier::UintClamped8Array_getIndexed(Assembler* assembler) { | |
| 684 Label fall_through; | |
| 685 TestByteArrayGetIndex(assembler, &fall_through); | |
| 686 // EBX: index as Smi. | |
| 687 // EAX: array. | |
| 688 __ SmiUntag(EBX); | |
| 689 __ movzxb(EAX, FieldAddress(EAX, | |
| 690 EBX, | |
| 691 TIMES_1, | |
| 692 Uint8ClampedArray::data_offset())); | |
| 693 __ SmiTag(EAX); | |
| 694 __ ret(); | |
| 695 __ Bind(&fall_through); | |
| 696 return false; | |
| 697 } | |
| 698 | |
| 699 | |
| 700 bool Intrinsifier::Uint8ClampedArray_setIndexed(Assembler* assembler) { | |
| 701 Label fall_through, store_value, load_0xff; | |
| 702 TestByteArraySetIndex(assembler, &fall_through); | |
| 703 // EBX: index as Smi. | |
| 704 // EAX: array. | |
| 705 __ SmiUntag(EBX); | |
| 706 // Free EBX for the value since we need a byte register. | |
| 707 __ leal(EAX, FieldAddress(EAX, EBX, TIMES_1, | |
| 708 Uint8ClampedArray::data_offset())); | |
| 709 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 710 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 711 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | |
| 712 | |
| 713 __ SmiUntag(EBX); | |
| 714 __ cmpl(EBX, Immediate(0xFF)); | |
| 715 __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump); | |
| 716 // Clamp to 0x00 or 0xFF respectively. | |
| 717 __ j(GREATER, &load_0xff, Assembler::kNearJump); | |
| 718 __ xorl(EBX, EBX); // Zero. | |
| 719 __ jmp(&store_value, Assembler::kNearJump); | |
| 720 __ Bind(&load_0xff); | |
| 721 __ movl(EBX, Immediate(0xFF)); | |
| 722 | |
| 723 __ Bind(&store_value); | |
| 724 __ movb(Address(EAX, 0), BL); | |
| 725 __ ret(); | |
| 726 __ Bind(&fall_through); | |
| 727 return false; | |
| 728 } | |
| 729 | |
| 730 | |
| 731 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) { | 569 bool Intrinsifier::Uint8ClampedArray_new(Assembler* assembler) { |
| 732 TYPED_ARRAY_ALLOCATION(Uint8ClampedArray, TIMES_1); | 570 TYPED_ARRAY_ALLOCATION(Uint8ClampedArray, TIMES_1); |
| 733 return false; | 571 return false; |
| 734 } | 572 } |
| 735 | 573 |
| 736 | 574 |
| 737 bool Intrinsifier::Int16Array_getIndexed(Assembler* assembler) { | |
| 738 Label fall_through; | |
| 739 TestByteArrayGetIndex(assembler, &fall_through); | |
| 740 // EBX: index as Smi. | |
| 741 // EAX: array. | |
| 742 __ movsxw(EAX, FieldAddress(EAX, | |
| 743 EBX, | |
| 744 TIMES_1, | |
| 745 Int16Array::data_offset())); | |
| 746 __ SmiTag(EAX); | |
| 747 __ ret(); | |
| 748 __ Bind(&fall_through); | |
| 749 return false; | |
| 750 } | |
| 751 | |
| 752 | |
| 753 bool Intrinsifier::Int16Array_new(Assembler* assembler) { | 575 bool Intrinsifier::Int16Array_new(Assembler* assembler) { |
| 754 TYPED_ARRAY_ALLOCATION(Int16Array, TIMES_2); | 576 TYPED_ARRAY_ALLOCATION(Int16Array, TIMES_2); |
| 755 return false; | 577 return false; |
| 756 } | 578 } |
| 757 | 579 |
| 758 | 580 |
| 759 bool Intrinsifier::Uint16Array_getIndexed(Assembler* assembler) { | |
| 760 Label fall_through; | |
| 761 TestByteArrayGetIndex(assembler, &fall_through); | |
| 762 // EBX: index as Smi. | |
| 763 // EAX: array. | |
| 764 __ movzxw(EAX, FieldAddress(EAX, | |
| 765 EBX, | |
| 766 TIMES_1, | |
| 767 Uint16Array::data_offset())); | |
| 768 __ SmiTag(EAX); | |
| 769 __ ret(); | |
| 770 __ Bind(&fall_through); | |
| 771 return false; | |
| 772 } | |
| 773 | |
| 774 | |
| 775 bool Intrinsifier::Uint16Array_setIndexed(Assembler* assembler) { | |
| 776 Label fall_through; | |
| 777 TestByteArraySetIndex(assembler, &fall_through); | |
| 778 // EBX: index as Smi. | |
| 779 // EAX: array. | |
| 780 __ movl(EDI, Address(ESP, + 1 * kWordSize)); | |
| 781 __ SmiUntag(EDI); | |
| 782 // EDI: undtagged value. | |
| 783 __ testl(EDI, Immediate(kSmiTagMask)); | |
| 784 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | |
| 785 __ movw(FieldAddress(EAX, EBX, TIMES_1, Uint16Array::data_offset()), EDI); | |
| 786 __ ret(); | |
| 787 __ Bind(&fall_through); | |
| 788 return false; | |
| 789 } | |
| 790 | |
| 791 | |
| 792 bool Intrinsifier::Uint16Array_new(Assembler* assembler) { | 581 bool Intrinsifier::Uint16Array_new(Assembler* assembler) { |
| 793 TYPED_ARRAY_ALLOCATION(Uint16Array, TIMES_2); | 582 TYPED_ARRAY_ALLOCATION(Uint16Array, TIMES_2); |
| 794 return false; | 583 return false; |
| 795 } | 584 } |
| 796 | 585 |
| 797 | 586 |
| 798 bool Intrinsifier::Int32Array_getIndexed(Assembler* assembler) { | |
| 799 Label fall_through; | |
| 800 TestByteArrayGetIndex(assembler, &fall_through); | |
| 801 // EBX: index as Smi. | |
| 802 // EAX: array. | |
| 803 __ movl(EAX, FieldAddress(EAX, | |
| 804 EBX, | |
| 805 TIMES_2, | |
| 806 Int32Array::data_offset())); | |
| 807 // Verify that the signed value in EAX can fit inside a Smi. | |
| 808 __ cmpl(EAX, Immediate(0xC0000000)); | |
| 809 __ j(NEGATIVE, &fall_through, Assembler::kNearJump); // Won't fit Smi. | |
| 810 __ SmiTag(EAX); | |
| 811 __ ret(); | |
| 812 __ Bind(&fall_through); | |
| 813 return false; | |
| 814 } | |
| 815 | |
| 816 | |
| 817 bool Intrinsifier::Int32Array_new(Assembler* assembler) { | 587 bool Intrinsifier::Int32Array_new(Assembler* assembler) { |
| 818 TYPED_ARRAY_ALLOCATION(Int32Array, TIMES_4); | 588 TYPED_ARRAY_ALLOCATION(Int32Array, TIMES_4); |
| 819 return false; | 589 return false; |
| 820 } | 590 } |
| 821 | 591 |
| 822 | 592 |
| 823 bool Intrinsifier::Uint32Array_getIndexed(Assembler* assembler) { | |
| 824 Label fall_through; | |
| 825 TestByteArrayGetIndex(assembler, &fall_through); | |
| 826 // EBX: index as Smi. | |
| 827 // EAX: array. | |
| 828 __ movl(EAX, FieldAddress(EAX, | |
| 829 EBX, | |
| 830 TIMES_2, | |
| 831 Uint32Array::data_offset())); | |
| 832 // Verify that the unsigned value in EAX can be stored in a Smi. | |
| 833 __ testl(EAX, Immediate(0xC0000000)); | |
| 834 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); // Won't fit Smi. | |
| 835 __ SmiTag(EAX); | |
| 836 __ ret(); | |
| 837 __ Bind(&fall_through); | |
| 838 return false; | |
| 839 } | |
| 840 | |
| 841 | |
| 842 bool Intrinsifier::Uint32Array_new(Assembler* assembler) { | 593 bool Intrinsifier::Uint32Array_new(Assembler* assembler) { |
| 843 TYPED_ARRAY_ALLOCATION(Uint32Array, TIMES_4); | 594 TYPED_ARRAY_ALLOCATION(Uint32Array, TIMES_4); |
| 844 return false; | 595 return false; |
| 845 } | 596 } |
| 846 | 597 |
| 847 | 598 |
| 848 bool Intrinsifier::Int64Array_getIndexed(Assembler* assembler) { | 599 bool Intrinsifier::Int64Array_getIndexed(Assembler* assembler) { |
| 849 return false; | 600 return false; |
| 850 } | 601 } |
| 851 | 602 |
| 852 | 603 |
| 853 bool Intrinsifier::Int64Array_new(Assembler* assembler) { | 604 bool Intrinsifier::Int64Array_new(Assembler* assembler) { |
| 854 TYPED_ARRAY_ALLOCATION(Int64Array, TIMES_8); | 605 TYPED_ARRAY_ALLOCATION(Int64Array, TIMES_8); |
| 855 return false; | 606 return false; |
| 856 } | 607 } |
| 857 | 608 |
| 858 | 609 |
| 859 bool Intrinsifier::Uint64Array_getIndexed(Assembler* assembler) { | 610 bool Intrinsifier::Uint64Array_getIndexed(Assembler* assembler) { |
| 860 return false; | 611 return false; |
| 861 } | 612 } |
| 862 | 613 |
| 863 | 614 |
| 864 bool Intrinsifier::Uint64Array_new(Assembler* assembler) { | 615 bool Intrinsifier::Uint64Array_new(Assembler* assembler) { |
| 865 TYPED_ARRAY_ALLOCATION(Uint64Array, TIMES_8); | 616 TYPED_ARRAY_ALLOCATION(Uint64Array, TIMES_8); |
| 866 return false; | 617 return false; |
| 867 } | 618 } |
| 868 | 619 |
| 869 | 620 |
| 870 bool Intrinsifier::Float32Array_getIndexed(Assembler* assembler) { | |
| 871 Label fall_through; | |
| 872 TestByteArrayGetIndex(assembler, &fall_through); | |
| 873 // EBX: index as Smi. | |
| 874 // EAX: array. | |
| 875 // Load single precision float into XMM7. | |
| 876 __ movss(XMM7, FieldAddress(EAX, EBX, TIMES_2, | |
| 877 Float32Array::data_offset())); | |
| 878 // Convert into a double precision float. | |
| 879 __ cvtss2sd(XMM7, XMM7); | |
| 880 // Allocate a double instance. | |
| 881 const Class& double_class = Class::Handle( | |
| 882 Isolate::Current()->object_store()->double_class()); | |
| 883 AssemblerMacros::TryAllocate(assembler, | |
| 884 double_class, | |
| 885 &fall_through, | |
| 886 Assembler::kNearJump, EAX); | |
| 887 // Store XMM7 into double instance. | |
| 888 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM7); | |
| 889 __ ret(); | |
| 890 __ Bind(&fall_through); | |
| 891 | |
| 892 return false; | |
| 893 } | |
| 894 | |
| 895 | |
| 896 bool Intrinsifier::Float32Array_setIndexed(Assembler* assembler) { | |
| 897 Label fall_through; | |
| 898 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 899 // If EAX is not an instance of double, jump to fall through. | |
| 900 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 901 __ j(ZERO, &fall_through); | |
| 902 __ CompareClassId(EAX, kDoubleCid, EDI); | |
| 903 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | |
| 904 // Load double value into XMM7. | |
| 905 __ movsd(XMM7, FieldAddress(EAX, Double::value_offset())); | |
| 906 TestByteArraySetIndex(assembler, &fall_through); | |
| 907 // EBX: index as Smi. | |
| 908 // EAX: array. | |
| 909 // Convert from double precision float to single precision float. | |
| 910 __ cvtsd2ss(XMM7, XMM7); | |
| 911 // Store into array. | |
| 912 __ movss(FieldAddress(EAX, EBX, TIMES_2, Float32Array::data_offset()), XMM7); | |
| 913 // End fast path. | |
| 914 __ ret(); | |
| 915 __ Bind(&fall_through); | |
| 916 return false; | |
| 917 } | |
| 918 | |
| 919 | |
| 920 bool Intrinsifier::Float32Array_new(Assembler* assembler) { | 621 bool Intrinsifier::Float32Array_new(Assembler* assembler) { |
| 921 TYPED_ARRAY_ALLOCATION(Float32Array, TIMES_4); | 622 TYPED_ARRAY_ALLOCATION(Float32Array, TIMES_4); |
| 922 return false; | 623 return false; |
| 923 } | 624 } |
| 924 | 625 |
| 925 | 626 |
| 926 bool Intrinsifier::Float64Array_getIndexed(Assembler* assembler) { | |
| 927 Label fall_through; | |
| 928 TestByteArrayGetIndex(assembler, &fall_through); | |
| 929 // EBX: index as Smi. | |
| 930 // EAX: array. | |
| 931 // Load double precision float into XMM7. | |
| 932 __ movsd(XMM7, FieldAddress(EAX, EBX, TIMES_4, | |
| 933 Float64Array::data_offset())); | |
| 934 // Allocate a double instance. | |
| 935 const Class& double_class = Class::Handle( | |
| 936 Isolate::Current()->object_store()->double_class()); | |
| 937 AssemblerMacros::TryAllocate(assembler, | |
| 938 double_class, | |
| 939 &fall_through, | |
| 940 Assembler::kNearJump, EAX); | |
| 941 // Store XMM7 into double instance. | |
| 942 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM7); | |
| 943 __ ret(); | |
| 944 __ Bind(&fall_through); | |
| 945 return false; | |
| 946 } | |
| 947 | |
| 948 | |
| 949 bool Intrinsifier::Float64Array_setIndexed(Assembler* assembler) { | |
| 950 Label fall_through; | |
| 951 __ movl(EAX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 952 // If EAX is not an instance of double, jump to fall through. | |
| 953 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 954 __ j(ZERO, &fall_through, Assembler::kNearJump); | |
| 955 __ CompareClassId(EAX, kDoubleCid, EDI); | |
| 956 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | |
| 957 // Load double value into XMM7. | |
| 958 __ movsd(XMM7, FieldAddress(EAX, Double::value_offset())); | |
| 959 TestByteArraySetIndex(assembler, &fall_through); | |
| 960 // EBX: index as Smi. | |
| 961 // EAX: array. | |
| 962 __ movsd(FieldAddress(EAX, EBX, TIMES_4, Float64Array::data_offset()), XMM7); | |
| 963 __ ret(); | |
| 964 __ Bind(&fall_through); | |
| 965 return false; | |
| 966 } | |
| 967 | |
| 968 | |
| 969 bool Intrinsifier::Float64Array_new(Assembler* assembler) { | 627 bool Intrinsifier::Float64Array_new(Assembler* assembler) { |
| 970 TYPED_ARRAY_ALLOCATION(Float64Array, TIMES_8); | 628 TYPED_ARRAY_ALLOCATION(Float64Array, TIMES_8); |
| 971 return false; | 629 return false; |
| 972 } | 630 } |
| 973 | 631 |
| 974 | 632 |
| 975 bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) { | |
| 976 Label fall_through; | |
| 977 TestByteArrayGetIndex(assembler, &fall_through); | |
| 978 // EBX: index as Smi. | |
| 979 // EAX: array. | |
| 980 __ SmiUntag(EBX); | |
| 981 __ movl(EAX, FieldAddress(EAX, ExternalUint8Array::data_offset())); | |
| 982 __ movzxb(EAX, Address(EAX, EBX, TIMES_1, 0)); | |
| 983 __ SmiTag(EAX); | |
| 984 __ ret(); | |
| 985 __ Bind(&fall_through); | |
| 986 return false; | |
| 987 } | |
| 988 | |
| 989 | |
| 990 bool Intrinsifier::ExternalUint8ClampedArray_getIndexed(Assembler* assembler) { | |
| 991 Label fall_through; | |
| 992 TestByteArrayGetIndex(assembler, &fall_through); | |
| 993 // EBX: index as Smi. | |
| 994 // EAX: array. | |
| 995 __ SmiUntag(EBX); | |
| 996 __ movl(EAX, FieldAddress(EAX, ExternalUint8ClampedArray::data_offset())); | |
| 997 __ movzxb(EAX, Address(EAX, EBX, TIMES_1, 0)); | |
| 998 __ SmiTag(EAX); | |
| 999 __ ret(); | |
| 1000 __ Bind(&fall_through); | |
| 1001 return false; | |
| 1002 } | |
| 1003 | |
| 1004 | |
| 1005 bool Intrinsifier::ExternalUint8ClampedArray_setIndexed(Assembler* assembler) { | |
| 1006 Label fall_through, store_value, load_0xff; | |
| 1007 TestByteArraySetIndex(assembler, &fall_through); | |
| 1008 // EBX: index as Smi. | |
| 1009 // EAX: array. | |
| 1010 __ SmiUntag(EBX); | |
| 1011 __ movl(EAX, FieldAddress(EAX, ExternalUint8ClampedArray::data_offset())); | |
| 1012 // Free EBX for the value since we need a byte register. | |
| 1013 __ leal(EAX, Address(EAX, EBX, TIMES_1, 0)); | |
| 1014 __ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value. | |
| 1015 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 1016 __ j(NOT_ZERO, &fall_through, Assembler::kNearJump); | |
| 1017 | |
| 1018 __ SmiUntag(EBX); | |
| 1019 __ cmpl(EBX, Immediate(0xFF)); | |
| 1020 __ j(BELOW_EQUAL, &store_value, Assembler::kNearJump); | |
| 1021 // Clamp to 0x00 or 0xFF respectively. | |
| 1022 __ j(GREATER, &load_0xff, Assembler::kNearJump); | |
| 1023 __ xorl(EBX, EBX); // Zero. | |
| 1024 __ jmp(&store_value, Assembler::kNearJump); | |
| 1025 __ Bind(&load_0xff); | |
| 1026 __ movl(EBX, Immediate(0xFF)); | |
| 1027 | |
| 1028 __ Bind(&store_value); | |
| 1029 __ movb(Address(EAX, 0), BL); | |
| 1030 __ ret(); | |
| 1031 __ Bind(&fall_through); | |
| 1032 return false; | |
| 1033 } | |
| 1034 | |
| 1035 | |
| 1036 // Tests if two top most arguments are smis, jumps to label not_smi if not. | 633 // Tests if two top most arguments are smis, jumps to label not_smi if not. |
| 1037 // Topmost argument is in EAX. | 634 // Topmost argument is in EAX. |
| 1038 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { | 635 static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) { |
| 1039 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 636 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1040 __ movl(EBX, Address(ESP, + 2 * kWordSize)); | 637 __ movl(EBX, Address(ESP, + 2 * kWordSize)); |
| 1041 __ orl(EBX, EAX); | 638 __ orl(EBX, EAX); |
| 1042 __ testl(EBX, Immediate(kSmiTagMask)); | 639 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1043 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); | 640 __ j(NOT_ZERO, not_smi, Assembler::kNearJump); |
| 1044 } | 641 } |
| 1045 | 642 |
| (...skipping 825 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1871 __ Bind(&is_true); | 1468 __ Bind(&is_true); |
| 1872 __ LoadObject(EAX, Bool::True()); | 1469 __ LoadObject(EAX, Bool::True()); |
| 1873 __ ret(); | 1470 __ ret(); |
| 1874 return true; | 1471 return true; |
| 1875 } | 1472 } |
| 1876 | 1473 |
| 1877 #undef __ | 1474 #undef __ |
| 1878 } // namespace dart | 1475 } // namespace dart |
| 1879 | 1476 |
| 1880 #endif // defined TARGET_ARCH_IA32 | 1477 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |