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

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

Issue 1520001: Start using String type info: (Closed)
Patch Set: Review Created 10 years, 8 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 | « src/type-info.cc ('k') | no next file » | 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 3111 matching lines...) Expand 10 before | Expand all | Expand 10 after
3122 break; 3122 break;
3123 } 3123 }
3124 3124
3125 default: 3125 default:
3126 UNREACHABLE(); 3126 UNREACHABLE();
3127 } 3127 }
3128 } 3128 }
3129 } 3129 }
3130 3130
3131 3131
3132 // The value in dst was optimistically incremented or decremented. The 3132 // The value in dst was optimistically incremented or decremented.
3133 // result overflowed or was not smi tagged. Undo the operation, call 3133 // The result overflowed or was not smi tagged. Call into the runtime
3134 // into the runtime to convert the argument to a number, and call the 3134 // to convert the argument to a number, and call the specialized add
3135 // specialized add or subtract stub. The result is left in dst. 3135 // or subtract stub. The result is left in dst.
3136 class DeferredPrefixCountOperation: public DeferredCode { 3136 class DeferredPrefixCountOperation: public DeferredCode {
3137 public: 3137 public:
3138 DeferredPrefixCountOperation(Register dst, bool is_increment) 3138 DeferredPrefixCountOperation(Register dst,
3139 : dst_(dst), is_increment_(is_increment) { 3139 bool is_increment,
3140 TypeInfo input_type)
3141 : dst_(dst), is_increment_(is_increment), input_type_(input_type) {
3140 set_comment("[ DeferredCountOperation"); 3142 set_comment("[ DeferredCountOperation");
3141 } 3143 }
3142 3144
3143 virtual void Generate(); 3145 virtual void Generate();
3144 3146
3145 private: 3147 private:
3146 Register dst_; 3148 Register dst_;
3147 bool is_increment_; 3149 bool is_increment_;
3150 TypeInfo input_type_;
3148 }; 3151 };
3149 3152
3150 3153
3151 void DeferredPrefixCountOperation::Generate() { 3154 void DeferredPrefixCountOperation::Generate() {
3152 __ push(dst_); 3155 __ push(dst_);
3153 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 3156 if (!input_type_.IsNumber()) {
3154 __ push(rax); 3157 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3158 __ push(rax);
3159 }
3155 __ Push(Smi::FromInt(1)); 3160 __ Push(Smi::FromInt(1));
3156 if (is_increment_) { 3161 if (is_increment_) {
3157 __ CallRuntime(Runtime::kNumberAdd, 2); 3162 __ CallRuntime(Runtime::kNumberAdd, 2);
3158 } else { 3163 } else {
3159 __ CallRuntime(Runtime::kNumberSub, 2); 3164 __ CallRuntime(Runtime::kNumberSub, 2);
3160 } 3165 }
3161 if (!dst_.is(rax)) __ movq(dst_, rax); 3166 if (!dst_.is(rax)) __ movq(dst_, rax);
3162 } 3167 }
3163 3168
3164 3169
3165 // The value in dst was optimistically incremented or decremented. The 3170 // The value in dst was optimistically incremented or decremented.
3166 // result overflowed or was not smi tagged. Undo the operation and call 3171 // The result overflowed or was not smi tagged. Call into the runtime
3167 // into the runtime to convert the argument to a number. Update the 3172 // to convert the argument to a number. Update the original value in
3168 // original value in old. Call the specialized add or subtract stub. 3173 // old. Call the specialized add or subtract stub. The result is
3169 // The result is left in dst. 3174 // left in dst.
3170 class DeferredPostfixCountOperation: public DeferredCode { 3175 class DeferredPostfixCountOperation: public DeferredCode {
3171 public: 3176 public:
3172 DeferredPostfixCountOperation(Register dst, Register old, bool is_increment) 3177 DeferredPostfixCountOperation(Register dst,
3173 : dst_(dst), old_(old), is_increment_(is_increment) { 3178 Register old,
3179 bool is_increment,
3180 TypeInfo input_type)
3181 : dst_(dst),
3182 old_(old),
3183 is_increment_(is_increment),
3184 input_type_(input_type) {
3174 set_comment("[ DeferredCountOperation"); 3185 set_comment("[ DeferredCountOperation");
3175 } 3186 }
3176 3187
3177 virtual void Generate(); 3188 virtual void Generate();
3178 3189
3179 private: 3190 private:
3180 Register dst_; 3191 Register dst_;
3181 Register old_; 3192 Register old_;
3182 bool is_increment_; 3193 bool is_increment_;
3194 TypeInfo input_type_;
3183 }; 3195 };
3184 3196
3185 3197
3186 void DeferredPostfixCountOperation::Generate() { 3198 void DeferredPostfixCountOperation::Generate() {
3187 __ push(dst_); 3199 if (input_type_.IsNumber()) {
3188 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 3200 __ push(dst_); // Save the input to use as the old value.
3189 3201 __ push(dst_);
3190 // Save the result of ToNumber to use as the old value. 3202 } else {
3191 __ push(rax); 3203 __ push(dst_);
3204 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3205 __ push(rax); // Save the result of ToNumber to use as the old value.
3206 __ push(rax);
3207 }
3192 3208
3193 // Call the runtime for the addition or subtraction. 3209 // Call the runtime for the addition or subtraction.
3194 __ push(rax);
3195 __ Push(Smi::FromInt(1)); 3210 __ Push(Smi::FromInt(1));
3196 if (is_increment_) { 3211 if (is_increment_) {
3197 __ CallRuntime(Runtime::kNumberAdd, 2); 3212 __ CallRuntime(Runtime::kNumberAdd, 2);
3198 } else { 3213 } else {
3199 __ CallRuntime(Runtime::kNumberSub, 2); 3214 __ CallRuntime(Runtime::kNumberSub, 2);
3200 } 3215 }
3201 if (!dst_.is(rax)) __ movq(dst_, rax); 3216 if (!dst_.is(rax)) __ movq(dst_, rax);
3202 __ pop(old_); 3217 __ pop(old_);
3203 } 3218 }
3204 3219
(...skipping 26 matching lines...) Expand all
3231 3246
3232 Result new_value = frame_->Pop(); 3247 Result new_value = frame_->Pop();
3233 new_value.ToRegister(); 3248 new_value.ToRegister();
3234 3249
3235 Result old_value; // Only allocated in the postfix case. 3250 Result old_value; // Only allocated in the postfix case.
3236 if (is_postfix) { 3251 if (is_postfix) {
3237 // Allocate a temporary to preserve the old value. 3252 // Allocate a temporary to preserve the old value.
3238 old_value = allocator_->Allocate(); 3253 old_value = allocator_->Allocate();
3239 ASSERT(old_value.is_valid()); 3254 ASSERT(old_value.is_valid());
3240 __ movq(old_value.reg(), new_value.reg()); 3255 __ movq(old_value.reg(), new_value.reg());
3256
3257 // The return value for postfix operations is ToNumber(input).
3258 // Keep more precise type info if the input is some kind of
3259 // number already. If the input is not a number we have to wait
3260 // for the deferred code to convert it.
3261 if (new_value.type_info().IsNumber()) {
3262 old_value.set_type_info(new_value.type_info());
3263 }
3241 } 3264 }
3242 // Ensure the new value is writable. 3265 // Ensure the new value is writable.
3243 frame_->Spill(new_value.reg()); 3266 frame_->Spill(new_value.reg());
3244 3267
3245 DeferredCode* deferred = NULL; 3268 DeferredCode* deferred = NULL;
3246 if (is_postfix) { 3269 if (is_postfix) {
3247 deferred = new DeferredPostfixCountOperation(new_value.reg(), 3270 deferred = new DeferredPostfixCountOperation(new_value.reg(),
3248 old_value.reg(), 3271 old_value.reg(),
3249 is_increment); 3272 is_increment,
3273 new_value.type_info());
3250 } else { 3274 } else {
3251 deferred = new DeferredPrefixCountOperation(new_value.reg(), 3275 deferred = new DeferredPrefixCountOperation(new_value.reg(),
3252 is_increment); 3276 is_increment,
3277 new_value.type_info());
3253 } 3278 }
3254 3279
3255 __ JumpIfNotSmi(new_value.reg(), deferred->entry_label()); 3280 __ JumpIfNotSmi(new_value.reg(), deferred->entry_label());
3256 if (is_increment) { 3281 if (is_increment) {
3257 __ SmiAddConstant(kScratchRegister, 3282 __ SmiAddConstant(kScratchRegister,
3258 new_value.reg(), 3283 new_value.reg(),
3259 Smi::FromInt(1), 3284 Smi::FromInt(1),
3260 deferred->entry_label()); 3285 deferred->entry_label());
3261 } else { 3286 } else {
3262 __ SmiSubConstant(kScratchRegister, 3287 __ SmiSubConstant(kScratchRegister,
3263 new_value.reg(), 3288 new_value.reg(),
3264 Smi::FromInt(1), 3289 Smi::FromInt(1),
3265 deferred->entry_label()); 3290 deferred->entry_label());
3266 } 3291 }
3267 __ movq(new_value.reg(), kScratchRegister); 3292 __ movq(new_value.reg(), kScratchRegister);
3268 deferred->BindExit(); 3293 deferred->BindExit();
3269 3294
3295 // Postfix count operations return their input converted to
3296 // number. The case when the input is already a number is covered
3297 // above in the allocation code for old_value.
3298 if (is_postfix && !new_value.type_info().IsNumber()) {
3299 old_value.set_type_info(TypeInfo::Number());
3300 }
3301
3302 new_value.set_type_info(TypeInfo::Number());
3303
3270 // Postfix: store the old value in the allocated slot under the 3304 // Postfix: store the old value in the allocated slot under the
3271 // reference. 3305 // reference.
3272 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); 3306 if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
3273 3307
3274 frame_->Push(&new_value); 3308 frame_->Push(&new_value);
3275 // Non-constant: update the reference. 3309 // Non-constant: update the reference.
3276 if (!is_const) target.SetValue(NOT_CONST_INIT); 3310 if (!is_const) target.SetValue(NOT_CONST_INIT);
3277 } 3311 }
3278 3312
3279 // Postfix: drop the new value and use the old. 3313 // Postfix: drop the new value and use the old.
(...skipping 1967 matching lines...) Expand 10 before | Expand all | Expand 10 after
5247 if (op == Token::COMMA) { 5281 if (op == Token::COMMA) {
5248 // Simply discard left value. 5282 // Simply discard left value.
5249 frame_->Nip(1); 5283 frame_->Nip(1);
5250 return; 5284 return;
5251 } 5285 }
5252 5286
5253 Result right = frame_->Pop(); 5287 Result right = frame_->Pop();
5254 Result left = frame_->Pop(); 5288 Result left = frame_->Pop();
5255 5289
5256 if (op == Token::ADD) { 5290 if (op == Token::ADD) {
5257 bool left_is_string = left.is_constant() && left.handle()->IsString(); 5291 const bool left_is_string = left.type_info().IsString();
5258 bool right_is_string = right.is_constant() && right.handle()->IsString(); 5292 const bool right_is_string = right.type_info().IsString();
5293 // Make sure constant strings have string type info.
5294 ASSERT(!(left.is_constant() && left.handle()->IsString()) ||
5295 left_is_string);
5296 ASSERT(!(right.is_constant() && right.handle()->IsString()) ||
5297 right_is_string);
5259 if (left_is_string || right_is_string) { 5298 if (left_is_string || right_is_string) {
5260 frame_->Push(&left); 5299 frame_->Push(&left);
5261 frame_->Push(&right); 5300 frame_->Push(&right);
5262 Result answer; 5301 Result answer;
5263 if (left_is_string) { 5302 if (left_is_string) {
5264 if (right_is_string) { 5303 if (right_is_string) {
5265 // TODO(lrn): if both are constant strings 5304 // TODO(lrn): if both are constant strings
5266 // -- do a compile time cons, if allocation during codegen is allowed. 5305 // -- do a compile time cons, if allocation during codegen is allowed.
5267 answer = frame_->CallRuntime(Runtime::kStringAdd, 2); 5306 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
5307 answer = frame_->CallStub(&stub, 2);
5268 } else { 5308 } else {
5269 answer = 5309 answer =
5270 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2); 5310 frame_->InvokeBuiltin(Builtins::STRING_ADD_LEFT, CALL_FUNCTION, 2);
5271 } 5311 }
5272 } else if (right_is_string) { 5312 } else if (right_is_string) {
5273 answer = 5313 answer =
5274 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); 5314 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2);
5275 } 5315 }
5316 answer.set_type_info(TypeInfo::String());
5276 frame_->Push(&answer); 5317 frame_->Push(&answer);
5277 return; 5318 return;
5278 } 5319 }
5279 // Neither operand is known to be a string. 5320 // Neither operand is known to be a string.
5280 } 5321 }
5281 5322
5282 bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi(); 5323 bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi();
5283 bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi(); 5324 bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi();
5284 bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi(); 5325 bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi();
5285 bool right_is_non_smi_constant = 5326 bool right_is_non_smi_constant =
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
5351 result_type = TypeInfo::Smi(); 5392 result_type = TypeInfo::Smi();
5352 break; 5393 break;
5353 case Token::SHR: 5394 case Token::SHR:
5354 // Result of x >>> y is always a smi if y >= 1, otherwise a number. 5395 // Result of x >>> y is always a smi if y >= 1, otherwise a number.
5355 result_type = (right.is_constant() && right.handle()->IsSmi() 5396 result_type = (right.is_constant() && right.handle()->IsSmi()
5356 && Smi::cast(*right.handle())->value() >= 1) 5397 && Smi::cast(*right.handle())->value() >= 1)
5357 ? TypeInfo::Smi() 5398 ? TypeInfo::Smi()
5358 : TypeInfo::Number(); 5399 : TypeInfo::Number();
5359 break; 5400 break;
5360 case Token::ADD: 5401 case Token::ADD:
5361 // Result could be a string or a number. Check types of inputs. 5402 if (operands_type.IsNumber()) {
5362 result_type = operands_type.IsNumber() 5403 result_type = TypeInfo::Number();
5363 ? TypeInfo::Number() 5404 } else if (operands_type.IsString()) {
5364 : TypeInfo::Unknown(); 5405 result_type = TypeInfo::String();
5406 } else {
5407 result_type = TypeInfo::Unknown();
5408 }
5365 break; 5409 break;
5366 case Token::SUB: 5410 case Token::SUB:
5367 case Token::MUL: 5411 case Token::MUL:
5368 case Token::DIV: 5412 case Token::DIV:
5369 case Token::MOD: 5413 case Token::MOD:
5370 // Result is always a number. 5414 // Result is always a number.
5371 result_type = TypeInfo::Number(); 5415 result_type = TypeInfo::Number();
5372 break; 5416 break;
5373 default: 5417 default:
5374 UNREACHABLE(); 5418 UNREACHABLE();
(...skipping 4618 matching lines...) Expand 10 before | Expand all | Expand 10 after
9993 // Call the function from C++. 10037 // Call the function from C++.
9994 return FUNCTION_CAST<ModuloFunction>(buffer); 10038 return FUNCTION_CAST<ModuloFunction>(buffer);
9995 } 10039 }
9996 10040
9997 #endif 10041 #endif
9998 10042
9999 10043
10000 #undef __ 10044 #undef __
10001 10045
10002 } } // namespace v8::internal 10046 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/type-info.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698