Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 1520001: Start using String type info: (Closed)
Patch Set: Review Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/type-info.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/type-info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698