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 3111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |