| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 // |done| label if a property with the given name is found leaving the | 101 // |done| label if a property with the given name is found leaving the |
| 102 // index into the dictionary in |r0|. Jump to the |miss| label | 102 // index into the dictionary in |r0|. Jump to the |miss| label |
| 103 // otherwise. | 103 // otherwise. |
| 104 static void GenerateStringDictionaryProbes(MacroAssembler* masm, | 104 static void GenerateStringDictionaryProbes(MacroAssembler* masm, |
| 105 Label* miss, | 105 Label* miss, |
| 106 Label* done, | 106 Label* done, |
| 107 Register elements, | 107 Register elements, |
| 108 Register name, | 108 Register name, |
| 109 Register r0, | 109 Register r0, |
| 110 Register r1) { | 110 Register r1) { |
| 111 // Assert that name contains a string. |
| 112 if (FLAG_debug_code) __ AbortIfNotString(name); |
| 113 |
| 111 // Compute the capacity mask. | 114 // Compute the capacity mask. |
| 112 const int kCapacityOffset = | 115 const int kCapacityOffset = |
| 113 StringDictionary::kHeaderSize + | 116 StringDictionary::kHeaderSize + |
| 114 StringDictionary::kCapacityIndex * kPointerSize; | 117 StringDictionary::kCapacityIndex * kPointerSize; |
| 115 __ mov(r1, FieldOperand(elements, kCapacityOffset)); | 118 __ mov(r1, FieldOperand(elements, kCapacityOffset)); |
| 116 __ shr(r1, kSmiTagSize); // convert smi to int | 119 __ shr(r1, kSmiTagSize); // convert smi to int |
| 117 __ dec(r1); | 120 __ dec(r1); |
| 118 | 121 |
| 119 // Generate an unrolled loop that performs a few probes before | 122 // Generate an unrolled loop that performs a few probes before |
| 120 // giving up. Measurements done on Gmail indicate that 2 probes | 123 // giving up. Measurements done on Gmail indicate that 2 probes |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 // -- esp[0] : return address | 384 // -- esp[0] : return address |
| 382 // ----------------------------------- | 385 // ----------------------------------- |
| 383 Label miss; | 386 Label miss; |
| 384 | 387 |
| 385 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); | 388 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss); |
| 386 __ bind(&miss); | 389 __ bind(&miss); |
| 387 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 390 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
| 388 } | 391 } |
| 389 | 392 |
| 390 | 393 |
| 391 void LoadIC::GenerateStringLength(MacroAssembler* masm) { | 394 void LoadIC::GenerateStringLength(MacroAssembler* masm, |
| 395 bool support_wrappers) { |
| 392 // ----------- S t a t e ------------- | 396 // ----------- S t a t e ------------- |
| 393 // -- eax : receiver | 397 // -- eax : receiver |
| 394 // -- ecx : name | 398 // -- ecx : name |
| 395 // -- esp[0] : return address | 399 // -- esp[0] : return address |
| 396 // ----------------------------------- | 400 // ----------------------------------- |
| 397 Label miss; | 401 Label miss; |
| 398 | 402 |
| 399 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss); | 403 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss, |
| 404 support_wrappers); |
| 400 __ bind(&miss); | 405 __ bind(&miss); |
| 401 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); | 406 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
| 402 } | 407 } |
| 403 | 408 |
| 404 | 409 |
| 405 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { | 410 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) { |
| 406 // ----------- S t a t e ------------- | 411 // ----------- S t a t e ------------- |
| 407 // -- eax : receiver | 412 // -- eax : receiver |
| 408 // -- ecx : name | 413 // -- ecx : name |
| 409 // -- esp[0] : return address | 414 // -- esp[0] : return address |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 edx, | 552 edx, |
| 548 eax, | 553 eax, |
| 549 ecx, | 554 ecx, |
| 550 eax, | 555 eax, |
| 551 NULL, | 556 NULL, |
| 552 &slow); | 557 &slow); |
| 553 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); | 558 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1); |
| 554 __ ret(0); | 559 __ ret(0); |
| 555 | 560 |
| 556 __ bind(&check_pixel_array); | 561 __ bind(&check_pixel_array); |
| 557 // Check whether the elements is a pixel array. | 562 GenerateFastPixelArrayLoad(masm, |
| 558 // edx: receiver | 563 edx, |
| 559 // eax: key | 564 eax, |
| 560 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | 565 ecx, |
| 561 __ mov(ebx, eax); | 566 ebx, |
| 562 __ SmiUntag(ebx); | 567 eax, |
| 563 __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true); | 568 &check_number_dictionary, |
| 564 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset)); | 569 NULL, |
| 565 __ j(above_equal, &slow); | 570 &slow); |
| 566 __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset)); | |
| 567 __ movzx_b(eax, Operand(eax, ebx, times_1, 0)); | |
| 568 __ SmiTag(eax); | |
| 569 __ ret(0); | |
| 570 | 571 |
| 571 __ bind(&check_number_dictionary); | 572 __ bind(&check_number_dictionary); |
| 572 // Check whether the elements is a number dictionary. | 573 // Check whether the elements is a number dictionary. |
| 573 // edx: receiver | 574 // edx: receiver |
| 574 // ebx: untagged index | 575 // ebx: untagged index |
| 575 // eax: key | 576 // eax: key |
| 576 // ecx: elements | 577 // ecx: elements |
| 577 __ CheckMap(ecx, Factory::hash_table_map(), &slow, true); | 578 __ CheckMap(ecx, Factory::hash_table_map(), &slow, true); |
| 578 Label slow_pop_receiver; | 579 Label slow_pop_receiver; |
| 579 // Push receiver on the stack to free up a register for the dictionary | 580 // Push receiver on the stack to free up a register for the dictionary |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 __ ret(0); | 712 __ ret(0); |
| 712 | 713 |
| 713 StubRuntimeCallHelper call_helper; | 714 StubRuntimeCallHelper call_helper; |
| 714 char_at_generator.GenerateSlow(masm, call_helper); | 715 char_at_generator.GenerateSlow(masm, call_helper); |
| 715 | 716 |
| 716 __ bind(&miss); | 717 __ bind(&miss); |
| 717 GenerateMiss(masm); | 718 GenerateMiss(masm); |
| 718 } | 719 } |
| 719 | 720 |
| 720 | 721 |
| 721 void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm, | |
| 722 ExternalArrayType array_type) { | |
| 723 // ----------- S t a t e ------------- | |
| 724 // -- eax : key | |
| 725 // -- edx : receiver | |
| 726 // -- esp[0] : return address | |
| 727 // ----------------------------------- | |
| 728 Label slow, failed_allocation; | |
| 729 | |
| 730 // Check that the object isn't a smi. | |
| 731 __ test(edx, Immediate(kSmiTagMask)); | |
| 732 __ j(zero, &slow, not_taken); | |
| 733 | |
| 734 // Check that the key is a smi. | |
| 735 __ test(eax, Immediate(kSmiTagMask)); | |
| 736 __ j(not_zero, &slow, not_taken); | |
| 737 | |
| 738 // Get the map of the receiver. | |
| 739 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 740 // Check that the receiver does not require access checks. We need | |
| 741 // to check this explicitly since this generic stub does not perform | |
| 742 // map checks. | |
| 743 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), | |
| 744 1 << Map::kIsAccessCheckNeeded); | |
| 745 __ j(not_zero, &slow, not_taken); | |
| 746 | |
| 747 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); | |
| 748 __ j(not_equal, &slow, not_taken); | |
| 749 | |
| 750 // Check that the elements array is the appropriate type of | |
| 751 // ExternalArray. | |
| 752 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 753 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); | |
| 754 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | |
| 755 Immediate(map)); | |
| 756 __ j(not_equal, &slow, not_taken); | |
| 757 | |
| 758 // eax: key, known to be a smi. | |
| 759 // edx: receiver, known to be a JSObject. | |
| 760 // ebx: elements object, known to be an external array. | |
| 761 // Check that the index is in range. | |
| 762 __ mov(ecx, eax); | |
| 763 __ SmiUntag(ecx); // Untag the index. | |
| 764 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); | |
| 765 // Unsigned comparison catches both negative and too-large values. | |
| 766 __ j(above_equal, &slow); | |
| 767 | |
| 768 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); | |
| 769 // ebx: base pointer of external storage | |
| 770 switch (array_type) { | |
| 771 case kExternalByteArray: | |
| 772 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); | |
| 773 break; | |
| 774 case kExternalUnsignedByteArray: | |
| 775 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); | |
| 776 break; | |
| 777 case kExternalShortArray: | |
| 778 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); | |
| 779 break; | |
| 780 case kExternalUnsignedShortArray: | |
| 781 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); | |
| 782 break; | |
| 783 case kExternalIntArray: | |
| 784 case kExternalUnsignedIntArray: | |
| 785 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); | |
| 786 break; | |
| 787 case kExternalFloatArray: | |
| 788 __ fld_s(Operand(ebx, ecx, times_4, 0)); | |
| 789 break; | |
| 790 default: | |
| 791 UNREACHABLE(); | |
| 792 break; | |
| 793 } | |
| 794 | |
| 795 // For integer array types: | |
| 796 // ecx: value | |
| 797 // For floating-point array type: | |
| 798 // FP(0): value | |
| 799 | |
| 800 if (array_type == kExternalIntArray || | |
| 801 array_type == kExternalUnsignedIntArray) { | |
| 802 // For the Int and UnsignedInt array types, we need to see whether | |
| 803 // the value can be represented in a Smi. If not, we need to convert | |
| 804 // it to a HeapNumber. | |
| 805 Label box_int; | |
| 806 if (array_type == kExternalIntArray) { | |
| 807 __ cmp(ecx, 0xC0000000); | |
| 808 __ j(sign, &box_int); | |
| 809 } else { | |
| 810 ASSERT_EQ(array_type, kExternalUnsignedIntArray); | |
| 811 // The test is different for unsigned int values. Since we need | |
| 812 // the value to be in the range of a positive smi, we can't | |
| 813 // handle either of the top two bits being set in the value. | |
| 814 __ test(ecx, Immediate(0xC0000000)); | |
| 815 __ j(not_zero, &box_int); | |
| 816 } | |
| 817 | |
| 818 __ mov(eax, ecx); | |
| 819 __ SmiTag(eax); | |
| 820 __ ret(0); | |
| 821 | |
| 822 __ bind(&box_int); | |
| 823 | |
| 824 // Allocate a HeapNumber for the int and perform int-to-double | |
| 825 // conversion. | |
| 826 if (array_type == kExternalIntArray) { | |
| 827 __ push(ecx); | |
| 828 __ fild_s(Operand(esp, 0)); | |
| 829 __ pop(ecx); | |
| 830 } else { | |
| 831 ASSERT(array_type == kExternalUnsignedIntArray); | |
| 832 // Need to zero-extend the value. | |
| 833 // There's no fild variant for unsigned values, so zero-extend | |
| 834 // to a 64-bit int manually. | |
| 835 __ push(Immediate(0)); | |
| 836 __ push(ecx); | |
| 837 __ fild_d(Operand(esp, 0)); | |
| 838 __ pop(ecx); | |
| 839 __ pop(ecx); | |
| 840 } | |
| 841 // FP(0): value | |
| 842 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); | |
| 843 // Set the value. | |
| 844 __ mov(eax, ecx); | |
| 845 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 846 __ ret(0); | |
| 847 } else if (array_type == kExternalFloatArray) { | |
| 848 // For the floating-point array type, we need to always allocate a | |
| 849 // HeapNumber. | |
| 850 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); | |
| 851 // Set the value. | |
| 852 __ mov(eax, ecx); | |
| 853 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 854 __ ret(0); | |
| 855 } else { | |
| 856 __ mov(eax, ecx); | |
| 857 __ SmiTag(eax); | |
| 858 __ ret(0); | |
| 859 } | |
| 860 | |
| 861 // If we fail allocation of the HeapNumber, we still have a value on | |
| 862 // top of the FPU stack. Remove it. | |
| 863 __ bind(&failed_allocation); | |
| 864 __ ffree(); | |
| 865 __ fincstp(); | |
| 866 // Fall through to slow case. | |
| 867 | |
| 868 // Slow case: Jump to runtime. | |
| 869 __ bind(&slow); | |
| 870 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); | |
| 871 GenerateRuntimeGetProperty(masm); | |
| 872 } | |
| 873 | |
| 874 | |
| 875 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { | 722 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { |
| 876 // ----------- S t a t e ------------- | 723 // ----------- S t a t e ------------- |
| 877 // -- eax : key | 724 // -- eax : key |
| 878 // -- edx : receiver | 725 // -- edx : receiver |
| 879 // -- esp[0] : return address | 726 // -- esp[0] : return address |
| 880 // ----------------------------------- | 727 // ----------------------------------- |
| 881 Label slow; | 728 Label slow; |
| 882 | 729 |
| 883 // Check that the receiver isn't a smi. | 730 // Check that the receiver isn't a smi. |
| 884 __ test(edx, Immediate(kSmiTagMask)); | 731 __ test(edx, Immediate(kSmiTagMask)); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 955 // Slow case: call runtime. | 802 // Slow case: call runtime. |
| 956 __ bind(&slow); | 803 __ bind(&slow); |
| 957 GenerateRuntimeSetProperty(masm); | 804 GenerateRuntimeSetProperty(masm); |
| 958 | 805 |
| 959 // Check whether the elements is a pixel array. | 806 // Check whether the elements is a pixel array. |
| 960 __ bind(&check_pixel_array); | 807 __ bind(&check_pixel_array); |
| 961 // eax: value | 808 // eax: value |
| 962 // ecx: key (a smi) | 809 // ecx: key (a smi) |
| 963 // edx: receiver | 810 // edx: receiver |
| 964 // edi: elements array | 811 // edi: elements array |
| 965 __ CheckMap(edi, Factory::pixel_array_map(), &slow, true); | 812 GenerateFastPixelArrayStore(masm, |
| 966 // Check that the value is a smi. If a conversion is needed call into the | 813 edx, |
| 967 // runtime to convert and clamp. | 814 ecx, |
| 968 __ test(eax, Immediate(kSmiTagMask)); | 815 eax, |
| 969 __ j(not_zero, &slow); | 816 edi, |
| 970 __ mov(ebx, ecx); | 817 ebx, |
| 971 __ SmiUntag(ebx); | 818 false, |
| 972 __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset)); | 819 NULL, |
| 973 __ j(above_equal, &slow); | 820 &slow, |
| 974 __ mov(ecx, eax); // Save the value. Key is not longer needed. | 821 &slow, |
| 975 __ SmiUntag(ecx); | 822 &slow); |
| 976 { // Clamp the value to [0..255]. | |
| 977 Label done; | |
| 978 __ test(ecx, Immediate(0xFFFFFF00)); | |
| 979 __ j(zero, &done); | |
| 980 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | |
| 981 __ dec_b(ecx); // 0 if negative, 255 if positive. | |
| 982 __ bind(&done); | |
| 983 } | |
| 984 __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset)); | |
| 985 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | |
| 986 __ ret(0); // Return value in eax. | |
| 987 | 823 |
| 988 // Extra capacity case: Check if there is extra capacity to | 824 // Extra capacity case: Check if there is extra capacity to |
| 989 // perform the store and update the length. Used for adding one | 825 // perform the store and update the length. Used for adding one |
| 990 // element to the array by writing to array[array.length]. | 826 // element to the array by writing to array[array.length]. |
| 991 __ bind(&extra); | 827 __ bind(&extra); |
| 992 // eax: value | 828 // eax: value |
| 993 // edx: receiver, a JSArray | 829 // edx: receiver, a JSArray |
| 994 // ecx: key, a smi. | 830 // ecx: key, a smi. |
| 995 // edi: receiver->elements, a FixedArray | 831 // edi: receiver->elements, a FixedArray |
| 996 // flags: compare (ecx, edx.length()) | 832 // flags: compare (ecx, edx.length()) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1025 // edi: FixedArray receiver->elements | 861 // edi: FixedArray receiver->elements |
| 1026 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); | 862 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax); |
| 1027 | 863 |
| 1028 // Update write barrier for the elements array address. | 864 // Update write barrier for the elements array address. |
| 1029 __ mov(edx, Operand(eax)); | 865 __ mov(edx, Operand(eax)); |
| 1030 __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs); | 866 __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs); |
| 1031 __ ret(0); | 867 __ ret(0); |
| 1032 } | 868 } |
| 1033 | 869 |
| 1034 | 870 |
| 1035 void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm, | |
| 1036 ExternalArrayType array_type) { | |
| 1037 // ----------- S t a t e ------------- | |
| 1038 // -- eax : value | |
| 1039 // -- ecx : key | |
| 1040 // -- edx : receiver | |
| 1041 // -- esp[0] : return address | |
| 1042 // ----------------------------------- | |
| 1043 Label slow, check_heap_number; | |
| 1044 | |
| 1045 // Check that the object isn't a smi. | |
| 1046 __ test(edx, Immediate(kSmiTagMask)); | |
| 1047 __ j(zero, &slow); | |
| 1048 // Get the map from the receiver. | |
| 1049 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 1050 // Check that the receiver does not require access checks. We need | |
| 1051 // to do this because this generic stub does not perform map checks. | |
| 1052 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), | |
| 1053 1 << Map::kIsAccessCheckNeeded); | |
| 1054 __ j(not_zero, &slow); | |
| 1055 // Check that the key is a smi. | |
| 1056 __ test(ecx, Immediate(kSmiTagMask)); | |
| 1057 __ j(not_zero, &slow); | |
| 1058 // Get the instance type from the map of the receiver. | |
| 1059 __ CmpInstanceType(edi, JS_OBJECT_TYPE); | |
| 1060 __ j(not_equal, &slow); | |
| 1061 | |
| 1062 // Check that the elements array is the appropriate type of | |
| 1063 // ExternalArray. | |
| 1064 // eax: value | |
| 1065 // edx: receiver, a JSObject | |
| 1066 // ecx: key, a smi | |
| 1067 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 1068 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)), | |
| 1069 &slow, true); | |
| 1070 | |
| 1071 // Check that the index is in range. | |
| 1072 __ mov(ebx, ecx); | |
| 1073 __ SmiUntag(ebx); | |
| 1074 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); | |
| 1075 // Unsigned comparison catches both negative and too-large values. | |
| 1076 __ j(above_equal, &slow); | |
| 1077 | |
| 1078 // Handle both smis and HeapNumbers in the fast path. Go to the | |
| 1079 // runtime for all other kinds of values. | |
| 1080 // eax: value | |
| 1081 // edx: receiver | |
| 1082 // ecx: key | |
| 1083 // edi: elements array | |
| 1084 // ebx: untagged index | |
| 1085 __ test(eax, Immediate(kSmiTagMask)); | |
| 1086 __ j(not_equal, &check_heap_number); | |
| 1087 // smi case | |
| 1088 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. | |
| 1089 __ SmiUntag(ecx); | |
| 1090 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | |
| 1091 // ecx: base pointer of external storage | |
| 1092 switch (array_type) { | |
| 1093 case kExternalByteArray: | |
| 1094 case kExternalUnsignedByteArray: | |
| 1095 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | |
| 1096 break; | |
| 1097 case kExternalShortArray: | |
| 1098 case kExternalUnsignedShortArray: | |
| 1099 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | |
| 1100 break; | |
| 1101 case kExternalIntArray: | |
| 1102 case kExternalUnsignedIntArray: | |
| 1103 __ mov(Operand(edi, ebx, times_4, 0), ecx); | |
| 1104 break; | |
| 1105 case kExternalFloatArray: | |
| 1106 // Need to perform int-to-float conversion. | |
| 1107 __ push(ecx); | |
| 1108 __ fild_s(Operand(esp, 0)); | |
| 1109 __ pop(ecx); | |
| 1110 __ fstp_s(Operand(edi, ebx, times_4, 0)); | |
| 1111 break; | |
| 1112 default: | |
| 1113 UNREACHABLE(); | |
| 1114 break; | |
| 1115 } | |
| 1116 __ ret(0); // Return the original value. | |
| 1117 | |
| 1118 __ bind(&check_heap_number); | |
| 1119 // eax: value | |
| 1120 // edx: receiver | |
| 1121 // ecx: key | |
| 1122 // edi: elements array | |
| 1123 // ebx: untagged index | |
| 1124 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | |
| 1125 Immediate(Factory::heap_number_map())); | |
| 1126 __ j(not_equal, &slow); | |
| 1127 | |
| 1128 // The WebGL specification leaves the behavior of storing NaN and | |
| 1129 // +/-Infinity into integer arrays basically undefined. For more | |
| 1130 // reproducible behavior, convert these to zero. | |
| 1131 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 1132 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | |
| 1133 // ebx: untagged index | |
| 1134 // edi: base pointer of external storage | |
| 1135 // top of FPU stack: value | |
| 1136 if (array_type == kExternalFloatArray) { | |
| 1137 __ fstp_s(Operand(edi, ebx, times_4, 0)); | |
| 1138 __ ret(0); | |
| 1139 } else { | |
| 1140 // Need to perform float-to-int conversion. | |
| 1141 // Test the top of the FP stack for NaN. | |
| 1142 Label is_nan; | |
| 1143 __ fucomi(0); | |
| 1144 __ j(parity_even, &is_nan); | |
| 1145 | |
| 1146 if (array_type != kExternalUnsignedIntArray) { | |
| 1147 __ push(ecx); // Make room on stack | |
| 1148 __ fistp_s(Operand(esp, 0)); | |
| 1149 __ pop(ecx); | |
| 1150 } else { | |
| 1151 // fistp stores values as signed integers. | |
| 1152 // To represent the entire range, we need to store as a 64-bit | |
| 1153 // int and discard the high 32 bits. | |
| 1154 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | |
| 1155 __ fistp_d(Operand(esp, 0)); | |
| 1156 __ pop(ecx); | |
| 1157 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 1158 } | |
| 1159 // ecx: untagged integer value | |
| 1160 switch (array_type) { | |
| 1161 case kExternalByteArray: | |
| 1162 case kExternalUnsignedByteArray: | |
| 1163 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | |
| 1164 break; | |
| 1165 case kExternalShortArray: | |
| 1166 case kExternalUnsignedShortArray: | |
| 1167 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | |
| 1168 break; | |
| 1169 case kExternalIntArray: | |
| 1170 case kExternalUnsignedIntArray: { | |
| 1171 // We also need to explicitly check for +/-Infinity. These are | |
| 1172 // converted to MIN_INT, but we need to be careful not to | |
| 1173 // confuse with legal uses of MIN_INT. | |
| 1174 Label not_infinity; | |
| 1175 // This test would apparently detect both NaN and Infinity, | |
| 1176 // but we've already checked for NaN using the FPU hardware | |
| 1177 // above. | |
| 1178 __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6)); | |
| 1179 __ and_(edx, 0x7FF0); | |
| 1180 __ cmp(edx, 0x7FF0); | |
| 1181 __ j(not_equal, ¬_infinity); | |
| 1182 __ mov(ecx, 0); | |
| 1183 __ bind(¬_infinity); | |
| 1184 __ mov(Operand(edi, ebx, times_4, 0), ecx); | |
| 1185 break; | |
| 1186 } | |
| 1187 default: | |
| 1188 UNREACHABLE(); | |
| 1189 break; | |
| 1190 } | |
| 1191 __ ret(0); // Return original value. | |
| 1192 | |
| 1193 __ bind(&is_nan); | |
| 1194 __ ffree(); | |
| 1195 __ fincstp(); | |
| 1196 switch (array_type) { | |
| 1197 case kExternalByteArray: | |
| 1198 case kExternalUnsignedByteArray: | |
| 1199 __ mov_b(Operand(edi, ebx, times_1, 0), 0); | |
| 1200 break; | |
| 1201 case kExternalShortArray: | |
| 1202 case kExternalUnsignedShortArray: | |
| 1203 __ Set(ecx, Immediate(0)); | |
| 1204 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | |
| 1205 break; | |
| 1206 case kExternalIntArray: | |
| 1207 case kExternalUnsignedIntArray: | |
| 1208 __ mov(Operand(edi, ebx, times_4, 0), Immediate(0)); | |
| 1209 break; | |
| 1210 default: | |
| 1211 UNREACHABLE(); | |
| 1212 break; | |
| 1213 } | |
| 1214 __ ret(0); // Return the original value. | |
| 1215 } | |
| 1216 | |
| 1217 // Slow case: call runtime. | |
| 1218 __ bind(&slow); | |
| 1219 GenerateRuntimeSetProperty(masm); | |
| 1220 } | |
| 1221 | |
| 1222 | |
| 1223 // The generated code does not accept smi keys. | 871 // The generated code does not accept smi keys. |
| 1224 // The generated code falls through if both probes miss. | 872 // The generated code falls through if both probes miss. |
| 1225 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, | 873 static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, |
| 1226 int argc, | 874 int argc, |
| 1227 Code::Kind kind) { | 875 Code::Kind kind) { |
| 1228 // ----------- S t a t e ------------- | 876 // ----------- S t a t e ------------- |
| 1229 // -- ecx : name | 877 // -- ecx : name |
| 1230 // -- edx : receiver | 878 // -- edx : receiver |
| 1231 // ----------------------------------- | 879 // ----------------------------------- |
| 1232 Label number, non_number, non_string, boolean, probe, miss; | 880 Label number, non_number, non_string, boolean, probe, miss; |
| 1233 | 881 |
| 1234 // Probe the stub cache. | 882 // Probe the stub cache. |
| 1235 Code::Flags flags = | 883 Code::Flags flags = Code::ComputeFlags(kind, |
| 1236 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); | 884 NOT_IN_LOOP, |
| 885 MONOMORPHIC, |
| 886 Code::kNoExtraICState, |
| 887 NORMAL, |
| 888 argc); |
| 1237 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); | 889 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax); |
| 1238 | 890 |
| 1239 // If the stub cache probing failed, the receiver might be a value. | 891 // If the stub cache probing failed, the receiver might be a value. |
| 1240 // For value objects, we use the map of the prototype objects for | 892 // For value objects, we use the map of the prototype objects for |
| 1241 // the corresponding JSValue for the cache and that is what we need | 893 // the corresponding JSValue for the cache and that is what we need |
| 1242 // to probe. | 894 // to probe. |
| 1243 // | 895 // |
| 1244 // Check for number. | 896 // Check for number. |
| 1245 __ test(edx, Immediate(kSmiTagMask)); | 897 __ test(edx, Immediate(kSmiTagMask)); |
| 1246 __ j(zero, &number, not_taken); | 898 __ j(zero, &number, not_taken); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 | 971 |
| 1320 // eax: elements | 972 // eax: elements |
| 1321 // Search the dictionary placing the result in edi. | 973 // Search the dictionary placing the result in edi. |
| 1322 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); | 974 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); |
| 1323 GenerateFunctionTailCall(masm, argc, &miss); | 975 GenerateFunctionTailCall(masm, argc, &miss); |
| 1324 | 976 |
| 1325 __ bind(&miss); | 977 __ bind(&miss); |
| 1326 } | 978 } |
| 1327 | 979 |
| 1328 | 980 |
| 1329 static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) { | 981 static void GenerateCallMiss(MacroAssembler* masm, |
| 982 int argc, |
| 983 IC::UtilityId id) { |
| 1330 // ----------- S t a t e ------------- | 984 // ----------- S t a t e ------------- |
| 1331 // -- ecx : name | 985 // -- ecx : name |
| 1332 // -- esp[0] : return address | 986 // -- esp[0] : return address |
| 1333 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 987 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1334 // -- ... | 988 // -- ... |
| 1335 // -- esp[(argc + 1) * 4] : receiver | 989 // -- esp[(argc + 1) * 4] : receiver |
| 1336 // ----------------------------------- | 990 // ----------------------------------- |
| 1337 | 991 |
| 1338 if (id == IC::kCallIC_Miss) { | 992 if (id == IC::kCallIC_Miss) { |
| 1339 __ IncrementCounter(&Counters::call_miss, 1); | 993 __ IncrementCounter(&Counters::call_miss, 1); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 | 1194 |
| 1541 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | 1195 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { |
| 1542 // ----------- S t a t e ------------- | 1196 // ----------- S t a t e ------------- |
| 1543 // -- ecx : name | 1197 // -- ecx : name |
| 1544 // -- esp[0] : return address | 1198 // -- esp[0] : return address |
| 1545 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1199 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1546 // -- ... | 1200 // -- ... |
| 1547 // -- esp[(argc + 1) * 4] : receiver | 1201 // -- esp[(argc + 1) * 4] : receiver |
| 1548 // ----------------------------------- | 1202 // ----------------------------------- |
| 1549 | 1203 |
| 1204 // Check if the name is a string. |
| 1205 Label miss; |
| 1206 __ test(ecx, Immediate(kSmiTagMask)); |
| 1207 __ j(zero, &miss); |
| 1208 Condition cond = masm->IsObjectStringType(ecx, eax, eax); |
| 1209 __ j(NegateCondition(cond), &miss); |
| 1550 GenerateCallNormal(masm, argc); | 1210 GenerateCallNormal(masm, argc); |
| 1211 __ bind(&miss); |
| 1551 GenerateMiss(masm, argc); | 1212 GenerateMiss(masm, argc); |
| 1552 } | 1213 } |
| 1553 | 1214 |
| 1554 | 1215 |
| 1555 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { | 1216 void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) { |
| 1556 // ----------- S t a t e ------------- | 1217 // ----------- S t a t e ------------- |
| 1557 // -- ecx : name | 1218 // -- ecx : name |
| 1558 // -- esp[0] : return address | 1219 // -- esp[0] : return address |
| 1559 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1220 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1560 // -- ... | 1221 // -- ... |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1820 __ pop(ebx); | 1481 __ pop(ebx); |
| 1821 __ push(edx); // receiver | 1482 __ push(edx); // receiver |
| 1822 __ push(eax); // name | 1483 __ push(eax); // name |
| 1823 __ push(ebx); // return address | 1484 __ push(ebx); // return address |
| 1824 | 1485 |
| 1825 // Perform tail call to the entry. | 1486 // Perform tail call to the entry. |
| 1826 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 1487 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 1827 } | 1488 } |
| 1828 | 1489 |
| 1829 | 1490 |
| 1830 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { | 1491 void StoreIC::GenerateMegamorphic(MacroAssembler* masm, |
| 1492 Code::ExtraICState extra_ic_state) { |
| 1831 // ----------- S t a t e ------------- | 1493 // ----------- S t a t e ------------- |
| 1832 // -- eax : value | 1494 // -- eax : value |
| 1833 // -- ecx : name | 1495 // -- ecx : name |
| 1834 // -- edx : receiver | 1496 // -- edx : receiver |
| 1835 // -- esp[0] : return address | 1497 // -- esp[0] : return address |
| 1836 // ----------------------------------- | 1498 // ----------------------------------- |
| 1837 | 1499 |
| 1838 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, | 1500 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, |
| 1839 NOT_IN_LOOP, | 1501 NOT_IN_LOOP, |
| 1840 MONOMORPHIC); | 1502 MONOMORPHIC, |
| 1503 extra_ic_state); |
| 1841 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); | 1504 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); |
| 1842 | 1505 |
| 1843 // Cache miss: Jump to runtime. | 1506 // Cache miss: Jump to runtime. |
| 1844 GenerateMiss(masm); | 1507 GenerateMiss(masm); |
| 1845 } | 1508 } |
| 1846 | 1509 |
| 1847 | 1510 |
| 1848 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 1511 void StoreIC::GenerateMiss(MacroAssembler* masm) { |
| 1849 // ----------- S t a t e ------------- | 1512 // ----------- S t a t e ------------- |
| 1850 // -- eax : value | 1513 // -- eax : value |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2108 Condition cc = *jmp_address == Assembler::kJncShortOpcode | 1771 Condition cc = *jmp_address == Assembler::kJncShortOpcode |
| 2109 ? not_zero | 1772 ? not_zero |
| 2110 : zero; | 1773 : zero; |
| 2111 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1774 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
| 2112 } | 1775 } |
| 2113 | 1776 |
| 2114 | 1777 |
| 2115 } } // namespace v8::internal | 1778 } } // namespace v8::internal |
| 2116 | 1779 |
| 2117 #endif // V8_TARGET_ARCH_IA32 | 1780 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |