OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 5012 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5023 OverwriteMode overwrite_mode) { | 5023 OverwriteMode overwrite_mode) { |
5024 Comment cmnt(masm_, "[ BinaryOperation"); | 5024 Comment cmnt(masm_, "[ BinaryOperation"); |
5025 Comment cmnt_token(masm_, Token::String(op)); | 5025 Comment cmnt_token(masm_, Token::String(op)); |
5026 | 5026 |
5027 if (op == Token::COMMA) { | 5027 if (op == Token::COMMA) { |
5028 // Simply discard left value. | 5028 // Simply discard left value. |
5029 frame_->Nip(1); | 5029 frame_->Nip(1); |
5030 return; | 5030 return; |
5031 } | 5031 } |
5032 | 5032 |
5033 // Set the flags based on the operation, type and loop nesting level. | |
5034 GenericBinaryFlags flags; | |
5035 switch (op) { | |
5036 case Token::BIT_OR: | |
5037 case Token::BIT_AND: | |
5038 case Token::BIT_XOR: | |
5039 case Token::SHL: | |
5040 case Token::SHR: | |
5041 case Token::SAR: | |
5042 // Bit operations always assume they likely operate on Smis. Still only | |
5043 // generate the inline Smi check code if this operation is part of a loop. | |
5044 flags = (loop_nesting() > 0) | |
5045 ? NO_SMI_CODE_IN_STUB | |
5046 : NO_GENERIC_BINARY_FLAGS; | |
5047 break; | |
5048 | |
5049 default: | |
5050 // By default only inline the Smi check code for likely smis if this | |
5051 // operation is part of a loop. | |
5052 flags = ((loop_nesting() > 0) && type->IsLikelySmi()) | |
5053 ? NO_SMI_CODE_IN_STUB | |
5054 : NO_GENERIC_BINARY_FLAGS; | |
5055 break; | |
5056 } | |
5057 | |
5058 Result right = frame_->Pop(); | 5033 Result right = frame_->Pop(); |
5059 Result left = frame_->Pop(); | 5034 Result left = frame_->Pop(); |
5060 | 5035 |
5061 if (op == Token::ADD) { | 5036 if (op == Token::ADD) { |
5062 bool left_is_string = left.is_constant() && left.handle()->IsString(); | 5037 bool left_is_string = left.is_constant() && left.handle()->IsString(); |
5063 bool right_is_string = right.is_constant() && right.handle()->IsString(); | 5038 bool right_is_string = right.is_constant() && right.handle()->IsString(); |
5064 if (left_is_string || right_is_string) { | 5039 if (left_is_string || right_is_string) { |
5065 frame_->Push(&left); | 5040 frame_->Push(&left); |
5066 frame_->Push(&right); | 5041 frame_->Push(&right); |
5067 Result answer; | 5042 Result answer; |
(...skipping 13 matching lines...) Expand all Loading... |
5081 frame_->Push(&answer); | 5056 frame_->Push(&answer); |
5082 return; | 5057 return; |
5083 } | 5058 } |
5084 // Neither operand is known to be a string. | 5059 // Neither operand is known to be a string. |
5085 } | 5060 } |
5086 | 5061 |
5087 bool left_is_smi = left.is_constant() && left.handle()->IsSmi(); | 5062 bool left_is_smi = left.is_constant() && left.handle()->IsSmi(); |
5088 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi(); | 5063 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi(); |
5089 bool right_is_smi = right.is_constant() && right.handle()->IsSmi(); | 5064 bool right_is_smi = right.is_constant() && right.handle()->IsSmi(); |
5090 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi(); | 5065 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi(); |
5091 bool generate_no_smi_code = false; // No smi code at all, inline or in stub. | |
5092 | 5066 |
5093 if (left_is_smi && right_is_smi) { | 5067 if (left_is_smi && right_is_smi) { |
5094 // Compute the constant result at compile time, and leave it on the frame. | 5068 // Compute the constant result at compile time, and leave it on the frame. |
5095 int left_int = Smi::cast(*left.handle())->value(); | 5069 int left_int = Smi::cast(*left.handle())->value(); |
5096 int right_int = Smi::cast(*right.handle())->value(); | 5070 int right_int = Smi::cast(*right.handle())->value(); |
5097 if (FoldConstantSmis(op, left_int, right_int)) return; | 5071 if (FoldConstantSmis(op, left_int, right_int)) return; |
5098 } | 5072 } |
5099 | 5073 |
| 5074 Result answer; |
5100 if (left_is_non_smi || right_is_non_smi) { | 5075 if (left_is_non_smi || right_is_non_smi) { |
5101 // Set flag so that we go straight to the slow case, with no smi code. | 5076 // Go straight to the slow case, with no smi code |
5102 generate_no_smi_code = true; | |
5103 } else if (right_is_smi) { | |
5104 ConstantSmiBinaryOperation(op, &left, right.handle(), | |
5105 type, false, overwrite_mode); | |
5106 return; | |
5107 } else if (left_is_smi) { | |
5108 ConstantSmiBinaryOperation(op, &right, left.handle(), | |
5109 type, true, overwrite_mode); | |
5110 return; | |
5111 } | |
5112 | |
5113 if ((flags & NO_SMI_CODE_IN_STUB) != 0 && !generate_no_smi_code) { | |
5114 LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | |
5115 } else { | |
5116 frame_->Push(&left); | 5077 frame_->Push(&left); |
5117 frame_->Push(&right); | 5078 frame_->Push(&right); |
5118 // If we know the arguments aren't smis, use the binary operation stub | 5079 GenericBinaryOpStub stub(op, overwrite_mode, NO_SMI_CODE_IN_STUB); |
5119 // that does not check for the fast smi case. | 5080 answer = frame_->CallStub(&stub, 2); |
5120 // The same stub is used for NO_SMI_CODE and SMI_CODE_INLINED. | 5081 } else if (right_is_smi) { |
5121 if (generate_no_smi_code) { | 5082 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
5122 flags = NO_SMI_CODE_IN_STUB; | 5083 type, false, overwrite_mode); |
| 5084 } else if (left_is_smi) { |
| 5085 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
| 5086 type, true, overwrite_mode); |
| 5087 } else { |
| 5088 // Set the flags based on the operation, type and loop nesting level. |
| 5089 // Bit operations always assume they likely operate on Smis. Still only |
| 5090 // generate the inline Smi check code if this operation is part of a loop. |
| 5091 // For all other operations only inline the Smi check code for likely smis |
| 5092 // if the operation is part of a loop. |
| 5093 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { |
| 5094 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
| 5095 } else { |
| 5096 frame_->Push(&left); |
| 5097 frame_->Push(&right); |
| 5098 GenericBinaryOpStub stub(op, overwrite_mode, NO_GENERIC_BINARY_FLAGS); |
| 5099 answer = frame_->CallStub(&stub, 2); |
5123 } | 5100 } |
5124 GenericBinaryOpStub stub(op, overwrite_mode, flags); | |
5125 Result answer = frame_->CallStub(&stub, 2); | |
5126 frame_->Push(&answer); | |
5127 } | 5101 } |
| 5102 frame_->Push(&answer); |
5128 } | 5103 } |
5129 | 5104 |
5130 | 5105 |
5131 // Emit a LoadIC call to get the value from receiver and leave it in | 5106 // Emit a LoadIC call to get the value from receiver and leave it in |
5132 // dst. The receiver register is restored after the call. | 5107 // dst. The receiver register is restored after the call. |
5133 class DeferredReferenceGetNamedValue: public DeferredCode { | 5108 class DeferredReferenceGetNamedValue: public DeferredCode { |
5134 public: | 5109 public: |
5135 DeferredReferenceGetNamedValue(Register dst, | 5110 DeferredReferenceGetNamedValue(Register dst, |
5136 Register receiver, | 5111 Register receiver, |
5137 Handle<String> name) | 5112 Handle<String> name) |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5198 // For mod we don't generate all the Smi code inline. | 5173 // For mod we don't generate all the Smi code inline. |
5199 GenericBinaryOpStub stub( | 5174 GenericBinaryOpStub stub( |
5200 op_, | 5175 op_, |
5201 overwrite_mode_, | 5176 overwrite_mode_, |
5202 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); | 5177 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); |
5203 stub.GenerateCall(masm_, src_, value_); | 5178 stub.GenerateCall(masm_, src_, value_); |
5204 if (!dst_.is(rax)) __ movq(dst_, rax); | 5179 if (!dst_.is(rax)) __ movq(dst_, rax); |
5205 } | 5180 } |
5206 | 5181 |
5207 | 5182 |
5208 void CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 5183 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
5209 Result* operand, | 5184 Result* operand, |
5210 Handle<Object> value, | 5185 Handle<Object> value, |
5211 StaticType* type, | 5186 StaticType* type, |
5212 bool reversed, | 5187 bool reversed, |
5213 OverwriteMode overwrite_mode) { | 5188 OverwriteMode overwrite_mode) { |
5214 // NOTE: This is an attempt to inline (a bit) more of the code for | 5189 // NOTE: This is an attempt to inline (a bit) more of the code for |
5215 // some possible smi operations (like + and -) when (at least) one | 5190 // some possible smi operations (like + and -) when (at least) one |
5216 // of the operands is a constant smi. | 5191 // of the operands is a constant smi. |
5217 // Consumes the argument "operand". | 5192 // Consumes the argument "operand". |
5218 | 5193 |
5219 // TODO(199): Optimize some special cases of operations involving a | 5194 // TODO(199): Optimize some special cases of operations involving a |
5220 // smi literal (multiply by 2, shift by 0, etc.). | 5195 // smi literal (multiply by 2, shift by 0, etc.). |
5221 if (IsUnsafeSmi(value)) { | 5196 if (IsUnsafeSmi(value)) { |
5222 Result unsafe_operand(value); | 5197 Result unsafe_operand(value); |
5223 if (reversed) { | 5198 if (reversed) { |
5224 LikelySmiBinaryOperation(op, &unsafe_operand, operand, | 5199 return LikelySmiBinaryOperation(op, &unsafe_operand, operand, |
5225 overwrite_mode); | 5200 overwrite_mode); |
5226 } else { | 5201 } else { |
5227 LikelySmiBinaryOperation(op, operand, &unsafe_operand, | 5202 return LikelySmiBinaryOperation(op, operand, &unsafe_operand, |
5228 overwrite_mode); | 5203 overwrite_mode); |
5229 } | 5204 } |
5230 ASSERT(!operand->is_valid()); | |
5231 return; | |
5232 } | 5205 } |
5233 | 5206 |
5234 // Get the literal value. | 5207 // Get the literal value. |
5235 Smi* smi_value = Smi::cast(*value); | 5208 Smi* smi_value = Smi::cast(*value); |
5236 int int_value = smi_value->value(); | 5209 int int_value = smi_value->value(); |
5237 | 5210 |
| 5211 Result answer; |
5238 switch (op) { | 5212 switch (op) { |
5239 case Token::ADD: { | 5213 case Token::ADD: { |
5240 operand->ToRegister(); | 5214 operand->ToRegister(); |
5241 frame_->Spill(operand->reg()); | 5215 frame_->Spill(operand->reg()); |
5242 DeferredCode* deferred = NULL; | 5216 DeferredCode* deferred = NULL; |
5243 if (reversed) { | 5217 if (reversed) { |
5244 deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 5218 deferred = new DeferredInlineSmiAddReversed(operand->reg(), |
5245 smi_value, | 5219 smi_value, |
5246 overwrite_mode); | 5220 overwrite_mode); |
5247 } else { | 5221 } else { |
5248 deferred = new DeferredInlineSmiAdd(operand->reg(), | 5222 deferred = new DeferredInlineSmiAdd(operand->reg(), |
5249 smi_value, | 5223 smi_value, |
5250 overwrite_mode); | 5224 overwrite_mode); |
5251 } | 5225 } |
5252 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5226 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5253 __ SmiAddConstant(operand->reg(), | 5227 __ SmiAddConstant(operand->reg(), |
5254 operand->reg(), | 5228 operand->reg(), |
5255 smi_value, | 5229 smi_value, |
5256 deferred->entry_label()); | 5230 deferred->entry_label()); |
5257 deferred->BindExit(); | 5231 deferred->BindExit(); |
5258 frame_->Push(operand); | 5232 answer = *operand; |
5259 break; | 5233 break; |
5260 } | 5234 } |
5261 | 5235 |
5262 case Token::SUB: { | 5236 case Token::SUB: { |
5263 if (reversed) { | 5237 if (reversed) { |
5264 Result constant_operand(value); | 5238 Result constant_operand(value); |
5265 LikelySmiBinaryOperation(op, &constant_operand, operand, | 5239 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
5266 overwrite_mode); | 5240 overwrite_mode); |
5267 } else { | 5241 } else { |
5268 operand->ToRegister(); | 5242 operand->ToRegister(); |
5269 frame_->Spill(operand->reg()); | 5243 frame_->Spill(operand->reg()); |
5270 DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), | 5244 DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), |
5271 smi_value, | 5245 smi_value, |
5272 overwrite_mode); | 5246 overwrite_mode); |
5273 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5247 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5274 // A smi currently fits in a 32-bit Immediate. | 5248 // A smi currently fits in a 32-bit Immediate. |
5275 __ SmiSubConstant(operand->reg(), | 5249 __ SmiSubConstant(operand->reg(), |
5276 operand->reg(), | 5250 operand->reg(), |
5277 smi_value, | 5251 smi_value, |
5278 deferred->entry_label()); | 5252 deferred->entry_label()); |
5279 deferred->BindExit(); | 5253 deferred->BindExit(); |
5280 frame_->Push(operand); | 5254 answer = *operand; |
5281 } | 5255 } |
5282 break; | 5256 break; |
5283 } | 5257 } |
5284 | 5258 |
5285 case Token::SAR: | 5259 case Token::SAR: |
5286 if (reversed) { | 5260 if (reversed) { |
5287 Result constant_operand(value); | 5261 Result constant_operand(value); |
5288 LikelySmiBinaryOperation(op, &constant_operand, operand, | 5262 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
5289 overwrite_mode); | 5263 overwrite_mode); |
5290 } else { | 5264 } else { |
5291 // Only the least significant 5 bits of the shift value are used. | 5265 // Only the least significant 5 bits of the shift value are used. |
5292 // In the slow case, this masking is done inside the runtime call. | 5266 // In the slow case, this masking is done inside the runtime call. |
5293 int shift_value = int_value & 0x1f; | 5267 int shift_value = int_value & 0x1f; |
5294 operand->ToRegister(); | 5268 operand->ToRegister(); |
5295 frame_->Spill(operand->reg()); | 5269 frame_->Spill(operand->reg()); |
5296 DeferredInlineSmiOperation* deferred = | 5270 DeferredInlineSmiOperation* deferred = |
5297 new DeferredInlineSmiOperation(op, | 5271 new DeferredInlineSmiOperation(op, |
5298 operand->reg(), | 5272 operand->reg(), |
5299 operand->reg(), | 5273 operand->reg(), |
5300 smi_value, | 5274 smi_value, |
5301 overwrite_mode); | 5275 overwrite_mode); |
5302 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5276 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5303 __ SmiShiftArithmeticRightConstant(operand->reg(), | 5277 __ SmiShiftArithmeticRightConstant(operand->reg(), |
5304 operand->reg(), | 5278 operand->reg(), |
5305 shift_value); | 5279 shift_value); |
5306 deferred->BindExit(); | 5280 deferred->BindExit(); |
5307 frame_->Push(operand); | 5281 answer = *operand; |
5308 } | 5282 } |
5309 break; | 5283 break; |
5310 | 5284 |
5311 case Token::SHR: | 5285 case Token::SHR: |
5312 if (reversed) { | 5286 if (reversed) { |
5313 Result constant_operand(value); | 5287 Result constant_operand(value); |
5314 LikelySmiBinaryOperation(op, &constant_operand, operand, | 5288 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
5315 overwrite_mode); | 5289 overwrite_mode); |
5316 } else { | 5290 } else { |
5317 // Only the least significant 5 bits of the shift value are used. | 5291 // Only the least significant 5 bits of the shift value are used. |
5318 // In the slow case, this masking is done inside the runtime call. | 5292 // In the slow case, this masking is done inside the runtime call. |
5319 int shift_value = int_value & 0x1f; | 5293 int shift_value = int_value & 0x1f; |
5320 operand->ToRegister(); | 5294 operand->ToRegister(); |
5321 Result answer = allocator()->Allocate(); | 5295 answer = allocator()->Allocate(); |
5322 ASSERT(answer.is_valid()); | 5296 ASSERT(answer.is_valid()); |
5323 DeferredInlineSmiOperation* deferred = | 5297 DeferredInlineSmiOperation* deferred = |
5324 new DeferredInlineSmiOperation(op, | 5298 new DeferredInlineSmiOperation(op, |
5325 answer.reg(), | 5299 answer.reg(), |
5326 operand->reg(), | 5300 operand->reg(), |
5327 smi_value, | 5301 smi_value, |
5328 overwrite_mode); | 5302 overwrite_mode); |
5329 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5303 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5330 __ SmiShiftLogicalRightConstant(answer.reg(), | 5304 __ SmiShiftLogicalRightConstant(answer.reg(), |
5331 operand->reg(), | 5305 operand->reg(), |
5332 shift_value, | 5306 shift_value, |
5333 deferred->entry_label()); | 5307 deferred->entry_label()); |
5334 deferred->BindExit(); | 5308 deferred->BindExit(); |
5335 operand->Unuse(); | 5309 operand->Unuse(); |
5336 frame_->Push(&answer); | |
5337 } | 5310 } |
5338 break; | 5311 break; |
5339 | 5312 |
5340 case Token::SHL: | 5313 case Token::SHL: |
5341 if (reversed) { | 5314 if (reversed) { |
5342 Result constant_operand(value); | 5315 Result constant_operand(value); |
5343 LikelySmiBinaryOperation(op, &constant_operand, operand, | 5316 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
5344 overwrite_mode); | 5317 overwrite_mode); |
5345 } else { | 5318 } else { |
5346 // Only the least significant 5 bits of the shift value are used. | 5319 // Only the least significant 5 bits of the shift value are used. |
5347 // In the slow case, this masking is done inside the runtime call. | 5320 // In the slow case, this masking is done inside the runtime call. |
5348 int shift_value = int_value & 0x1f; | 5321 int shift_value = int_value & 0x1f; |
5349 operand->ToRegister(); | 5322 operand->ToRegister(); |
5350 if (shift_value == 0) { | 5323 if (shift_value == 0) { |
5351 // Spill operand so it can be overwritten in the slow case. | 5324 // Spill operand so it can be overwritten in the slow case. |
5352 frame_->Spill(operand->reg()); | 5325 frame_->Spill(operand->reg()); |
5353 DeferredInlineSmiOperation* deferred = | 5326 DeferredInlineSmiOperation* deferred = |
5354 new DeferredInlineSmiOperation(op, | 5327 new DeferredInlineSmiOperation(op, |
5355 operand->reg(), | 5328 operand->reg(), |
5356 operand->reg(), | 5329 operand->reg(), |
5357 smi_value, | 5330 smi_value, |
5358 overwrite_mode); | 5331 overwrite_mode); |
5359 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5332 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5360 deferred->BindExit(); | 5333 deferred->BindExit(); |
5361 frame_->Push(operand); | 5334 answer = *operand; |
5362 } else { | 5335 } else { |
5363 // Use a fresh temporary for nonzero shift values. | 5336 // Use a fresh temporary for nonzero shift values. |
5364 Result answer = allocator()->Allocate(); | 5337 answer = allocator()->Allocate(); |
5365 ASSERT(answer.is_valid()); | 5338 ASSERT(answer.is_valid()); |
5366 DeferredInlineSmiOperation* deferred = | 5339 DeferredInlineSmiOperation* deferred = |
5367 new DeferredInlineSmiOperation(op, | 5340 new DeferredInlineSmiOperation(op, |
5368 answer.reg(), | 5341 answer.reg(), |
5369 operand->reg(), | 5342 operand->reg(), |
5370 smi_value, | 5343 smi_value, |
5371 overwrite_mode); | 5344 overwrite_mode); |
5372 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); | 5345 __ JumpIfNotSmi(operand->reg(), deferred->entry_label()); |
5373 __ SmiShiftLeftConstant(answer.reg(), | 5346 __ SmiShiftLeftConstant(answer.reg(), |
5374 operand->reg(), | 5347 operand->reg(), |
5375 shift_value, | 5348 shift_value, |
5376 deferred->entry_label()); | 5349 deferred->entry_label()); |
5377 deferred->BindExit(); | 5350 deferred->BindExit(); |
5378 operand->Unuse(); | 5351 operand->Unuse(); |
5379 frame_->Push(&answer); | |
5380 } | 5352 } |
5381 } | 5353 } |
5382 break; | 5354 break; |
5383 | 5355 |
5384 case Token::BIT_OR: | 5356 case Token::BIT_OR: |
5385 case Token::BIT_XOR: | 5357 case Token::BIT_XOR: |
5386 case Token::BIT_AND: { | 5358 case Token::BIT_AND: { |
5387 operand->ToRegister(); | 5359 operand->ToRegister(); |
5388 frame_->Spill(operand->reg()); | 5360 frame_->Spill(operand->reg()); |
5389 if (reversed) { | 5361 if (reversed) { |
(...skipping 14 matching lines...) Expand all Loading... |
5404 if (int_value != 0) { | 5376 if (int_value != 0) { |
5405 __ SmiXorConstant(operand->reg(), operand->reg(), smi_value); | 5377 __ SmiXorConstant(operand->reg(), operand->reg(), smi_value); |
5406 } | 5378 } |
5407 } else { | 5379 } else { |
5408 ASSERT(op == Token::BIT_OR); | 5380 ASSERT(op == Token::BIT_OR); |
5409 if (int_value != 0) { | 5381 if (int_value != 0) { |
5410 __ SmiOrConstant(operand->reg(), operand->reg(), smi_value); | 5382 __ SmiOrConstant(operand->reg(), operand->reg(), smi_value); |
5411 } | 5383 } |
5412 } | 5384 } |
5413 deferred->BindExit(); | 5385 deferred->BindExit(); |
5414 frame_->Push(operand); | 5386 answer = *operand; |
5415 break; | 5387 break; |
5416 } | 5388 } |
5417 | 5389 |
5418 // Generate inline code for mod of powers of 2 and negative powers of 2. | 5390 // Generate inline code for mod of powers of 2 and negative powers of 2. |
5419 case Token::MOD: | 5391 case Token::MOD: |
5420 if (!reversed && | 5392 if (!reversed && |
5421 int_value != 0 && | 5393 int_value != 0 && |
5422 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 5394 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
5423 operand->ToRegister(); | 5395 operand->ToRegister(); |
5424 frame_->Spill(operand->reg()); | 5396 frame_->Spill(operand->reg()); |
5425 DeferredCode* deferred = | 5397 DeferredCode* deferred = |
5426 new DeferredInlineSmiOperation(op, | 5398 new DeferredInlineSmiOperation(op, |
5427 operand->reg(), | 5399 operand->reg(), |
5428 operand->reg(), | 5400 operand->reg(), |
5429 smi_value, | 5401 smi_value, |
5430 overwrite_mode); | 5402 overwrite_mode); |
5431 // Check for negative or non-Smi left hand side. | 5403 // Check for negative or non-Smi left hand side. |
5432 __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label()); | 5404 __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label()); |
5433 if (int_value < 0) int_value = -int_value; | 5405 if (int_value < 0) int_value = -int_value; |
5434 if (int_value == 1) { | 5406 if (int_value == 1) { |
5435 __ Move(operand->reg(), Smi::FromInt(0)); | 5407 __ Move(operand->reg(), Smi::FromInt(0)); |
5436 } else { | 5408 } else { |
5437 __ SmiAndConstant(operand->reg(), | 5409 __ SmiAndConstant(operand->reg(), |
5438 operand->reg(), | 5410 operand->reg(), |
5439 Smi::FromInt(int_value - 1)); | 5411 Smi::FromInt(int_value - 1)); |
5440 } | 5412 } |
5441 deferred->BindExit(); | 5413 deferred->BindExit(); |
5442 frame_->Push(operand); | 5414 answer = *operand; |
5443 break; // This break only applies if we generated code for MOD. | 5415 break; // This break only applies if we generated code for MOD. |
5444 } | 5416 } |
5445 // Fall through if we did not find a power of 2 on the right hand side! | 5417 // Fall through if we did not find a power of 2 on the right hand side! |
5446 // The next case must be the default. | 5418 // The next case must be the default. |
5447 | 5419 |
5448 default: { | 5420 default: { |
5449 Result constant_operand(value); | 5421 Result constant_operand(value); |
5450 if (reversed) { | 5422 if (reversed) { |
5451 LikelySmiBinaryOperation(op, &constant_operand, operand, | 5423 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
5452 overwrite_mode); | 5424 overwrite_mode); |
5453 } else { | 5425 } else { |
5454 LikelySmiBinaryOperation(op, operand, &constant_operand, | 5426 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
5455 overwrite_mode); | 5427 overwrite_mode); |
5456 } | 5428 } |
5457 break; | 5429 break; |
5458 } | 5430 } |
5459 } | 5431 } |
5460 ASSERT(!operand->is_valid()); | 5432 ASSERT(answer.is_valid()); |
| 5433 return answer; |
5461 } | 5434 } |
5462 | 5435 |
5463 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 5436 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
5464 Result* left, | 5437 Result* left, |
5465 Result* right, | 5438 Result* right, |
5466 OverwriteMode overwrite_mode) { | 5439 OverwriteMode overwrite_mode) { |
| 5440 Result answer; |
5467 // Special handling of div and mod because they use fixed registers. | 5441 // Special handling of div and mod because they use fixed registers. |
5468 if (op == Token::DIV || op == Token::MOD) { | 5442 if (op == Token::DIV || op == Token::MOD) { |
5469 // We need rax as the quotient register, rdx as the remainder | 5443 // We need rax as the quotient register, rdx as the remainder |
5470 // register, neither left nor right in rax or rdx, and left copied | 5444 // register, neither left nor right in rax or rdx, and left copied |
5471 // to rax. | 5445 // to rax. |
5472 Result quotient; | 5446 Result quotient; |
5473 Result remainder; | 5447 Result remainder; |
5474 bool left_is_in_rax = false; | 5448 bool left_is_in_rax = false; |
5475 // Step 1: get rax for quotient. | 5449 // Step 1: get rax for quotient. |
5476 if ((left->is_register() && left->reg().is(rax)) || | 5450 if ((left->is_register() && left->reg().is(rax)) || |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5538 left->reg(), | 5512 left->reg(), |
5539 right->reg(), | 5513 right->reg(), |
5540 overwrite_mode); | 5514 overwrite_mode); |
5541 __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); | 5515 __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); |
5542 | 5516 |
5543 if (op == Token::DIV) { | 5517 if (op == Token::DIV) { |
5544 __ SmiDiv(rax, left->reg(), right->reg(), deferred->entry_label()); | 5518 __ SmiDiv(rax, left->reg(), right->reg(), deferred->entry_label()); |
5545 deferred->BindExit(); | 5519 deferred->BindExit(); |
5546 left->Unuse(); | 5520 left->Unuse(); |
5547 right->Unuse(); | 5521 right->Unuse(); |
5548 frame_->Push("ient); | 5522 answer = quotient; |
5549 } else { | 5523 } else { |
5550 ASSERT(op == Token::MOD); | 5524 ASSERT(op == Token::MOD); |
5551 __ SmiMod(rdx, left->reg(), right->reg(), deferred->entry_label()); | 5525 __ SmiMod(rdx, left->reg(), right->reg(), deferred->entry_label()); |
5552 deferred->BindExit(); | 5526 deferred->BindExit(); |
5553 left->Unuse(); | 5527 left->Unuse(); |
5554 right->Unuse(); | 5528 right->Unuse(); |
5555 frame_->Push(&remainder); | 5529 answer = remainder; |
5556 } | 5530 } |
5557 return; | 5531 ASSERT(answer.is_valid()); |
| 5532 return answer; |
5558 } | 5533 } |
5559 | 5534 |
5560 // Special handling of shift operations because they use fixed | 5535 // Special handling of shift operations because they use fixed |
5561 // registers. | 5536 // registers. |
5562 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { | 5537 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { |
5563 // Move left out of rcx if necessary. | 5538 // Move left out of rcx if necessary. |
5564 if (left->is_register() && left->reg().is(rcx)) { | 5539 if (left->is_register() && left->reg().is(rcx)) { |
5565 *left = allocator_->Allocate(); | 5540 *left = allocator_->Allocate(); |
5566 ASSERT(left->is_valid()); | 5541 ASSERT(left->is_valid()); |
5567 __ movq(left->reg(), rcx); | 5542 __ movq(left->reg(), rcx); |
5568 } | 5543 } |
5569 right->ToRegister(rcx); | 5544 right->ToRegister(rcx); |
5570 left->ToRegister(); | 5545 left->ToRegister(); |
5571 ASSERT(left->is_register() && !left->reg().is(rcx)); | 5546 ASSERT(left->is_register() && !left->reg().is(rcx)); |
5572 ASSERT(right->is_register() && right->reg().is(rcx)); | 5547 ASSERT(right->is_register() && right->reg().is(rcx)); |
5573 | 5548 |
5574 // We will modify right, it must be spilled. | 5549 // We will modify right, it must be spilled. |
5575 frame_->Spill(rcx); | 5550 frame_->Spill(rcx); |
5576 | 5551 |
5577 // Use a fresh answer register to avoid spilling the left operand. | 5552 // Use a fresh answer register to avoid spilling the left operand. |
5578 Result answer = allocator_->Allocate(); | 5553 answer = allocator_->Allocate(); |
5579 ASSERT(answer.is_valid()); | 5554 ASSERT(answer.is_valid()); |
5580 // Check that both operands are smis using the answer register as a | 5555 // Check that both operands are smis using the answer register as a |
5581 // temporary. | 5556 // temporary. |
5582 DeferredInlineBinaryOperation* deferred = | 5557 DeferredInlineBinaryOperation* deferred = |
5583 new DeferredInlineBinaryOperation(op, | 5558 new DeferredInlineBinaryOperation(op, |
5584 answer.reg(), | 5559 answer.reg(), |
5585 left->reg(), | 5560 left->reg(), |
5586 rcx, | 5561 rcx, |
5587 overwrite_mode); | 5562 overwrite_mode); |
5588 __ movq(answer.reg(), left->reg()); | 5563 __ movq(answer.reg(), left->reg()); |
(...skipping 18 matching lines...) Expand all Loading... |
5607 rcx, | 5582 rcx, |
5608 deferred->entry_label()); | 5583 deferred->entry_label()); |
5609 break; | 5584 break; |
5610 } | 5585 } |
5611 default: | 5586 default: |
5612 UNREACHABLE(); | 5587 UNREACHABLE(); |
5613 } | 5588 } |
5614 deferred->BindExit(); | 5589 deferred->BindExit(); |
5615 left->Unuse(); | 5590 left->Unuse(); |
5616 right->Unuse(); | 5591 right->Unuse(); |
5617 frame_->Push(&answer); | 5592 ASSERT(answer.is_valid()); |
5618 return; | 5593 return answer; |
5619 } | 5594 } |
5620 | 5595 |
5621 // Handle the other binary operations. | 5596 // Handle the other binary operations. |
5622 left->ToRegister(); | 5597 left->ToRegister(); |
5623 right->ToRegister(); | 5598 right->ToRegister(); |
5624 // A newly allocated register answer is used to hold the answer. The | 5599 // A newly allocated register answer is used to hold the answer. The |
5625 // registers containing left and right are not modified so they don't | 5600 // registers containing left and right are not modified so they don't |
5626 // need to be spilled in the fast case. | 5601 // need to be spilled in the fast case. |
5627 Result answer = allocator_->Allocate(); | 5602 answer = allocator_->Allocate(); |
5628 ASSERT(answer.is_valid()); | 5603 ASSERT(answer.is_valid()); |
5629 | 5604 |
5630 // Perform the smi tag check. | 5605 // Perform the smi tag check. |
5631 DeferredInlineBinaryOperation* deferred = | 5606 DeferredInlineBinaryOperation* deferred = |
5632 new DeferredInlineBinaryOperation(op, | 5607 new DeferredInlineBinaryOperation(op, |
5633 answer.reg(), | 5608 answer.reg(), |
5634 left->reg(), | 5609 left->reg(), |
5635 right->reg(), | 5610 right->reg(), |
5636 overwrite_mode); | 5611 overwrite_mode); |
5637 __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); | 5612 __ JumpIfNotBothSmi(left->reg(), right->reg(), deferred->entry_label()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5671 __ SmiXor(answer.reg(), left->reg(), right->reg()); | 5646 __ SmiXor(answer.reg(), left->reg(), right->reg()); |
5672 break; | 5647 break; |
5673 | 5648 |
5674 default: | 5649 default: |
5675 UNREACHABLE(); | 5650 UNREACHABLE(); |
5676 break; | 5651 break; |
5677 } | 5652 } |
5678 deferred->BindExit(); | 5653 deferred->BindExit(); |
5679 left->Unuse(); | 5654 left->Unuse(); |
5680 right->Unuse(); | 5655 right->Unuse(); |
5681 frame_->Push(&answer); | 5656 ASSERT(answer.is_valid()); |
| 5657 return answer; |
5682 } | 5658 } |
5683 | 5659 |
5684 | 5660 |
5685 #undef __ | 5661 #undef __ |
5686 #define __ ACCESS_MASM(masm) | 5662 #define __ ACCESS_MASM(masm) |
5687 | 5663 |
5688 | 5664 |
5689 Handle<String> Reference::GetName() { | 5665 Handle<String> Reference::GetName() { |
5690 ASSERT(type_ == NAMED); | 5666 ASSERT(type_ == NAMED); |
5691 Property* property = expression_->AsProperty(); | 5667 Property* property = expression_->AsProperty(); |
(...skipping 2709 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8401 // Call the function from C++. | 8377 // Call the function from C++. |
8402 return FUNCTION_CAST<ModuloFunction>(buffer); | 8378 return FUNCTION_CAST<ModuloFunction>(buffer); |
8403 } | 8379 } |
8404 | 8380 |
8405 #endif | 8381 #endif |
8406 | 8382 |
8407 | 8383 |
8408 #undef __ | 8384 #undef __ |
8409 | 8385 |
8410 } } // namespace v8::internal | 8386 } } // namespace v8::internal |
OLD | NEW |