OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 static Register registers[] = { eax }; | 223 static Register registers[] = { eax }; |
224 descriptor->register_param_count_ = 1; | 224 descriptor->register_param_count_ = 1; |
225 descriptor->register_params_ = registers; | 225 descriptor->register_params_ = registers; |
226 descriptor->deoptimization_handler_ = | 226 descriptor->deoptimization_handler_ = |
227 FUNCTION_ADDR(ToBooleanIC_Miss); | 227 FUNCTION_ADDR(ToBooleanIC_Miss); |
228 descriptor->SetMissHandler( | 228 descriptor->SetMissHandler( |
229 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate)); | 229 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate)); |
230 } | 230 } |
231 | 231 |
232 | 232 |
233 void UnaryOpStub::InitializeInterfaceDescriptor( | |
234 Isolate* isolate, | |
235 CodeStubInterfaceDescriptor* descriptor) { | |
236 static Register registers[] = { eax }; | |
237 descriptor->register_param_count_ = 1; | |
238 descriptor->register_params_ = registers; | |
239 descriptor->deoptimization_handler_ = | |
240 FUNCTION_ADDR(UnaryOpIC_Miss); | |
241 } | |
242 | |
243 | |
244 #define __ ACCESS_MASM(masm) | 233 #define __ ACCESS_MASM(masm) |
245 | 234 |
246 | 235 |
247 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { | 236 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { |
248 // Update the static counter each time a new code stub is generated. | 237 // Update the static counter each time a new code stub is generated. |
249 Isolate* isolate = masm->isolate(); | 238 Isolate* isolate = masm->isolate(); |
250 isolate->counters()->code_stubs()->Increment(); | 239 isolate->counters()->code_stubs()->Increment(); |
251 | 240 |
252 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); | 241 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); |
253 int param_count = descriptor->register_param_count_; | 242 int param_count = descriptor->register_param_count_; |
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 // Result is in ecx. Trashes ebx, xmm0, and xmm1. | 752 // Result is in ecx. Trashes ebx, xmm0, and xmm1. |
764 static void ConvertHeapNumberToInt32(MacroAssembler* masm, | 753 static void ConvertHeapNumberToInt32(MacroAssembler* masm, |
765 Register source, | 754 Register source, |
766 Label* conversion_failure) { | 755 Label* conversion_failure) { |
767 __ movdbl(xmm0, FieldOperand(source, HeapNumber::kValueOffset)); | 756 __ movdbl(xmm0, FieldOperand(source, HeapNumber::kValueOffset)); |
768 FloatingPointHelper::CheckSSE2OperandIsInt32( | 757 FloatingPointHelper::CheckSSE2OperandIsInt32( |
769 masm, conversion_failure, xmm0, ecx, ebx, xmm1); | 758 masm, conversion_failure, xmm0, ecx, ebx, xmm1); |
770 } | 759 } |
771 | 760 |
772 | 761 |
| 762 void UnaryOpStub::PrintName(StringStream* stream) { |
| 763 const char* op_name = Token::Name(op_); |
| 764 const char* overwrite_name = NULL; // Make g++ happy. |
| 765 switch (mode_) { |
| 766 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 767 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
| 768 } |
| 769 stream->Add("UnaryOpStub_%s_%s_%s", |
| 770 op_name, |
| 771 overwrite_name, |
| 772 UnaryOpIC::GetName(operand_type_)); |
| 773 } |
| 774 |
| 775 |
| 776 // TODO(svenpanne): Use virtual functions instead of switch. |
| 777 void UnaryOpStub::Generate(MacroAssembler* masm) { |
| 778 switch (operand_type_) { |
| 779 case UnaryOpIC::UNINITIALIZED: |
| 780 GenerateTypeTransition(masm); |
| 781 break; |
| 782 case UnaryOpIC::SMI: |
| 783 GenerateSmiStub(masm); |
| 784 break; |
| 785 case UnaryOpIC::NUMBER: |
| 786 GenerateNumberStub(masm); |
| 787 break; |
| 788 case UnaryOpIC::GENERIC: |
| 789 GenerateGenericStub(masm); |
| 790 break; |
| 791 } |
| 792 } |
| 793 |
| 794 |
| 795 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 796 __ pop(ecx); // Save return address. |
| 797 |
| 798 __ push(eax); // the operand |
| 799 __ push(Immediate(Smi::FromInt(op_))); |
| 800 __ push(Immediate(Smi::FromInt(mode_))); |
| 801 __ push(Immediate(Smi::FromInt(operand_type_))); |
| 802 |
| 803 __ push(ecx); // Push return address. |
| 804 |
| 805 // Patch the caller to an appropriate specialized stub and return the |
| 806 // operation result to the caller of the stub. |
| 807 __ TailCallExternalReference( |
| 808 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); |
| 809 } |
| 810 |
| 811 |
| 812 // TODO(svenpanne): Use virtual functions instead of switch. |
| 813 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 814 switch (op_) { |
| 815 case Token::SUB: |
| 816 GenerateSmiStubSub(masm); |
| 817 break; |
| 818 case Token::BIT_NOT: |
| 819 GenerateSmiStubBitNot(masm); |
| 820 break; |
| 821 default: |
| 822 UNREACHABLE(); |
| 823 } |
| 824 } |
| 825 |
| 826 |
| 827 void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { |
| 828 Label non_smi, undo, slow; |
| 829 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, |
| 830 Label::kNear, Label::kNear, Label::kNear); |
| 831 __ bind(&undo); |
| 832 GenerateSmiCodeUndo(masm); |
| 833 __ bind(&non_smi); |
| 834 __ bind(&slow); |
| 835 GenerateTypeTransition(masm); |
| 836 } |
| 837 |
| 838 |
| 839 void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { |
| 840 Label non_smi; |
| 841 GenerateSmiCodeBitNot(masm, &non_smi); |
| 842 __ bind(&non_smi); |
| 843 GenerateTypeTransition(masm); |
| 844 } |
| 845 |
| 846 |
| 847 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, |
| 848 Label* non_smi, |
| 849 Label* undo, |
| 850 Label* slow, |
| 851 Label::Distance non_smi_near, |
| 852 Label::Distance undo_near, |
| 853 Label::Distance slow_near) { |
| 854 // Check whether the value is a smi. |
| 855 __ JumpIfNotSmi(eax, non_smi, non_smi_near); |
| 856 |
| 857 // We can't handle -0 with smis, so use a type transition for that case. |
| 858 __ test(eax, eax); |
| 859 __ j(zero, slow, slow_near); |
| 860 |
| 861 // Try optimistic subtraction '0 - value', saving operand in eax for undo. |
| 862 __ mov(edx, eax); |
| 863 __ Set(eax, Immediate(0)); |
| 864 __ sub(eax, edx); |
| 865 __ j(overflow, undo, undo_near); |
| 866 __ ret(0); |
| 867 } |
| 868 |
| 869 |
| 870 void UnaryOpStub::GenerateSmiCodeBitNot( |
| 871 MacroAssembler* masm, |
| 872 Label* non_smi, |
| 873 Label::Distance non_smi_near) { |
| 874 // Check whether the value is a smi. |
| 875 __ JumpIfNotSmi(eax, non_smi, non_smi_near); |
| 876 |
| 877 // Flip bits and revert inverted smi-tag. |
| 878 __ not_(eax); |
| 879 __ and_(eax, ~kSmiTagMask); |
| 880 __ ret(0); |
| 881 } |
| 882 |
| 883 |
| 884 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { |
| 885 __ mov(eax, edx); |
| 886 } |
| 887 |
| 888 |
| 889 // TODO(svenpanne): Use virtual functions instead of switch. |
| 890 void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) { |
| 891 switch (op_) { |
| 892 case Token::SUB: |
| 893 GenerateNumberStubSub(masm); |
| 894 break; |
| 895 case Token::BIT_NOT: |
| 896 GenerateNumberStubBitNot(masm); |
| 897 break; |
| 898 default: |
| 899 UNREACHABLE(); |
| 900 } |
| 901 } |
| 902 |
| 903 |
| 904 void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) { |
| 905 Label non_smi, undo, slow, call_builtin; |
| 906 GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); |
| 907 __ bind(&non_smi); |
| 908 GenerateHeapNumberCodeSub(masm, &slow); |
| 909 __ bind(&undo); |
| 910 GenerateSmiCodeUndo(masm); |
| 911 __ bind(&slow); |
| 912 GenerateTypeTransition(masm); |
| 913 __ bind(&call_builtin); |
| 914 GenerateGenericCodeFallback(masm); |
| 915 } |
| 916 |
| 917 |
| 918 void UnaryOpStub::GenerateNumberStubBitNot( |
| 919 MacroAssembler* masm) { |
| 920 Label non_smi, slow; |
| 921 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 922 __ bind(&non_smi); |
| 923 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 924 __ bind(&slow); |
| 925 GenerateTypeTransition(masm); |
| 926 } |
| 927 |
| 928 |
| 929 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, |
| 930 Label* slow) { |
| 931 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 932 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); |
| 933 __ j(not_equal, slow); |
| 934 |
| 935 if (mode_ == UNARY_OVERWRITE) { |
| 936 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), |
| 937 Immediate(HeapNumber::kSignMask)); // Flip sign. |
| 938 } else { |
| 939 __ mov(edx, eax); |
| 940 // edx: operand |
| 941 |
| 942 Label slow_allocate_heapnumber, heapnumber_allocated; |
| 943 __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); |
| 944 __ jmp(&heapnumber_allocated, Label::kNear); |
| 945 |
| 946 __ bind(&slow_allocate_heapnumber); |
| 947 { |
| 948 FrameScope scope(masm, StackFrame::INTERNAL); |
| 949 __ push(edx); |
| 950 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 951 __ pop(edx); |
| 952 } |
| 953 |
| 954 __ bind(&heapnumber_allocated); |
| 955 // eax: allocated 'empty' number |
| 956 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 957 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. |
| 958 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); |
| 959 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); |
| 960 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 961 } |
| 962 __ ret(0); |
| 963 } |
| 964 |
| 965 |
| 966 void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, |
| 967 Label* slow) { |
| 968 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 969 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); |
| 970 __ j(not_equal, slow); |
| 971 |
| 972 // Convert the heap number in eax to an untagged integer in ecx. |
| 973 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); |
| 974 |
| 975 // Do the bitwise operation and check if the result fits in a smi. |
| 976 Label try_float; |
| 977 __ not_(ecx); |
| 978 __ cmp(ecx, 0xc0000000); |
| 979 __ j(sign, &try_float, Label::kNear); |
| 980 |
| 981 // Tag the result as a smi and we're done. |
| 982 STATIC_ASSERT(kSmiTagSize == 1); |
| 983 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
| 984 __ ret(0); |
| 985 |
| 986 // Try to store the result in a heap number. |
| 987 __ bind(&try_float); |
| 988 if (mode_ == UNARY_NO_OVERWRITE) { |
| 989 Label slow_allocate_heapnumber, heapnumber_allocated; |
| 990 __ mov(ebx, eax); |
| 991 __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber); |
| 992 __ jmp(&heapnumber_allocated); |
| 993 |
| 994 __ bind(&slow_allocate_heapnumber); |
| 995 { |
| 996 FrameScope scope(masm, StackFrame::INTERNAL); |
| 997 // Push the original HeapNumber on the stack. The integer value can't |
| 998 // be stored since it's untagged and not in the smi range (so we can't |
| 999 // smi-tag it). We'll recalculate the value after the GC instead. |
| 1000 __ push(ebx); |
| 1001 __ CallRuntime(Runtime::kNumberAlloc, 0); |
| 1002 // New HeapNumber is in eax. |
| 1003 __ pop(edx); |
| 1004 } |
| 1005 // IntegerConvert uses ebx and edi as scratch registers. |
| 1006 // This conversion won't go slow-case. |
| 1007 IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); |
| 1008 __ not_(ecx); |
| 1009 |
| 1010 __ bind(&heapnumber_allocated); |
| 1011 } |
| 1012 if (CpuFeatures::IsSupported(SSE2)) { |
| 1013 CpuFeatureScope use_sse2(masm, SSE2); |
| 1014 __ cvtsi2sd(xmm0, ecx); |
| 1015 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 1016 } else { |
| 1017 __ push(ecx); |
| 1018 __ fild_s(Operand(esp, 0)); |
| 1019 __ pop(ecx); |
| 1020 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1021 } |
| 1022 __ ret(0); |
| 1023 } |
| 1024 |
| 1025 |
| 1026 // TODO(svenpanne): Use virtual functions instead of switch. |
| 1027 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { |
| 1028 switch (op_) { |
| 1029 case Token::SUB: |
| 1030 GenerateGenericStubSub(masm); |
| 1031 break; |
| 1032 case Token::BIT_NOT: |
| 1033 GenerateGenericStubBitNot(masm); |
| 1034 break; |
| 1035 default: |
| 1036 UNREACHABLE(); |
| 1037 } |
| 1038 } |
| 1039 |
| 1040 |
| 1041 void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { |
| 1042 Label non_smi, undo, slow; |
| 1043 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); |
| 1044 __ bind(&non_smi); |
| 1045 GenerateHeapNumberCodeSub(masm, &slow); |
| 1046 __ bind(&undo); |
| 1047 GenerateSmiCodeUndo(masm); |
| 1048 __ bind(&slow); |
| 1049 GenerateGenericCodeFallback(masm); |
| 1050 } |
| 1051 |
| 1052 |
| 1053 void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { |
| 1054 Label non_smi, slow; |
| 1055 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); |
| 1056 __ bind(&non_smi); |
| 1057 GenerateHeapNumberCodeBitNot(masm, &slow); |
| 1058 __ bind(&slow); |
| 1059 GenerateGenericCodeFallback(masm); |
| 1060 } |
| 1061 |
| 1062 |
| 1063 void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { |
| 1064 // Handle the slow case by jumping to the corresponding JavaScript builtin. |
| 1065 __ pop(ecx); // pop return address. |
| 1066 __ push(eax); |
| 1067 __ push(ecx); // push return address |
| 1068 switch (op_) { |
| 1069 case Token::SUB: |
| 1070 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); |
| 1071 break; |
| 1072 case Token::BIT_NOT: |
| 1073 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
| 1074 break; |
| 1075 default: |
| 1076 UNREACHABLE(); |
| 1077 } |
| 1078 } |
| 1079 |
| 1080 |
773 void BinaryOpStub::Initialize() { | 1081 void BinaryOpStub::Initialize() { |
774 platform_specific_bit_ = CpuFeatures::IsSupported(SSE3); | 1082 platform_specific_bit_ = CpuFeatures::IsSupported(SSE3); |
775 } | 1083 } |
776 | 1084 |
777 | 1085 |
778 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1086 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
779 __ pop(ecx); // Save return address. | 1087 __ pop(ecx); // Save return address. |
780 __ push(edx); | 1088 __ push(edx); |
781 __ push(eax); | 1089 __ push(eax); |
782 // Left and right arguments are now on top. | 1090 // Left and right arguments are now on top. |
(...skipping 6928 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7711 __ bind(&fast_elements_case); | 8019 __ bind(&fast_elements_case); |
7712 GenerateCase(masm, FAST_ELEMENTS); | 8020 GenerateCase(masm, FAST_ELEMENTS); |
7713 } | 8021 } |
7714 | 8022 |
7715 | 8023 |
7716 #undef __ | 8024 #undef __ |
7717 | 8025 |
7718 } } // namespace v8::internal | 8026 } } // namespace v8::internal |
7719 | 8027 |
7720 #endif // V8_TARGET_ARCH_IA32 | 8028 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |