Chromium Code Reviews| 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 |