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 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
726 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 726 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
727 // convert it to a boolean in the condition code register or jump to | 727 // convert it to a boolean in the condition code register or jump to |
728 // 'false_target'/'true_target' as appropriate. | 728 // 'false_target'/'true_target' as appropriate. |
729 void CodeGenerator::ToBoolean(ControlDestination* dest) { | 729 void CodeGenerator::ToBoolean(ControlDestination* dest) { |
730 Comment cmnt(masm_, "[ ToBoolean"); | 730 Comment cmnt(masm_, "[ ToBoolean"); |
731 | 731 |
732 // The value to convert should be popped from the frame. | 732 // The value to convert should be popped from the frame. |
733 Result value = frame_->Pop(); | 733 Result value = frame_->Pop(); |
734 value.ToRegister(); | 734 value.ToRegister(); |
735 | 735 |
736 if (value.is_number()) { | 736 if (value.is_integer32()) { // Also takes Smi case. |
737 Comment cmnt(masm_, "ONLY_INTEGER_32"); | |
738 if (FLAG_debug_code) { | |
739 Label ok; | |
740 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | |
741 __ test(value.reg(), Immediate(kSmiTagMask)); | |
742 __ j(zero, &ok); | |
743 __ fldz(); | |
744 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | |
745 __ FCmp(); | |
746 __ j(not_zero, &ok); | |
747 __ Abort("Smi was wrapped in HeapNumber in output from bitop"); | |
748 __ bind(&ok); | |
749 } | |
750 // In the integer32 case there are no Smis hidden in heap numbers, so we | |
751 // need only test for Smi zero. | |
752 __ test(value.reg(), Operand(value.reg())); | |
753 dest->false_target()->Branch(zero); | |
754 value.Unuse(); | |
755 dest->Split(not_zero); | |
756 } else if (value.is_number()) { | |
737 Comment cmnt(masm_, "ONLY_NUMBER"); | 757 Comment cmnt(masm_, "ONLY_NUMBER"); |
738 // Fast case if NumberInfo indicates only numbers. | 758 // Fast case if NumberInfo indicates only numbers. |
739 if (FLAG_debug_code) { | 759 if (FLAG_debug_code) { |
740 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 760 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); |
741 } | 761 } |
742 // Smi => false iff zero. | 762 // Smi => false iff zero. |
743 ASSERT(kSmiTag == 0); | 763 ASSERT(kSmiTag == 0); |
744 __ test(value.reg(), Operand(value.reg())); | 764 __ test(value.reg(), Operand(value.reg())); |
745 dest->false_target()->Branch(zero); | 765 dest->false_target()->Branch(zero); |
746 __ test(value.reg(), Immediate(kSmiTagMask)); | 766 __ test(value.reg(), Immediate(kSmiTagMask)); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
810 | 830 |
811 // Test if operands are smi or number objects (fp). Requirements: | 831 // Test if operands are smi or number objects (fp). Requirements: |
812 // operand_1 in eax, operand_2 in edx; falls through on float | 832 // operand_1 in eax, operand_2 in edx; falls through on float |
813 // operands, jumps to the non_float label otherwise. | 833 // operands, jumps to the non_float label otherwise. |
814 static void CheckFloatOperands(MacroAssembler* masm, | 834 static void CheckFloatOperands(MacroAssembler* masm, |
815 Label* non_float, | 835 Label* non_float, |
816 Register scratch); | 836 Register scratch); |
817 // Takes the operands in edx and eax and loads them as integers in eax | 837 // Takes the operands in edx and eax and loads them as integers in eax |
818 // and ecx. | 838 // and ecx. |
819 static void LoadAsIntegers(MacroAssembler* masm, | 839 static void LoadAsIntegers(MacroAssembler* masm, |
840 NumberInfo number_info, | |
820 bool use_sse3, | 841 bool use_sse3, |
821 Label* operand_conversion_failure); | 842 Label* operand_conversion_failure); |
822 // Test if operands are smis or heap numbers and load them | 843 // Test if operands are smis or heap numbers and load them |
823 // into xmm0 and xmm1 if they are. Operands are in edx and eax. | 844 // into xmm0 and xmm1 if they are. Operands are in edx and eax. |
824 // Leaves operands unchanged. | 845 // Leaves operands unchanged. |
825 static void LoadSSE2Operands(MacroAssembler* masm); | 846 static void LoadSSE2Operands(MacroAssembler* masm); |
826 // Test if operands are numbers (smi or HeapNumber objects), and load | 847 // Test if operands are numbers (smi or HeapNumber objects), and load |
827 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | 848 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
828 // either operand is not a number. Operands are in edx and eax. | 849 // either operand is not a number. Operands are in edx and eax. |
829 // Leaves operands unchanged. | 850 // Leaves operands unchanged. |
(...skipping 19 matching lines...) Expand all Loading... | |
849 default: overwrite_name = "UnknownOverwrite"; break; | 870 default: overwrite_name = "UnknownOverwrite"; break; |
850 } | 871 } |
851 | 872 |
852 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 873 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
853 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", | 874 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", |
854 op_name, | 875 op_name, |
855 overwrite_name, | 876 overwrite_name, |
856 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 877 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
857 args_in_registers_ ? "RegArgs" : "StackArgs", | 878 args_in_registers_ ? "RegArgs" : "StackArgs", |
858 args_reversed_ ? "_R" : "", | 879 args_reversed_ ? "_R" : "", |
859 NumberInfo::ToString(static_operands_type_), | 880 static_operands_type_.ToString(), |
860 BinaryOpIC::GetName(runtime_operands_type_)); | 881 BinaryOpIC::GetName(runtime_operands_type_)); |
861 return name_; | 882 return name_; |
862 } | 883 } |
863 | 884 |
864 | 885 |
865 // Call the specialized stub for a binary operation. | 886 // Call the specialized stub for a binary operation. |
866 class DeferredInlineBinaryOperation: public DeferredCode { | 887 class DeferredInlineBinaryOperation: public DeferredCode { |
867 public: | 888 public: |
868 DeferredInlineBinaryOperation(Token::Value op, | 889 DeferredInlineBinaryOperation(Token::Value op, |
869 Register dst, | 890 Register dst, |
870 Register left, | 891 Register left, |
871 Register right, | 892 Register right, |
893 NumberInfo left_info, | |
894 NumberInfo right_info, | |
872 OverwriteMode mode) | 895 OverwriteMode mode) |
873 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { | 896 : op_(op), dst_(dst), left_(left), right_(right), |
897 left_info_(left_info), right_info_(right_info), mode_(mode) { | |
874 set_comment("[ DeferredInlineBinaryOperation"); | 898 set_comment("[ DeferredInlineBinaryOperation"); |
875 } | 899 } |
876 | 900 |
877 virtual void Generate(); | 901 virtual void Generate(); |
878 | 902 |
879 private: | 903 private: |
880 Token::Value op_; | 904 Token::Value op_; |
881 Register dst_; | 905 Register dst_; |
882 Register left_; | 906 Register left_; |
883 Register right_; | 907 Register right_; |
908 NumberInfo left_info_; | |
909 NumberInfo right_info_; | |
884 OverwriteMode mode_; | 910 OverwriteMode mode_; |
885 }; | 911 }; |
886 | 912 |
887 | 913 |
888 void DeferredInlineBinaryOperation::Generate() { | 914 void DeferredInlineBinaryOperation::Generate() { |
889 Label done; | 915 Label done; |
890 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || | 916 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || |
891 (op_ ==Token::SUB) || | 917 (op_ ==Token::SUB) || |
892 (op_ == Token::MUL) || | 918 (op_ == Token::MUL) || |
893 (op_ == Token::DIV))) { | 919 (op_ == Token::DIV))) { |
894 CpuFeatures::Scope use_sse2(SSE2); | 920 CpuFeatures::Scope use_sse2(SSE2); |
895 Label call_runtime, after_alloc_failure; | 921 Label call_runtime, after_alloc_failure; |
896 Label left_smi, right_smi, load_right, do_op; | 922 Label left_smi, right_smi, load_right, do_op; |
897 __ test(left_, Immediate(kSmiTagMask)); | 923 if (!left_info_.IsSmi()) { |
898 __ j(zero, &left_smi); | 924 __ test(left_, Immediate(kSmiTagMask)); |
899 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), | 925 __ j(zero, &left_smi); |
900 Factory::heap_number_map()); | 926 if (!left_info_.IsNumber()) { |
901 __ j(not_equal, &call_runtime); | 927 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), |
902 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 928 Factory::heap_number_map()); |
903 if (mode_ == OVERWRITE_LEFT) { | 929 __ j(not_equal, &call_runtime); |
904 __ mov(dst_, left_); | 930 } |
931 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | |
932 if (mode_ == OVERWRITE_LEFT) { | |
933 __ mov(dst_, left_); | |
934 } | |
935 __ jmp(&load_right); | |
936 | |
937 __ bind(&left_smi); | |
905 } | 938 } |
906 __ jmp(&load_right); | |
907 | |
908 __ bind(&left_smi); | |
909 __ SmiUntag(left_); | 939 __ SmiUntag(left_); |
910 __ cvtsi2sd(xmm0, Operand(left_)); | 940 __ cvtsi2sd(xmm0, Operand(left_)); |
911 __ SmiTag(left_); | 941 __ SmiTag(left_); |
912 if (mode_ == OVERWRITE_LEFT) { | 942 if (mode_ == OVERWRITE_LEFT) { |
913 Label alloc_failure; | 943 Label alloc_failure; |
914 __ push(left_); | 944 __ push(left_); |
915 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 945 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
916 __ pop(left_); | 946 __ pop(left_); |
917 } | 947 } |
918 | 948 |
919 __ bind(&load_right); | 949 __ bind(&load_right); |
920 __ test(right_, Immediate(kSmiTagMask)); | 950 if (!right_info_.IsSmi()) { |
921 __ j(zero, &right_smi); | 951 __ test(right_, Immediate(kSmiTagMask)); |
922 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), | 952 __ j(zero, &right_smi); |
923 Factory::heap_number_map()); | 953 if (!right_info_.IsNumber()) { |
924 __ j(not_equal, &call_runtime); | 954 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), |
925 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); | 955 Factory::heap_number_map()); |
926 if (mode_ == OVERWRITE_RIGHT) { | 956 __ j(not_equal, &call_runtime); |
927 __ mov(dst_, right_); | 957 } |
928 } else if (mode_ == NO_OVERWRITE) { | 958 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); |
929 Label alloc_failure; | 959 if (mode_ == OVERWRITE_RIGHT) { |
930 __ push(left_); | 960 __ mov(dst_, right_); |
931 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 961 } else if (mode_ == NO_OVERWRITE) { |
932 __ pop(left_); | 962 Label alloc_failure; |
963 __ push(left_); | |
964 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | |
965 __ pop(left_); | |
966 } | |
967 __ jmp(&do_op); | |
968 | |
969 __ bind(&right_smi); | |
933 } | 970 } |
934 __ jmp(&do_op); | |
935 | |
936 __ bind(&right_smi); | |
937 __ SmiUntag(right_); | 971 __ SmiUntag(right_); |
938 __ cvtsi2sd(xmm1, Operand(right_)); | 972 __ cvtsi2sd(xmm1, Operand(right_)); |
939 __ SmiTag(right_); | 973 __ SmiTag(right_); |
940 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { | 974 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { |
941 Label alloc_failure; | 975 Label alloc_failure; |
942 __ push(left_); | 976 __ push(left_); |
943 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 977 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
944 __ pop(left_); | 978 __ pop(left_); |
945 } | 979 } |
946 | 980 |
947 __ bind(&do_op); | 981 __ bind(&do_op); |
948 switch (op_) { | 982 switch (op_) { |
949 case Token::ADD: __ addsd(xmm0, xmm1); break; | 983 case Token::ADD: __ addsd(xmm0, xmm1); break; |
950 case Token::SUB: __ subsd(xmm0, xmm1); break; | 984 case Token::SUB: __ subsd(xmm0, xmm1); break; |
951 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 985 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
952 case Token::DIV: __ divsd(xmm0, xmm1); break; | 986 case Token::DIV: __ divsd(xmm0, xmm1); break; |
953 default: UNREACHABLE(); | 987 default: UNREACHABLE(); |
954 } | 988 } |
955 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); | 989 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); |
956 __ jmp(&done); | 990 __ jmp(&done); |
957 | 991 |
958 __ bind(&after_alloc_failure); | 992 __ bind(&after_alloc_failure); |
959 __ pop(left_); | 993 __ pop(left_); |
960 __ bind(&call_runtime); | 994 __ bind(&call_runtime); |
961 } | 995 } |
962 GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); | 996 GenericBinaryOpStub stub(op_, |
997 mode_, | |
998 NO_SMI_CODE_IN_STUB, | |
999 NumberInfo::Combine(left_info_, right_info_)); | |
963 stub.GenerateCall(masm_, left_, right_); | 1000 stub.GenerateCall(masm_, left_, right_); |
964 if (!dst_.is(eax)) __ mov(dst_, eax); | 1001 if (!dst_.is(eax)) __ mov(dst_, eax); |
965 __ bind(&done); | 1002 __ bind(&done); |
966 } | 1003 } |
967 | 1004 |
968 | 1005 |
1006 static NumberInfo CalculateNumberInfo(NumberInfo operands_type, | |
1007 Token::Value op, | |
1008 const Result& right, | |
1009 const Result& left) { | |
1010 // Set NumberInfo of result according to the operation performed. | |
1011 // Rely on the fact that smis have a 31 bit payload on ia32. | |
1012 ASSERT(kSmiValueSize == 31); | |
1013 switch (op) { | |
1014 case Token::COMMA: | |
1015 return right.number_info(); | |
1016 case Token::OR: | |
1017 case Token::AND: | |
1018 // Result type can be either of the two input types. | |
1019 return operands_type; | |
1020 case Token::BIT_AND: { | |
1021 // Anding with positive Smis will give you a Smi. | |
1022 if (right.is_constant() && right.handle()->IsSmi() && | |
1023 Smi::cast(*right.handle())->value() >= 0) { | |
1024 return NumberInfo::Smi(); | |
1025 } else if (left.is_constant() && left.handle()->IsSmi() && | |
1026 Smi::cast(*left.handle())->value() >= 0) { | |
1027 return NumberInfo::Smi(); | |
1028 } | |
1029 return (operands_type.IsSmi()) | |
1030 ? NumberInfo::Smi() | |
1031 : NumberInfo::Integer32(); | |
1032 } | |
1033 case Token::BIT_OR: { | |
1034 // Oring with negative Smis will give you a Smi. | |
1035 if (right.is_constant() && right.handle()->IsSmi() && | |
1036 Smi::cast(*right.handle())->value() < 0) { | |
1037 return NumberInfo::Smi(); | |
1038 } else if (left.is_constant() && left.handle()->IsSmi() && | |
1039 Smi::cast(*left.handle())->value() < 0) { | |
1040 return NumberInfo::Smi(); | |
1041 } | |
1042 return (operands_type.IsSmi()) | |
1043 ? NumberInfo::Smi() | |
1044 : NumberInfo::Integer32(); | |
1045 } | |
1046 case Token::BIT_XOR: | |
1047 // Result is always a number. Smi property of inputs is preserved. | |
fschneider
2010/03/05 15:01:07
// Result is always a integer32.
| |
1048 return (operands_type.IsSmi()) | |
1049 ? NumberInfo::Smi() | |
1050 : NumberInfo::Integer32(); | |
1051 case Token::SAR: | |
1052 if (left.is_smi()) return NumberInfo::Smi(); | |
1053 // Result is a smi if we shift by a constant >= 1, otherwise a number. | |
fschneider
2010/03/05 15:01:07
number --> integer32
| |
1054 return (right.is_constant() && right.handle()->IsSmi() | |
1055 && Smi::cast(*right.handle())->value() >= 1) | |
1056 ? NumberInfo::Smi() | |
1057 : NumberInfo::Integer32(); | |
1058 case Token::SHR: | |
1059 // Result is a smi if we shift by a constant >= 2, otherwise a number. | |
fschneider
2010/03/05 15:01:07
number --> integer32
| |
1060 return (right.is_constant() && right.handle()->IsSmi() | |
1061 && Smi::cast(*right.handle())->value() >= 2) | |
1062 ? NumberInfo::Smi() | |
1063 : NumberInfo::Integer32(); | |
1064 case Token::ADD: | |
1065 if (operands_type.IsSmi()) { | |
1066 // The Integer32 range is big enough to take the sum of any two Smis. | |
1067 return NumberInfo::Integer32(); | |
1068 } else { | |
1069 // Result could be a string or a number. Check types of inputs. | |
1070 return operands_type.IsNumber() | |
1071 ? NumberInfo::Number() | |
1072 : NumberInfo::Unknown(); | |
1073 } | |
1074 case Token::SHL: | |
1075 return NumberInfo::Integer32(); | |
1076 case Token::SUB: | |
1077 // The Integer32 range is big enough to take the difference of any two Smi s. | |
fschneider
2010/03/05 15:01:07
long line
| |
1078 return (operands_type.IsSmi()) ? | |
1079 NumberInfo::Integer32() : | |
1080 NumberInfo::Number(); | |
1081 case Token::MUL: | |
1082 case Token::DIV: | |
1083 case Token::MOD: | |
1084 // Result is always a number. | |
1085 return NumberInfo::Number(); | |
1086 default: | |
1087 UNREACHABLE(); | |
1088 } | |
1089 UNREACHABLE(); | |
1090 return NumberInfo::Unknown(); | |
1091 } | |
1092 | |
1093 | |
969 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 1094 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
970 StaticType* type, | 1095 StaticType* type, |
971 OverwriteMode overwrite_mode) { | 1096 OverwriteMode overwrite_mode) { |
972 Comment cmnt(masm_, "[ BinaryOperation"); | 1097 Comment cmnt(masm_, "[ BinaryOperation"); |
973 Comment cmnt_token(masm_, Token::String(op)); | 1098 Comment cmnt_token(masm_, Token::String(op)); |
974 | 1099 |
975 if (op == Token::COMMA) { | 1100 if (op == Token::COMMA) { |
976 // Simply discard left value. | 1101 // Simply discard left value. |
977 frame_->Nip(1); | 1102 frame_->Nip(1); |
978 return; | 1103 return; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1014 right.is_constant() && !right.handle()->IsSmi(); | 1139 right.is_constant() && !right.handle()->IsSmi(); |
1015 | 1140 |
1016 if (left_is_smi_constant && right_is_smi_constant) { | 1141 if (left_is_smi_constant && right_is_smi_constant) { |
1017 // Compute the constant result at compile time, and leave it on the frame. | 1142 // Compute the constant result at compile time, and leave it on the frame. |
1018 int left_int = Smi::cast(*left.handle())->value(); | 1143 int left_int = Smi::cast(*left.handle())->value(); |
1019 int right_int = Smi::cast(*right.handle())->value(); | 1144 int right_int = Smi::cast(*right.handle())->value(); |
1020 if (FoldConstantSmis(op, left_int, right_int)) return; | 1145 if (FoldConstantSmis(op, left_int, right_int)) return; |
1021 } | 1146 } |
1022 | 1147 |
1023 // Get number type of left and right sub-expressions. | 1148 // Get number type of left and right sub-expressions. |
1024 NumberInfo::Type operands_type = | 1149 NumberInfo operands_type = |
1025 NumberInfo::Combine(left.number_info(), right.number_info()); | 1150 NumberInfo::Combine(left.number_info(), right.number_info()); |
1026 | 1151 |
1152 NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left); | |
1153 | |
1027 Result answer; | 1154 Result answer; |
1028 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 1155 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
1029 // Go straight to the slow case, with no smi code. | 1156 // Go straight to the slow case, with no smi code. |
1030 GenericBinaryOpStub stub(op, | 1157 GenericBinaryOpStub stub(op, |
1031 overwrite_mode, | 1158 overwrite_mode, |
1032 NO_SMI_CODE_IN_STUB, | 1159 NO_SMI_CODE_IN_STUB, |
1033 operands_type); | 1160 operands_type); |
1034 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1161 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
1035 } else if (right_is_smi_constant) { | 1162 } else if (right_is_smi_constant) { |
1036 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 1163 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
1037 type, false, overwrite_mode); | 1164 type, false, overwrite_mode); |
1038 } else if (left_is_smi_constant) { | 1165 } else if (left_is_smi_constant) { |
1039 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), | 1166 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
1040 type, true, overwrite_mode); | 1167 type, true, overwrite_mode); |
1041 } else { | 1168 } else { |
1042 // Set the flags based on the operation, type and loop nesting level. | 1169 // Set the flags based on the operation, type and loop nesting level. |
1043 // Bit operations always assume they likely operate on Smis. Still only | 1170 // Bit operations always assume they likely operate on Smis. Still only |
1044 // generate the inline Smi check code if this operation is part of a loop. | 1171 // generate the inline Smi check code if this operation is part of a loop. |
1045 // For all other operations only inline the Smi check code for likely smis | 1172 // For all other operations only inline the Smi check code for likely smis |
1046 // if the operation is part of a loop. | 1173 // if the operation is part of a loop. |
1047 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { | 1174 if (loop_nesting() > 0 && |
1175 (Token::IsBitOp(op) || | |
1176 operands_type.IsInteger32() || | |
1177 type->IsLikelySmi())) { | |
1048 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 1178 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
1049 } else { | 1179 } else { |
1050 GenericBinaryOpStub stub(op, | 1180 GenericBinaryOpStub stub(op, |
1051 overwrite_mode, | 1181 overwrite_mode, |
1052 NO_GENERIC_BINARY_FLAGS, | 1182 NO_GENERIC_BINARY_FLAGS, |
1053 operands_type); | 1183 operands_type); |
1054 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1184 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
1055 } | 1185 } |
1056 } | 1186 } |
1057 | 1187 |
1058 // Set NumberInfo of result according to the operation performed. | |
1059 // Rely on the fact that smis have a 31 bit payload on ia32. | |
1060 ASSERT(kSmiValueSize == 31); | |
1061 NumberInfo::Type result_type = NumberInfo::kUnknown; | |
1062 switch (op) { | |
1063 case Token::COMMA: | |
1064 result_type = right.number_info(); | |
1065 break; | |
1066 case Token::OR: | |
1067 case Token::AND: | |
1068 // Result type can be either of the two input types. | |
1069 result_type = operands_type; | |
1070 break; | |
1071 case Token::BIT_OR: | |
1072 case Token::BIT_XOR: | |
1073 case Token::BIT_AND: | |
1074 // Result is always a number. Smi property of inputs is preserved. | |
1075 result_type = (operands_type == NumberInfo::kSmi) | |
1076 ? NumberInfo::kSmi | |
1077 : NumberInfo::kNumber; | |
1078 break; | |
1079 case Token::SAR: | |
1080 // Result is a smi if we shift by a constant >= 1, otherwise a number. | |
1081 result_type = (right.is_constant() && right.handle()->IsSmi() | |
1082 && Smi::cast(*right.handle())->value() >= 1) | |
1083 ? NumberInfo::kSmi | |
1084 : NumberInfo::kNumber; | |
1085 break; | |
1086 case Token::SHR: | |
1087 // Result is a smi if we shift by a constant >= 2, otherwise a number. | |
1088 result_type = (right.is_constant() && right.handle()->IsSmi() | |
1089 && Smi::cast(*right.handle())->value() >= 2) | |
1090 ? NumberInfo::kSmi | |
1091 : NumberInfo::kNumber; | |
1092 break; | |
1093 case Token::ADD: | |
1094 // Result could be a string or a number. Check types of inputs. | |
1095 result_type = NumberInfo::IsNumber(operands_type) | |
1096 ? NumberInfo::kNumber | |
1097 : NumberInfo::kUnknown; | |
1098 break; | |
1099 case Token::SHL: | |
1100 case Token::SUB: | |
1101 case Token::MUL: | |
1102 case Token::DIV: | |
1103 case Token::MOD: | |
1104 // Result is always a number. | |
1105 result_type = NumberInfo::kNumber; | |
1106 break; | |
1107 default: | |
1108 UNREACHABLE(); | |
1109 } | |
1110 answer.set_number_info(result_type); | 1188 answer.set_number_info(result_type); |
1111 frame_->Push(&answer); | 1189 frame_->Push(&answer); |
1112 } | 1190 } |
1113 | 1191 |
1114 | 1192 |
1115 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1193 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
1116 Object* answer_object = Heap::undefined_value(); | 1194 Object* answer_object = Heap::undefined_value(); |
1117 switch (op) { | 1195 switch (op) { |
1118 case Token::ADD: | 1196 case Token::ADD: |
1119 if (Smi::IsValid(left + right)) { | 1197 if (Smi::IsValid(left + right)) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1186 break; | 1264 break; |
1187 } | 1265 } |
1188 if (answer_object == Heap::undefined_value()) { | 1266 if (answer_object == Heap::undefined_value()) { |
1189 return false; | 1267 return false; |
1190 } | 1268 } |
1191 frame_->Push(Handle<Object>(answer_object)); | 1269 frame_->Push(Handle<Object>(answer_object)); |
1192 return true; | 1270 return true; |
1193 } | 1271 } |
1194 | 1272 |
1195 | 1273 |
1274 static void CheckTwoForSminess(MacroAssembler* masm, | |
1275 Register left, Register right, Register scratch, | |
1276 NumberInfo left_info, NumberInfo right_info, | |
1277 DeferredInlineBinaryOperation* deferred); | |
1278 | |
1279 | |
1196 // Implements a binary operation using a deferred code object and some | 1280 // Implements a binary operation using a deferred code object and some |
1197 // inline code to operate on smis quickly. | 1281 // inline code to operate on smis quickly. |
1198 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 1282 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
1199 Result* left, | 1283 Result* left, |
1200 Result* right, | 1284 Result* right, |
1201 OverwriteMode overwrite_mode) { | 1285 OverwriteMode overwrite_mode) { |
1202 Result answer; | 1286 Result answer; |
1203 // Special handling of div and mod because they use fixed registers. | 1287 // Special handling of div and mod because they use fixed registers. |
1204 if (op == Token::DIV || op == Token::MOD) { | 1288 if (op == Token::DIV || op == Token::MOD) { |
1205 // We need eax as the quotient register, edx as the remainder | 1289 // We need eax as the quotient register, edx as the remainder |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1266 right->ToRegister(); | 1350 right->ToRegister(); |
1267 frame_->Spill(eax); | 1351 frame_->Spill(eax); |
1268 frame_->Spill(edx); | 1352 frame_->Spill(edx); |
1269 | 1353 |
1270 // Check that left and right are smi tagged. | 1354 // Check that left and right are smi tagged. |
1271 DeferredInlineBinaryOperation* deferred = | 1355 DeferredInlineBinaryOperation* deferred = |
1272 new DeferredInlineBinaryOperation(op, | 1356 new DeferredInlineBinaryOperation(op, |
1273 (op == Token::DIV) ? eax : edx, | 1357 (op == Token::DIV) ? eax : edx, |
1274 left->reg(), | 1358 left->reg(), |
1275 right->reg(), | 1359 right->reg(), |
1360 left->number_info(), | |
1361 right->number_info(), | |
1276 overwrite_mode); | 1362 overwrite_mode); |
1277 if (left->reg().is(right->reg())) { | 1363 if (left->reg().is(right->reg())) { |
1278 __ test(left->reg(), Immediate(kSmiTagMask)); | 1364 __ test(left->reg(), Immediate(kSmiTagMask)); |
1279 } else { | 1365 } else { |
1280 // Use the quotient register as a scratch for the tag check. | 1366 // Use the quotient register as a scratch for the tag check. |
1281 if (!left_is_in_eax) __ mov(eax, left->reg()); | 1367 if (!left_is_in_eax) __ mov(eax, left->reg()); |
1282 left_is_in_eax = false; // About to destroy the value in eax. | 1368 left_is_in_eax = false; // About to destroy the value in eax. |
1283 __ or_(eax, Operand(right->reg())); | 1369 __ or_(eax, Operand(right->reg())); |
1284 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 1370 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
1285 __ test(eax, Immediate(kSmiTagMask)); | 1371 __ test(eax, Immediate(kSmiTagMask)); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1363 // Use a fresh answer register to avoid spilling the left operand. | 1449 // Use a fresh answer register to avoid spilling the left operand. |
1364 answer = allocator_->Allocate(); | 1450 answer = allocator_->Allocate(); |
1365 ASSERT(answer.is_valid()); | 1451 ASSERT(answer.is_valid()); |
1366 // Check that both operands are smis using the answer register as a | 1452 // Check that both operands are smis using the answer register as a |
1367 // temporary. | 1453 // temporary. |
1368 DeferredInlineBinaryOperation* deferred = | 1454 DeferredInlineBinaryOperation* deferred = |
1369 new DeferredInlineBinaryOperation(op, | 1455 new DeferredInlineBinaryOperation(op, |
1370 answer.reg(), | 1456 answer.reg(), |
1371 left->reg(), | 1457 left->reg(), |
1372 ecx, | 1458 ecx, |
1459 left->number_info(), | |
1460 right->number_info(), | |
1373 overwrite_mode); | 1461 overwrite_mode); |
1374 __ mov(answer.reg(), left->reg()); | 1462 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
1375 __ or_(answer.reg(), Operand(ecx)); | 1463 left->number_info(), right->number_info(), deferred); |
1376 __ test(answer.reg(), Immediate(kSmiTagMask)); | |
1377 deferred->Branch(not_zero); | |
1378 | 1464 |
1379 // Untag both operands. | 1465 // Untag both operands. |
1380 __ mov(answer.reg(), left->reg()); | 1466 __ mov(answer.reg(), left->reg()); |
1381 __ SmiUntag(answer.reg()); | 1467 __ SmiUntag(answer.reg()); |
1382 __ SmiUntag(ecx); | 1468 __ SmiUntag(ecx); |
1383 // Perform the operation. | 1469 // Perform the operation. |
1384 switch (op) { | 1470 switch (op) { |
1385 case Token::SAR: | 1471 case Token::SAR: |
1386 __ sar_cl(answer.reg()); | 1472 __ sar_cl(answer.reg()); |
1387 // No checks of result necessary | 1473 // No checks of result necessary |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1437 // need to be spilled in the fast case. | 1523 // need to be spilled in the fast case. |
1438 answer = allocator_->Allocate(); | 1524 answer = allocator_->Allocate(); |
1439 ASSERT(answer.is_valid()); | 1525 ASSERT(answer.is_valid()); |
1440 | 1526 |
1441 // Perform the smi tag check. | 1527 // Perform the smi tag check. |
1442 DeferredInlineBinaryOperation* deferred = | 1528 DeferredInlineBinaryOperation* deferred = |
1443 new DeferredInlineBinaryOperation(op, | 1529 new DeferredInlineBinaryOperation(op, |
1444 answer.reg(), | 1530 answer.reg(), |
1445 left->reg(), | 1531 left->reg(), |
1446 right->reg(), | 1532 right->reg(), |
1533 left->number_info(), | |
1534 right->number_info(), | |
1447 overwrite_mode); | 1535 overwrite_mode); |
1448 if (left->reg().is(right->reg())) { | 1536 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
1449 __ test(left->reg(), Immediate(kSmiTagMask)); | 1537 left->number_info(), right->number_info(), deferred); |
1450 } else { | 1538 |
1451 __ mov(answer.reg(), left->reg()); | |
1452 __ or_(answer.reg(), Operand(right->reg())); | |
1453 ASSERT(kSmiTag == 0); // Adjust test if not the case. | |
1454 __ test(answer.reg(), Immediate(kSmiTagMask)); | |
1455 } | |
1456 deferred->Branch(not_zero); | |
1457 __ mov(answer.reg(), left->reg()); | 1539 __ mov(answer.reg(), left->reg()); |
1458 switch (op) { | 1540 switch (op) { |
1459 case Token::ADD: | 1541 case Token::ADD: |
1460 __ add(answer.reg(), Operand(right->reg())); | 1542 __ add(answer.reg(), Operand(right->reg())); |
1461 deferred->Branch(overflow); | 1543 deferred->Branch(overflow); |
1462 break; | 1544 break; |
1463 | 1545 |
1464 case Token::SUB: | 1546 case Token::SUB: |
1465 __ sub(answer.reg(), Operand(right->reg())); | 1547 __ sub(answer.reg(), Operand(right->reg())); |
1466 deferred->Branch(overflow); | 1548 deferred->Branch(overflow); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1515 } | 1597 } |
1516 | 1598 |
1517 | 1599 |
1518 // Call the appropriate binary operation stub to compute src op value | 1600 // Call the appropriate binary operation stub to compute src op value |
1519 // and leave the result in dst. | 1601 // and leave the result in dst. |
1520 class DeferredInlineSmiOperation: public DeferredCode { | 1602 class DeferredInlineSmiOperation: public DeferredCode { |
1521 public: | 1603 public: |
1522 DeferredInlineSmiOperation(Token::Value op, | 1604 DeferredInlineSmiOperation(Token::Value op, |
1523 Register dst, | 1605 Register dst, |
1524 Register src, | 1606 Register src, |
1607 NumberInfo number_info, | |
1525 Smi* value, | 1608 Smi* value, |
1526 OverwriteMode overwrite_mode) | 1609 OverwriteMode overwrite_mode) |
1527 : op_(op), | 1610 : op_(op), |
1528 dst_(dst), | 1611 dst_(dst), |
1529 src_(src), | 1612 src_(src), |
1613 number_info_(number_info), | |
1530 value_(value), | 1614 value_(value), |
1531 overwrite_mode_(overwrite_mode) { | 1615 overwrite_mode_(overwrite_mode) { |
1616 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | |
1532 set_comment("[ DeferredInlineSmiOperation"); | 1617 set_comment("[ DeferredInlineSmiOperation"); |
1533 } | 1618 } |
1534 | 1619 |
1535 virtual void Generate(); | 1620 virtual void Generate(); |
1536 | 1621 |
1537 private: | 1622 private: |
1538 Token::Value op_; | 1623 Token::Value op_; |
1539 Register dst_; | 1624 Register dst_; |
1540 Register src_; | 1625 Register src_; |
1626 NumberInfo number_info_; | |
1541 Smi* value_; | 1627 Smi* value_; |
1542 OverwriteMode overwrite_mode_; | 1628 OverwriteMode overwrite_mode_; |
1543 }; | 1629 }; |
1544 | 1630 |
1545 | 1631 |
1546 void DeferredInlineSmiOperation::Generate() { | 1632 void DeferredInlineSmiOperation::Generate() { |
1547 // For mod we don't generate all the Smi code inline. | 1633 // For mod we don't generate all the Smi code inline. |
1548 GenericBinaryOpStub stub( | 1634 GenericBinaryOpStub stub( |
1549 op_, | 1635 op_, |
1550 overwrite_mode_, | 1636 overwrite_mode_, |
1551 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); | 1637 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB, |
1638 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | |
1552 stub.GenerateCall(masm_, src_, value_); | 1639 stub.GenerateCall(masm_, src_, value_); |
1553 if (!dst_.is(eax)) __ mov(dst_, eax); | 1640 if (!dst_.is(eax)) __ mov(dst_, eax); |
1554 } | 1641 } |
1555 | 1642 |
1556 | 1643 |
1557 // Call the appropriate binary operation stub to compute value op src | 1644 // Call the appropriate binary operation stub to compute value op src |
1558 // and leave the result in dst. | 1645 // and leave the result in dst. |
1559 class DeferredInlineSmiOperationReversed: public DeferredCode { | 1646 class DeferredInlineSmiOperationReversed: public DeferredCode { |
1560 public: | 1647 public: |
1561 DeferredInlineSmiOperationReversed(Token::Value op, | 1648 DeferredInlineSmiOperationReversed(Token::Value op, |
1562 Register dst, | 1649 Register dst, |
1563 Smi* value, | 1650 Smi* value, |
1564 Register src, | 1651 Register src, |
1652 NumberInfo number_info, | |
1565 OverwriteMode overwrite_mode) | 1653 OverwriteMode overwrite_mode) |
1566 : op_(op), | 1654 : op_(op), |
1567 dst_(dst), | 1655 dst_(dst), |
1656 number_info_(number_info), | |
1568 value_(value), | 1657 value_(value), |
1569 src_(src), | 1658 src_(src), |
1570 overwrite_mode_(overwrite_mode) { | 1659 overwrite_mode_(overwrite_mode) { |
1571 set_comment("[ DeferredInlineSmiOperationReversed"); | 1660 set_comment("[ DeferredInlineSmiOperationReversed"); |
1572 } | 1661 } |
1573 | 1662 |
1574 virtual void Generate(); | 1663 virtual void Generate(); |
1575 | 1664 |
1576 private: | 1665 private: |
1577 Token::Value op_; | 1666 Token::Value op_; |
1578 Register dst_; | 1667 Register dst_; |
1668 NumberInfo number_info_; | |
1579 Smi* value_; | 1669 Smi* value_; |
1580 Register src_; | 1670 Register src_; |
1581 OverwriteMode overwrite_mode_; | 1671 OverwriteMode overwrite_mode_; |
1582 }; | 1672 }; |
1583 | 1673 |
1584 | 1674 |
1585 void DeferredInlineSmiOperationReversed::Generate() { | 1675 void DeferredInlineSmiOperationReversed::Generate() { |
1586 GenericBinaryOpStub igostub(op_, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1676 GenericBinaryOpStub igostub( |
1677 op_, | |
1678 overwrite_mode_, | |
1679 NO_SMI_CODE_IN_STUB, | |
1680 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | |
1587 igostub.GenerateCall(masm_, value_, src_); | 1681 igostub.GenerateCall(masm_, value_, src_); |
1588 if (!dst_.is(eax)) __ mov(dst_, eax); | 1682 if (!dst_.is(eax)) __ mov(dst_, eax); |
1589 } | 1683 } |
1590 | 1684 |
1591 | 1685 |
1592 // The result of src + value is in dst. It either overflowed or was not | 1686 // The result of src + value is in dst. It either overflowed or was not |
1593 // smi tagged. Undo the speculative addition and call the appropriate | 1687 // smi tagged. Undo the speculative addition and call the appropriate |
1594 // specialized stub for add. The result is left in dst. | 1688 // specialized stub for add. The result is left in dst. |
1595 class DeferredInlineSmiAdd: public DeferredCode { | 1689 class DeferredInlineSmiAdd: public DeferredCode { |
1596 public: | 1690 public: |
1597 DeferredInlineSmiAdd(Register dst, | 1691 DeferredInlineSmiAdd(Register dst, |
1692 NumberInfo number_info, | |
1598 Smi* value, | 1693 Smi* value, |
1599 OverwriteMode overwrite_mode) | 1694 OverwriteMode overwrite_mode) |
1600 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1695 : dst_(dst), |
1696 number_info_(number_info), | |
1697 value_(value), | |
1698 overwrite_mode_(overwrite_mode) { | |
1699 if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | |
1601 set_comment("[ DeferredInlineSmiAdd"); | 1700 set_comment("[ DeferredInlineSmiAdd"); |
1602 } | 1701 } |
1603 | 1702 |
1604 virtual void Generate(); | 1703 virtual void Generate(); |
1605 | 1704 |
1606 private: | 1705 private: |
1607 Register dst_; | 1706 Register dst_; |
1707 NumberInfo number_info_; | |
1608 Smi* value_; | 1708 Smi* value_; |
1609 OverwriteMode overwrite_mode_; | 1709 OverwriteMode overwrite_mode_; |
1610 }; | 1710 }; |
1611 | 1711 |
1612 | 1712 |
1613 void DeferredInlineSmiAdd::Generate() { | 1713 void DeferredInlineSmiAdd::Generate() { |
1614 // Undo the optimistic add operation and call the shared stub. | 1714 // Undo the optimistic add operation and call the shared stub. |
1615 __ sub(Operand(dst_), Immediate(value_)); | 1715 __ sub(Operand(dst_), Immediate(value_)); |
1616 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1716 GenericBinaryOpStub igostub( |
1717 Token::ADD, | |
1718 overwrite_mode_, | |
1719 NO_SMI_CODE_IN_STUB, | |
1720 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | |
1617 igostub.GenerateCall(masm_, dst_, value_); | 1721 igostub.GenerateCall(masm_, dst_, value_); |
1618 if (!dst_.is(eax)) __ mov(dst_, eax); | 1722 if (!dst_.is(eax)) __ mov(dst_, eax); |
1619 } | 1723 } |
1620 | 1724 |
1621 | 1725 |
1622 // The result of value + src is in dst. It either overflowed or was not | 1726 // The result of value + src is in dst. It either overflowed or was not |
1623 // smi tagged. Undo the speculative addition and call the appropriate | 1727 // smi tagged. Undo the speculative addition and call the appropriate |
1624 // specialized stub for add. The result is left in dst. | 1728 // specialized stub for add. The result is left in dst. |
1625 class DeferredInlineSmiAddReversed: public DeferredCode { | 1729 class DeferredInlineSmiAddReversed: public DeferredCode { |
1626 public: | 1730 public: |
1627 DeferredInlineSmiAddReversed(Register dst, | 1731 DeferredInlineSmiAddReversed(Register dst, |
1732 NumberInfo number_info, | |
1628 Smi* value, | 1733 Smi* value, |
1629 OverwriteMode overwrite_mode) | 1734 OverwriteMode overwrite_mode) |
1630 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1735 : dst_(dst), |
1736 number_info_(number_info), | |
1737 value_(value), | |
1738 overwrite_mode_(overwrite_mode) { | |
1631 set_comment("[ DeferredInlineSmiAddReversed"); | 1739 set_comment("[ DeferredInlineSmiAddReversed"); |
1632 } | 1740 } |
1633 | 1741 |
1634 virtual void Generate(); | 1742 virtual void Generate(); |
1635 | 1743 |
1636 private: | 1744 private: |
1637 Register dst_; | 1745 Register dst_; |
1746 NumberInfo number_info_; | |
1638 Smi* value_; | 1747 Smi* value_; |
1639 OverwriteMode overwrite_mode_; | 1748 OverwriteMode overwrite_mode_; |
1640 }; | 1749 }; |
1641 | 1750 |
1642 | 1751 |
1643 void DeferredInlineSmiAddReversed::Generate() { | 1752 void DeferredInlineSmiAddReversed::Generate() { |
1644 // Undo the optimistic add operation and call the shared stub. | 1753 // Undo the optimistic add operation and call the shared stub. |
1645 __ sub(Operand(dst_), Immediate(value_)); | 1754 __ sub(Operand(dst_), Immediate(value_)); |
1646 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1755 GenericBinaryOpStub igostub(Token::ADD, |
1756 overwrite_mode_, | |
1757 NO_SMI_CODE_IN_STUB, | |
1758 NumberInfo::Combine(NumberInfo::Smi(), number_info _)); | |
1647 igostub.GenerateCall(masm_, value_, dst_); | 1759 igostub.GenerateCall(masm_, value_, dst_); |
1648 if (!dst_.is(eax)) __ mov(dst_, eax); | 1760 if (!dst_.is(eax)) __ mov(dst_, eax); |
1649 } | 1761 } |
1650 | 1762 |
1651 | 1763 |
1652 // The result of src - value is in dst. It either overflowed or was not | 1764 // The result of src - value is in dst. It either overflowed or was not |
1653 // smi tagged. Undo the speculative subtraction and call the | 1765 // smi tagged. Undo the speculative subtraction and call the |
1654 // appropriate specialized stub for subtract. The result is left in | 1766 // appropriate specialized stub for subtract. The result is left in |
1655 // dst. | 1767 // dst. |
1656 class DeferredInlineSmiSub: public DeferredCode { | 1768 class DeferredInlineSmiSub: public DeferredCode { |
1657 public: | 1769 public: |
1658 DeferredInlineSmiSub(Register dst, | 1770 DeferredInlineSmiSub(Register dst, |
1771 NumberInfo number_info, | |
1659 Smi* value, | 1772 Smi* value, |
1660 OverwriteMode overwrite_mode) | 1773 OverwriteMode overwrite_mode) |
1661 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1774 : dst_(dst), |
1775 number_info_(number_info), | |
1776 value_(value), | |
1777 overwrite_mode_(overwrite_mode) { | |
1778 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | |
1662 set_comment("[ DeferredInlineSmiSub"); | 1779 set_comment("[ DeferredInlineSmiSub"); |
1663 } | 1780 } |
1664 | 1781 |
1665 virtual void Generate(); | 1782 virtual void Generate(); |
1666 | 1783 |
1667 private: | 1784 private: |
1668 Register dst_; | 1785 Register dst_; |
1786 NumberInfo number_info_; | |
1669 Smi* value_; | 1787 Smi* value_; |
1670 OverwriteMode overwrite_mode_; | 1788 OverwriteMode overwrite_mode_; |
1671 }; | 1789 }; |
1672 | 1790 |
1673 | 1791 |
1674 void DeferredInlineSmiSub::Generate() { | 1792 void DeferredInlineSmiSub::Generate() { |
1675 // Undo the optimistic sub operation and call the shared stub. | 1793 // Undo the optimistic sub operation and call the shared stub. |
1676 __ add(Operand(dst_), Immediate(value_)); | 1794 __ add(Operand(dst_), Immediate(value_)); |
1677 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1795 GenericBinaryOpStub igostub(Token::SUB, |
1796 overwrite_mode_, | |
1797 NO_SMI_CODE_IN_STUB, | |
1798 NumberInfo::Combine(NumberInfo::Smi(), number_info _)); | |
1678 igostub.GenerateCall(masm_, dst_, value_); | 1799 igostub.GenerateCall(masm_, dst_, value_); |
1679 if (!dst_.is(eax)) __ mov(dst_, eax); | 1800 if (!dst_.is(eax)) __ mov(dst_, eax); |
1680 } | 1801 } |
1681 | 1802 |
1682 | 1803 |
1683 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1804 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
1684 Result* operand, | 1805 Result* operand, |
1685 Handle<Object> value, | 1806 Handle<Object> value, |
1686 StaticType* type, | 1807 StaticType* type, |
1687 bool reversed, | 1808 bool reversed, |
(...skipping 23 matching lines...) Expand all Loading... | |
1711 switch (op) { | 1832 switch (op) { |
1712 case Token::ADD: { | 1833 case Token::ADD: { |
1713 operand->ToRegister(); | 1834 operand->ToRegister(); |
1714 frame_->Spill(operand->reg()); | 1835 frame_->Spill(operand->reg()); |
1715 | 1836 |
1716 // Optimistically add. Call the specialized add stub if the | 1837 // Optimistically add. Call the specialized add stub if the |
1717 // result is not a smi or overflows. | 1838 // result is not a smi or overflows. |
1718 DeferredCode* deferred = NULL; | 1839 DeferredCode* deferred = NULL; |
1719 if (reversed) { | 1840 if (reversed) { |
1720 deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 1841 deferred = new DeferredInlineSmiAddReversed(operand->reg(), |
1842 operand->number_info(), | |
1721 smi_value, | 1843 smi_value, |
1722 overwrite_mode); | 1844 overwrite_mode); |
1723 } else { | 1845 } else { |
1724 deferred = new DeferredInlineSmiAdd(operand->reg(), | 1846 deferred = new DeferredInlineSmiAdd(operand->reg(), |
1847 operand->number_info(), | |
1725 smi_value, | 1848 smi_value, |
1726 overwrite_mode); | 1849 overwrite_mode); |
1727 } | 1850 } |
1728 __ add(Operand(operand->reg()), Immediate(value)); | 1851 __ add(Operand(operand->reg()), Immediate(value)); |
1729 deferred->Branch(overflow); | 1852 deferred->Branch(overflow); |
1730 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1853 if (!operand->number_info().IsSmi()) { |
1731 deferred->Branch(not_zero); | 1854 __ test(operand->reg(), Immediate(kSmiTagMask)); |
1855 deferred->Branch(not_zero); | |
1856 } | |
1732 deferred->BindExit(); | 1857 deferred->BindExit(); |
1733 answer = *operand; | 1858 answer = *operand; |
1734 break; | 1859 break; |
1735 } | 1860 } |
1736 | 1861 |
1737 case Token::SUB: { | 1862 case Token::SUB: { |
1738 DeferredCode* deferred = NULL; | 1863 DeferredCode* deferred = NULL; |
1739 if (reversed) { | 1864 if (reversed) { |
1740 // The reversed case is only hit when the right operand is not a | 1865 // The reversed case is only hit when the right operand is not a |
1741 // constant. | 1866 // constant. |
1742 ASSERT(operand->is_register()); | 1867 ASSERT(operand->is_register()); |
1743 answer = allocator()->Allocate(); | 1868 answer = allocator()->Allocate(); |
1744 ASSERT(answer.is_valid()); | 1869 ASSERT(answer.is_valid()); |
1745 __ Set(answer.reg(), Immediate(value)); | 1870 __ Set(answer.reg(), Immediate(value)); |
1746 deferred = new DeferredInlineSmiOperationReversed(op, | 1871 deferred = new DeferredInlineSmiOperationReversed(op, |
1747 answer.reg(), | 1872 answer.reg(), |
1748 smi_value, | 1873 smi_value, |
1749 operand->reg(), | 1874 operand->reg(), |
1875 operand->number_info() , | |
fschneider
2010/03/05 15:01:07
long line?
| |
1750 overwrite_mode); | 1876 overwrite_mode); |
1751 __ sub(answer.reg(), Operand(operand->reg())); | 1877 __ sub(answer.reg(), Operand(operand->reg())); |
1752 } else { | 1878 } else { |
1753 operand->ToRegister(); | 1879 operand->ToRegister(); |
1754 frame_->Spill(operand->reg()); | 1880 frame_->Spill(operand->reg()); |
1755 answer = *operand; | 1881 answer = *operand; |
1756 deferred = new DeferredInlineSmiSub(operand->reg(), | 1882 deferred = new DeferredInlineSmiSub(operand->reg(), |
1883 operand->number_info(), | |
1757 smi_value, | 1884 smi_value, |
1758 overwrite_mode); | 1885 overwrite_mode); |
1759 __ sub(Operand(operand->reg()), Immediate(value)); | 1886 __ sub(Operand(operand->reg()), Immediate(value)); |
1760 } | 1887 } |
1761 deferred->Branch(overflow); | 1888 deferred->Branch(overflow); |
1762 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1889 if (!operand->number_info().IsSmi()) { |
1763 deferred->Branch(not_zero); | 1890 __ test(answer.reg(), Immediate(kSmiTagMask)); |
1891 deferred->Branch(not_zero); | |
1892 } | |
1764 deferred->BindExit(); | 1893 deferred->BindExit(); |
1765 operand->Unuse(); | 1894 operand->Unuse(); |
1766 break; | 1895 break; |
1767 } | 1896 } |
1768 | 1897 |
1769 case Token::SAR: | 1898 case Token::SAR: |
1770 if (reversed) { | 1899 if (reversed) { |
1771 Result constant_operand(value); | 1900 Result constant_operand(value); |
1772 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 1901 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
1773 overwrite_mode); | 1902 overwrite_mode); |
1774 } else { | 1903 } else { |
1775 // Only the least significant 5 bits of the shift value are used. | 1904 // Only the least significant 5 bits of the shift value are used. |
1776 // In the slow case, this masking is done inside the runtime call. | 1905 // In the slow case, this masking is done inside the runtime call. |
1777 int shift_value = int_value & 0x1f; | 1906 int shift_value = int_value & 0x1f; |
1778 operand->ToRegister(); | 1907 operand->ToRegister(); |
1779 frame_->Spill(operand->reg()); | 1908 frame_->Spill(operand->reg()); |
1780 DeferredInlineSmiOperation* deferred = | 1909 DeferredInlineSmiOperation* deferred = |
1781 new DeferredInlineSmiOperation(op, | 1910 new DeferredInlineSmiOperation(op, |
1782 operand->reg(), | 1911 operand->reg(), |
1783 operand->reg(), | 1912 operand->reg(), |
1913 operand->number_info(), | |
fschneider
2010/03/05 15:01:07
You could avoid creating the DeferredInlineSmiOper
| |
1784 smi_value, | 1914 smi_value, |
1785 overwrite_mode); | 1915 overwrite_mode); |
1786 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1916 if (!operand->number_info().IsSmi()) { |
1787 deferred->Branch(not_zero); | 1917 __ test(operand->reg(), Immediate(kSmiTagMask)); |
1918 deferred->Branch(not_zero); | |
1919 } | |
1788 if (shift_value > 0) { | 1920 if (shift_value > 0) { |
1789 __ sar(operand->reg(), shift_value); | 1921 __ sar(operand->reg(), shift_value); |
1790 __ and_(operand->reg(), ~kSmiTagMask); | 1922 __ and_(operand->reg(), ~kSmiTagMask); |
1791 } | 1923 } |
1792 deferred->BindExit(); | 1924 deferred->BindExit(); |
1793 answer = *operand; | 1925 answer = *operand; |
1794 } | 1926 } |
1795 break; | 1927 break; |
1796 | 1928 |
1797 case Token::SHR: | 1929 case Token::SHR: |
1798 if (reversed) { | 1930 if (reversed) { |
1799 Result constant_operand(value); | 1931 Result constant_operand(value); |
1800 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 1932 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
1801 overwrite_mode); | 1933 overwrite_mode); |
1802 } else { | 1934 } else { |
1803 // Only the least significant 5 bits of the shift value are used. | 1935 // Only the least significant 5 bits of the shift value are used. |
1804 // In the slow case, this masking is done inside the runtime call. | 1936 // In the slow case, this masking is done inside the runtime call. |
1805 int shift_value = int_value & 0x1f; | 1937 int shift_value = int_value & 0x1f; |
1806 operand->ToRegister(); | 1938 operand->ToRegister(); |
1807 answer = allocator()->Allocate(); | 1939 answer = allocator()->Allocate(); |
1808 ASSERT(answer.is_valid()); | 1940 ASSERT(answer.is_valid()); |
1809 DeferredInlineSmiOperation* deferred = | 1941 DeferredInlineSmiOperation* deferred = |
1810 new DeferredInlineSmiOperation(op, | 1942 new DeferredInlineSmiOperation(op, |
1811 answer.reg(), | 1943 answer.reg(), |
1812 operand->reg(), | 1944 operand->reg(), |
1945 operand->number_info(), | |
1813 smi_value, | 1946 smi_value, |
1814 overwrite_mode); | 1947 overwrite_mode); |
1815 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1948 if (!operand->number_info().IsSmi()) { |
1816 deferred->Branch(not_zero); | 1949 __ test(operand->reg(), Immediate(kSmiTagMask)); |
1950 deferred->Branch(not_zero); | |
1951 } | |
1817 __ mov(answer.reg(), operand->reg()); | 1952 __ mov(answer.reg(), operand->reg()); |
1818 __ SmiUntag(answer.reg()); | 1953 __ SmiUntag(answer.reg()); |
1819 __ shr(answer.reg(), shift_value); | 1954 __ shr(answer.reg(), shift_value); |
1820 // A negative Smi shifted right two is in the positive Smi range. | 1955 // A negative Smi shifted right two is in the positive Smi range. |
1821 if (shift_value < 2) { | 1956 if (shift_value < 2) { |
1822 __ test(answer.reg(), Immediate(0xc0000000)); | 1957 __ test(answer.reg(), Immediate(0xc0000000)); |
1823 deferred->Branch(not_zero); | 1958 deferred->Branch(not_zero); |
1824 } | 1959 } |
1825 operand->Unuse(); | 1960 operand->Unuse(); |
1826 __ SmiTag(answer.reg()); | 1961 __ SmiTag(answer.reg()); |
(...skipping 21 matching lines...) Expand all Loading... | |
1848 right = *operand; | 1983 right = *operand; |
1849 } | 1984 } |
1850 operand->Unuse(); | 1985 operand->Unuse(); |
1851 | 1986 |
1852 answer = allocator()->Allocate(); | 1987 answer = allocator()->Allocate(); |
1853 DeferredInlineSmiOperationReversed* deferred = | 1988 DeferredInlineSmiOperationReversed* deferred = |
1854 new DeferredInlineSmiOperationReversed(op, | 1989 new DeferredInlineSmiOperationReversed(op, |
1855 answer.reg(), | 1990 answer.reg(), |
1856 smi_value, | 1991 smi_value, |
1857 right.reg(), | 1992 right.reg(), |
1993 right.number_info(), | |
1858 overwrite_mode); | 1994 overwrite_mode); |
1859 __ mov(answer.reg(), Immediate(int_value)); | 1995 __ mov(answer.reg(), Immediate(int_value)); |
1860 __ sar(ecx, kSmiTagSize); | 1996 __ sar(ecx, kSmiTagSize); |
1861 deferred->Branch(carry); | 1997 if (!right.number_info().IsSmi()) { |
1998 deferred->Branch(carry); | |
1999 } | |
1862 __ shl_cl(answer.reg()); | 2000 __ shl_cl(answer.reg()); |
1863 __ cmp(answer.reg(), 0xc0000000); | 2001 __ cmp(answer.reg(), 0xc0000000); |
1864 deferred->Branch(sign); | 2002 deferred->Branch(sign); |
1865 __ SmiTag(answer.reg()); | 2003 __ SmiTag(answer.reg()); |
1866 | 2004 |
1867 deferred->BindExit(); | 2005 deferred->BindExit(); |
1868 } else { | 2006 } else { |
1869 // Only the least significant 5 bits of the shift value are used. | 2007 // Only the least significant 5 bits of the shift value are used. |
1870 // In the slow case, this masking is done inside the runtime call. | 2008 // In the slow case, this masking is done inside the runtime call. |
1871 int shift_value = int_value & 0x1f; | 2009 int shift_value = int_value & 0x1f; |
1872 operand->ToRegister(); | 2010 operand->ToRegister(); |
1873 if (shift_value == 0) { | 2011 if (shift_value == 0) { |
1874 // Spill operand so it can be overwritten in the slow case. | 2012 // Spill operand so it can be overwritten in the slow case. |
1875 frame_->Spill(operand->reg()); | 2013 frame_->Spill(operand->reg()); |
1876 DeferredInlineSmiOperation* deferred = | 2014 DeferredInlineSmiOperation* deferred = |
1877 new DeferredInlineSmiOperation(op, | 2015 new DeferredInlineSmiOperation(op, |
1878 operand->reg(), | 2016 operand->reg(), |
1879 operand->reg(), | 2017 operand->reg(), |
2018 operand->number_info(), | |
1880 smi_value, | 2019 smi_value, |
1881 overwrite_mode); | 2020 overwrite_mode); |
1882 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2021 if (!operand->number_info().IsSmi()) { |
fschneider
2010/03/05 15:01:07
Also here only instantiate DeferredInlineSmiOperat
| |
1883 deferred->Branch(not_zero); | 2022 __ test(operand->reg(), Immediate(kSmiTagMask)); |
2023 deferred->Branch(not_zero); | |
2024 } | |
1884 deferred->BindExit(); | 2025 deferred->BindExit(); |
1885 answer = *operand; | 2026 answer = *operand; |
1886 } else { | 2027 } else { |
1887 // Use a fresh temporary for nonzero shift values. | 2028 // Use a fresh temporary for nonzero shift values. |
1888 answer = allocator()->Allocate(); | 2029 answer = allocator()->Allocate(); |
1889 ASSERT(answer.is_valid()); | 2030 ASSERT(answer.is_valid()); |
1890 DeferredInlineSmiOperation* deferred = | 2031 DeferredInlineSmiOperation* deferred = |
1891 new DeferredInlineSmiOperation(op, | 2032 new DeferredInlineSmiOperation(op, |
1892 answer.reg(), | 2033 answer.reg(), |
1893 operand->reg(), | 2034 operand->reg(), |
2035 operand->number_info(), | |
1894 smi_value, | 2036 smi_value, |
1895 overwrite_mode); | 2037 overwrite_mode); |
1896 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2038 if (!operand->number_info().IsSmi()) { |
1897 deferred->Branch(not_zero); | 2039 __ test(operand->reg(), Immediate(kSmiTagMask)); |
2040 deferred->Branch(not_zero); | |
2041 } | |
1898 __ mov(answer.reg(), operand->reg()); | 2042 __ mov(answer.reg(), operand->reg()); |
1899 ASSERT(kSmiTag == 0); // adjust code if not the case | 2043 ASSERT(kSmiTag == 0); // adjust code if not the case |
1900 // We do no shifts, only the Smi conversion, if shift_value is 1. | 2044 // We do no shifts, only the Smi conversion, if shift_value is 1. |
1901 if (shift_value > 1) { | 2045 if (shift_value > 1) { |
1902 __ shl(answer.reg(), shift_value - 1); | 2046 __ shl(answer.reg(), shift_value - 1); |
1903 } | 2047 } |
1904 // Convert int result to Smi, checking that it is in int range. | 2048 // Convert int result to Smi, checking that it is in int range. |
1905 ASSERT(kSmiTagSize == 1); // adjust code if not the case | 2049 ASSERT(kSmiTagSize == 1); // adjust code if not the case |
1906 __ add(answer.reg(), Operand(answer.reg())); | 2050 __ add(answer.reg(), Operand(answer.reg())); |
1907 deferred->Branch(overflow); | 2051 deferred->Branch(overflow); |
1908 deferred->BindExit(); | 2052 deferred->BindExit(); |
1909 operand->Unuse(); | 2053 operand->Unuse(); |
1910 } | 2054 } |
1911 } | 2055 } |
1912 break; | 2056 break; |
1913 | 2057 |
1914 case Token::BIT_OR: | 2058 case Token::BIT_OR: |
1915 case Token::BIT_XOR: | 2059 case Token::BIT_XOR: |
1916 case Token::BIT_AND: { | 2060 case Token::BIT_AND: { |
1917 operand->ToRegister(); | 2061 operand->ToRegister(); |
1918 frame_->Spill(operand->reg()); | 2062 frame_->Spill(operand->reg()); |
1919 DeferredCode* deferred = NULL; | 2063 DeferredCode* deferred = NULL; |
1920 if (reversed) { | 2064 if (reversed) { |
1921 deferred = new DeferredInlineSmiOperationReversed(op, | 2065 deferred = new DeferredInlineSmiOperationReversed(op, |
1922 operand->reg(), | 2066 operand->reg(), |
1923 smi_value, | 2067 smi_value, |
1924 operand->reg(), | 2068 operand->reg(), |
2069 operand->number_info() , | |
fschneider
2010/03/05 15:01:07
long line.
| |
1925 overwrite_mode); | 2070 overwrite_mode); |
1926 } else { | 2071 } else { |
1927 deferred = new DeferredInlineSmiOperation(op, | 2072 deferred = new DeferredInlineSmiOperation(op, |
1928 operand->reg(), | 2073 operand->reg(), |
1929 operand->reg(), | 2074 operand->reg(), |
2075 operand->number_info(), | |
1930 smi_value, | 2076 smi_value, |
1931 overwrite_mode); | 2077 overwrite_mode); |
1932 } | 2078 } |
1933 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2079 if (!operand->number_info().IsSmi()) { |
fschneider
2010/03/05 15:01:07
Also here only instantiate DeferredInlineSmiOperat
Erik Corry
2010/03/05 20:20:15
Actually instead I will remove the 'if' since shif
| |
1934 deferred->Branch(not_zero); | 2080 __ test(operand->reg(), Immediate(kSmiTagMask)); |
2081 deferred->Branch(not_zero); | |
2082 } | |
1935 if (op == Token::BIT_AND) { | 2083 if (op == Token::BIT_AND) { |
1936 __ and_(Operand(operand->reg()), Immediate(value)); | 2084 __ and_(Operand(operand->reg()), Immediate(value)); |
1937 } else if (op == Token::BIT_XOR) { | 2085 } else if (op == Token::BIT_XOR) { |
1938 if (int_value != 0) { | 2086 if (int_value != 0) { |
1939 __ xor_(Operand(operand->reg()), Immediate(value)); | 2087 __ xor_(Operand(operand->reg()), Immediate(value)); |
1940 } | 2088 } |
1941 } else { | 2089 } else { |
1942 ASSERT(op == Token::BIT_OR); | 2090 ASSERT(op == Token::BIT_OR); |
1943 if (int_value != 0) { | 2091 if (int_value != 0) { |
1944 __ or_(Operand(operand->reg()), Immediate(value)); | 2092 __ or_(Operand(operand->reg()), Immediate(value)); |
1945 } | 2093 } |
1946 } | 2094 } |
1947 deferred->BindExit(); | 2095 deferred->BindExit(); |
1948 answer = *operand; | 2096 answer = *operand; |
1949 break; | 2097 break; |
1950 } | 2098 } |
1951 | 2099 |
1952 case Token::DIV: | 2100 case Token::DIV: |
1953 if (!reversed && int_value == 2) { | 2101 if (!reversed && int_value == 2) { |
1954 operand->ToRegister(); | 2102 operand->ToRegister(); |
1955 frame_->Spill(operand->reg()); | 2103 frame_->Spill(operand->reg()); |
1956 | 2104 |
1957 DeferredInlineSmiOperation* deferred = | 2105 DeferredInlineSmiOperation* deferred = |
1958 new DeferredInlineSmiOperation(op, | 2106 new DeferredInlineSmiOperation(op, |
1959 operand->reg(), | 2107 operand->reg(), |
1960 operand->reg(), | 2108 operand->reg(), |
2109 operand->number_info(), | |
1961 smi_value, | 2110 smi_value, |
1962 overwrite_mode); | 2111 overwrite_mode); |
1963 // Check that lowest log2(value) bits of operand are zero, and test | 2112 // Check that lowest log2(value) bits of operand are zero, and test |
1964 // smi tag at the same time. | 2113 // smi tag at the same time. |
1965 ASSERT_EQ(0, kSmiTag); | 2114 ASSERT_EQ(0, kSmiTag); |
1966 ASSERT_EQ(1, kSmiTagSize); | 2115 ASSERT_EQ(1, kSmiTagSize); |
1967 __ test(operand->reg(), Immediate(3)); | 2116 __ test(operand->reg(), Immediate(3)); |
1968 deferred->Branch(not_zero); // Branch if non-smi or odd smi. | 2117 deferred->Branch(not_zero); // Branch if non-smi or odd smi. |
1969 __ sar(operand->reg(), 1); | 2118 __ sar(operand->reg(), 1); |
1970 deferred->BindExit(); | 2119 deferred->BindExit(); |
(...skipping 14 matching lines...) Expand all Loading... | |
1985 // Generate inline code for mod of powers of 2 and negative powers of 2. | 2134 // Generate inline code for mod of powers of 2 and negative powers of 2. |
1986 case Token::MOD: | 2135 case Token::MOD: |
1987 if (!reversed && | 2136 if (!reversed && |
1988 int_value != 0 && | 2137 int_value != 0 && |
1989 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 2138 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
1990 operand->ToRegister(); | 2139 operand->ToRegister(); |
1991 frame_->Spill(operand->reg()); | 2140 frame_->Spill(operand->reg()); |
1992 DeferredCode* deferred = new DeferredInlineSmiOperation(op, | 2141 DeferredCode* deferred = new DeferredInlineSmiOperation(op, |
1993 operand->reg(), | 2142 operand->reg(), |
1994 operand->reg(), | 2143 operand->reg(), |
2144 operand->number_ info(), | |
fschneider
2010/03/05 15:01:07
Long line.
| |
1995 smi_value, | 2145 smi_value, |
1996 overwrite_mode); | 2146 overwrite_mode); |
1997 // Check for negative or non-Smi left hand side. | 2147 // Check for negative or non-Smi left hand side. |
1998 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); | 2148 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
1999 deferred->Branch(not_zero); | 2149 deferred->Branch(not_zero); |
2000 if (int_value < 0) int_value = -int_value; | 2150 if (int_value < 0) int_value = -int_value; |
2001 if (int_value == 1) { | 2151 if (int_value == 1) { |
2002 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 2152 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
2003 } else { | 2153 } else { |
2004 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 2154 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
(...skipping 15 matching lines...) Expand all Loading... | |
2020 } | 2170 } |
2021 break; | 2171 break; |
2022 } | 2172 } |
2023 } | 2173 } |
2024 ASSERT(answer.is_valid()); | 2174 ASSERT(answer.is_valid()); |
2025 return answer; | 2175 return answer; |
2026 } | 2176 } |
2027 | 2177 |
2028 | 2178 |
2029 static bool CouldBeNaN(const Result& result) { | 2179 static bool CouldBeNaN(const Result& result) { |
2180 if (result.number_info().IsSmi()) return false; | |
2181 if (result.number_info().IsInteger32()) return false; | |
2030 if (!result.is_constant()) return true; | 2182 if (!result.is_constant()) return true; |
2031 if (!result.handle()->IsHeapNumber()) return false; | 2183 if (!result.handle()->IsHeapNumber()) return false; |
2032 return isnan(HeapNumber::cast(*result.handle())->value()); | 2184 return isnan(HeapNumber::cast(*result.handle())->value()); |
2033 } | 2185 } |
2034 | 2186 |
2035 | 2187 |
2036 void CodeGenerator::Comparison(AstNode* node, | 2188 void CodeGenerator::Comparison(AstNode* node, |
2037 Condition cc, | 2189 Condition cc, |
2038 bool strict, | 2190 bool strict, |
2039 ControlDestination* dest) { | 2191 ControlDestination* dest) { |
(...skipping 5083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7123 // Initially, use an invalid map. The map is patched in the IC | 7275 // Initially, use an invalid map. The map is patched in the IC |
7124 // initialization code. | 7276 // initialization code. |
7125 __ bind(deferred->patch_site()); | 7277 __ bind(deferred->patch_site()); |
7126 // Use masm-> here instead of the double underscore macro since extra | 7278 // Use masm-> here instead of the double underscore macro since extra |
7127 // coverage code can interfere with the patching. | 7279 // coverage code can interfere with the patching. |
7128 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 7280 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
7129 Immediate(Factory::null_value())); | 7281 Immediate(Factory::null_value())); |
7130 deferred->Branch(not_equal); | 7282 deferred->Branch(not_equal); |
7131 | 7283 |
7132 // Check that the key is a smi. | 7284 // Check that the key is a smi. |
7133 __ test(key.reg(), Immediate(kSmiTagMask)); | 7285 if (!key.is_smi()) { |
7134 deferred->Branch(not_zero); | 7286 __ test(key.reg(), Immediate(kSmiTagMask)); |
7287 deferred->Branch(not_zero); | |
7288 } | |
7135 | 7289 |
7136 // Get the elements array from the receiver and check that it | 7290 // Get the elements array from the receiver and check that it |
7137 // is not a dictionary. | 7291 // is not a dictionary. |
7138 __ mov(elements.reg(), | 7292 __ mov(elements.reg(), |
7139 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | 7293 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); |
7140 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), | 7294 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), |
7141 Immediate(Factory::fixed_array_map())); | 7295 Immediate(Factory::fixed_array_map())); |
7142 deferred->Branch(not_equal); | 7296 deferred->Branch(not_equal); |
7143 | 7297 |
7144 // Shift the key to get the actual index value and check that | 7298 // Shift the key to get the actual index value and check that |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7269 } | 7423 } |
7270 ASSERT(frame()->height() == original_height - 3); | 7424 ASSERT(frame()->height() == original_height - 3); |
7271 return result; | 7425 return result; |
7272 } | 7426 } |
7273 | 7427 |
7274 | 7428 |
7275 #undef __ | 7429 #undef __ |
7276 #define __ ACCESS_MASM(masm) | 7430 #define __ ACCESS_MASM(masm) |
7277 | 7431 |
7278 | 7432 |
7433 static void CheckTwoForSminess(MacroAssembler* masm, | |
7434 Register left, Register right, Register scratch, | |
7435 NumberInfo left_info, NumberInfo right_info, | |
7436 DeferredInlineBinaryOperation* deferred) { | |
7437 if (left.is(right)) { | |
7438 if (!left_info.IsSmi()) { | |
7439 __ test(left, Immediate(kSmiTagMask)); | |
7440 deferred->Branch(not_zero); | |
7441 } | |
7442 } else if (!left_info.IsSmi()) { | |
7443 if (!right_info.IsSmi()) { | |
7444 __ mov(scratch, left); | |
7445 __ or_(scratch, Operand(right)); | |
7446 __ test(scratch, Immediate(kSmiTagMask)); | |
7447 deferred->Branch(not_zero); | |
7448 } else { | |
7449 __ test (left, Immediate(kSmiTagMask)); | |
7450 deferred->Branch(not_zero); | |
7451 } | |
7452 } else { | |
7453 if (!right_info.IsSmi()) { | |
7454 __ test(right, Immediate(kSmiTagMask)); | |
7455 deferred->Branch(not_zero); | |
7456 } | |
7457 } | |
7458 } | |
7459 | |
7460 | |
7279 Handle<String> Reference::GetName() { | 7461 Handle<String> Reference::GetName() { |
7280 ASSERT(type_ == NAMED); | 7462 ASSERT(type_ == NAMED); |
7281 Property* property = expression_->AsProperty(); | 7463 Property* property = expression_->AsProperty(); |
7282 if (property == NULL) { | 7464 if (property == NULL) { |
7283 // Global variable reference treated as a named property reference. | 7465 // Global variable reference treated as a named property reference. |
7284 VariableProxy* proxy = expression_->AsVariableProxy(); | 7466 VariableProxy* proxy = expression_->AsVariableProxy(); |
7285 ASSERT(proxy->AsVariable() != NULL); | 7467 ASSERT(proxy->AsVariable() != NULL); |
7286 ASSERT(proxy->AsVariable()->is_global()); | 7468 ASSERT(proxy->AsVariable()->is_global()); |
7287 return proxy->name(); | 7469 return proxy->name(); |
7288 } else { | 7470 } else { |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7769 if (HasArgsInRegisters()) { | 7951 if (HasArgsInRegisters()) { |
7770 __ mov(ebx, eax); | 7952 __ mov(ebx, eax); |
7771 __ mov(eax, edx); | 7953 __ mov(eax, edx); |
7772 } | 7954 } |
7773 } | 7955 } |
7774 if (!HasArgsInRegisters()) { | 7956 if (!HasArgsInRegisters()) { |
7775 __ mov(right, Operand(esp, 1 * kPointerSize)); | 7957 __ mov(right, Operand(esp, 1 * kPointerSize)); |
7776 __ mov(left, Operand(esp, 2 * kPointerSize)); | 7958 __ mov(left, Operand(esp, 2 * kPointerSize)); |
7777 } | 7959 } |
7778 | 7960 |
7961 if (static_operands_type_.IsSmi()) { | |
7962 if (op_ == Token::BIT_OR) { | |
7963 __ or_(right, Operand(left)); | |
7964 GenerateReturn(masm); | |
7965 return; | |
7966 } else if (op_ == Token::BIT_AND) { | |
7967 __ and_(right, Operand(left)); | |
7968 GenerateReturn(masm); | |
7969 return; | |
7970 } else if (op_ == Token::BIT_XOR) { | |
7971 __ xor_(right, Operand(left)); | |
7972 GenerateReturn(masm); | |
7973 return; | |
7974 } | |
7975 } | |
7976 | |
7779 // 2. Prepare the smi check of both operands by oring them together. | 7977 // 2. Prepare the smi check of both operands by oring them together. |
7780 Comment smi_check_comment(masm, "-- Smi check arguments"); | 7978 Comment smi_check_comment(masm, "-- Smi check arguments"); |
7781 Label not_smis; | 7979 Label not_smis; |
7782 Register combined = ecx; | 7980 Register combined = ecx; |
7783 ASSERT(!left.is(combined) && !right.is(combined)); | 7981 ASSERT(!left.is(combined) && !right.is(combined)); |
7784 switch (op_) { | 7982 switch (op_) { |
7785 case Token::BIT_OR: | 7983 case Token::BIT_OR: |
7786 // Perform the operation into eax and smi check the result. Preserve | 7984 // Perform the operation into eax and smi check the result. Preserve |
7787 // eax in case the result is not a smi. | 7985 // eax in case the result is not a smi. |
7788 ASSERT(!left.is(ecx) && !right.is(ecx)); | 7986 ASSERT(!left.is(ecx) && !right.is(ecx)); |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8105 // (and only if smi code is generated). This is the right moment to | 8303 // (and only if smi code is generated). This is the right moment to |
8106 // patch to HEAP_NUMBERS state. The transition is attempted only for | 8304 // patch to HEAP_NUMBERS state. The transition is attempted only for |
8107 // the four basic operations. The stub stays in the DEFAULT state | 8305 // the four basic operations. The stub stays in the DEFAULT state |
8108 // forever for all other operations (also if smi code is skipped). | 8306 // forever for all other operations (also if smi code is skipped). |
8109 GenerateTypeTransition(masm); | 8307 GenerateTypeTransition(masm); |
8110 } | 8308 } |
8111 | 8309 |
8112 Label not_floats; | 8310 Label not_floats; |
8113 if (CpuFeatures::IsSupported(SSE2)) { | 8311 if (CpuFeatures::IsSupported(SSE2)) { |
8114 CpuFeatures::Scope use_sse2(SSE2); | 8312 CpuFeatures::Scope use_sse2(SSE2); |
8115 if (NumberInfo::IsNumber(static_operands_type_)) { | 8313 if (static_operands_type_.IsNumber()) { |
8116 if (FLAG_debug_code) { | 8314 if (FLAG_debug_code) { |
8117 // Assert at runtime that inputs are only numbers. | 8315 // Assert at runtime that inputs are only numbers. |
8118 __ AbortIfNotNumber(edx, | 8316 __ AbortIfNotNumber(edx, |
8119 "GenericBinaryOpStub operand not a number."); | 8317 "GenericBinaryOpStub operand not a number."); |
8120 __ AbortIfNotNumber(eax, | 8318 __ AbortIfNotNumber(eax, |
8121 "GenericBinaryOpStub operand not a number."); | 8319 "GenericBinaryOpStub operand not a number."); |
8122 } | 8320 } |
8123 FloatingPointHelper::LoadSSE2Operands(masm); | 8321 if (static_operands_type_.IsSmi()) { |
8322 FloatingPointHelper::LoadSSE2Smis(masm, ecx); | |
8323 } else { | |
8324 FloatingPointHelper::LoadSSE2Operands(masm); | |
8325 } | |
8124 } else { | 8326 } else { |
8125 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | 8327 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); |
8126 } | 8328 } |
8127 | 8329 |
8128 switch (op_) { | 8330 switch (op_) { |
8129 case Token::ADD: __ addsd(xmm0, xmm1); break; | 8331 case Token::ADD: __ addsd(xmm0, xmm1); break; |
8130 case Token::SUB: __ subsd(xmm0, xmm1); break; | 8332 case Token::SUB: __ subsd(xmm0, xmm1); break; |
8131 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 8333 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
8132 case Token::DIV: __ divsd(xmm0, xmm1); break; | 8334 case Token::DIV: __ divsd(xmm0, xmm1); break; |
8133 default: UNREACHABLE(); | 8335 default: UNREACHABLE(); |
8134 } | 8336 } |
8135 GenerateHeapResultAllocation(masm, &call_runtime); | 8337 GenerateHeapResultAllocation(masm, &call_runtime); |
8136 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 8338 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
8137 GenerateReturn(masm); | 8339 GenerateReturn(masm); |
8138 } else { // SSE2 not available, use FPU. | 8340 } else { // SSE2 not available, use FPU. |
8139 if (NumberInfo::IsNumber(static_operands_type_)) { | 8341 if (static_operands_type_.IsNumber()) { |
8140 if (FLAG_debug_code) { | 8342 if (FLAG_debug_code) { |
8141 // Assert at runtime that inputs are only numbers. | 8343 // Assert at runtime that inputs are only numbers. |
8142 __ AbortIfNotNumber(edx, | 8344 __ AbortIfNotNumber(edx, |
8143 "GenericBinaryOpStub operand not a number."); | 8345 "GenericBinaryOpStub operand not a number."); |
8144 __ AbortIfNotNumber(eax, | 8346 __ AbortIfNotNumber(eax, |
8145 "GenericBinaryOpStub operand not a number."); | 8347 "GenericBinaryOpStub operand not a number."); |
8146 } | 8348 } |
8147 } else { | 8349 } else { |
8148 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 8350 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
8149 } | 8351 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8183 // For MOD we go directly to runtime in the non-smi case. | 8385 // For MOD we go directly to runtime in the non-smi case. |
8184 break; | 8386 break; |
8185 } | 8387 } |
8186 case Token::BIT_OR: | 8388 case Token::BIT_OR: |
8187 case Token::BIT_AND: | 8389 case Token::BIT_AND: |
8188 case Token::BIT_XOR: | 8390 case Token::BIT_XOR: |
8189 case Token::SAR: | 8391 case Token::SAR: |
8190 case Token::SHL: | 8392 case Token::SHL: |
8191 case Token::SHR: { | 8393 case Token::SHR: { |
8192 Label non_smi_result; | 8394 Label non_smi_result; |
8193 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | 8395 FloatingPointHelper::LoadAsIntegers(masm, |
8396 static_operands_type_, | |
8397 use_sse3_, | |
8398 &call_runtime); | |
8194 switch (op_) { | 8399 switch (op_) { |
8195 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | 8400 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; |
8196 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | 8401 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |
8197 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | 8402 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |
8198 case Token::SAR: __ sar_cl(eax); break; | 8403 case Token::SAR: __ sar_cl(eax); break; |
8199 case Token::SHL: __ shl_cl(eax); break; | 8404 case Token::SHL: __ shl_cl(eax); break; |
8200 case Token::SHR: __ shr_cl(eax); break; | 8405 case Token::SHR: __ shr_cl(eax); break; |
8201 default: UNREACHABLE(); | 8406 default: UNREACHABLE(); |
8202 } | 8407 } |
8203 if (op_ == Token::SHR) { | 8408 if (op_ == Token::SHR) { |
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8712 __ bind(&done); | 8917 __ bind(&done); |
8713 } | 8918 } |
8714 | 8919 |
8715 | 8920 |
8716 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 8921 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
8717 // is faster than using the built-in instructions on floating point registers. | 8922 // is faster than using the built-in instructions on floating point registers. |
8718 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 8923 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
8719 // trashed registers. | 8924 // trashed registers. |
8720 void IntegerConvert(MacroAssembler* masm, | 8925 void IntegerConvert(MacroAssembler* masm, |
8721 Register source, | 8926 Register source, |
8927 NumberInfo number_info, | |
8722 bool use_sse3, | 8928 bool use_sse3, |
8723 Label* conversion_failure) { | 8929 Label* conversion_failure) { |
8724 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 8930 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); |
8725 Label done, right_exponent, normal_exponent; | 8931 Label done, right_exponent, normal_exponent; |
8726 Register scratch = ebx; | 8932 Register scratch = ebx; |
8727 Register scratch2 = edi; | 8933 Register scratch2 = edi; |
8728 // Get exponent word. | 8934 if (!number_info.IsInteger32() || !use_sse3) { |
8729 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 8935 // Get exponent word. |
8730 // Get exponent alone in scratch2. | 8936 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |
8731 __ mov(scratch2, scratch); | 8937 // Get exponent alone in scratch2. |
8732 __ and_(scratch2, HeapNumber::kExponentMask); | 8938 __ mov(scratch2, scratch); |
8939 __ and_(scratch2, HeapNumber::kExponentMask); | |
8940 } | |
8733 if (use_sse3) { | 8941 if (use_sse3) { |
8734 CpuFeatures::Scope scope(SSE3); | 8942 CpuFeatures::Scope scope(SSE3); |
8735 // Check whether the exponent is too big for a 64 bit signed integer. | 8943 if (!number_info.IsInteger32()) { |
8736 static const uint32_t kTooBigExponent = | 8944 // Check whether the exponent is too big for a 64 bit signed integer. |
8737 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 8945 static const uint32_t kTooBigExponent = |
8738 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); | 8946 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; |
8739 __ j(greater_equal, conversion_failure); | 8947 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); |
8948 __ j(greater_equal, conversion_failure); | |
8949 } | |
8740 // Load x87 register with heap number. | 8950 // Load x87 register with heap number. |
8741 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 8951 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); |
8742 // Reserve space for 64 bit answer. | 8952 // Reserve space for 64 bit answer. |
8743 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. | 8953 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. |
8744 // Do conversion, which cannot fail because we checked the exponent. | 8954 // Do conversion, which cannot fail because we checked the exponent. |
8745 __ fisttp_d(Operand(esp, 0)); | 8955 __ fisttp_d(Operand(esp, 0)); |
8746 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. | 8956 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. |
8747 __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. | 8957 __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. |
8748 } else { | 8958 } else { |
8749 // Load ecx with zero. We use this either for the final shift or | 8959 // Load ecx with zero. We use this either for the final shift or |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8844 __ bind(&negative); | 9054 __ bind(&negative); |
8845 __ sub(ecx, Operand(scratch2)); | 9055 __ sub(ecx, Operand(scratch2)); |
8846 __ bind(&done); | 9056 __ bind(&done); |
8847 } | 9057 } |
8848 } | 9058 } |
8849 | 9059 |
8850 | 9060 |
8851 // Input: edx, eax are the left and right objects of a bit op. | 9061 // Input: edx, eax are the left and right objects of a bit op. |
8852 // Output: eax, ecx are left and right integers for a bit op. | 9062 // Output: eax, ecx are left and right integers for a bit op. |
8853 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 9063 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
9064 NumberInfo number_info, | |
8854 bool use_sse3, | 9065 bool use_sse3, |
8855 Label* conversion_failure) { | 9066 Label* conversion_failure) { |
8856 // Check float operands. | 9067 // Check float operands. |
8857 Label arg1_is_object, check_undefined_arg1; | 9068 Label arg1_is_object, check_undefined_arg1; |
8858 Label arg2_is_object, check_undefined_arg2; | 9069 Label arg2_is_object, check_undefined_arg2; |
8859 Label load_arg2, done; | 9070 Label load_arg2, done; |
8860 | 9071 |
8861 __ test(edx, Immediate(kSmiTagMask)); | 9072 if (number_info.IsHeapNumber()) { |
fschneider
2010/03/05 15:01:07
This function is getting quite messy with all the
| |
8862 __ j(not_zero, &arg1_is_object); | 9073 __ jmp (&arg1_is_object); |
fschneider
2010/03/05 15:01:07
Remove extra space.
| |
8863 __ SmiUntag(edx); | 9074 } else { |
8864 __ jmp(&load_arg2); | 9075 if (!number_info.IsSmi()) { |
9076 __ test(edx, Immediate(kSmiTagMask)); | |
9077 __ j(not_zero, &arg1_is_object); | |
9078 } | |
9079 __ SmiUntag(edx); | |
9080 __ jmp(&load_arg2); | |
9081 } | |
8865 | 9082 |
8866 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 9083 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
8867 __ bind(&check_undefined_arg1); | 9084 if (!number_info.IsNumber()) { |
8868 __ cmp(edx, Factory::undefined_value()); | 9085 __ bind(&check_undefined_arg1); |
8869 __ j(not_equal, conversion_failure); | 9086 __ cmp(edx, Factory::undefined_value()); |
8870 __ mov(edx, Immediate(0)); | 9087 __ j(not_equal, conversion_failure); |
8871 __ jmp(&load_arg2); | 9088 __ mov(edx, Immediate(0)); |
9089 __ jmp(&load_arg2); | |
9090 } | |
8872 | 9091 |
8873 __ bind(&arg1_is_object); | 9092 __ bind(&arg1_is_object); |
8874 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 9093 if (!number_info.IsNumber()) { |
8875 __ cmp(ebx, Factory::heap_number_map()); | 9094 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
8876 __ j(not_equal, &check_undefined_arg1); | 9095 __ cmp(ebx, Factory::heap_number_map()); |
9096 __ j(not_equal, &check_undefined_arg1); | |
9097 } | |
8877 // Get the untagged integer version of the edx heap number in ecx. | 9098 // Get the untagged integer version of the edx heap number in ecx. |
8878 IntegerConvert(masm, edx, use_sse3, conversion_failure); | 9099 IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); |
8879 __ mov(edx, ecx); | 9100 __ mov(edx, ecx); |
8880 | 9101 |
8881 // Here edx has the untagged integer, eax has a Smi or a heap number. | 9102 // Here edx has the untagged integer, eax has a Smi or a heap number. |
8882 __ bind(&load_arg2); | 9103 __ bind(&load_arg2); |
8883 // Test if arg2 is a Smi. | 9104 if (number_info.IsHeapNumber()) { |
8884 __ test(eax, Immediate(kSmiTagMask)); | 9105 __ jmp(&arg2_is_object); |
8885 __ j(not_zero, &arg2_is_object); | 9106 } else { |
8886 __ SmiUntag(eax); | 9107 // Test if arg2 is a Smi. |
8887 __ mov(ecx, eax); | 9108 if (!number_info.IsSmi()) { |
8888 __ jmp(&done); | 9109 __ test(eax, Immediate(kSmiTagMask)); |
9110 __ j(not_zero, &arg2_is_object); | |
9111 } | |
9112 __ SmiUntag(eax); | |
9113 __ mov(ecx, eax); | |
9114 __ jmp(&done); | |
9115 } | |
8889 | 9116 |
8890 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 9117 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
8891 __ bind(&check_undefined_arg2); | 9118 if (!number_info.IsNumber()) { |
8892 __ cmp(eax, Factory::undefined_value()); | 9119 __ bind(&check_undefined_arg2); |
8893 __ j(not_equal, conversion_failure); | 9120 __ cmp(eax, Factory::undefined_value()); |
8894 __ mov(ecx, Immediate(0)); | 9121 __ j(not_equal, conversion_failure); |
8895 __ jmp(&done); | 9122 __ mov(ecx, Immediate(0)); |
9123 __ jmp(&done); | |
9124 } | |
8896 | 9125 |
8897 __ bind(&arg2_is_object); | 9126 __ bind(&arg2_is_object); |
8898 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 9127 if (!number_info.IsNumber()) { |
8899 __ cmp(ebx, Factory::heap_number_map()); | 9128 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
8900 __ j(not_equal, &check_undefined_arg2); | 9129 __ cmp(ebx, Factory::heap_number_map()); |
9130 __ j(not_equal, &check_undefined_arg2); | |
9131 } | |
8901 // Get the untagged integer version of the eax heap number in ecx. | 9132 // Get the untagged integer version of the eax heap number in ecx. |
8902 IntegerConvert(masm, eax, use_sse3, conversion_failure); | 9133 IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); |
8903 __ bind(&done); | 9134 __ bind(&done); |
8904 __ mov(eax, edx); | 9135 __ mov(eax, edx); |
8905 } | 9136 } |
8906 | 9137 |
8907 | 9138 |
8908 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9139 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
8909 Register number) { | 9140 Register number) { |
8910 Label load_smi, done; | 9141 Label load_smi, done; |
8911 | 9142 |
8912 __ test(number, Immediate(kSmiTagMask)); | 9143 __ test(number, Immediate(kSmiTagMask)); |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9134 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); | 9365 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); |
9135 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | 9366 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
9136 } | 9367 } |
9137 } else if (op_ == Token::BIT_NOT) { | 9368 } else if (op_ == Token::BIT_NOT) { |
9138 // Check if the operand is a heap number. | 9369 // Check if the operand is a heap number. |
9139 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 9370 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
9140 __ cmp(edx, Factory::heap_number_map()); | 9371 __ cmp(edx, Factory::heap_number_map()); |
9141 __ j(not_equal, &slow, not_taken); | 9372 __ j(not_equal, &slow, not_taken); |
9142 | 9373 |
9143 // Convert the heap number in eax to an untagged integer in ecx. | 9374 // Convert the heap number in eax to an untagged integer in ecx. |
9144 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow); | 9375 IntegerConvert(masm, |
9376 eax, | |
9377 NumberInfo::Unknown(), | |
9378 CpuFeatures::IsSupported(SSE3), | |
9379 &slow); | |
9145 | 9380 |
9146 // Do the bitwise operation and check if the result fits in a smi. | 9381 // Do the bitwise operation and check if the result fits in a smi. |
9147 Label try_float; | 9382 Label try_float; |
9148 __ not_(ecx); | 9383 __ not_(ecx); |
9149 __ cmp(ecx, 0xc0000000); | 9384 __ cmp(ecx, 0xc0000000); |
9150 __ j(sign, &try_float, not_taken); | 9385 __ j(sign, &try_float, not_taken); |
9151 | 9386 |
9152 // Tag the result as a smi and we're done. | 9387 // Tag the result as a smi and we're done. |
9153 ASSERT(kSmiTagSize == 1); | 9388 ASSERT(kSmiTagSize == 1); |
9154 __ lea(eax, Operand(ecx, times_2, kSmiTag)); | 9389 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
(...skipping 2229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11384 | 11619 |
11385 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 11620 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
11386 // tagged as a small integer. | 11621 // tagged as a small integer. |
11387 __ bind(&runtime); | 11622 __ bind(&runtime); |
11388 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 11623 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
11389 } | 11624 } |
11390 | 11625 |
11391 #undef __ | 11626 #undef __ |
11392 | 11627 |
11393 } } // namespace v8::internal | 11628 } } // namespace v8::internal |
OLD | NEW |