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 1114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1125 mode_, | 1125 mode_, |
1126 NO_SMI_CODE_IN_STUB, | 1126 NO_SMI_CODE_IN_STUB, |
1127 TypeInfo::Combine(left_info_, right_info_)); | 1127 TypeInfo::Combine(left_info_, right_info_)); |
1128 stub.GenerateCall(masm_, left_, right_); | 1128 stub.GenerateCall(masm_, left_, right_); |
1129 if (!dst_.is(eax)) __ mov(dst_, eax); | 1129 if (!dst_.is(eax)) __ mov(dst_, eax); |
1130 __ bind(&done); | 1130 __ bind(&done); |
1131 } | 1131 } |
1132 | 1132 |
1133 | 1133 |
1134 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, | 1134 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, |
1135 Token::Value op, | 1135 Token::Value op, |
1136 const Result& right, | 1136 const Result& right, |
1137 const Result& left) { | 1137 const Result& left) { |
1138 // Set TypeInfo of result according to the operation performed. | 1138 // Set TypeInfo of result according to the operation performed. |
1139 // Rely on the fact that smis have a 31 bit payload on ia32. | 1139 // Rely on the fact that smis have a 31 bit payload on ia32. |
1140 ASSERT(kSmiValueSize == 31); | 1140 ASSERT(kSmiValueSize == 31); |
1141 switch (op) { | 1141 switch (op) { |
1142 case Token::COMMA: | 1142 case Token::COMMA: |
1143 return right.type_info(); | 1143 return right.type_info(); |
1144 case Token::OR: | 1144 case Token::OR: |
1145 case Token::AND: | 1145 case Token::AND: |
1146 // Result type can be either of the two input types. | 1146 // Result type can be either of the two input types. |
1147 return operands_type; | 1147 return operands_type; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1186 case Token::SHR: | 1186 case Token::SHR: |
1187 // Result is a smi if we shift by a constant >= 2, otherwise an integer32. | 1187 // Result is a smi if we shift by a constant >= 2, otherwise an integer32. |
1188 return (right.is_constant() && right.handle()->IsSmi() | 1188 return (right.is_constant() && right.handle()->IsSmi() |
1189 && Smi::cast(*right.handle())->value() >= 2) | 1189 && Smi::cast(*right.handle())->value() >= 2) |
1190 ? TypeInfo::Smi() | 1190 ? TypeInfo::Smi() |
1191 : TypeInfo::Integer32(); | 1191 : TypeInfo::Integer32(); |
1192 case Token::ADD: | 1192 case Token::ADD: |
1193 if (operands_type.IsSmi()) { | 1193 if (operands_type.IsSmi()) { |
1194 // The Integer32 range is big enough to take the sum of any two Smis. | 1194 // The Integer32 range is big enough to take the sum of any two Smis. |
1195 return TypeInfo::Integer32(); | 1195 return TypeInfo::Integer32(); |
| 1196 } else if (operands_type.IsNumber()) { |
| 1197 return TypeInfo::Number(); |
| 1198 } else if (left.type_info().IsString() || right.type_info().IsString()) { |
| 1199 return TypeInfo::String(); |
1196 } else { | 1200 } else { |
1197 // Result could be a string or a number. Check types of inputs. | 1201 return TypeInfo::Unknown(); |
1198 return operands_type.IsNumber() | |
1199 ? TypeInfo::Number() | |
1200 : TypeInfo::Unknown(); | |
1201 } | 1202 } |
1202 case Token::SHL: | 1203 case Token::SHL: |
1203 return TypeInfo::Integer32(); | 1204 return TypeInfo::Integer32(); |
1204 case Token::SUB: | 1205 case Token::SUB: |
1205 // The Integer32 range is big enough to take the difference of any two | 1206 // The Integer32 range is big enough to take the difference of any two |
1206 // Smis. | 1207 // Smis. |
1207 return (operands_type.IsSmi()) ? | 1208 return (operands_type.IsSmi()) ? |
1208 TypeInfo::Integer32() : | 1209 TypeInfo::Integer32() : |
1209 TypeInfo::Number(); | 1210 TypeInfo::Number(); |
1210 case Token::MUL: | 1211 case Token::MUL: |
(...skipping 19 matching lines...) Expand all Loading... |
1230 if (op == Token::COMMA) { | 1231 if (op == Token::COMMA) { |
1231 // Simply discard left value. | 1232 // Simply discard left value. |
1232 frame_->Nip(1); | 1233 frame_->Nip(1); |
1233 return; | 1234 return; |
1234 } | 1235 } |
1235 | 1236 |
1236 Result right = frame_->Pop(); | 1237 Result right = frame_->Pop(); |
1237 Result left = frame_->Pop(); | 1238 Result left = frame_->Pop(); |
1238 | 1239 |
1239 if (op == Token::ADD) { | 1240 if (op == Token::ADD) { |
1240 bool left_is_string = left.is_constant() && left.handle()->IsString(); | 1241 const bool left_is_string = left.type_info().IsString(); |
1241 bool right_is_string = right.is_constant() && right.handle()->IsString(); | 1242 const bool right_is_string = right.type_info().IsString(); |
| 1243 // Make sure constant strings have string type info. |
| 1244 ASSERT(!(left.is_constant() && left.handle()->IsString()) || |
| 1245 left_is_string); |
| 1246 ASSERT(!(right.is_constant() && right.handle()->IsString()) || |
| 1247 right_is_string); |
1242 if (left_is_string || right_is_string) { | 1248 if (left_is_string || right_is_string) { |
1243 frame_->Push(&left); | 1249 frame_->Push(&left); |
1244 frame_->Push(&right); | 1250 frame_->Push(&right); |
1245 Result answer; | 1251 Result answer; |
1246 if (left_is_string) { | 1252 if (left_is_string) { |
1247 if (right_is_string) { | 1253 if (right_is_string) { |
1248 // TODO(lrn): if both are constant strings | 1254 // TODO(lrn): if both are constant strings |
1249 // -- do a compile time cons, if allocation during codegen is allowed. | 1255 // -- do a compile time cons, if allocation during codegen is allowed. |
1250 answer = frame_->CallRuntime(Runtime::kStringAdd, 2); | 1256 StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
| 1257 answer = frame_->CallStub(&stub, 2); |
1251 } else { | 1258 } else { |
1252 answer = | 1259 answer = |
1253 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); | 1260 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); |
1254 } | 1261 } |
1255 } else if (right_is_string) { | 1262 } else if (right_is_string) { |
1256 answer = | 1263 answer = |
1257 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); | 1264 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); |
1258 } | 1265 } |
| 1266 answer.set_type_info(TypeInfo::String()); |
1259 frame_->Push(&answer); | 1267 frame_->Push(&answer); |
1260 return; | 1268 return; |
1261 } | 1269 } |
1262 // Neither operand is known to be a string. | 1270 // Neither operand is known to be a string. |
1263 } | 1271 } |
1264 | 1272 |
1265 bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi(); | 1273 bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi(); |
1266 bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi(); | 1274 bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi(); |
1267 bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi(); | 1275 bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi(); |
1268 bool right_is_non_smi_constant = | 1276 bool right_is_non_smi_constant = |
(...skipping 5727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6996 } | 7004 } |
6997 } | 7005 } |
6998 | 7006 |
6999 | 7007 |
7000 // The value in dst was optimistically incremented or decremented. The | 7008 // The value in dst was optimistically incremented or decremented. The |
7001 // result overflowed or was not smi tagged. Undo the operation, call | 7009 // result overflowed or was not smi tagged. Undo the operation, call |
7002 // into the runtime to convert the argument to a number, and call the | 7010 // into the runtime to convert the argument to a number, and call the |
7003 // specialized add or subtract stub. The result is left in dst. | 7011 // specialized add or subtract stub. The result is left in dst. |
7004 class DeferredPrefixCountOperation: public DeferredCode { | 7012 class DeferredPrefixCountOperation: public DeferredCode { |
7005 public: | 7013 public: |
7006 DeferredPrefixCountOperation(Register dst, bool is_increment) | 7014 DeferredPrefixCountOperation(Register dst, |
7007 : dst_(dst), is_increment_(is_increment) { | 7015 bool is_increment, |
| 7016 TypeInfo input_type) |
| 7017 : dst_(dst), is_increment_(is_increment), input_type_(input_type) { |
7008 set_comment("[ DeferredCountOperation"); | 7018 set_comment("[ DeferredCountOperation"); |
7009 } | 7019 } |
7010 | 7020 |
7011 virtual void Generate(); | 7021 virtual void Generate(); |
7012 | 7022 |
7013 private: | 7023 private: |
7014 Register dst_; | 7024 Register dst_; |
7015 bool is_increment_; | 7025 bool is_increment_; |
| 7026 TypeInfo input_type_; |
7016 }; | 7027 }; |
7017 | 7028 |
7018 | 7029 |
7019 void DeferredPrefixCountOperation::Generate() { | 7030 void DeferredPrefixCountOperation::Generate() { |
7020 // Undo the optimistic smi operation. | 7031 // Undo the optimistic smi operation. |
7021 if (is_increment_) { | 7032 if (is_increment_) { |
7022 __ sub(Operand(dst_), Immediate(Smi::FromInt(1))); | 7033 __ sub(Operand(dst_), Immediate(Smi::FromInt(1))); |
7023 } else { | 7034 } else { |
7024 __ add(Operand(dst_), Immediate(Smi::FromInt(1))); | 7035 __ add(Operand(dst_), Immediate(Smi::FromInt(1))); |
7025 } | 7036 } |
7026 __ push(dst_); | 7037 __ push(dst_); |
7027 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 7038 if (!input_type_.IsNumber()) { |
7028 __ push(eax); | 7039 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 7040 __ push(eax); |
| 7041 } |
7029 __ push(Immediate(Smi::FromInt(1))); | 7042 __ push(Immediate(Smi::FromInt(1))); |
7030 if (is_increment_) { | 7043 if (is_increment_) { |
7031 __ CallRuntime(Runtime::kNumberAdd, 2); | 7044 __ CallRuntime(Runtime::kNumberAdd, 2); |
7032 } else { | 7045 } else { |
7033 __ CallRuntime(Runtime::kNumberSub, 2); | 7046 __ CallRuntime(Runtime::kNumberSub, 2); |
7034 } | 7047 } |
7035 if (!dst_.is(eax)) __ mov(dst_, eax); | 7048 if (!dst_.is(eax)) __ mov(dst_, eax); |
7036 } | 7049 } |
7037 | 7050 |
7038 | 7051 |
7039 // The value in dst was optimistically incremented or decremented. The | 7052 // The value in dst was optimistically incremented or decremented. The |
7040 // result overflowed or was not smi tagged. Undo the operation and call | 7053 // result overflowed or was not smi tagged. Undo the operation and call |
7041 // into the runtime to convert the argument to a number. Update the | 7054 // into the runtime to convert the argument to a number. Update the |
7042 // original value in old. Call the specialized add or subtract stub. | 7055 // original value in old. Call the specialized add or subtract stub. |
7043 // The result is left in dst. | 7056 // The result is left in dst. |
7044 class DeferredPostfixCountOperation: public DeferredCode { | 7057 class DeferredPostfixCountOperation: public DeferredCode { |
7045 public: | 7058 public: |
7046 DeferredPostfixCountOperation(Register dst, Register old, bool is_increment) | 7059 DeferredPostfixCountOperation(Register dst, |
7047 : dst_(dst), old_(old), is_increment_(is_increment) { | 7060 Register old, |
| 7061 bool is_increment, |
| 7062 TypeInfo input_type) |
| 7063 : dst_(dst), |
| 7064 old_(old), |
| 7065 is_increment_(is_increment), |
| 7066 input_type_(input_type) { |
7048 set_comment("[ DeferredCountOperation"); | 7067 set_comment("[ DeferredCountOperation"); |
7049 } | 7068 } |
7050 | 7069 |
7051 virtual void Generate(); | 7070 virtual void Generate(); |
7052 | 7071 |
7053 private: | 7072 private: |
7054 Register dst_; | 7073 Register dst_; |
7055 Register old_; | 7074 Register old_; |
7056 bool is_increment_; | 7075 bool is_increment_; |
| 7076 TypeInfo input_type_; |
7057 }; | 7077 }; |
7058 | 7078 |
7059 | 7079 |
7060 void DeferredPostfixCountOperation::Generate() { | 7080 void DeferredPostfixCountOperation::Generate() { |
7061 // Undo the optimistic smi operation. | 7081 // Undo the optimistic smi operation. |
7062 if (is_increment_) { | 7082 if (is_increment_) { |
7063 __ sub(Operand(dst_), Immediate(Smi::FromInt(1))); | 7083 __ sub(Operand(dst_), Immediate(Smi::FromInt(1))); |
7064 } else { | 7084 } else { |
7065 __ add(Operand(dst_), Immediate(Smi::FromInt(1))); | 7085 __ add(Operand(dst_), Immediate(Smi::FromInt(1))); |
7066 } | 7086 } |
7067 __ push(dst_); | 7087 if (input_type_.IsNumber()) { |
7068 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 7088 __ push(dst_); // Save the input to use as the old value. |
7069 | 7089 __ push(dst_); |
7070 // Save the result of ToNumber to use as the old value. | 7090 } else { |
7071 __ push(eax); | 7091 __ push(dst_); |
| 7092 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
| 7093 __ push(eax); // Save the result of ToNumber to use as the old value. |
| 7094 __ push(eax); |
| 7095 } |
7072 | 7096 |
7073 // Call the runtime for the addition or subtraction. | 7097 // Call the runtime for the addition or subtraction. |
7074 __ push(eax); | |
7075 __ push(Immediate(Smi::FromInt(1))); | 7098 __ push(Immediate(Smi::FromInt(1))); |
7076 if (is_increment_) { | 7099 if (is_increment_) { |
7077 __ CallRuntime(Runtime::kNumberAdd, 2); | 7100 __ CallRuntime(Runtime::kNumberAdd, 2); |
7078 } else { | 7101 } else { |
7079 __ CallRuntime(Runtime::kNumberSub, 2); | 7102 __ CallRuntime(Runtime::kNumberSub, 2); |
7080 } | 7103 } |
7081 if (!dst_.is(eax)) __ mov(dst_, eax); | 7104 if (!dst_.is(eax)) __ mov(dst_, eax); |
7082 __ pop(old_); | 7105 __ pop(old_); |
7083 } | 7106 } |
7084 | 7107 |
(...skipping 28 matching lines...) Expand all Loading... |
7113 Result new_value = frame_->Pop(); | 7136 Result new_value = frame_->Pop(); |
7114 new_value.ToRegister(); | 7137 new_value.ToRegister(); |
7115 | 7138 |
7116 Result old_value; // Only allocated in the postfix case. | 7139 Result old_value; // Only allocated in the postfix case. |
7117 if (is_postfix) { | 7140 if (is_postfix) { |
7118 // Allocate a temporary to preserve the old value. | 7141 // Allocate a temporary to preserve the old value. |
7119 old_value = allocator_->Allocate(); | 7142 old_value = allocator_->Allocate(); |
7120 ASSERT(old_value.is_valid()); | 7143 ASSERT(old_value.is_valid()); |
7121 __ mov(old_value.reg(), new_value.reg()); | 7144 __ mov(old_value.reg(), new_value.reg()); |
7122 | 7145 |
7123 // The return value for postfix operations is the | 7146 // The return value for postfix operations is ToNumber(input). |
7124 // same as the input, and has the same number info. | 7147 // Keep more precise type info if the input is some kind of |
7125 old_value.set_type_info(new_value.type_info()); | 7148 // number already. If the input is not a number we have to wait |
| 7149 // for the deferred code to convert it. |
| 7150 if (new_value.type_info().IsNumber()) { |
| 7151 old_value.set_type_info(new_value.type_info()); |
| 7152 } |
7126 } | 7153 } |
7127 | 7154 |
7128 // Ensure the new value is writable. | 7155 // Ensure the new value is writable. |
7129 frame_->Spill(new_value.reg()); | 7156 frame_->Spill(new_value.reg()); |
7130 | 7157 |
7131 Result tmp; | 7158 Result tmp; |
7132 if (new_value.is_smi()) { | 7159 if (new_value.is_smi()) { |
7133 if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg()); | 7160 if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg()); |
7134 } else { | 7161 } else { |
7135 // We don't know statically if the input is a smi. | 7162 // We don't know statically if the input is a smi. |
(...skipping 13 matching lines...) Expand all Loading... |
7149 if (is_increment) { | 7176 if (is_increment) { |
7150 __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); | 7177 __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); |
7151 } else { | 7178 } else { |
7152 __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); | 7179 __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); |
7153 } | 7180 } |
7154 | 7181 |
7155 DeferredCode* deferred = NULL; | 7182 DeferredCode* deferred = NULL; |
7156 if (is_postfix) { | 7183 if (is_postfix) { |
7157 deferred = new DeferredPostfixCountOperation(new_value.reg(), | 7184 deferred = new DeferredPostfixCountOperation(new_value.reg(), |
7158 old_value.reg(), | 7185 old_value.reg(), |
7159 is_increment); | 7186 is_increment, |
| 7187 new_value.type_info()); |
7160 } else { | 7188 } else { |
7161 deferred = new DeferredPrefixCountOperation(new_value.reg(), | 7189 deferred = new DeferredPrefixCountOperation(new_value.reg(), |
7162 is_increment); | 7190 is_increment, |
| 7191 new_value.type_info()); |
7163 } | 7192 } |
7164 | 7193 |
7165 if (new_value.is_smi()) { | 7194 if (new_value.is_smi()) { |
7166 // In case we have a smi as input just check for overflow. | 7195 // In case we have a smi as input just check for overflow. |
7167 deferred->Branch(overflow); | 7196 deferred->Branch(overflow); |
7168 } else { | 7197 } else { |
7169 // If the count operation didn't overflow and the result is a valid | 7198 // If the count operation didn't overflow and the result is a valid |
7170 // smi, we're done. Otherwise, we jump to the deferred slow-case | 7199 // smi, we're done. Otherwise, we jump to the deferred slow-case |
7171 // code. | 7200 // code. |
7172 // We combine the overflow and the smi tag check if we could | 7201 // We combine the overflow and the smi tag check if we could |
7173 // successfully allocate a temporary byte register. | 7202 // successfully allocate a temporary byte register. |
7174 if (tmp.is_valid()) { | 7203 if (tmp.is_valid()) { |
7175 __ setcc(overflow, tmp.reg()); | 7204 __ setcc(overflow, tmp.reg()); |
7176 __ or_(Operand(tmp.reg()), new_value.reg()); | 7205 __ or_(Operand(tmp.reg()), new_value.reg()); |
7177 __ test(tmp.reg(), Immediate(kSmiTagMask)); | 7206 __ test(tmp.reg(), Immediate(kSmiTagMask)); |
7178 tmp.Unuse(); | 7207 tmp.Unuse(); |
7179 deferred->Branch(not_zero); | 7208 deferred->Branch(not_zero); |
7180 } else { | 7209 } else { |
7181 // Otherwise we test separately for overflow and smi tag. | 7210 // Otherwise we test separately for overflow and smi tag. |
7182 deferred->Branch(overflow); | 7211 deferred->Branch(overflow); |
7183 __ test(new_value.reg(), Immediate(kSmiTagMask)); | 7212 __ test(new_value.reg(), Immediate(kSmiTagMask)); |
7184 deferred->Branch(not_zero); | 7213 deferred->Branch(not_zero); |
7185 } | 7214 } |
7186 } | 7215 } |
7187 deferred->BindExit(); | 7216 deferred->BindExit(); |
7188 | 7217 |
| 7218 // Postfix count operations return their input converted to |
| 7219 // number. The case when the input is already a number is covered |
| 7220 // above in the allocation code for old_value. |
| 7221 if (is_postfix && !new_value.type_info().IsNumber()) { |
| 7222 old_value.set_type_info(TypeInfo::Number()); |
| 7223 } |
| 7224 |
7189 // The result of ++ or -- is an Integer32 if the | 7225 // The result of ++ or -- is an Integer32 if the |
7190 // input is a smi. Otherwise it is a number. | 7226 // input is a smi. Otherwise it is a number. |
7191 if (new_value.is_smi()) { | 7227 if (new_value.is_smi()) { |
7192 new_value.set_type_info(TypeInfo::Integer32()); | 7228 new_value.set_type_info(TypeInfo::Integer32()); |
7193 } else { | 7229 } else { |
7194 new_value.set_type_info(TypeInfo::Number()); | 7230 new_value.set_type_info(TypeInfo::Number()); |
7195 } | 7231 } |
7196 | 7232 |
7197 // Postfix: store the old value in the allocated slot under the | 7233 // Postfix: store the old value in the allocated slot under the |
7198 // reference. | 7234 // reference. |
(...skipping 5365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12564 | 12600 |
12565 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12601 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
12566 // tagged as a small integer. | 12602 // tagged as a small integer. |
12567 __ bind(&runtime); | 12603 __ bind(&runtime); |
12568 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12604 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
12569 } | 12605 } |
12570 | 12606 |
12571 #undef __ | 12607 #undef __ |
12572 | 12608 |
12573 } } // namespace v8::internal | 12609 } } // namespace v8::internal |
OLD | NEW |