| 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 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 __ bind(&ok); | 843 __ bind(&ok); |
| 844 } | 844 } |
| 845 // In the integer32 case there are no Smis hidden in heap numbers, so we | 845 // In the integer32 case there are no Smis hidden in heap numbers, so we |
| 846 // need only test for Smi zero. | 846 // need only test for Smi zero. |
| 847 __ test(value.reg(), Operand(value.reg())); | 847 __ test(value.reg(), Operand(value.reg())); |
| 848 dest->false_target()->Branch(zero); | 848 dest->false_target()->Branch(zero); |
| 849 value.Unuse(); | 849 value.Unuse(); |
| 850 dest->Split(not_zero); | 850 dest->Split(not_zero); |
| 851 } else if (value.is_number()) { | 851 } else if (value.is_number()) { |
| 852 Comment cmnt(masm_, "ONLY_NUMBER"); | 852 Comment cmnt(masm_, "ONLY_NUMBER"); |
| 853 // Fast case if NumberInfo indicates only numbers. | 853 // Fast case if TypeInfo indicates only numbers. |
| 854 if (FLAG_debug_code) { | 854 if (FLAG_debug_code) { |
| 855 __ AbortIfNotNumber(value.reg()); | 855 __ AbortIfNotNumber(value.reg()); |
| 856 } | 856 } |
| 857 // Smi => false iff zero. | 857 // Smi => false iff zero. |
| 858 ASSERT(kSmiTag == 0); | 858 ASSERT(kSmiTag == 0); |
| 859 __ test(value.reg(), Operand(value.reg())); | 859 __ test(value.reg(), Operand(value.reg())); |
| 860 dest->false_target()->Branch(zero); | 860 dest->false_target()->Branch(zero); |
| 861 __ test(value.reg(), Immediate(kSmiTagMask)); | 861 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 862 dest->true_target()->Branch(zero); | 862 dest->true_target()->Branch(zero); |
| 863 __ fldz(); | 863 __ fldz(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 925 | 925 |
| 926 // Test if operands are smi or number objects (fp). Requirements: | 926 // Test if operands are smi or number objects (fp). Requirements: |
| 927 // operand_1 in eax, operand_2 in edx; falls through on float | 927 // operand_1 in eax, operand_2 in edx; falls through on float |
| 928 // operands, jumps to the non_float label otherwise. | 928 // operands, jumps to the non_float label otherwise. |
| 929 static void CheckFloatOperands(MacroAssembler* masm, | 929 static void CheckFloatOperands(MacroAssembler* masm, |
| 930 Label* non_float, | 930 Label* non_float, |
| 931 Register scratch); | 931 Register scratch); |
| 932 // Takes the operands in edx and eax and loads them as integers in eax | 932 // Takes the operands in edx and eax and loads them as integers in eax |
| 933 // and ecx. | 933 // and ecx. |
| 934 static void LoadAsIntegers(MacroAssembler* masm, | 934 static void LoadAsIntegers(MacroAssembler* masm, |
| 935 NumberInfo number_info, | 935 TypeInfo type_info, |
| 936 bool use_sse3, | 936 bool use_sse3, |
| 937 Label* operand_conversion_failure); | 937 Label* operand_conversion_failure); |
| 938 static void LoadNumbersAsIntegers(MacroAssembler* masm, | 938 static void LoadNumbersAsIntegers(MacroAssembler* masm, |
| 939 NumberInfo number_info, | 939 TypeInfo type_info, |
| 940 bool use_sse3, | 940 bool use_sse3, |
| 941 Label* operand_conversion_failure); | 941 Label* operand_conversion_failure); |
| 942 static void LoadUnknownsAsIntegers(MacroAssembler* masm, | 942 static void LoadUnknownsAsIntegers(MacroAssembler* masm, |
| 943 bool use_sse3, | 943 bool use_sse3, |
| 944 Label* operand_conversion_failure); | 944 Label* operand_conversion_failure); |
| 945 | 945 |
| 946 // Test if operands are smis or heap numbers and load them | 946 // Test if operands are smis or heap numbers and load them |
| 947 // into xmm0 and xmm1 if they are. Operands are in edx and eax. | 947 // into xmm0 and xmm1 if they are. Operands are in edx and eax. |
| 948 // Leaves operands unchanged. | 948 // Leaves operands unchanged. |
| 949 static void LoadSSE2Operands(MacroAssembler* masm); | 949 static void LoadSSE2Operands(MacroAssembler* masm); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 986 } | 986 } |
| 987 | 987 |
| 988 | 988 |
| 989 // Call the specialized stub for a binary operation. | 989 // Call the specialized stub for a binary operation. |
| 990 class DeferredInlineBinaryOperation: public DeferredCode { | 990 class DeferredInlineBinaryOperation: public DeferredCode { |
| 991 public: | 991 public: |
| 992 DeferredInlineBinaryOperation(Token::Value op, | 992 DeferredInlineBinaryOperation(Token::Value op, |
| 993 Register dst, | 993 Register dst, |
| 994 Register left, | 994 Register left, |
| 995 Register right, | 995 Register right, |
| 996 NumberInfo left_info, | 996 TypeInfo left_info, |
| 997 NumberInfo right_info, | 997 TypeInfo right_info, |
| 998 OverwriteMode mode) | 998 OverwriteMode mode) |
| 999 : op_(op), dst_(dst), left_(left), right_(right), | 999 : op_(op), dst_(dst), left_(left), right_(right), |
| 1000 left_info_(left_info), right_info_(right_info), mode_(mode) { | 1000 left_info_(left_info), right_info_(right_info), mode_(mode) { |
| 1001 set_comment("[ DeferredInlineBinaryOperation"); | 1001 set_comment("[ DeferredInlineBinaryOperation"); |
| 1002 } | 1002 } |
| 1003 | 1003 |
| 1004 virtual void Generate(); | 1004 virtual void Generate(); |
| 1005 | 1005 |
| 1006 private: | 1006 private: |
| 1007 Token::Value op_; | 1007 Token::Value op_; |
| 1008 Register dst_; | 1008 Register dst_; |
| 1009 Register left_; | 1009 Register left_; |
| 1010 Register right_; | 1010 Register right_; |
| 1011 NumberInfo left_info_; | 1011 TypeInfo left_info_; |
| 1012 NumberInfo right_info_; | 1012 TypeInfo right_info_; |
| 1013 OverwriteMode mode_; | 1013 OverwriteMode mode_; |
| 1014 }; | 1014 }; |
| 1015 | 1015 |
| 1016 | 1016 |
| 1017 void DeferredInlineBinaryOperation::Generate() { | 1017 void DeferredInlineBinaryOperation::Generate() { |
| 1018 Label done; | 1018 Label done; |
| 1019 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || | 1019 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || |
| 1020 (op_ ==Token::SUB) || | 1020 (op_ ==Token::SUB) || |
| 1021 (op_ == Token::MUL) || | 1021 (op_ == Token::MUL) || |
| 1022 (op_ == Token::DIV))) { | 1022 (op_ == Token::DIV))) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); | 1096 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); |
| 1097 __ jmp(&done); | 1097 __ jmp(&done); |
| 1098 | 1098 |
| 1099 __ bind(&after_alloc_failure); | 1099 __ bind(&after_alloc_failure); |
| 1100 __ pop(left_); | 1100 __ pop(left_); |
| 1101 __ bind(&call_runtime); | 1101 __ bind(&call_runtime); |
| 1102 } | 1102 } |
| 1103 GenericBinaryOpStub stub(op_, | 1103 GenericBinaryOpStub stub(op_, |
| 1104 mode_, | 1104 mode_, |
| 1105 NO_SMI_CODE_IN_STUB, | 1105 NO_SMI_CODE_IN_STUB, |
| 1106 NumberInfo::Combine(left_info_, right_info_)); | 1106 TypeInfo::Combine(left_info_, right_info_)); |
| 1107 stub.GenerateCall(masm_, left_, right_); | 1107 stub.GenerateCall(masm_, left_, right_); |
| 1108 if (!dst_.is(eax)) __ mov(dst_, eax); | 1108 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1109 __ bind(&done); | 1109 __ bind(&done); |
| 1110 } | 1110 } |
| 1111 | 1111 |
| 1112 | 1112 |
| 1113 static NumberInfo CalculateNumberInfo(NumberInfo operands_type, | 1113 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, |
| 1114 Token::Value op, | 1114 Token::Value op, |
| 1115 const Result& right, | 1115 const Result& right, |
| 1116 const Result& left) { | 1116 const Result& left) { |
| 1117 // Set NumberInfo of result according to the operation performed. | 1117 // Set TypeInfo of result according to the operation performed. |
| 1118 // Rely on the fact that smis have a 31 bit payload on ia32. | 1118 // Rely on the fact that smis have a 31 bit payload on ia32. |
| 1119 ASSERT(kSmiValueSize == 31); | 1119 ASSERT(kSmiValueSize == 31); |
| 1120 switch (op) { | 1120 switch (op) { |
| 1121 case Token::COMMA: | 1121 case Token::COMMA: |
| 1122 return right.number_info(); | 1122 return right.type_info(); |
| 1123 case Token::OR: | 1123 case Token::OR: |
| 1124 case Token::AND: | 1124 case Token::AND: |
| 1125 // Result type can be either of the two input types. | 1125 // Result type can be either of the two input types. |
| 1126 return operands_type; | 1126 return operands_type; |
| 1127 case Token::BIT_AND: { | 1127 case Token::BIT_AND: { |
| 1128 // Anding with positive Smis will give you a Smi. | 1128 // Anding with positive Smis will give you a Smi. |
| 1129 if (right.is_constant() && right.handle()->IsSmi() && | 1129 if (right.is_constant() && right.handle()->IsSmi() && |
| 1130 Smi::cast(*right.handle())->value() >= 0) { | 1130 Smi::cast(*right.handle())->value() >= 0) { |
| 1131 return NumberInfo::Smi(); | 1131 return TypeInfo::Smi(); |
| 1132 } else if (left.is_constant() && left.handle()->IsSmi() && | 1132 } else if (left.is_constant() && left.handle()->IsSmi() && |
| 1133 Smi::cast(*left.handle())->value() >= 0) { | 1133 Smi::cast(*left.handle())->value() >= 0) { |
| 1134 return NumberInfo::Smi(); | 1134 return TypeInfo::Smi(); |
| 1135 } | 1135 } |
| 1136 return (operands_type.IsSmi()) | 1136 return (operands_type.IsSmi()) |
| 1137 ? NumberInfo::Smi() | 1137 ? TypeInfo::Smi() |
| 1138 : NumberInfo::Integer32(); | 1138 : TypeInfo::Integer32(); |
| 1139 } | 1139 } |
| 1140 case Token::BIT_OR: { | 1140 case Token::BIT_OR: { |
| 1141 // Oring with negative Smis will give you a Smi. | 1141 // Oring with negative Smis will give you a Smi. |
| 1142 if (right.is_constant() && right.handle()->IsSmi() && | 1142 if (right.is_constant() && right.handle()->IsSmi() && |
| 1143 Smi::cast(*right.handle())->value() < 0) { | 1143 Smi::cast(*right.handle())->value() < 0) { |
| 1144 return NumberInfo::Smi(); | 1144 return TypeInfo::Smi(); |
| 1145 } else if (left.is_constant() && left.handle()->IsSmi() && | 1145 } else if (left.is_constant() && left.handle()->IsSmi() && |
| 1146 Smi::cast(*left.handle())->value() < 0) { | 1146 Smi::cast(*left.handle())->value() < 0) { |
| 1147 return NumberInfo::Smi(); | 1147 return TypeInfo::Smi(); |
| 1148 } | 1148 } |
| 1149 return (operands_type.IsSmi()) | 1149 return (operands_type.IsSmi()) |
| 1150 ? NumberInfo::Smi() | 1150 ? TypeInfo::Smi() |
| 1151 : NumberInfo::Integer32(); | 1151 : TypeInfo::Integer32(); |
| 1152 } | 1152 } |
| 1153 case Token::BIT_XOR: | 1153 case Token::BIT_XOR: |
| 1154 // Result is always a 32 bit integer. Smi property of inputs is preserved. | 1154 // Result is always a 32 bit integer. Smi property of inputs is preserved. |
| 1155 return (operands_type.IsSmi()) | 1155 return (operands_type.IsSmi()) |
| 1156 ? NumberInfo::Smi() | 1156 ? TypeInfo::Smi() |
| 1157 : NumberInfo::Integer32(); | 1157 : TypeInfo::Integer32(); |
| 1158 case Token::SAR: | 1158 case Token::SAR: |
| 1159 if (left.is_smi()) return NumberInfo::Smi(); | 1159 if (left.is_smi()) return TypeInfo::Smi(); |
| 1160 // Result is a smi if we shift by a constant >= 1, otherwise an integer32. | 1160 // Result is a smi if we shift by a constant >= 1, otherwise an integer32. |
| 1161 return (right.is_constant() && right.handle()->IsSmi() | 1161 return (right.is_constant() && right.handle()->IsSmi() |
| 1162 && Smi::cast(*right.handle())->value() >= 1) | 1162 && Smi::cast(*right.handle())->value() >= 1) |
| 1163 ? NumberInfo::Smi() | 1163 ? TypeInfo::Smi() |
| 1164 : NumberInfo::Integer32(); | 1164 : TypeInfo::Integer32(); |
| 1165 case Token::SHR: | 1165 case Token::SHR: |
| 1166 // Result is a smi if we shift by a constant >= 2, otherwise an integer32. | 1166 // Result is a smi if we shift by a constant >= 2, otherwise an integer32. |
| 1167 return (right.is_constant() && right.handle()->IsSmi() | 1167 return (right.is_constant() && right.handle()->IsSmi() |
| 1168 && Smi::cast(*right.handle())->value() >= 2) | 1168 && Smi::cast(*right.handle())->value() >= 2) |
| 1169 ? NumberInfo::Smi() | 1169 ? TypeInfo::Smi() |
| 1170 : NumberInfo::Integer32(); | 1170 : TypeInfo::Integer32(); |
| 1171 case Token::ADD: | 1171 case Token::ADD: |
| 1172 if (operands_type.IsSmi()) { | 1172 if (operands_type.IsSmi()) { |
| 1173 // The Integer32 range is big enough to take the sum of any two Smis. | 1173 // The Integer32 range is big enough to take the sum of any two Smis. |
| 1174 return NumberInfo::Integer32(); | 1174 return TypeInfo::Integer32(); |
| 1175 } else { | 1175 } else { |
| 1176 // Result could be a string or a number. Check types of inputs. | 1176 // Result could be a string or a number. Check types of inputs. |
| 1177 return operands_type.IsNumber() | 1177 return operands_type.IsNumber() |
| 1178 ? NumberInfo::Number() | 1178 ? TypeInfo::Number() |
| 1179 : NumberInfo::Unknown(); | 1179 : TypeInfo::Unknown(); |
| 1180 } | 1180 } |
| 1181 case Token::SHL: | 1181 case Token::SHL: |
| 1182 return NumberInfo::Integer32(); | 1182 return TypeInfo::Integer32(); |
| 1183 case Token::SUB: | 1183 case Token::SUB: |
| 1184 // The Integer32 range is big enough to take the difference of any two | 1184 // The Integer32 range is big enough to take the difference of any two |
| 1185 // Smis. | 1185 // Smis. |
| 1186 return (operands_type.IsSmi()) ? | 1186 return (operands_type.IsSmi()) ? |
| 1187 NumberInfo::Integer32() : | 1187 TypeInfo::Integer32() : |
| 1188 NumberInfo::Number(); | 1188 TypeInfo::Number(); |
| 1189 case Token::MUL: | 1189 case Token::MUL: |
| 1190 case Token::DIV: | 1190 case Token::DIV: |
| 1191 case Token::MOD: | 1191 case Token::MOD: |
| 1192 // Result is always a number. | 1192 // Result is always a number. |
| 1193 return NumberInfo::Number(); | 1193 return TypeInfo::Number(); |
| 1194 default: | 1194 default: |
| 1195 UNREACHABLE(); | 1195 UNREACHABLE(); |
| 1196 } | 1196 } |
| 1197 UNREACHABLE(); | 1197 UNREACHABLE(); |
| 1198 return NumberInfo::Unknown(); | 1198 return TypeInfo::Unknown(); |
| 1199 } | 1199 } |
| 1200 | 1200 |
| 1201 | 1201 |
| 1202 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 1202 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 1203 StaticType* type, | 1203 StaticType* type, |
| 1204 OverwriteMode overwrite_mode, | 1204 OverwriteMode overwrite_mode, |
| 1205 bool no_negative_zero) { | 1205 bool no_negative_zero) { |
| 1206 Comment cmnt(masm_, "[ BinaryOperation"); | 1206 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1207 Comment cmnt_token(masm_, Token::String(op)); | 1207 Comment cmnt_token(masm_, Token::String(op)); |
| 1208 | 1208 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1248 right.is_constant() && !right.handle()->IsSmi(); | 1248 right.is_constant() && !right.handle()->IsSmi(); |
| 1249 | 1249 |
| 1250 if (left_is_smi_constant && right_is_smi_constant) { | 1250 if (left_is_smi_constant && right_is_smi_constant) { |
| 1251 // Compute the constant result at compile time, and leave it on the frame. | 1251 // Compute the constant result at compile time, and leave it on the frame. |
| 1252 int left_int = Smi::cast(*left.handle())->value(); | 1252 int left_int = Smi::cast(*left.handle())->value(); |
| 1253 int right_int = Smi::cast(*right.handle())->value(); | 1253 int right_int = Smi::cast(*right.handle())->value(); |
| 1254 if (FoldConstantSmis(op, left_int, right_int)) return; | 1254 if (FoldConstantSmis(op, left_int, right_int)) return; |
| 1255 } | 1255 } |
| 1256 | 1256 |
| 1257 // Get number type of left and right sub-expressions. | 1257 // Get number type of left and right sub-expressions. |
| 1258 NumberInfo operands_type = | 1258 TypeInfo operands_type = |
| 1259 NumberInfo::Combine(left.number_info(), right.number_info()); | 1259 TypeInfo::Combine(left.type_info(), right.type_info()); |
| 1260 | 1260 |
| 1261 NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left); | 1261 TypeInfo result_type = CalculateTypeInfo(operands_type, op, right, left); |
| 1262 | 1262 |
| 1263 Result answer; | 1263 Result answer; |
| 1264 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 1264 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
| 1265 // Go straight to the slow case, with no smi code. | 1265 // Go straight to the slow case, with no smi code. |
| 1266 GenericBinaryOpStub stub(op, | 1266 GenericBinaryOpStub stub(op, |
| 1267 overwrite_mode, | 1267 overwrite_mode, |
| 1268 NO_SMI_CODE_IN_STUB, | 1268 NO_SMI_CODE_IN_STUB, |
| 1269 operands_type); | 1269 operands_type); |
| 1270 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1270 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1271 } else if (right_is_smi_constant) { | 1271 } else if (right_is_smi_constant) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1290 overwrite_mode, no_negative_zero); | 1290 overwrite_mode, no_negative_zero); |
| 1291 } else { | 1291 } else { |
| 1292 GenericBinaryOpStub stub(op, | 1292 GenericBinaryOpStub stub(op, |
| 1293 overwrite_mode, | 1293 overwrite_mode, |
| 1294 NO_GENERIC_BINARY_FLAGS, | 1294 NO_GENERIC_BINARY_FLAGS, |
| 1295 operands_type); | 1295 operands_type); |
| 1296 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1296 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1297 } | 1297 } |
| 1298 } | 1298 } |
| 1299 | 1299 |
| 1300 answer.set_number_info(result_type); | 1300 answer.set_type_info(result_type); |
| 1301 frame_->Push(&answer); | 1301 frame_->Push(&answer); |
| 1302 } | 1302 } |
| 1303 | 1303 |
| 1304 | 1304 |
| 1305 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1305 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
| 1306 Object* answer_object = Heap::undefined_value(); | 1306 Object* answer_object = Heap::undefined_value(); |
| 1307 switch (op) { | 1307 switch (op) { |
| 1308 case Token::ADD: | 1308 case Token::ADD: |
| 1309 if (Smi::IsValid(left + right)) { | 1309 if (Smi::IsValid(left + right)) { |
| 1310 answer_object = Smi::FromInt(left + right); | 1310 answer_object = Smi::FromInt(left + right); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1378 if (answer_object == Heap::undefined_value()) { | 1378 if (answer_object == Heap::undefined_value()) { |
| 1379 return false; | 1379 return false; |
| 1380 } | 1380 } |
| 1381 frame_->Push(Handle<Object>(answer_object)); | 1381 frame_->Push(Handle<Object>(answer_object)); |
| 1382 return true; | 1382 return true; |
| 1383 } | 1383 } |
| 1384 | 1384 |
| 1385 | 1385 |
| 1386 static void CheckTwoForSminess(MacroAssembler* masm, | 1386 static void CheckTwoForSminess(MacroAssembler* masm, |
| 1387 Register left, Register right, Register scratch, | 1387 Register left, Register right, Register scratch, |
| 1388 NumberInfo left_info, NumberInfo right_info, | 1388 TypeInfo left_info, TypeInfo right_info, |
| 1389 DeferredInlineBinaryOperation* deferred); | 1389 DeferredInlineBinaryOperation* deferred); |
| 1390 | 1390 |
| 1391 | 1391 |
| 1392 // Implements a binary operation using a deferred code object and some | 1392 // Implements a binary operation using a deferred code object and some |
| 1393 // inline code to operate on smis quickly. | 1393 // inline code to operate on smis quickly. |
| 1394 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 1394 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| 1395 Result* left, | 1395 Result* left, |
| 1396 Result* right, | 1396 Result* right, |
| 1397 OverwriteMode overwrite_mode, | 1397 OverwriteMode overwrite_mode, |
| 1398 bool no_negative_zero) { | 1398 bool no_negative_zero) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1463 right->ToRegister(); | 1463 right->ToRegister(); |
| 1464 frame_->Spill(eax); | 1464 frame_->Spill(eax); |
| 1465 frame_->Spill(edx); | 1465 frame_->Spill(edx); |
| 1466 | 1466 |
| 1467 // Check that left and right are smi tagged. | 1467 // Check that left and right are smi tagged. |
| 1468 DeferredInlineBinaryOperation* deferred = | 1468 DeferredInlineBinaryOperation* deferred = |
| 1469 new DeferredInlineBinaryOperation(op, | 1469 new DeferredInlineBinaryOperation(op, |
| 1470 (op == Token::DIV) ? eax : edx, | 1470 (op == Token::DIV) ? eax : edx, |
| 1471 left->reg(), | 1471 left->reg(), |
| 1472 right->reg(), | 1472 right->reg(), |
| 1473 left->number_info(), | 1473 left->type_info(), |
| 1474 right->number_info(), | 1474 right->type_info(), |
| 1475 overwrite_mode); | 1475 overwrite_mode); |
| 1476 if (left->reg().is(right->reg())) { | 1476 if (left->reg().is(right->reg())) { |
| 1477 __ test(left->reg(), Immediate(kSmiTagMask)); | 1477 __ test(left->reg(), Immediate(kSmiTagMask)); |
| 1478 } else { | 1478 } else { |
| 1479 // Use the quotient register as a scratch for the tag check. | 1479 // Use the quotient register as a scratch for the tag check. |
| 1480 if (!left_is_in_eax) __ mov(eax, left->reg()); | 1480 if (!left_is_in_eax) __ mov(eax, left->reg()); |
| 1481 left_is_in_eax = false; // About to destroy the value in eax. | 1481 left_is_in_eax = false; // About to destroy the value in eax. |
| 1482 __ or_(eax, Operand(right->reg())); | 1482 __ or_(eax, Operand(right->reg())); |
| 1483 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 1483 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| 1484 __ test(eax, Immediate(kSmiTagMask)); | 1484 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1567 // Use a fresh answer register to avoid spilling the left operand. | 1567 // Use a fresh answer register to avoid spilling the left operand. |
| 1568 answer = allocator_->Allocate(); | 1568 answer = allocator_->Allocate(); |
| 1569 ASSERT(answer.is_valid()); | 1569 ASSERT(answer.is_valid()); |
| 1570 // Check that both operands are smis using the answer register as a | 1570 // Check that both operands are smis using the answer register as a |
| 1571 // temporary. | 1571 // temporary. |
| 1572 DeferredInlineBinaryOperation* deferred = | 1572 DeferredInlineBinaryOperation* deferred = |
| 1573 new DeferredInlineBinaryOperation(op, | 1573 new DeferredInlineBinaryOperation(op, |
| 1574 answer.reg(), | 1574 answer.reg(), |
| 1575 left->reg(), | 1575 left->reg(), |
| 1576 ecx, | 1576 ecx, |
| 1577 left->number_info(), | 1577 left->type_info(), |
| 1578 right->number_info(), | 1578 right->type_info(), |
| 1579 overwrite_mode); | 1579 overwrite_mode); |
| 1580 | 1580 |
| 1581 Label do_op, left_nonsmi; | 1581 Label do_op, left_nonsmi; |
| 1582 // If right is a smi we make a fast case if left is either a smi | 1582 // If right is a smi we make a fast case if left is either a smi |
| 1583 // or a heapnumber. | 1583 // or a heapnumber. |
| 1584 if (CpuFeatures::IsSupported(SSE2) && right->number_info().IsSmi()) { | 1584 if (CpuFeatures::IsSupported(SSE2) && right->type_info().IsSmi()) { |
| 1585 CpuFeatures::Scope use_sse2(SSE2); | 1585 CpuFeatures::Scope use_sse2(SSE2); |
| 1586 __ mov(answer.reg(), left->reg()); | 1586 __ mov(answer.reg(), left->reg()); |
| 1587 // Fast case - both are actually smis. | 1587 // Fast case - both are actually smis. |
| 1588 if (!left->number_info().IsSmi()) { | 1588 if (!left->type_info().IsSmi()) { |
| 1589 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1589 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1590 __ j(not_zero, &left_nonsmi); | 1590 __ j(not_zero, &left_nonsmi); |
| 1591 } else { | 1591 } else { |
| 1592 if (FLAG_debug_code) __ AbortIfNotSmi(left->reg()); | 1592 if (FLAG_debug_code) __ AbortIfNotSmi(left->reg()); |
| 1593 } | 1593 } |
| 1594 if (FLAG_debug_code) __ AbortIfNotSmi(right->reg()); | 1594 if (FLAG_debug_code) __ AbortIfNotSmi(right->reg()); |
| 1595 __ SmiUntag(answer.reg()); | 1595 __ SmiUntag(answer.reg()); |
| 1596 __ jmp(&do_op); | 1596 __ jmp(&do_op); |
| 1597 | 1597 |
| 1598 __ bind(&left_nonsmi); | 1598 __ bind(&left_nonsmi); |
| 1599 // Branch if not a heapnumber. | 1599 // Branch if not a heapnumber. |
| 1600 __ cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), | 1600 __ cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), |
| 1601 Factory::heap_number_map()); | 1601 Factory::heap_number_map()); |
| 1602 deferred->Branch(not_equal); | 1602 deferred->Branch(not_equal); |
| 1603 | 1603 |
| 1604 // Load integer value into answer register using truncation. | 1604 // Load integer value into answer register using truncation. |
| 1605 __ cvttsd2si(answer.reg(), | 1605 __ cvttsd2si(answer.reg(), |
| 1606 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); | 1606 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); |
| 1607 // Branch if we do not fit in a smi. | 1607 // Branch if we do not fit in a smi. |
| 1608 __ cmp(answer.reg(), 0xc0000000); | 1608 __ cmp(answer.reg(), 0xc0000000); |
| 1609 deferred->Branch(negative); | 1609 deferred->Branch(negative); |
| 1610 } else { | 1610 } else { |
| 1611 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), | 1611 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
| 1612 left->number_info(), right->number_info(), deferred); | 1612 left->type_info(), right->type_info(), deferred); |
| 1613 | 1613 |
| 1614 // Untag both operands. | 1614 // Untag both operands. |
| 1615 __ mov(answer.reg(), left->reg()); | 1615 __ mov(answer.reg(), left->reg()); |
| 1616 __ SmiUntag(answer.reg()); | 1616 __ SmiUntag(answer.reg()); |
| 1617 } | 1617 } |
| 1618 | 1618 |
| 1619 __ bind(&do_op); | 1619 __ bind(&do_op); |
| 1620 __ SmiUntag(ecx); | 1620 __ SmiUntag(ecx); |
| 1621 // Perform the operation. | 1621 // Perform the operation. |
| 1622 switch (op) { | 1622 switch (op) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1675 // need to be spilled in the fast case. | 1675 // need to be spilled in the fast case. |
| 1676 answer = allocator_->Allocate(); | 1676 answer = allocator_->Allocate(); |
| 1677 ASSERT(answer.is_valid()); | 1677 ASSERT(answer.is_valid()); |
| 1678 | 1678 |
| 1679 // Perform the smi tag check. | 1679 // Perform the smi tag check. |
| 1680 DeferredInlineBinaryOperation* deferred = | 1680 DeferredInlineBinaryOperation* deferred = |
| 1681 new DeferredInlineBinaryOperation(op, | 1681 new DeferredInlineBinaryOperation(op, |
| 1682 answer.reg(), | 1682 answer.reg(), |
| 1683 left->reg(), | 1683 left->reg(), |
| 1684 right->reg(), | 1684 right->reg(), |
| 1685 left->number_info(), | 1685 left->type_info(), |
| 1686 right->number_info(), | 1686 right->type_info(), |
| 1687 overwrite_mode); | 1687 overwrite_mode); |
| 1688 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), | 1688 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
| 1689 left->number_info(), right->number_info(), deferred); | 1689 left->type_info(), right->type_info(), deferred); |
| 1690 | 1690 |
| 1691 __ mov(answer.reg(), left->reg()); | 1691 __ mov(answer.reg(), left->reg()); |
| 1692 switch (op) { | 1692 switch (op) { |
| 1693 case Token::ADD: | 1693 case Token::ADD: |
| 1694 __ add(answer.reg(), Operand(right->reg())); | 1694 __ add(answer.reg(), Operand(right->reg())); |
| 1695 deferred->Branch(overflow); | 1695 deferred->Branch(overflow); |
| 1696 break; | 1696 break; |
| 1697 | 1697 |
| 1698 case Token::SUB: | 1698 case Token::SUB: |
| 1699 __ sub(answer.reg(), Operand(right->reg())); | 1699 __ sub(answer.reg(), Operand(right->reg())); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1751 } | 1751 } |
| 1752 | 1752 |
| 1753 | 1753 |
| 1754 // Call the appropriate binary operation stub to compute src op value | 1754 // Call the appropriate binary operation stub to compute src op value |
| 1755 // and leave the result in dst. | 1755 // and leave the result in dst. |
| 1756 class DeferredInlineSmiOperation: public DeferredCode { | 1756 class DeferredInlineSmiOperation: public DeferredCode { |
| 1757 public: | 1757 public: |
| 1758 DeferredInlineSmiOperation(Token::Value op, | 1758 DeferredInlineSmiOperation(Token::Value op, |
| 1759 Register dst, | 1759 Register dst, |
| 1760 Register src, | 1760 Register src, |
| 1761 NumberInfo number_info, | 1761 TypeInfo type_info, |
| 1762 Smi* value, | 1762 Smi* value, |
| 1763 OverwriteMode overwrite_mode) | 1763 OverwriteMode overwrite_mode) |
| 1764 : op_(op), | 1764 : op_(op), |
| 1765 dst_(dst), | 1765 dst_(dst), |
| 1766 src_(src), | 1766 src_(src), |
| 1767 number_info_(number_info), | 1767 type_info_(type_info), |
| 1768 value_(value), | 1768 value_(value), |
| 1769 overwrite_mode_(overwrite_mode) { | 1769 overwrite_mode_(overwrite_mode) { |
| 1770 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 1770 if (type_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1771 set_comment("[ DeferredInlineSmiOperation"); | 1771 set_comment("[ DeferredInlineSmiOperation"); |
| 1772 } | 1772 } |
| 1773 | 1773 |
| 1774 virtual void Generate(); | 1774 virtual void Generate(); |
| 1775 | 1775 |
| 1776 private: | 1776 private: |
| 1777 Token::Value op_; | 1777 Token::Value op_; |
| 1778 Register dst_; | 1778 Register dst_; |
| 1779 Register src_; | 1779 Register src_; |
| 1780 NumberInfo number_info_; | 1780 TypeInfo type_info_; |
| 1781 Smi* value_; | 1781 Smi* value_; |
| 1782 OverwriteMode overwrite_mode_; | 1782 OverwriteMode overwrite_mode_; |
| 1783 }; | 1783 }; |
| 1784 | 1784 |
| 1785 | 1785 |
| 1786 void DeferredInlineSmiOperation::Generate() { | 1786 void DeferredInlineSmiOperation::Generate() { |
| 1787 // For mod we don't generate all the Smi code inline. | 1787 // For mod we don't generate all the Smi code inline. |
| 1788 GenericBinaryOpStub stub( | 1788 GenericBinaryOpStub stub( |
| 1789 op_, | 1789 op_, |
| 1790 overwrite_mode_, | 1790 overwrite_mode_, |
| 1791 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB, | 1791 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB, |
| 1792 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 1792 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
| 1793 stub.GenerateCall(masm_, src_, value_); | 1793 stub.GenerateCall(masm_, src_, value_); |
| 1794 if (!dst_.is(eax)) __ mov(dst_, eax); | 1794 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1795 } | 1795 } |
| 1796 | 1796 |
| 1797 | 1797 |
| 1798 // Call the appropriate binary operation stub to compute value op src | 1798 // Call the appropriate binary operation stub to compute value op src |
| 1799 // and leave the result in dst. | 1799 // and leave the result in dst. |
| 1800 class DeferredInlineSmiOperationReversed: public DeferredCode { | 1800 class DeferredInlineSmiOperationReversed: public DeferredCode { |
| 1801 public: | 1801 public: |
| 1802 DeferredInlineSmiOperationReversed(Token::Value op, | 1802 DeferredInlineSmiOperationReversed(Token::Value op, |
| 1803 Register dst, | 1803 Register dst, |
| 1804 Smi* value, | 1804 Smi* value, |
| 1805 Register src, | 1805 Register src, |
| 1806 NumberInfo number_info, | 1806 TypeInfo type_info, |
| 1807 OverwriteMode overwrite_mode) | 1807 OverwriteMode overwrite_mode) |
| 1808 : op_(op), | 1808 : op_(op), |
| 1809 dst_(dst), | 1809 dst_(dst), |
| 1810 number_info_(number_info), | 1810 type_info_(type_info), |
| 1811 value_(value), | 1811 value_(value), |
| 1812 src_(src), | 1812 src_(src), |
| 1813 overwrite_mode_(overwrite_mode) { | 1813 overwrite_mode_(overwrite_mode) { |
| 1814 set_comment("[ DeferredInlineSmiOperationReversed"); | 1814 set_comment("[ DeferredInlineSmiOperationReversed"); |
| 1815 } | 1815 } |
| 1816 | 1816 |
| 1817 virtual void Generate(); | 1817 virtual void Generate(); |
| 1818 | 1818 |
| 1819 private: | 1819 private: |
| 1820 Token::Value op_; | 1820 Token::Value op_; |
| 1821 Register dst_; | 1821 Register dst_; |
| 1822 NumberInfo number_info_; | 1822 TypeInfo type_info_; |
| 1823 Smi* value_; | 1823 Smi* value_; |
| 1824 Register src_; | 1824 Register src_; |
| 1825 OverwriteMode overwrite_mode_; | 1825 OverwriteMode overwrite_mode_; |
| 1826 }; | 1826 }; |
| 1827 | 1827 |
| 1828 | 1828 |
| 1829 void DeferredInlineSmiOperationReversed::Generate() { | 1829 void DeferredInlineSmiOperationReversed::Generate() { |
| 1830 GenericBinaryOpStub igostub( | 1830 GenericBinaryOpStub igostub( |
| 1831 op_, | 1831 op_, |
| 1832 overwrite_mode_, | 1832 overwrite_mode_, |
| 1833 NO_SMI_CODE_IN_STUB, | 1833 NO_SMI_CODE_IN_STUB, |
| 1834 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 1834 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
| 1835 igostub.GenerateCall(masm_, value_, src_); | 1835 igostub.GenerateCall(masm_, value_, src_); |
| 1836 if (!dst_.is(eax)) __ mov(dst_, eax); | 1836 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1837 } | 1837 } |
| 1838 | 1838 |
| 1839 | 1839 |
| 1840 // The result of src + value is in dst. It either overflowed or was not | 1840 // The result of src + value is in dst. It either overflowed or was not |
| 1841 // smi tagged. Undo the speculative addition and call the appropriate | 1841 // smi tagged. Undo the speculative addition and call the appropriate |
| 1842 // specialized stub for add. The result is left in dst. | 1842 // specialized stub for add. The result is left in dst. |
| 1843 class DeferredInlineSmiAdd: public DeferredCode { | 1843 class DeferredInlineSmiAdd: public DeferredCode { |
| 1844 public: | 1844 public: |
| 1845 DeferredInlineSmiAdd(Register dst, | 1845 DeferredInlineSmiAdd(Register dst, |
| 1846 NumberInfo number_info, | 1846 TypeInfo type_info, |
| 1847 Smi* value, | 1847 Smi* value, |
| 1848 OverwriteMode overwrite_mode) | 1848 OverwriteMode overwrite_mode) |
| 1849 : dst_(dst), | 1849 : dst_(dst), |
| 1850 number_info_(number_info), | 1850 type_info_(type_info), |
| 1851 value_(value), | 1851 value_(value), |
| 1852 overwrite_mode_(overwrite_mode) { | 1852 overwrite_mode_(overwrite_mode) { |
| 1853 if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 1853 if (type_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1854 set_comment("[ DeferredInlineSmiAdd"); | 1854 set_comment("[ DeferredInlineSmiAdd"); |
| 1855 } | 1855 } |
| 1856 | 1856 |
| 1857 virtual void Generate(); | 1857 virtual void Generate(); |
| 1858 | 1858 |
| 1859 private: | 1859 private: |
| 1860 Register dst_; | 1860 Register dst_; |
| 1861 NumberInfo number_info_; | 1861 TypeInfo type_info_; |
| 1862 Smi* value_; | 1862 Smi* value_; |
| 1863 OverwriteMode overwrite_mode_; | 1863 OverwriteMode overwrite_mode_; |
| 1864 }; | 1864 }; |
| 1865 | 1865 |
| 1866 | 1866 |
| 1867 void DeferredInlineSmiAdd::Generate() { | 1867 void DeferredInlineSmiAdd::Generate() { |
| 1868 // Undo the optimistic add operation and call the shared stub. | 1868 // Undo the optimistic add operation and call the shared stub. |
| 1869 __ sub(Operand(dst_), Immediate(value_)); | 1869 __ sub(Operand(dst_), Immediate(value_)); |
| 1870 GenericBinaryOpStub igostub( | 1870 GenericBinaryOpStub igostub( |
| 1871 Token::ADD, | 1871 Token::ADD, |
| 1872 overwrite_mode_, | 1872 overwrite_mode_, |
| 1873 NO_SMI_CODE_IN_STUB, | 1873 NO_SMI_CODE_IN_STUB, |
| 1874 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 1874 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
| 1875 igostub.GenerateCall(masm_, dst_, value_); | 1875 igostub.GenerateCall(masm_, dst_, value_); |
| 1876 if (!dst_.is(eax)) __ mov(dst_, eax); | 1876 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1877 } | 1877 } |
| 1878 | 1878 |
| 1879 | 1879 |
| 1880 // The result of value + src is in dst. It either overflowed or was not | 1880 // The result of value + src is in dst. It either overflowed or was not |
| 1881 // smi tagged. Undo the speculative addition and call the appropriate | 1881 // smi tagged. Undo the speculative addition and call the appropriate |
| 1882 // specialized stub for add. The result is left in dst. | 1882 // specialized stub for add. The result is left in dst. |
| 1883 class DeferredInlineSmiAddReversed: public DeferredCode { | 1883 class DeferredInlineSmiAddReversed: public DeferredCode { |
| 1884 public: | 1884 public: |
| 1885 DeferredInlineSmiAddReversed(Register dst, | 1885 DeferredInlineSmiAddReversed(Register dst, |
| 1886 NumberInfo number_info, | 1886 TypeInfo type_info, |
| 1887 Smi* value, | 1887 Smi* value, |
| 1888 OverwriteMode overwrite_mode) | 1888 OverwriteMode overwrite_mode) |
| 1889 : dst_(dst), | 1889 : dst_(dst), |
| 1890 number_info_(number_info), | 1890 type_info_(type_info), |
| 1891 value_(value), | 1891 value_(value), |
| 1892 overwrite_mode_(overwrite_mode) { | 1892 overwrite_mode_(overwrite_mode) { |
| 1893 set_comment("[ DeferredInlineSmiAddReversed"); | 1893 set_comment("[ DeferredInlineSmiAddReversed"); |
| 1894 } | 1894 } |
| 1895 | 1895 |
| 1896 virtual void Generate(); | 1896 virtual void Generate(); |
| 1897 | 1897 |
| 1898 private: | 1898 private: |
| 1899 Register dst_; | 1899 Register dst_; |
| 1900 NumberInfo number_info_; | 1900 TypeInfo type_info_; |
| 1901 Smi* value_; | 1901 Smi* value_; |
| 1902 OverwriteMode overwrite_mode_; | 1902 OverwriteMode overwrite_mode_; |
| 1903 }; | 1903 }; |
| 1904 | 1904 |
| 1905 | 1905 |
| 1906 void DeferredInlineSmiAddReversed::Generate() { | 1906 void DeferredInlineSmiAddReversed::Generate() { |
| 1907 // Undo the optimistic add operation and call the shared stub. | 1907 // Undo the optimistic add operation and call the shared stub. |
| 1908 __ sub(Operand(dst_), Immediate(value_)); | 1908 __ sub(Operand(dst_), Immediate(value_)); |
| 1909 GenericBinaryOpStub igostub( | 1909 GenericBinaryOpStub igostub( |
| 1910 Token::ADD, | 1910 Token::ADD, |
| 1911 overwrite_mode_, | 1911 overwrite_mode_, |
| 1912 NO_SMI_CODE_IN_STUB, | 1912 NO_SMI_CODE_IN_STUB, |
| 1913 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 1913 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
| 1914 igostub.GenerateCall(masm_, value_, dst_); | 1914 igostub.GenerateCall(masm_, value_, dst_); |
| 1915 if (!dst_.is(eax)) __ mov(dst_, eax); | 1915 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1916 } | 1916 } |
| 1917 | 1917 |
| 1918 | 1918 |
| 1919 // The result of src - value is in dst. It either overflowed or was not | 1919 // The result of src - value is in dst. It either overflowed or was not |
| 1920 // smi tagged. Undo the speculative subtraction and call the | 1920 // smi tagged. Undo the speculative subtraction and call the |
| 1921 // appropriate specialized stub for subtract. The result is left in | 1921 // appropriate specialized stub for subtract. The result is left in |
| 1922 // dst. | 1922 // dst. |
| 1923 class DeferredInlineSmiSub: public DeferredCode { | 1923 class DeferredInlineSmiSub: public DeferredCode { |
| 1924 public: | 1924 public: |
| 1925 DeferredInlineSmiSub(Register dst, | 1925 DeferredInlineSmiSub(Register dst, |
| 1926 NumberInfo number_info, | 1926 TypeInfo type_info, |
| 1927 Smi* value, | 1927 Smi* value, |
| 1928 OverwriteMode overwrite_mode) | 1928 OverwriteMode overwrite_mode) |
| 1929 : dst_(dst), | 1929 : dst_(dst), |
| 1930 number_info_(number_info), | 1930 type_info_(type_info), |
| 1931 value_(value), | 1931 value_(value), |
| 1932 overwrite_mode_(overwrite_mode) { | 1932 overwrite_mode_(overwrite_mode) { |
| 1933 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; | 1933 if (type_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1934 set_comment("[ DeferredInlineSmiSub"); | 1934 set_comment("[ DeferredInlineSmiSub"); |
| 1935 } | 1935 } |
| 1936 | 1936 |
| 1937 virtual void Generate(); | 1937 virtual void Generate(); |
| 1938 | 1938 |
| 1939 private: | 1939 private: |
| 1940 Register dst_; | 1940 Register dst_; |
| 1941 NumberInfo number_info_; | 1941 TypeInfo type_info_; |
| 1942 Smi* value_; | 1942 Smi* value_; |
| 1943 OverwriteMode overwrite_mode_; | 1943 OverwriteMode overwrite_mode_; |
| 1944 }; | 1944 }; |
| 1945 | 1945 |
| 1946 | 1946 |
| 1947 void DeferredInlineSmiSub::Generate() { | 1947 void DeferredInlineSmiSub::Generate() { |
| 1948 // Undo the optimistic sub operation and call the shared stub. | 1948 // Undo the optimistic sub operation and call the shared stub. |
| 1949 __ add(Operand(dst_), Immediate(value_)); | 1949 __ add(Operand(dst_), Immediate(value_)); |
| 1950 GenericBinaryOpStub igostub( | 1950 GenericBinaryOpStub igostub( |
| 1951 Token::SUB, | 1951 Token::SUB, |
| 1952 overwrite_mode_, | 1952 overwrite_mode_, |
| 1953 NO_SMI_CODE_IN_STUB, | 1953 NO_SMI_CODE_IN_STUB, |
| 1954 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); | 1954 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
| 1955 igostub.GenerateCall(masm_, dst_, value_); | 1955 igostub.GenerateCall(masm_, dst_, value_); |
| 1956 if (!dst_.is(eax)) __ mov(dst_, eax); | 1956 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1957 } | 1957 } |
| 1958 | 1958 |
| 1959 | 1959 |
| 1960 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1960 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| 1961 Result* operand, | 1961 Result* operand, |
| 1962 Handle<Object> value, | 1962 Handle<Object> value, |
| 1963 StaticType* type, | 1963 StaticType* type, |
| 1964 bool reversed, | 1964 bool reversed, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1989 switch (op) { | 1989 switch (op) { |
| 1990 case Token::ADD: { | 1990 case Token::ADD: { |
| 1991 operand->ToRegister(); | 1991 operand->ToRegister(); |
| 1992 frame_->Spill(operand->reg()); | 1992 frame_->Spill(operand->reg()); |
| 1993 | 1993 |
| 1994 // Optimistically add. Call the specialized add stub if the | 1994 // Optimistically add. Call the specialized add stub if the |
| 1995 // result is not a smi or overflows. | 1995 // result is not a smi or overflows. |
| 1996 DeferredCode* deferred = NULL; | 1996 DeferredCode* deferred = NULL; |
| 1997 if (reversed) { | 1997 if (reversed) { |
| 1998 deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 1998 deferred = new DeferredInlineSmiAddReversed(operand->reg(), |
| 1999 operand->number_info(), | 1999 operand->type_info(), |
| 2000 smi_value, | 2000 smi_value, |
| 2001 overwrite_mode); | 2001 overwrite_mode); |
| 2002 } else { | 2002 } else { |
| 2003 deferred = new DeferredInlineSmiAdd(operand->reg(), | 2003 deferred = new DeferredInlineSmiAdd(operand->reg(), |
| 2004 operand->number_info(), | 2004 operand->type_info(), |
| 2005 smi_value, | 2005 smi_value, |
| 2006 overwrite_mode); | 2006 overwrite_mode); |
| 2007 } | 2007 } |
| 2008 __ add(Operand(operand->reg()), Immediate(value)); | 2008 __ add(Operand(operand->reg()), Immediate(value)); |
| 2009 deferred->Branch(overflow); | 2009 deferred->Branch(overflow); |
| 2010 if (!operand->number_info().IsSmi()) { | 2010 if (!operand->type_info().IsSmi()) { |
| 2011 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2011 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2012 deferred->Branch(not_zero); | 2012 deferred->Branch(not_zero); |
| 2013 } else { | 2013 } else { |
| 2014 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); | 2014 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2015 } | 2015 } |
| 2016 deferred->BindExit(); | 2016 deferred->BindExit(); |
| 2017 answer = *operand; | 2017 answer = *operand; |
| 2018 break; | 2018 break; |
| 2019 } | 2019 } |
| 2020 | 2020 |
| 2021 case Token::SUB: { | 2021 case Token::SUB: { |
| 2022 DeferredCode* deferred = NULL; | 2022 DeferredCode* deferred = NULL; |
| 2023 if (reversed) { | 2023 if (reversed) { |
| 2024 // The reversed case is only hit when the right operand is not a | 2024 // The reversed case is only hit when the right operand is not a |
| 2025 // constant. | 2025 // constant. |
| 2026 ASSERT(operand->is_register()); | 2026 ASSERT(operand->is_register()); |
| 2027 answer = allocator()->Allocate(); | 2027 answer = allocator()->Allocate(); |
| 2028 ASSERT(answer.is_valid()); | 2028 ASSERT(answer.is_valid()); |
| 2029 __ Set(answer.reg(), Immediate(value)); | 2029 __ Set(answer.reg(), Immediate(value)); |
| 2030 deferred = | 2030 deferred = |
| 2031 new DeferredInlineSmiOperationReversed(op, | 2031 new DeferredInlineSmiOperationReversed(op, |
| 2032 answer.reg(), | 2032 answer.reg(), |
| 2033 smi_value, | 2033 smi_value, |
| 2034 operand->reg(), | 2034 operand->reg(), |
| 2035 operand->number_info(), | 2035 operand->type_info(), |
| 2036 overwrite_mode); | 2036 overwrite_mode); |
| 2037 __ sub(answer.reg(), Operand(operand->reg())); | 2037 __ sub(answer.reg(), Operand(operand->reg())); |
| 2038 } else { | 2038 } else { |
| 2039 operand->ToRegister(); | 2039 operand->ToRegister(); |
| 2040 frame_->Spill(operand->reg()); | 2040 frame_->Spill(operand->reg()); |
| 2041 answer = *operand; | 2041 answer = *operand; |
| 2042 deferred = new DeferredInlineSmiSub(operand->reg(), | 2042 deferred = new DeferredInlineSmiSub(operand->reg(), |
| 2043 operand->number_info(), | 2043 operand->type_info(), |
| 2044 smi_value, | 2044 smi_value, |
| 2045 overwrite_mode); | 2045 overwrite_mode); |
| 2046 __ sub(Operand(operand->reg()), Immediate(value)); | 2046 __ sub(Operand(operand->reg()), Immediate(value)); |
| 2047 } | 2047 } |
| 2048 deferred->Branch(overflow); | 2048 deferred->Branch(overflow); |
| 2049 if (!operand->number_info().IsSmi()) { | 2049 if (!operand->type_info().IsSmi()) { |
| 2050 __ test(answer.reg(), Immediate(kSmiTagMask)); | 2050 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 2051 deferred->Branch(not_zero); | 2051 deferred->Branch(not_zero); |
| 2052 } else { | 2052 } else { |
| 2053 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); | 2053 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2054 } | 2054 } |
| 2055 deferred->BindExit(); | 2055 deferred->BindExit(); |
| 2056 operand->Unuse(); | 2056 operand->Unuse(); |
| 2057 break; | 2057 break; |
| 2058 } | 2058 } |
| 2059 | 2059 |
| 2060 case Token::SAR: | 2060 case Token::SAR: |
| 2061 if (reversed) { | 2061 if (reversed) { |
| 2062 Result constant_operand(value); | 2062 Result constant_operand(value); |
| 2063 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 2063 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 2064 overwrite_mode, no_negative_zero); | 2064 overwrite_mode, no_negative_zero); |
| 2065 } else { | 2065 } else { |
| 2066 // Only the least significant 5 bits of the shift value are used. | 2066 // Only the least significant 5 bits of the shift value are used. |
| 2067 // In the slow case, this masking is done inside the runtime call. | 2067 // In the slow case, this masking is done inside the runtime call. |
| 2068 int shift_value = int_value & 0x1f; | 2068 int shift_value = int_value & 0x1f; |
| 2069 operand->ToRegister(); | 2069 operand->ToRegister(); |
| 2070 frame_->Spill(operand->reg()); | 2070 frame_->Spill(operand->reg()); |
| 2071 if (!operand->number_info().IsSmi()) { | 2071 if (!operand->type_info().IsSmi()) { |
| 2072 DeferredInlineSmiOperation* deferred = | 2072 DeferredInlineSmiOperation* deferred = |
| 2073 new DeferredInlineSmiOperation(op, | 2073 new DeferredInlineSmiOperation(op, |
| 2074 operand->reg(), | 2074 operand->reg(), |
| 2075 operand->reg(), | 2075 operand->reg(), |
| 2076 operand->number_info(), | 2076 operand->type_info(), |
| 2077 smi_value, | 2077 smi_value, |
| 2078 overwrite_mode); | 2078 overwrite_mode); |
| 2079 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2079 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2080 deferred->Branch(not_zero); | 2080 deferred->Branch(not_zero); |
| 2081 if (shift_value > 0) { | 2081 if (shift_value > 0) { |
| 2082 __ sar(operand->reg(), shift_value); | 2082 __ sar(operand->reg(), shift_value); |
| 2083 __ and_(operand->reg(), ~kSmiTagMask); | 2083 __ and_(operand->reg(), ~kSmiTagMask); |
| 2084 } | 2084 } |
| 2085 deferred->BindExit(); | 2085 deferred->BindExit(); |
| 2086 } else { | 2086 } else { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2103 // Only the least significant 5 bits of the shift value are used. | 2103 // Only the least significant 5 bits of the shift value are used. |
| 2104 // In the slow case, this masking is done inside the runtime call. | 2104 // In the slow case, this masking is done inside the runtime call. |
| 2105 int shift_value = int_value & 0x1f; | 2105 int shift_value = int_value & 0x1f; |
| 2106 operand->ToRegister(); | 2106 operand->ToRegister(); |
| 2107 answer = allocator()->Allocate(); | 2107 answer = allocator()->Allocate(); |
| 2108 ASSERT(answer.is_valid()); | 2108 ASSERT(answer.is_valid()); |
| 2109 DeferredInlineSmiOperation* deferred = | 2109 DeferredInlineSmiOperation* deferred = |
| 2110 new DeferredInlineSmiOperation(op, | 2110 new DeferredInlineSmiOperation(op, |
| 2111 answer.reg(), | 2111 answer.reg(), |
| 2112 operand->reg(), | 2112 operand->reg(), |
| 2113 operand->number_info(), | 2113 operand->type_info(), |
| 2114 smi_value, | 2114 smi_value, |
| 2115 overwrite_mode); | 2115 overwrite_mode); |
| 2116 if (!operand->number_info().IsSmi()) { | 2116 if (!operand->type_info().IsSmi()) { |
| 2117 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2117 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2118 deferred->Branch(not_zero); | 2118 deferred->Branch(not_zero); |
| 2119 } else { | 2119 } else { |
| 2120 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); | 2120 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2121 } | 2121 } |
| 2122 __ mov(answer.reg(), operand->reg()); | 2122 __ mov(answer.reg(), operand->reg()); |
| 2123 __ SmiUntag(answer.reg()); | 2123 __ SmiUntag(answer.reg()); |
| 2124 __ shr(answer.reg(), shift_value); | 2124 __ shr(answer.reg(), shift_value); |
| 2125 // A negative Smi shifted right two is in the positive Smi range. | 2125 // A negative Smi shifted right two is in the positive Smi range. |
| 2126 if (shift_value < 2) { | 2126 if (shift_value < 2) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2153 right = *operand; | 2153 right = *operand; |
| 2154 } | 2154 } |
| 2155 operand->Unuse(); | 2155 operand->Unuse(); |
| 2156 | 2156 |
| 2157 answer = allocator()->Allocate(); | 2157 answer = allocator()->Allocate(); |
| 2158 DeferredInlineSmiOperationReversed* deferred = | 2158 DeferredInlineSmiOperationReversed* deferred = |
| 2159 new DeferredInlineSmiOperationReversed(op, | 2159 new DeferredInlineSmiOperationReversed(op, |
| 2160 answer.reg(), | 2160 answer.reg(), |
| 2161 smi_value, | 2161 smi_value, |
| 2162 right.reg(), | 2162 right.reg(), |
| 2163 right.number_info(), | 2163 right.type_info(), |
| 2164 overwrite_mode); | 2164 overwrite_mode); |
| 2165 __ mov(answer.reg(), Immediate(int_value)); | 2165 __ mov(answer.reg(), Immediate(int_value)); |
| 2166 __ sar(ecx, kSmiTagSize); | 2166 __ sar(ecx, kSmiTagSize); |
| 2167 if (!right.number_info().IsSmi()) { | 2167 if (!right.type_info().IsSmi()) { |
| 2168 deferred->Branch(carry); | 2168 deferred->Branch(carry); |
| 2169 } else { | 2169 } else { |
| 2170 if (FLAG_debug_code) __ AbortIfNotSmi(right.reg()); | 2170 if (FLAG_debug_code) __ AbortIfNotSmi(right.reg()); |
| 2171 } | 2171 } |
| 2172 __ shl_cl(answer.reg()); | 2172 __ shl_cl(answer.reg()); |
| 2173 __ cmp(answer.reg(), 0xc0000000); | 2173 __ cmp(answer.reg(), 0xc0000000); |
| 2174 deferred->Branch(sign); | 2174 deferred->Branch(sign); |
| 2175 __ SmiTag(answer.reg()); | 2175 __ SmiTag(answer.reg()); |
| 2176 | 2176 |
| 2177 deferred->BindExit(); | 2177 deferred->BindExit(); |
| 2178 } else { | 2178 } else { |
| 2179 // Only the least significant 5 bits of the shift value are used. | 2179 // Only the least significant 5 bits of the shift value are used. |
| 2180 // In the slow case, this masking is done inside the runtime call. | 2180 // In the slow case, this masking is done inside the runtime call. |
| 2181 int shift_value = int_value & 0x1f; | 2181 int shift_value = int_value & 0x1f; |
| 2182 operand->ToRegister(); | 2182 operand->ToRegister(); |
| 2183 if (shift_value == 0) { | 2183 if (shift_value == 0) { |
| 2184 // Spill operand so it can be overwritten in the slow case. | 2184 // Spill operand so it can be overwritten in the slow case. |
| 2185 frame_->Spill(operand->reg()); | 2185 frame_->Spill(operand->reg()); |
| 2186 DeferredInlineSmiOperation* deferred = | 2186 DeferredInlineSmiOperation* deferred = |
| 2187 new DeferredInlineSmiOperation(op, | 2187 new DeferredInlineSmiOperation(op, |
| 2188 operand->reg(), | 2188 operand->reg(), |
| 2189 operand->reg(), | 2189 operand->reg(), |
| 2190 operand->number_info(), | 2190 operand->type_info(), |
| 2191 smi_value, | 2191 smi_value, |
| 2192 overwrite_mode); | 2192 overwrite_mode); |
| 2193 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2193 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2194 deferred->Branch(not_zero); | 2194 deferred->Branch(not_zero); |
| 2195 deferred->BindExit(); | 2195 deferred->BindExit(); |
| 2196 answer = *operand; | 2196 answer = *operand; |
| 2197 } else { | 2197 } else { |
| 2198 // Use a fresh temporary for nonzero shift values. | 2198 // Use a fresh temporary for nonzero shift values. |
| 2199 answer = allocator()->Allocate(); | 2199 answer = allocator()->Allocate(); |
| 2200 ASSERT(answer.is_valid()); | 2200 ASSERT(answer.is_valid()); |
| 2201 DeferredInlineSmiOperation* deferred = | 2201 DeferredInlineSmiOperation* deferred = |
| 2202 new DeferredInlineSmiOperation(op, | 2202 new DeferredInlineSmiOperation(op, |
| 2203 answer.reg(), | 2203 answer.reg(), |
| 2204 operand->reg(), | 2204 operand->reg(), |
| 2205 operand->number_info(), | 2205 operand->type_info(), |
| 2206 smi_value, | 2206 smi_value, |
| 2207 overwrite_mode); | 2207 overwrite_mode); |
| 2208 if (!operand->number_info().IsSmi()) { | 2208 if (!operand->type_info().IsSmi()) { |
| 2209 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2209 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2210 deferred->Branch(not_zero); | 2210 deferred->Branch(not_zero); |
| 2211 } else { | 2211 } else { |
| 2212 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); | 2212 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2213 } | 2213 } |
| 2214 __ mov(answer.reg(), operand->reg()); | 2214 __ mov(answer.reg(), operand->reg()); |
| 2215 ASSERT(kSmiTag == 0); // adjust code if not the case | 2215 ASSERT(kSmiTag == 0); // adjust code if not the case |
| 2216 // We do no shifts, only the Smi conversion, if shift_value is 1. | 2216 // We do no shifts, only the Smi conversion, if shift_value is 1. |
| 2217 if (shift_value > 1) { | 2217 if (shift_value > 1) { |
| 2218 __ shl(answer.reg(), shift_value - 1); | 2218 __ shl(answer.reg(), shift_value - 1); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2232 case Token::BIT_AND: { | 2232 case Token::BIT_AND: { |
| 2233 operand->ToRegister(); | 2233 operand->ToRegister(); |
| 2234 frame_->Spill(operand->reg()); | 2234 frame_->Spill(operand->reg()); |
| 2235 DeferredCode* deferred = NULL; | 2235 DeferredCode* deferred = NULL; |
| 2236 if (reversed) { | 2236 if (reversed) { |
| 2237 deferred = | 2237 deferred = |
| 2238 new DeferredInlineSmiOperationReversed(op, | 2238 new DeferredInlineSmiOperationReversed(op, |
| 2239 operand->reg(), | 2239 operand->reg(), |
| 2240 smi_value, | 2240 smi_value, |
| 2241 operand->reg(), | 2241 operand->reg(), |
| 2242 operand->number_info(), | 2242 operand->type_info(), |
| 2243 overwrite_mode); | 2243 overwrite_mode); |
| 2244 } else { | 2244 } else { |
| 2245 deferred = new DeferredInlineSmiOperation(op, | 2245 deferred = new DeferredInlineSmiOperation(op, |
| 2246 operand->reg(), | 2246 operand->reg(), |
| 2247 operand->reg(), | 2247 operand->reg(), |
| 2248 operand->number_info(), | 2248 operand->type_info(), |
| 2249 smi_value, | 2249 smi_value, |
| 2250 overwrite_mode); | 2250 overwrite_mode); |
| 2251 } | 2251 } |
| 2252 if (!operand->number_info().IsSmi()) { | 2252 if (!operand->type_info().IsSmi()) { |
| 2253 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2253 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2254 deferred->Branch(not_zero); | 2254 deferred->Branch(not_zero); |
| 2255 } else { | 2255 } else { |
| 2256 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); | 2256 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2257 } | 2257 } |
| 2258 if (op == Token::BIT_AND) { | 2258 if (op == Token::BIT_AND) { |
| 2259 __ and_(Operand(operand->reg()), Immediate(value)); | 2259 __ and_(Operand(operand->reg()), Immediate(value)); |
| 2260 } else if (op == Token::BIT_XOR) { | 2260 } else if (op == Token::BIT_XOR) { |
| 2261 if (int_value != 0) { | 2261 if (int_value != 0) { |
| 2262 __ xor_(Operand(operand->reg()), Immediate(value)); | 2262 __ xor_(Operand(operand->reg()), Immediate(value)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2274 | 2274 |
| 2275 case Token::DIV: | 2275 case Token::DIV: |
| 2276 if (!reversed && int_value == 2) { | 2276 if (!reversed && int_value == 2) { |
| 2277 operand->ToRegister(); | 2277 operand->ToRegister(); |
| 2278 frame_->Spill(operand->reg()); | 2278 frame_->Spill(operand->reg()); |
| 2279 | 2279 |
| 2280 DeferredInlineSmiOperation* deferred = | 2280 DeferredInlineSmiOperation* deferred = |
| 2281 new DeferredInlineSmiOperation(op, | 2281 new DeferredInlineSmiOperation(op, |
| 2282 operand->reg(), | 2282 operand->reg(), |
| 2283 operand->reg(), | 2283 operand->reg(), |
| 2284 operand->number_info(), | 2284 operand->type_info(), |
| 2285 smi_value, | 2285 smi_value, |
| 2286 overwrite_mode); | 2286 overwrite_mode); |
| 2287 // Check that lowest log2(value) bits of operand are zero, and test | 2287 // Check that lowest log2(value) bits of operand are zero, and test |
| 2288 // smi tag at the same time. | 2288 // smi tag at the same time. |
| 2289 ASSERT_EQ(0, kSmiTag); | 2289 ASSERT_EQ(0, kSmiTag); |
| 2290 ASSERT_EQ(1, kSmiTagSize); | 2290 ASSERT_EQ(1, kSmiTagSize); |
| 2291 __ test(operand->reg(), Immediate(3)); | 2291 __ test(operand->reg(), Immediate(3)); |
| 2292 deferred->Branch(not_zero); // Branch if non-smi or odd smi. | 2292 deferred->Branch(not_zero); // Branch if non-smi or odd smi. |
| 2293 __ sar(operand->reg(), 1); | 2293 __ sar(operand->reg(), 1); |
| 2294 deferred->BindExit(); | 2294 deferred->BindExit(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2310 case Token::MOD: | 2310 case Token::MOD: |
| 2311 if (!reversed && | 2311 if (!reversed && |
| 2312 int_value != 0 && | 2312 int_value != 0 && |
| 2313 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 2313 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
| 2314 operand->ToRegister(); | 2314 operand->ToRegister(); |
| 2315 frame_->Spill(operand->reg()); | 2315 frame_->Spill(operand->reg()); |
| 2316 DeferredCode* deferred = | 2316 DeferredCode* deferred = |
| 2317 new DeferredInlineSmiOperation(op, | 2317 new DeferredInlineSmiOperation(op, |
| 2318 operand->reg(), | 2318 operand->reg(), |
| 2319 operand->reg(), | 2319 operand->reg(), |
| 2320 operand->number_info(), | 2320 operand->type_info(), |
| 2321 smi_value, | 2321 smi_value, |
| 2322 overwrite_mode); | 2322 overwrite_mode); |
| 2323 // Check for negative or non-Smi left hand side. | 2323 // Check for negative or non-Smi left hand side. |
| 2324 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); | 2324 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 2325 deferred->Branch(not_zero); | 2325 deferred->Branch(not_zero); |
| 2326 if (int_value < 0) int_value = -int_value; | 2326 if (int_value < 0) int_value = -int_value; |
| 2327 if (int_value == 1) { | 2327 if (int_value == 1) { |
| 2328 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 2328 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
| 2329 } else { | 2329 } else { |
| 2330 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 2330 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2346 } | 2346 } |
| 2347 break; | 2347 break; |
| 2348 } | 2348 } |
| 2349 } | 2349 } |
| 2350 ASSERT(answer.is_valid()); | 2350 ASSERT(answer.is_valid()); |
| 2351 return answer; | 2351 return answer; |
| 2352 } | 2352 } |
| 2353 | 2353 |
| 2354 | 2354 |
| 2355 static bool CouldBeNaN(const Result& result) { | 2355 static bool CouldBeNaN(const Result& result) { |
| 2356 if (result.number_info().IsSmi()) return false; | 2356 if (result.type_info().IsSmi()) return false; |
| 2357 if (result.number_info().IsInteger32()) return false; | 2357 if (result.type_info().IsInteger32()) return false; |
| 2358 if (!result.is_constant()) return true; | 2358 if (!result.is_constant()) return true; |
| 2359 if (!result.handle()->IsHeapNumber()) return false; | 2359 if (!result.handle()->IsHeapNumber()) return false; |
| 2360 return isnan(HeapNumber::cast(*result.handle())->value()); | 2360 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 2361 } | 2361 } |
| 2362 | 2362 |
| 2363 | 2363 |
| 2364 void CodeGenerator::Comparison(AstNode* node, | 2364 void CodeGenerator::Comparison(AstNode* node, |
| 2365 Condition cc, | 2365 Condition cc, |
| 2366 bool strict, | 2366 bool strict, |
| 2367 ControlDestination* dest) { | 2367 ControlDestination* dest) { |
| (...skipping 1277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3645 | 3645 |
| 3646 // The break target may be already bound (by the condition), or there | 3646 // The break target may be already bound (by the condition), or there |
| 3647 // may not be a valid frame. Bind it only if needed. | 3647 // may not be a valid frame. Bind it only if needed. |
| 3648 if (node->break_target()->is_linked()) { | 3648 if (node->break_target()->is_linked()) { |
| 3649 node->break_target()->Bind(); | 3649 node->break_target()->Bind(); |
| 3650 } | 3650 } |
| 3651 DecrementLoopNesting(); | 3651 DecrementLoopNesting(); |
| 3652 } | 3652 } |
| 3653 | 3653 |
| 3654 | 3654 |
| 3655 void CodeGenerator::SetTypeForStackSlot(Slot* slot, NumberInfo info) { | 3655 void CodeGenerator::SetTypeForStackSlot(Slot* slot, TypeInfo info) { |
| 3656 ASSERT(slot->type() == Slot::LOCAL || slot->type() == Slot::PARAMETER); | 3656 ASSERT(slot->type() == Slot::LOCAL || slot->type() == Slot::PARAMETER); |
| 3657 if (slot->type() == Slot::LOCAL) { | 3657 if (slot->type() == Slot::LOCAL) { |
| 3658 frame_->SetTypeForLocalAt(slot->index(), info); | 3658 frame_->SetTypeForLocalAt(slot->index(), info); |
| 3659 } else { | 3659 } else { |
| 3660 frame_->SetTypeForParamAt(slot->index(), info); | 3660 frame_->SetTypeForParamAt(slot->index(), info); |
| 3661 } | 3661 } |
| 3662 if (FLAG_debug_code && info.IsSmi()) { | 3662 if (FLAG_debug_code && info.IsSmi()) { |
| 3663 if (slot->type() == Slot::LOCAL) { | 3663 if (slot->type() == Slot::LOCAL) { |
| 3664 frame_->PushLocalAt(slot->index()); | 3664 frame_->PushLocalAt(slot->index()); |
| 3665 } else { | 3665 } else { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3765 | 3765 |
| 3766 CheckStack(); // TODO(1222600): ignore if body contains calls. | 3766 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 3767 | 3767 |
| 3768 // We know that the loop index is a smi if it is not modified in the | 3768 // We know that the loop index is a smi if it is not modified in the |
| 3769 // loop body and it is checked against a constant limit in the loop | 3769 // loop body and it is checked against a constant limit in the loop |
| 3770 // condition. In this case, we reset the static type information of the | 3770 // condition. In this case, we reset the static type information of the |
| 3771 // loop index to smi before compiling the body, the update expression, and | 3771 // loop index to smi before compiling the body, the update expression, and |
| 3772 // the bottom check of the loop condition. | 3772 // the bottom check of the loop condition. |
| 3773 if (node->is_fast_smi_loop()) { | 3773 if (node->is_fast_smi_loop()) { |
| 3774 // Set number type of the loop variable to smi. | 3774 // Set number type of the loop variable to smi. |
| 3775 SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi()); | 3775 SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi()); |
| 3776 } | 3776 } |
| 3777 | 3777 |
| 3778 Visit(node->body()); | 3778 Visit(node->body()); |
| 3779 | 3779 |
| 3780 // If there is an update expression, compile it if necessary. | 3780 // If there is an update expression, compile it if necessary. |
| 3781 if (node->next() != NULL) { | 3781 if (node->next() != NULL) { |
| 3782 if (node->continue_target()->is_linked()) { | 3782 if (node->continue_target()->is_linked()) { |
| 3783 node->continue_target()->Bind(); | 3783 node->continue_target()->Bind(); |
| 3784 } | 3784 } |
| 3785 | 3785 |
| 3786 // Control can reach the update by falling out of the body or by a | 3786 // Control can reach the update by falling out of the body or by a |
| 3787 // continue. | 3787 // continue. |
| 3788 if (has_valid_frame()) { | 3788 if (has_valid_frame()) { |
| 3789 // Record the source position of the statement as this code which | 3789 // Record the source position of the statement as this code which |
| 3790 // is after the code for the body actually belongs to the loop | 3790 // is after the code for the body actually belongs to the loop |
| 3791 // statement and not the body. | 3791 // statement and not the body. |
| 3792 CodeForStatementPosition(node); | 3792 CodeForStatementPosition(node); |
| 3793 Visit(node->next()); | 3793 Visit(node->next()); |
| 3794 } | 3794 } |
| 3795 } | 3795 } |
| 3796 | 3796 |
| 3797 // Set the type of the loop variable to smi before compiling the test | 3797 // Set the type of the loop variable to smi before compiling the test |
| 3798 // expression if we are in a fast smi loop condition. | 3798 // expression if we are in a fast smi loop condition. |
| 3799 if (node->is_fast_smi_loop() && has_valid_frame()) { | 3799 if (node->is_fast_smi_loop() && has_valid_frame()) { |
| 3800 // Set number type of the loop variable to smi. | 3800 // Set number type of the loop variable to smi. |
| 3801 SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi()); | 3801 SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi()); |
| 3802 } | 3802 } |
| 3803 | 3803 |
| 3804 // Based on the condition analysis, compile the backward jump as | 3804 // Based on the condition analysis, compile the backward jump as |
| 3805 // necessary. | 3805 // necessary. |
| 3806 switch (info) { | 3806 switch (info) { |
| 3807 case ALWAYS_TRUE: | 3807 case ALWAYS_TRUE: |
| 3808 if (has_valid_frame()) { | 3808 if (has_valid_frame()) { |
| 3809 if (node->next() == NULL) { | 3809 if (node->next() == NULL) { |
| 3810 node->continue_target()->Jump(); | 3810 node->continue_target()->Jump(); |
| 3811 } else { | 3811 } else { |
| (...skipping 2882 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6694 } else { | 6694 } else { |
| 6695 Load(node->expression()); | 6695 Load(node->expression()); |
| 6696 bool overwrite = | 6696 bool overwrite = |
| 6697 (node->expression()->AsBinaryOperation() != NULL && | 6697 (node->expression()->AsBinaryOperation() != NULL && |
| 6698 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); | 6698 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 6699 switch (op) { | 6699 switch (op) { |
| 6700 case Token::SUB: { | 6700 case Token::SUB: { |
| 6701 GenericUnaryOpStub stub(Token::SUB, overwrite); | 6701 GenericUnaryOpStub stub(Token::SUB, overwrite); |
| 6702 Result operand = frame_->Pop(); | 6702 Result operand = frame_->Pop(); |
| 6703 Result answer = frame_->CallStub(&stub, &operand); | 6703 Result answer = frame_->CallStub(&stub, &operand); |
| 6704 answer.set_number_info(NumberInfo::Number()); | 6704 answer.set_type_info(TypeInfo::Number()); |
| 6705 frame_->Push(&answer); | 6705 frame_->Push(&answer); |
| 6706 break; | 6706 break; |
| 6707 } | 6707 } |
| 6708 case Token::BIT_NOT: { | 6708 case Token::BIT_NOT: { |
| 6709 // Smi check. | 6709 // Smi check. |
| 6710 JumpTarget smi_label; | 6710 JumpTarget smi_label; |
| 6711 JumpTarget continue_label; | 6711 JumpTarget continue_label; |
| 6712 Result operand = frame_->Pop(); | 6712 Result operand = frame_->Pop(); |
| 6713 NumberInfo operand_info = operand.number_info(); | 6713 TypeInfo operand_info = operand.type_info(); |
| 6714 operand.ToRegister(); | 6714 operand.ToRegister(); |
| 6715 if (operand_info.IsSmi()) { | 6715 if (operand_info.IsSmi()) { |
| 6716 if (FLAG_debug_code) __ AbortIfNotSmi(operand.reg()); | 6716 if (FLAG_debug_code) __ AbortIfNotSmi(operand.reg()); |
| 6717 frame_->Spill(operand.reg()); | 6717 frame_->Spill(operand.reg()); |
| 6718 // Set smi tag bit. It will be reset by the not operation. | 6718 // Set smi tag bit. It will be reset by the not operation. |
| 6719 __ lea(operand.reg(), Operand(operand.reg(), kSmiTagMask)); | 6719 __ lea(operand.reg(), Operand(operand.reg(), kSmiTagMask)); |
| 6720 __ not_(operand.reg()); | 6720 __ not_(operand.reg()); |
| 6721 Result answer = operand; | 6721 Result answer = operand; |
| 6722 answer.set_number_info(NumberInfo::Smi()); | 6722 answer.set_type_info(TypeInfo::Smi()); |
| 6723 frame_->Push(&answer); | 6723 frame_->Push(&answer); |
| 6724 } else { | 6724 } else { |
| 6725 __ test(operand.reg(), Immediate(kSmiTagMask)); | 6725 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6726 smi_label.Branch(zero, &operand, taken); | 6726 smi_label.Branch(zero, &operand, taken); |
| 6727 | 6727 |
| 6728 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); | 6728 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); |
| 6729 Result answer = frame_->CallStub(&stub, &operand); | 6729 Result answer = frame_->CallStub(&stub, &operand); |
| 6730 continue_label.Jump(&answer); | 6730 continue_label.Jump(&answer); |
| 6731 | 6731 |
| 6732 smi_label.Bind(&answer); | 6732 smi_label.Bind(&answer); |
| 6733 answer.ToRegister(); | 6733 answer.ToRegister(); |
| 6734 frame_->Spill(answer.reg()); | 6734 frame_->Spill(answer.reg()); |
| 6735 // Set smi tag bit. It will be reset by the not operation. | 6735 // Set smi tag bit. It will be reset by the not operation. |
| 6736 __ lea(answer.reg(), Operand(answer.reg(), kSmiTagMask)); | 6736 __ lea(answer.reg(), Operand(answer.reg(), kSmiTagMask)); |
| 6737 __ not_(answer.reg()); | 6737 __ not_(answer.reg()); |
| 6738 | 6738 |
| 6739 continue_label.Bind(&answer); | 6739 continue_label.Bind(&answer); |
| 6740 if (operand_info.IsInteger32()) { | 6740 if (operand_info.IsInteger32()) { |
| 6741 answer.set_number_info(NumberInfo::Integer32()); | 6741 answer.set_type_info(TypeInfo::Integer32()); |
| 6742 } else { | 6742 } else { |
| 6743 answer.set_number_info(NumberInfo::Number()); | 6743 answer.set_type_info(TypeInfo::Number()); |
| 6744 } | 6744 } |
| 6745 frame_->Push(&answer); | 6745 frame_->Push(&answer); |
| 6746 } | 6746 } |
| 6747 break; | 6747 break; |
| 6748 } | 6748 } |
| 6749 case Token::ADD: { | 6749 case Token::ADD: { |
| 6750 // Smi check. | 6750 // Smi check. |
| 6751 JumpTarget continue_label; | 6751 JumpTarget continue_label; |
| 6752 Result operand = frame_->Pop(); | 6752 Result operand = frame_->Pop(); |
| 6753 NumberInfo operand_info = operand.number_info(); | 6753 TypeInfo operand_info = operand.type_info(); |
| 6754 operand.ToRegister(); | 6754 operand.ToRegister(); |
| 6755 __ test(operand.reg(), Immediate(kSmiTagMask)); | 6755 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6756 continue_label.Branch(zero, &operand, taken); | 6756 continue_label.Branch(zero, &operand, taken); |
| 6757 | 6757 |
| 6758 frame_->Push(&operand); | 6758 frame_->Push(&operand); |
| 6759 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, | 6759 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
| 6760 CALL_FUNCTION, 1); | 6760 CALL_FUNCTION, 1); |
| 6761 | 6761 |
| 6762 continue_label.Bind(&answer); | 6762 continue_label.Bind(&answer); |
| 6763 if (operand_info.IsSmi()) { | 6763 if (operand_info.IsSmi()) { |
| 6764 answer.set_number_info(NumberInfo::Smi()); | 6764 answer.set_type_info(TypeInfo::Smi()); |
| 6765 } else if (operand_info.IsInteger32()) { | 6765 } else if (operand_info.IsInteger32()) { |
| 6766 answer.set_number_info(NumberInfo::Integer32()); | 6766 answer.set_type_info(TypeInfo::Integer32()); |
| 6767 } else { | 6767 } else { |
| 6768 answer.set_number_info(NumberInfo::Number()); | 6768 answer.set_type_info(TypeInfo::Number()); |
| 6769 } | 6769 } |
| 6770 frame_->Push(&answer); | 6770 frame_->Push(&answer); |
| 6771 break; | 6771 break; |
| 6772 } | 6772 } |
| 6773 default: | 6773 default: |
| 6774 // NOT, DELETE, TYPEOF, and VOID are handled outside the | 6774 // NOT, DELETE, TYPEOF, and VOID are handled outside the |
| 6775 // switch. | 6775 // switch. |
| 6776 UNREACHABLE(); | 6776 UNREACHABLE(); |
| 6777 } | 6777 } |
| 6778 } | 6778 } |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6898 | 6898 |
| 6899 Result old_value; // Only allocated in the postfix case. | 6899 Result old_value; // Only allocated in the postfix case. |
| 6900 if (is_postfix) { | 6900 if (is_postfix) { |
| 6901 // Allocate a temporary to preserve the old value. | 6901 // Allocate a temporary to preserve the old value. |
| 6902 old_value = allocator_->Allocate(); | 6902 old_value = allocator_->Allocate(); |
| 6903 ASSERT(old_value.is_valid()); | 6903 ASSERT(old_value.is_valid()); |
| 6904 __ mov(old_value.reg(), new_value.reg()); | 6904 __ mov(old_value.reg(), new_value.reg()); |
| 6905 | 6905 |
| 6906 // The return value for postfix operations is the | 6906 // The return value for postfix operations is the |
| 6907 // same as the input, and has the same number info. | 6907 // same as the input, and has the same number info. |
| 6908 old_value.set_number_info(new_value.number_info()); | 6908 old_value.set_type_info(new_value.type_info()); |
| 6909 } | 6909 } |
| 6910 | 6910 |
| 6911 // Ensure the new value is writable. | 6911 // Ensure the new value is writable. |
| 6912 frame_->Spill(new_value.reg()); | 6912 frame_->Spill(new_value.reg()); |
| 6913 | 6913 |
| 6914 Result tmp; | 6914 Result tmp; |
| 6915 if (new_value.is_smi()) { | 6915 if (new_value.is_smi()) { |
| 6916 if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg()); | 6916 if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg()); |
| 6917 } else { | 6917 } else { |
| 6918 // We don't know statically if the input is a smi. | 6918 // We don't know statically if the input is a smi. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6965 deferred->Branch(overflow); | 6965 deferred->Branch(overflow); |
| 6966 __ test(new_value.reg(), Immediate(kSmiTagMask)); | 6966 __ test(new_value.reg(), Immediate(kSmiTagMask)); |
| 6967 deferred->Branch(not_zero); | 6967 deferred->Branch(not_zero); |
| 6968 } | 6968 } |
| 6969 } | 6969 } |
| 6970 deferred->BindExit(); | 6970 deferred->BindExit(); |
| 6971 | 6971 |
| 6972 // The result of ++ or -- is an Integer32 if the | 6972 // The result of ++ or -- is an Integer32 if the |
| 6973 // input is a smi. Otherwise it is a number. | 6973 // input is a smi. Otherwise it is a number. |
| 6974 if (new_value.is_smi()) { | 6974 if (new_value.is_smi()) { |
| 6975 new_value.set_number_info(NumberInfo::Integer32()); | 6975 new_value.set_type_info(TypeInfo::Integer32()); |
| 6976 } else { | 6976 } else { |
| 6977 new_value.set_number_info(NumberInfo::Number()); | 6977 new_value.set_type_info(TypeInfo::Number()); |
| 6978 } | 6978 } |
| 6979 | 6979 |
| 6980 // Postfix: store the old value in the allocated slot under the | 6980 // Postfix: store the old value in the allocated slot under the |
| 6981 // reference. | 6981 // reference. |
| 6982 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); | 6982 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); |
| 6983 | 6983 |
| 6984 frame_->Push(&new_value); | 6984 frame_->Push(&new_value); |
| 6985 // Non-constant: update the reference. | 6985 // Non-constant: update the reference. |
| 6986 if (!is_const) target.SetValue(NOT_CONST_INIT); | 6986 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 6987 } | 6987 } |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7181 if (op == Token::MOD) { | 7181 if (op == Token::MOD) { |
| 7182 // Negative zero can arise as a negative divident with a zero result. | 7182 // Negative zero can arise as a negative divident with a zero result. |
| 7183 if (!node->no_negative_zero()) { | 7183 if (!node->no_negative_zero()) { |
| 7184 Label not_negative_zero; | 7184 Label not_negative_zero; |
| 7185 __ test(edx, Operand(edx)); | 7185 __ test(edx, Operand(edx)); |
| 7186 __ j(not_zero, ¬_negative_zero); | 7186 __ j(not_zero, ¬_negative_zero); |
| 7187 __ test(eax, Operand(eax)); | 7187 __ test(eax, Operand(eax)); |
| 7188 unsafe_bailout_->Branch(negative); | 7188 unsafe_bailout_->Branch(negative); |
| 7189 __ bind(¬_negative_zero); | 7189 __ bind(¬_negative_zero); |
| 7190 } | 7190 } |
| 7191 Result edx_result(edx, NumberInfo::Integer32()); | 7191 Result edx_result(edx, TypeInfo::Integer32()); |
| 7192 edx_result.set_untagged_int32(true); | 7192 edx_result.set_untagged_int32(true); |
| 7193 frame_->Push(&edx_result); | 7193 frame_->Push(&edx_result); |
| 7194 } else { | 7194 } else { |
| 7195 ASSERT(op == Token::DIV); | 7195 ASSERT(op == Token::DIV); |
| 7196 __ test(edx, Operand(edx)); | 7196 __ test(edx, Operand(edx)); |
| 7197 unsafe_bailout_->Branch(not_equal); | 7197 unsafe_bailout_->Branch(not_equal); |
| 7198 Result eax_result(eax, NumberInfo::Integer32()); | 7198 Result eax_result(eax, TypeInfo::Integer32()); |
| 7199 eax_result.set_untagged_int32(true); | 7199 eax_result.set_untagged_int32(true); |
| 7200 frame_->Push(&eax_result); | 7200 frame_->Push(&eax_result); |
| 7201 } | 7201 } |
| 7202 break; | 7202 break; |
| 7203 } | 7203 } |
| 7204 default: | 7204 default: |
| 7205 UNREACHABLE(); | 7205 UNREACHABLE(); |
| 7206 break; | 7206 break; |
| 7207 } | 7207 } |
| 7208 } | 7208 } |
| (...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8075 return result; | 8075 return result; |
| 8076 } | 8076 } |
| 8077 | 8077 |
| 8078 | 8078 |
| 8079 #undef __ | 8079 #undef __ |
| 8080 #define __ ACCESS_MASM(masm) | 8080 #define __ ACCESS_MASM(masm) |
| 8081 | 8081 |
| 8082 | 8082 |
| 8083 static void CheckTwoForSminess(MacroAssembler* masm, | 8083 static void CheckTwoForSminess(MacroAssembler* masm, |
| 8084 Register left, Register right, Register scratch, | 8084 Register left, Register right, Register scratch, |
| 8085 NumberInfo left_info, NumberInfo right_info, | 8085 TypeInfo left_info, TypeInfo right_info, |
| 8086 DeferredInlineBinaryOperation* deferred) { | 8086 DeferredInlineBinaryOperation* deferred) { |
| 8087 if (left.is(right)) { | 8087 if (left.is(right)) { |
| 8088 if (!left_info.IsSmi()) { | 8088 if (!left_info.IsSmi()) { |
| 8089 __ test(left, Immediate(kSmiTagMask)); | 8089 __ test(left, Immediate(kSmiTagMask)); |
| 8090 deferred->Branch(not_zero); | 8090 deferred->Branch(not_zero); |
| 8091 } else { | 8091 } else { |
| 8092 if (FLAG_debug_code) __ AbortIfNotSmi(left); | 8092 if (FLAG_debug_code) __ AbortIfNotSmi(left); |
| 8093 } | 8093 } |
| 8094 } else if (!left_info.IsSmi()) { | 8094 } else if (!left_info.IsSmi()) { |
| 8095 if (!right_info.IsSmi()) { | 8095 if (!right_info.IsSmi()) { |
| (...skipping 1480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9576 __ bind(&done); | 9576 __ bind(&done); |
| 9577 } | 9577 } |
| 9578 | 9578 |
| 9579 | 9579 |
| 9580 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 9580 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
| 9581 // is faster than using the built-in instructions on floating point registers. | 9581 // is faster than using the built-in instructions on floating point registers. |
| 9582 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 9582 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
| 9583 // trashed registers. | 9583 // trashed registers. |
| 9584 void IntegerConvert(MacroAssembler* masm, | 9584 void IntegerConvert(MacroAssembler* masm, |
| 9585 Register source, | 9585 Register source, |
| 9586 NumberInfo number_info, | 9586 TypeInfo type_info, |
| 9587 bool use_sse3, | 9587 bool use_sse3, |
| 9588 Label* conversion_failure) { | 9588 Label* conversion_failure) { |
| 9589 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 9589 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); |
| 9590 Label done, right_exponent, normal_exponent; | 9590 Label done, right_exponent, normal_exponent; |
| 9591 Register scratch = ebx; | 9591 Register scratch = ebx; |
| 9592 Register scratch2 = edi; | 9592 Register scratch2 = edi; |
| 9593 if (!number_info.IsInteger32() || !use_sse3) { | 9593 if (!type_info.IsInteger32() || !use_sse3) { |
| 9594 // Get exponent word. | 9594 // Get exponent word. |
| 9595 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 9595 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |
| 9596 // Get exponent alone in scratch2. | 9596 // Get exponent alone in scratch2. |
| 9597 __ mov(scratch2, scratch); | 9597 __ mov(scratch2, scratch); |
| 9598 __ and_(scratch2, HeapNumber::kExponentMask); | 9598 __ and_(scratch2, HeapNumber::kExponentMask); |
| 9599 } | 9599 } |
| 9600 if (use_sse3) { | 9600 if (use_sse3) { |
| 9601 CpuFeatures::Scope scope(SSE3); | 9601 CpuFeatures::Scope scope(SSE3); |
| 9602 if (!number_info.IsInteger32()) { | 9602 if (!type_info.IsInteger32()) { |
| 9603 // Check whether the exponent is too big for a 64 bit signed integer. | 9603 // Check whether the exponent is too big for a 64 bit signed integer. |
| 9604 static const uint32_t kTooBigExponent = | 9604 static const uint32_t kTooBigExponent = |
| 9605 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 9605 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; |
| 9606 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); | 9606 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); |
| 9607 __ j(greater_equal, conversion_failure); | 9607 __ j(greater_equal, conversion_failure); |
| 9608 } | 9608 } |
| 9609 // Load x87 register with heap number. | 9609 // Load x87 register with heap number. |
| 9610 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 9610 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); |
| 9611 // Reserve space for 64 bit answer. | 9611 // Reserve space for 64 bit answer. |
| 9612 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. | 9612 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9713 __ bind(&negative); | 9713 __ bind(&negative); |
| 9714 __ sub(ecx, Operand(scratch2)); | 9714 __ sub(ecx, Operand(scratch2)); |
| 9715 __ bind(&done); | 9715 __ bind(&done); |
| 9716 } | 9716 } |
| 9717 } | 9717 } |
| 9718 | 9718 |
| 9719 | 9719 |
| 9720 // Input: edx, eax are the left and right objects of a bit op. | 9720 // Input: edx, eax are the left and right objects of a bit op. |
| 9721 // Output: eax, ecx are left and right integers for a bit op. | 9721 // Output: eax, ecx are left and right integers for a bit op. |
| 9722 void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm, | 9722 void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm, |
| 9723 NumberInfo number_info, | 9723 TypeInfo type_info, |
| 9724 bool use_sse3, | 9724 bool use_sse3, |
| 9725 Label* conversion_failure) { | 9725 Label* conversion_failure) { |
| 9726 // Check float operands. | 9726 // Check float operands. |
| 9727 Label arg1_is_object, check_undefined_arg1; | 9727 Label arg1_is_object, check_undefined_arg1; |
| 9728 Label arg2_is_object, check_undefined_arg2; | 9728 Label arg2_is_object, check_undefined_arg2; |
| 9729 Label load_arg2, done; | 9729 Label load_arg2, done; |
| 9730 | 9730 |
| 9731 if (!number_info.IsDouble()) { | 9731 if (!type_info.IsDouble()) { |
| 9732 if (!number_info.IsSmi()) { | 9732 if (!type_info.IsSmi()) { |
| 9733 __ test(edx, Immediate(kSmiTagMask)); | 9733 __ test(edx, Immediate(kSmiTagMask)); |
| 9734 __ j(not_zero, &arg1_is_object); | 9734 __ j(not_zero, &arg1_is_object); |
| 9735 } else { | 9735 } else { |
| 9736 if (FLAG_debug_code) __ AbortIfNotSmi(edx); | 9736 if (FLAG_debug_code) __ AbortIfNotSmi(edx); |
| 9737 } | 9737 } |
| 9738 __ SmiUntag(edx); | 9738 __ SmiUntag(edx); |
| 9739 __ jmp(&load_arg2); | 9739 __ jmp(&load_arg2); |
| 9740 } | 9740 } |
| 9741 | 9741 |
| 9742 __ bind(&arg1_is_object); | 9742 __ bind(&arg1_is_object); |
| 9743 | 9743 |
| 9744 // Get the untagged integer version of the edx heap number in ecx. | 9744 // Get the untagged integer version of the edx heap number in ecx. |
| 9745 IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); | 9745 IntegerConvert(masm, edx, type_info, use_sse3, conversion_failure); |
| 9746 __ mov(edx, ecx); | 9746 __ mov(edx, ecx); |
| 9747 | 9747 |
| 9748 // Here edx has the untagged integer, eax has a Smi or a heap number. | 9748 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 9749 __ bind(&load_arg2); | 9749 __ bind(&load_arg2); |
| 9750 if (!number_info.IsDouble()) { | 9750 if (!type_info.IsDouble()) { |
| 9751 // Test if arg2 is a Smi. | 9751 // Test if arg2 is a Smi. |
| 9752 if (!number_info.IsSmi()) { | 9752 if (!type_info.IsSmi()) { |
| 9753 __ test(eax, Immediate(kSmiTagMask)); | 9753 __ test(eax, Immediate(kSmiTagMask)); |
| 9754 __ j(not_zero, &arg2_is_object); | 9754 __ j(not_zero, &arg2_is_object); |
| 9755 } else { | 9755 } else { |
| 9756 if (FLAG_debug_code) __ AbortIfNotSmi(eax); | 9756 if (FLAG_debug_code) __ AbortIfNotSmi(eax); |
| 9757 } | 9757 } |
| 9758 __ SmiUntag(eax); | 9758 __ SmiUntag(eax); |
| 9759 __ mov(ecx, eax); | 9759 __ mov(ecx, eax); |
| 9760 __ jmp(&done); | 9760 __ jmp(&done); |
| 9761 } | 9761 } |
| 9762 | 9762 |
| 9763 __ bind(&arg2_is_object); | 9763 __ bind(&arg2_is_object); |
| 9764 | 9764 |
| 9765 // Get the untagged integer version of the eax heap number in ecx. | 9765 // Get the untagged integer version of the eax heap number in ecx. |
| 9766 IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); | 9766 IntegerConvert(masm, eax, type_info, use_sse3, conversion_failure); |
| 9767 __ bind(&done); | 9767 __ bind(&done); |
| 9768 __ mov(eax, edx); | 9768 __ mov(eax, edx); |
| 9769 } | 9769 } |
| 9770 | 9770 |
| 9771 | 9771 |
| 9772 // Input: edx, eax are the left and right objects of a bit op. | 9772 // Input: edx, eax are the left and right objects of a bit op. |
| 9773 // Output: eax, ecx are left and right integers for a bit op. | 9773 // Output: eax, ecx are left and right integers for a bit op. |
| 9774 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, | 9774 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, |
| 9775 bool use_sse3, | 9775 bool use_sse3, |
| 9776 Label* conversion_failure) { | 9776 Label* conversion_failure) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 9794 __ jmp(&load_arg2); | 9794 __ jmp(&load_arg2); |
| 9795 | 9795 |
| 9796 __ bind(&arg1_is_object); | 9796 __ bind(&arg1_is_object); |
| 9797 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 9797 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 9798 __ cmp(ebx, Factory::heap_number_map()); | 9798 __ cmp(ebx, Factory::heap_number_map()); |
| 9799 __ j(not_equal, &check_undefined_arg1); | 9799 __ j(not_equal, &check_undefined_arg1); |
| 9800 | 9800 |
| 9801 // Get the untagged integer version of the edx heap number in ecx. | 9801 // Get the untagged integer version of the edx heap number in ecx. |
| 9802 IntegerConvert(masm, | 9802 IntegerConvert(masm, |
| 9803 edx, | 9803 edx, |
| 9804 NumberInfo::Unknown(), | 9804 TypeInfo::Unknown(), |
| 9805 use_sse3, | 9805 use_sse3, |
| 9806 conversion_failure); | 9806 conversion_failure); |
| 9807 __ mov(edx, ecx); | 9807 __ mov(edx, ecx); |
| 9808 | 9808 |
| 9809 // Here edx has the untagged integer, eax has a Smi or a heap number. | 9809 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 9810 __ bind(&load_arg2); | 9810 __ bind(&load_arg2); |
| 9811 | 9811 |
| 9812 // Test if arg2 is a Smi. | 9812 // Test if arg2 is a Smi. |
| 9813 __ test(eax, Immediate(kSmiTagMask)); | 9813 __ test(eax, Immediate(kSmiTagMask)); |
| 9814 __ j(not_zero, &arg2_is_object); | 9814 __ j(not_zero, &arg2_is_object); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 9825 __ jmp(&done); | 9825 __ jmp(&done); |
| 9826 | 9826 |
| 9827 __ bind(&arg2_is_object); | 9827 __ bind(&arg2_is_object); |
| 9828 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 9828 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 9829 __ cmp(ebx, Factory::heap_number_map()); | 9829 __ cmp(ebx, Factory::heap_number_map()); |
| 9830 __ j(not_equal, &check_undefined_arg2); | 9830 __ j(not_equal, &check_undefined_arg2); |
| 9831 | 9831 |
| 9832 // Get the untagged integer version of the eax heap number in ecx. | 9832 // Get the untagged integer version of the eax heap number in ecx. |
| 9833 IntegerConvert(masm, | 9833 IntegerConvert(masm, |
| 9834 eax, | 9834 eax, |
| 9835 NumberInfo::Unknown(), | 9835 TypeInfo::Unknown(), |
| 9836 use_sse3, | 9836 use_sse3, |
| 9837 conversion_failure); | 9837 conversion_failure); |
| 9838 __ bind(&done); | 9838 __ bind(&done); |
| 9839 __ mov(eax, edx); | 9839 __ mov(eax, edx); |
| 9840 } | 9840 } |
| 9841 | 9841 |
| 9842 | 9842 |
| 9843 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 9843 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
| 9844 NumberInfo number_info, | 9844 TypeInfo type_info, |
| 9845 bool use_sse3, | 9845 bool use_sse3, |
| 9846 Label* conversion_failure) { | 9846 Label* conversion_failure) { |
| 9847 if (number_info.IsNumber()) { | 9847 if (type_info.IsNumber()) { |
| 9848 LoadNumbersAsIntegers(masm, number_info, use_sse3, conversion_failure); | 9848 LoadNumbersAsIntegers(masm, type_info, use_sse3, conversion_failure); |
| 9849 } else { | 9849 } else { |
| 9850 LoadUnknownsAsIntegers(masm, use_sse3, conversion_failure); | 9850 LoadUnknownsAsIntegers(masm, use_sse3, conversion_failure); |
| 9851 } | 9851 } |
| 9852 } | 9852 } |
| 9853 | 9853 |
| 9854 | 9854 |
| 9855 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9855 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| 9856 Register number) { | 9856 Register number) { |
| 9857 Label load_smi, done; | 9857 Label load_smi, done; |
| 9858 | 9858 |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10083 } | 10083 } |
| 10084 } else if (op_ == Token::BIT_NOT) { | 10084 } else if (op_ == Token::BIT_NOT) { |
| 10085 // Check if the operand is a heap number. | 10085 // Check if the operand is a heap number. |
| 10086 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 10086 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 10087 __ cmp(edx, Factory::heap_number_map()); | 10087 __ cmp(edx, Factory::heap_number_map()); |
| 10088 __ j(not_equal, &slow, not_taken); | 10088 __ j(not_equal, &slow, not_taken); |
| 10089 | 10089 |
| 10090 // Convert the heap number in eax to an untagged integer in ecx. | 10090 // Convert the heap number in eax to an untagged integer in ecx. |
| 10091 IntegerConvert(masm, | 10091 IntegerConvert(masm, |
| 10092 eax, | 10092 eax, |
| 10093 NumberInfo::Unknown(), | 10093 TypeInfo::Unknown(), |
| 10094 CpuFeatures::IsSupported(SSE3), | 10094 CpuFeatures::IsSupported(SSE3), |
| 10095 &slow); | 10095 &slow); |
| 10096 | 10096 |
| 10097 // Do the bitwise operation and check if the result fits in a smi. | 10097 // Do the bitwise operation and check if the result fits in a smi. |
| 10098 Label try_float; | 10098 Label try_float; |
| 10099 __ not_(ecx); | 10099 __ not_(ecx); |
| 10100 __ cmp(ecx, 0xc0000000); | 10100 __ cmp(ecx, 0xc0000000); |
| 10101 __ j(sign, &try_float, not_taken); | 10101 __ j(sign, &try_float, not_taken); |
| 10102 | 10102 |
| 10103 // Tag the result as a smi and we're done. | 10103 // Tag the result as a smi and we're done. |
| (...skipping 2225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12329 | 12329 |
| 12330 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12330 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 12331 // tagged as a small integer. | 12331 // tagged as a small integer. |
| 12332 __ bind(&runtime); | 12332 __ bind(&runtime); |
| 12333 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12333 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 12334 } | 12334 } |
| 12335 | 12335 |
| 12336 #undef __ | 12336 #undef __ |
| 12337 | 12337 |
| 12338 } } // namespace v8::internal | 12338 } } // namespace v8::internal |
| OLD | NEW |