| 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 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 public: | 195 public: |
| 196 // Code pattern for loading a floating point value. Input value must | 196 // Code pattern for loading a floating point value. Input value must |
| 197 // be either a smi or a heap number object (fp value). Requirements: | 197 // be either a smi or a heap number object (fp value). Requirements: |
| 198 // operand on TOS+1. Returns operand as floating point number on FPU | 198 // operand on TOS+1. Returns operand as floating point number on FPU |
| 199 // stack. | 199 // stack. |
| 200 static void LoadFloatOperand(MacroAssembler* masm, Register scratch); | 200 static void LoadFloatOperand(MacroAssembler* masm, Register scratch); |
| 201 | 201 |
| 202 // Code pattern for loading a floating point value. Input value must | 202 // Code pattern for loading a floating point value. Input value must |
| 203 // be either a smi or a heap number object (fp value). Requirements: | 203 // be either a smi or a heap number object (fp value). Requirements: |
| 204 // operand in src register. Returns operand as floating point number | 204 // operand in src register. Returns operand as floating point number |
| 205 // in XMM register | 205 // in XMM register. May destroy src register. |
| 206 static void LoadFloatOperand(MacroAssembler* masm, | 206 static void LoadFloatOperand(MacroAssembler* masm, |
| 207 Register src, | 207 Register src, |
| 208 XMMRegister dst); | 208 XMMRegister dst); |
| 209 | 209 |
| 210 // Code pattern for loading a possible number into a XMM register. |
| 211 // If the contents of src is not a number, control branches to |
| 212 // the Label not_number. If contents of src is a smi or a heap number |
| 213 // object (fp value), it is loaded into the XMM register as a double. |
| 214 // The register src is not changed, and src may not be kScratchRegister. |
| 215 static void LoadFloatOperand(MacroAssembler* masm, |
| 216 Register src, |
| 217 XMMRegister dst, |
| 218 Label *not_number); |
| 219 |
| 210 // Code pattern for loading floating point values. Input values must | 220 // Code pattern for loading floating point values. Input values must |
| 211 // be either smi or heap number objects (fp values). Requirements: | 221 // be either smi or heap number objects (fp values). Requirements: |
| 212 // operand_1 in rdx, operand_2 in rax; Returns operands as | 222 // operand_1 in rdx, operand_2 in rax; Returns operands as |
| 213 // floating point numbers in XMM registers. | 223 // floating point numbers in XMM registers. |
| 214 static void LoadFloatOperands(MacroAssembler* masm, | 224 static void LoadFloatOperands(MacroAssembler* masm, |
| 215 XMMRegister dst1, | 225 XMMRegister dst1, |
| 216 XMMRegister dst2); | 226 XMMRegister dst2); |
| 217 | 227 |
| 218 // Similar to LoadFloatOperands, assumes that the operands are smis. | 228 // Similar to LoadFloatOperands, assumes that the operands are smis. |
| 219 static void LoadFloatOperandsFromSmis(MacroAssembler* masm, | 229 static void LoadFloatOperandsFromSmis(MacroAssembler* masm, |
| (...skipping 5093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5313 | 5323 |
| 5314 static bool CouldBeNaN(const Result& result) { | 5324 static bool CouldBeNaN(const Result& result) { |
| 5315 if (result.type_info().IsSmi()) return false; | 5325 if (result.type_info().IsSmi()) return false; |
| 5316 if (result.type_info().IsInteger32()) return false; | 5326 if (result.type_info().IsInteger32()) return false; |
| 5317 if (!result.is_constant()) return true; | 5327 if (!result.is_constant()) return true; |
| 5318 if (!result.handle()->IsHeapNumber()) return false; | 5328 if (!result.handle()->IsHeapNumber()) return false; |
| 5319 return isnan(HeapNumber::cast(*result.handle())->value()); | 5329 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 5320 } | 5330 } |
| 5321 | 5331 |
| 5322 | 5332 |
| 5333 // Convert from signed to unsigned comparison to match the way EFLAGS are set |
| 5334 // by FPU and XMM compare instructions. |
| 5335 static Condition DoubleCondition(Condition cc) { |
| 5336 switch (cc) { |
| 5337 case less: return below; |
| 5338 case equal: return equal; |
| 5339 case less_equal: return below_equal; |
| 5340 case greater: return above; |
| 5341 case greater_equal: return above_equal; |
| 5342 default: UNREACHABLE(); |
| 5343 } |
| 5344 UNREACHABLE(); |
| 5345 return equal; |
| 5346 } |
| 5347 |
| 5348 |
| 5323 void CodeGenerator::Comparison(AstNode* node, | 5349 void CodeGenerator::Comparison(AstNode* node, |
| 5324 Condition cc, | 5350 Condition cc, |
| 5325 bool strict, | 5351 bool strict, |
| 5326 ControlDestination* dest) { | 5352 ControlDestination* dest) { |
| 5327 // Strict only makes sense for equality comparisons. | 5353 // Strict only makes sense for equality comparisons. |
| 5328 ASSERT(!strict || cc == equal); | 5354 ASSERT(!strict || cc == equal); |
| 5329 | 5355 |
| 5330 Result left_side; | 5356 Result left_side; |
| 5331 Result right_side; | 5357 Result right_side; |
| 5332 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 5358 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5384 } | 5410 } |
| 5385 } else { | 5411 } else { |
| 5386 // Only one side is a constant Smi. | 5412 // Only one side is a constant Smi. |
| 5387 // If left side is a constant Smi, reverse the operands. | 5413 // If left side is a constant Smi, reverse the operands. |
| 5388 // Since one side is a constant Smi, conversion order does not matter. | 5414 // Since one side is a constant Smi, conversion order does not matter. |
| 5389 if (left_side_constant_smi) { | 5415 if (left_side_constant_smi) { |
| 5390 Result temp = left_side; | 5416 Result temp = left_side; |
| 5391 left_side = right_side; | 5417 left_side = right_side; |
| 5392 right_side = temp; | 5418 right_side = temp; |
| 5393 cc = ReverseCondition(cc); | 5419 cc = ReverseCondition(cc); |
| 5394 // This may reintroduce greater or less_equal as the value of cc. | 5420 // This may re-introduce greater or less_equal as the value of cc. |
| 5395 // CompareStub and the inline code both support all values of cc. | 5421 // CompareStub and the inline code both support all values of cc. |
| 5396 } | 5422 } |
| 5397 // Implement comparison against a constant Smi, inlining the case | 5423 // Implement comparison against a constant Smi, inlining the case |
| 5398 // where both sides are Smis. | 5424 // where both sides are Smis. |
| 5399 left_side.ToRegister(); | 5425 left_side.ToRegister(); |
| 5400 Register left_reg = left_side.reg(); | 5426 Register left_reg = left_side.reg(); |
| 5401 Handle<Object> right_val = right_side.handle(); | 5427 Handle<Object> right_val = right_side.handle(); |
| 5402 | 5428 |
| 5403 // Here we split control flow to the stub call and inlined cases | 5429 // Here we split control flow to the stub call and inlined cases |
| 5404 // before finally splitting it to the control destination. We use | 5430 // before finally splitting it to the control destination. We use |
| (...skipping 22 matching lines...) Expand all Loading... |
| 5427 } else { | 5453 } else { |
| 5428 Result temp = allocator()->Allocate(); | 5454 Result temp = allocator()->Allocate(); |
| 5429 __ movl(temp.reg(), Immediate(value)); | 5455 __ movl(temp.reg(), Immediate(value)); |
| 5430 __ cvtlsi2sd(xmm0, temp.reg()); | 5456 __ cvtlsi2sd(xmm0, temp.reg()); |
| 5431 temp.Unuse(); | 5457 temp.Unuse(); |
| 5432 } | 5458 } |
| 5433 __ ucomisd(xmm1, xmm0); | 5459 __ ucomisd(xmm1, xmm0); |
| 5434 // Jump to builtin for NaN. | 5460 // Jump to builtin for NaN. |
| 5435 not_number.Branch(parity_even, &left_side); | 5461 not_number.Branch(parity_even, &left_side); |
| 5436 left_side.Unuse(); | 5462 left_side.Unuse(); |
| 5437 Condition double_cc = cc; | 5463 dest->true_target()->Branch(DoubleCondition(cc)); |
| 5438 switch (cc) { | |
| 5439 case less: double_cc = below; break; | |
| 5440 case equal: double_cc = equal; break; | |
| 5441 case less_equal: double_cc = below_equal; break; | |
| 5442 case greater: double_cc = above; break; | |
| 5443 case greater_equal: double_cc = above_equal; break; | |
| 5444 default: UNREACHABLE(); | |
| 5445 } | |
| 5446 dest->true_target()->Branch(double_cc); | |
| 5447 dest->false_target()->Jump(); | 5464 dest->false_target()->Jump(); |
| 5448 not_number.Bind(&left_side); | 5465 not_number.Bind(&left_side); |
| 5449 } | 5466 } |
| 5450 | 5467 |
| 5451 // Setup and call the compare stub. | 5468 // Setup and call the compare stub. |
| 5452 CompareStub stub(cc, strict); | 5469 CompareStub stub(cc, strict, kCantBothBeNaN); |
| 5453 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 5470 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
| 5454 result.ToRegister(); | 5471 result.ToRegister(); |
| 5455 __ testq(result.reg(), result.reg()); | 5472 __ testq(result.reg(), result.reg()); |
| 5456 result.Unuse(); | 5473 result.Unuse(); |
| 5457 dest->true_target()->Branch(cc); | 5474 dest->true_target()->Branch(cc); |
| 5458 dest->false_target()->Jump(); | 5475 dest->false_target()->Jump(); |
| 5459 | 5476 |
| 5460 is_smi.Bind(); | 5477 is_smi.Bind(); |
| 5461 left_side = Result(left_reg); | 5478 left_side = Result(left_reg); |
| 5462 right_side = Result(right_val); | 5479 right_side = Result(right_val); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5635 temp2.Unuse(); | 5652 temp2.Unuse(); |
| 5636 left_side.Unuse(); | 5653 left_side.Unuse(); |
| 5637 right_side.Unuse(); | 5654 right_side.Unuse(); |
| 5638 dest->Split(cc); | 5655 dest->Split(cc); |
| 5639 } | 5656 } |
| 5640 } else { | 5657 } else { |
| 5641 // Neither side is a constant Smi, constant 1-char string, or constant null. | 5658 // Neither side is a constant Smi, constant 1-char string, or constant null. |
| 5642 // If either side is a non-smi constant, skip the smi check. | 5659 // If either side is a non-smi constant, skip the smi check. |
| 5643 bool known_non_smi = | 5660 bool known_non_smi = |
| 5644 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 5661 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
| 5645 (right_side.is_constant() && !right_side.handle()->IsSmi()); | 5662 (right_side.is_constant() && !right_side.handle()->IsSmi()) || |
| 5663 left_side.type_info().IsDouble() || |
| 5664 right_side.type_info().IsDouble(); |
| 5646 | 5665 |
| 5647 NaNInformation nan_info = | 5666 NaNInformation nan_info = |
| 5648 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? | 5667 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
| 5649 kBothCouldBeNaN : | 5668 kBothCouldBeNaN : |
| 5650 kCantBothBeNaN; | 5669 kCantBothBeNaN; |
| 5651 | 5670 |
| 5671 // Inline number comparison handling any combination of smi's and heap |
| 5672 // numbers if: |
| 5673 // code is in a loop |
| 5674 // the compare operation is different from equal |
| 5675 // compare is not a for-loop comparison |
| 5676 // The reason for excluding equal is that it will most likely be done |
| 5677 // with smi's (not heap numbers) and the code to comparing smi's is inlined |
| 5678 // separately. The same reason applies for for-loop comparison which will |
| 5679 // also most likely be smi comparisons. |
| 5680 bool is_loop_condition = (node->AsExpression() != NULL) |
| 5681 && node->AsExpression()->is_loop_condition(); |
| 5682 bool inline_number_compare = |
| 5683 loop_nesting() > 0 && cc != equal && !is_loop_condition; |
| 5684 |
| 5652 left_side.ToRegister(); | 5685 left_side.ToRegister(); |
| 5653 right_side.ToRegister(); | 5686 right_side.ToRegister(); |
| 5654 | 5687 |
| 5655 if (known_non_smi) { | 5688 if (known_non_smi) { |
| 5689 // Inlined equality check: |
| 5656 // If at least one of the objects is not NaN, then if the objects | 5690 // If at least one of the objects is not NaN, then if the objects |
| 5657 // are identical, they are equal. | 5691 // are identical, they are equal. |
| 5658 if (nan_info == kCantBothBeNaN && cc == equal) { | 5692 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 5659 __ cmpq(left_side.reg(), right_side.reg()); | 5693 __ cmpq(left_side.reg(), right_side.reg()); |
| 5660 dest->true_target()->Branch(equal); | 5694 dest->true_target()->Branch(equal); |
| 5661 } | 5695 } |
| 5662 | 5696 |
| 5663 // When non-smi, call out to the compare stub. | 5697 // Inlined number comparison: |
| 5664 CompareStub stub(cc, strict); | 5698 if (inline_number_compare) { |
| 5699 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 5700 } |
| 5701 |
| 5702 // Call the compare stub. |
| 5703 // TODO(whesse@chromium.org): Enable the inlining flag once |
| 5704 // GenerateInlineNumberComparison is implemented. |
| 5705 CompareStub stub(cc, strict, nan_info, true || !inline_number_compare); |
| 5665 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 5706 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
| 5666 // The result is a Smi, which is negative, zero, or positive. | 5707 // The result is a Smi, which is negative, zero, or positive. |
| 5667 __ SmiTest(answer.reg()); // Sets both zero and sign flag. | 5708 __ SmiTest(answer.reg()); // Sets both zero and sign flag. |
| 5668 answer.Unuse(); | 5709 answer.Unuse(); |
| 5669 dest->Split(cc); | 5710 dest->Split(cc); |
| 5670 } else { | 5711 } else { |
| 5671 // Here we split control flow to the stub call and inlined cases | 5712 // Here we split control flow to the stub call and inlined cases |
| 5672 // before finally splitting it to the control destination. We use | 5713 // before finally splitting it to the control destination. We use |
| 5673 // a jump target and branching to duplicate the virtual frame at | 5714 // a jump target and branching to duplicate the virtual frame at |
| 5674 // the first split. We manually handle the off-frame references | 5715 // the first split. We manually handle the off-frame references |
| 5675 // by reconstituting them on the non-fall-through path. | 5716 // by reconstituting them on the non-fall-through path. |
| 5676 JumpTarget is_smi; | 5717 JumpTarget is_smi; |
| 5677 Register left_reg = left_side.reg(); | 5718 Register left_reg = left_side.reg(); |
| 5678 Register right_reg = right_side.reg(); | 5719 Register right_reg = right_side.reg(); |
| 5679 | 5720 |
| 5680 Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); | 5721 Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); |
| 5681 is_smi.Branch(both_smi); | 5722 is_smi.Branch(both_smi); |
| 5682 // When non-smi, call out to the compare stub, after inlined checks. | 5723 |
| 5683 // If at least one of the objects is not NaN, then if the objects | 5724 // Inline the equality check if both operands can't be a NaN. If both |
| 5684 // are identical, they are equal. | 5725 // objects are the same they are equal. |
| 5685 if (nan_info == kCantBothBeNaN && cc == equal) { | 5726 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 5686 __ cmpq(left_side.reg(), right_side.reg()); | 5727 __ cmpq(left_side.reg(), right_side.reg()); |
| 5687 dest->true_target()->Branch(equal); | 5728 dest->true_target()->Branch(equal); |
| 5688 } | 5729 } |
| 5689 | 5730 |
| 5690 CompareStub stub(cc, strict); | 5731 // Inlined number comparison: |
| 5732 if (inline_number_compare) { |
| 5733 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 5734 } |
| 5735 |
| 5736 // Call the compare stub. |
| 5737 // TODO(whesse@chromium.org): Enable the inlining flag once |
| 5738 // GenerateInlineNumberComparison is implemented. |
| 5739 CompareStub stub(cc, strict, nan_info, true || !inline_number_compare); |
| 5691 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 5740 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
| 5692 __ SmiTest(answer.reg()); // Sets both zero and sign flags. | 5741 __ SmiTest(answer.reg()); // Sets both zero and sign flags. |
| 5693 answer.Unuse(); | 5742 answer.Unuse(); |
| 5694 dest->true_target()->Branch(cc); | 5743 dest->true_target()->Branch(cc); |
| 5695 dest->false_target()->Jump(); | 5744 dest->false_target()->Jump(); |
| 5696 | 5745 |
| 5697 is_smi.Bind(); | 5746 is_smi.Bind(); |
| 5698 left_side = Result(left_reg); | 5747 left_side = Result(left_reg); |
| 5699 right_side = Result(right_reg); | 5748 right_side = Result(right_reg); |
| 5700 __ SmiCompare(left_side.reg(), right_side.reg()); | 5749 __ SmiCompare(left_side.reg(), right_side.reg()); |
| 5701 right_side.Unuse(); | 5750 right_side.Unuse(); |
| 5702 left_side.Unuse(); | 5751 left_side.Unuse(); |
| 5703 dest->Split(cc); | 5752 dest->Split(cc); |
| 5704 } | 5753 } |
| 5705 } | 5754 } |
| 5706 } | 5755 } |
| 5707 | 5756 |
| 5708 | 5757 |
| 5758 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
| 5759 Result* right_side, |
| 5760 Condition cc, |
| 5761 ControlDestination* dest) { |
| 5762 ASSERT(left_side->is_register()); |
| 5763 ASSERT(right_side->is_register()); |
| 5764 // TODO(whesse@chromium.org): Implement this function, and enable the |
| 5765 // corresponding flags in the CompareStub. |
| 5766 } |
| 5767 |
| 5768 |
| 5709 class DeferredInlineBinaryOperation: public DeferredCode { | 5769 class DeferredInlineBinaryOperation: public DeferredCode { |
| 5710 public: | 5770 public: |
| 5711 DeferredInlineBinaryOperation(Token::Value op, | 5771 DeferredInlineBinaryOperation(Token::Value op, |
| 5712 Register dst, | 5772 Register dst, |
| 5713 Register left, | 5773 Register left, |
| 5714 Register right, | 5774 Register right, |
| 5715 OverwriteMode mode) | 5775 OverwriteMode mode) |
| 5716 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { | 5776 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { |
| 5717 set_comment("[ DeferredInlineBinaryOperation"); | 5777 set_comment("[ DeferredInlineBinaryOperation"); |
| 5718 } | 5778 } |
| (...skipping 2055 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7774 // Generate code to lookup number in the number string cache. | 7834 // Generate code to lookup number in the number string cache. |
| 7775 GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime); | 7835 GenerateLookupNumberStringCache(masm, rbx, rax, r8, r9, false, &runtime); |
| 7776 __ ret(1 * kPointerSize); | 7836 __ ret(1 * kPointerSize); |
| 7777 | 7837 |
| 7778 __ bind(&runtime); | 7838 __ bind(&runtime); |
| 7779 // Handle number to string in the runtime system if not found in the cache. | 7839 // Handle number to string in the runtime system if not found in the cache. |
| 7780 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); | 7840 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); |
| 7781 } | 7841 } |
| 7782 | 7842 |
| 7783 | 7843 |
| 7844 static int NegativeComparisonResult(Condition cc) { |
| 7845 ASSERT(cc != equal); |
| 7846 ASSERT((cc == less) || (cc == less_equal) |
| 7847 || (cc == greater) || (cc == greater_equal)); |
| 7848 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
| 7849 } |
| 7850 |
| 7784 void CompareStub::Generate(MacroAssembler* masm) { | 7851 void CompareStub::Generate(MacroAssembler* masm) { |
| 7785 Label call_builtin, done; | 7852 Label call_builtin, done; |
| 7786 | 7853 |
| 7787 // NOTICE! This code is only reached after a smi-fast-case check, so | 7854 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 7788 // it is certain that at least one operand isn't a smi. | 7855 // it is certain that at least one operand isn't a smi. |
| 7789 | 7856 |
| 7857 // Identical objects can be compared fast, but there are some tricky cases |
| 7858 // for NaN and undefined. |
| 7859 { |
| 7860 Label not_identical; |
| 7861 __ cmpq(rax, rdx); |
| 7862 __ j(not_equal, ¬_identical); |
| 7863 |
| 7864 if (cc_ != equal) { |
| 7865 // Check for undefined. undefined OP undefined is false even though |
| 7866 // undefined == undefined. |
| 7867 Label check_for_nan; |
| 7868 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 7869 __ j(not_equal, &check_for_nan); |
| 7870 __ Set(rax, NegativeComparisonResult(cc_)); |
| 7871 __ ret(0); |
| 7872 __ bind(&check_for_nan); |
| 7873 } |
| 7874 |
| 7875 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
| 7876 // so we do the second best thing - test it ourselves. |
| 7877 // Note: if cc_ != equal, never_nan_nan_ is not used. |
| 7878 if (never_nan_nan_ && (cc_ == equal)) { |
| 7879 __ Set(rax, EQUAL); |
| 7880 __ ret(0); |
| 7881 } else { |
| 7882 Label return_equal; |
| 7883 Label heap_number; |
| 7884 // If it's not a heap number, then return equal. |
| 7885 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
| 7886 Factory::heap_number_map()); |
| 7887 __ j(equal, &heap_number); |
| 7888 __ bind(&return_equal); |
| 7889 __ Set(rax, EQUAL); |
| 7890 __ ret(0); |
| 7891 |
| 7892 __ bind(&heap_number); |
| 7893 // It is a heap number, so return non-equal if it's NaN and equal if |
| 7894 // it's not NaN. |
| 7895 // The representation of NaN values has all exponent bits (52..62) set, |
| 7896 // and not all mantissa bits (0..51) clear. |
| 7897 // We only allow QNaNs, which have bit 51 set (which also rules out |
| 7898 // the value being Infinity). |
| 7899 |
| 7900 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., |
| 7901 // all bits in the mask are set. We only need to check the word |
| 7902 // that contains the exponent and high bit of the mantissa. |
| 7903 ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); |
| 7904 __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset)); |
| 7905 __ xorl(rax, rax); |
| 7906 __ addl(rdx, rdx); // Shift value and mask so mask applies to top bits. |
| 7907 __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1)); |
| 7908 if (cc_ == equal) { |
| 7909 __ setcc(above_equal, rax); |
| 7910 __ ret(0); |
| 7911 } else { |
| 7912 Label nan; |
| 7913 __ j(above_equal, &nan); |
| 7914 __ Set(rax, EQUAL); |
| 7915 __ ret(0); |
| 7916 __ bind(&nan); |
| 7917 __ Set(rax, NegativeComparisonResult(cc_)); |
| 7918 __ ret(0); |
| 7919 } |
| 7920 } |
| 7921 |
| 7922 __ bind(¬_identical); |
| 7923 } |
| 7924 |
| 7790 if (cc_ == equal) { // Both strict and non-strict. | 7925 if (cc_ == equal) { // Both strict and non-strict. |
| 7791 Label slow; // Fallthrough label. | 7926 Label slow; // Fallthrough label. |
| 7792 // Equality is almost reflexive (everything but NaN), so start by testing | |
| 7793 // for "identity and not NaN". | |
| 7794 { | |
| 7795 Label not_identical; | |
| 7796 __ cmpq(rax, rdx); | |
| 7797 __ j(not_equal, ¬_identical); | |
| 7798 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | |
| 7799 // so we do the second best thing - test it ourselves. | |
| 7800 | |
| 7801 if (never_nan_nan_) { | |
| 7802 __ xor_(rax, rax); | |
| 7803 __ ret(0); | |
| 7804 } else { | |
| 7805 Label return_equal; | |
| 7806 Label heap_number; | |
| 7807 // If it's not a heap number, then return equal. | |
| 7808 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | |
| 7809 Factory::heap_number_map()); | |
| 7810 __ j(equal, &heap_number); | |
| 7811 __ bind(&return_equal); | |
| 7812 __ xor_(rax, rax); | |
| 7813 __ ret(0); | |
| 7814 | |
| 7815 __ bind(&heap_number); | |
| 7816 // It is a heap number, so return non-equal if it's NaN and equal if | |
| 7817 // it's not NaN. | |
| 7818 // The representation of NaN values has all exponent bits (52..62) set, | |
| 7819 // and not all mantissa bits (0..51) clear. | |
| 7820 // We only allow QNaNs, which have bit 51 set (which also rules out | |
| 7821 // the value being Infinity). | |
| 7822 | |
| 7823 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., | |
| 7824 // all bits in the mask are set. We only need to check the word | |
| 7825 // that contains the exponent and high bit of the mantissa. | |
| 7826 ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); | |
| 7827 __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset)); | |
| 7828 __ xorl(rax, rax); | |
| 7829 __ addl(rdx, rdx); // Shift value and mask so mask applies to top bits. | |
| 7830 __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1)); | |
| 7831 __ setcc(above_equal, rax); | |
| 7832 __ ret(0); | |
| 7833 } | |
| 7834 | |
| 7835 __ bind(¬_identical); | |
| 7836 } | |
| 7837 | 7927 |
| 7838 // If we're doing a strict equality comparison, we don't have to do | 7928 // If we're doing a strict equality comparison, we don't have to do |
| 7839 // type conversion, so we generate code to do fast comparison for objects | 7929 // type conversion, so we generate code to do fast comparison for objects |
| 7840 // and oddballs. Non-smi numbers and strings still go through the usual | 7930 // and oddballs. Non-smi numbers and strings still go through the usual |
| 7841 // slow-case code. | 7931 // slow-case code. |
| 7842 if (strict_) { | 7932 if (strict_) { |
| 7843 // If either is a Smi (we know that not both are), then they can only | 7933 // If either is a Smi (we know that not both are), then they can only |
| 7844 // be equal if the other is a HeapNumber. If so, use the slow case. | 7934 // be equal if the other is a HeapNumber. If so, use the slow case. |
| 7845 { | 7935 { |
| 7846 Label not_smis; | 7936 Label not_smis; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7889 } | 7979 } |
| 7890 __ bind(&slow); | 7980 __ bind(&slow); |
| 7891 } | 7981 } |
| 7892 | 7982 |
| 7893 // Push arguments below the return address to prepare jump to builtin. | 7983 // Push arguments below the return address to prepare jump to builtin. |
| 7894 __ pop(rcx); | 7984 __ pop(rcx); |
| 7895 __ push(rax); | 7985 __ push(rax); |
| 7896 __ push(rdx); | 7986 __ push(rdx); |
| 7897 __ push(rcx); | 7987 __ push(rcx); |
| 7898 | 7988 |
| 7899 // Inlined floating point compare. | 7989 // Generate the number comparison code. |
| 7900 // Call builtin if operands are not floating point or smi. | 7990 if (include_number_compare_) { |
| 7901 Label check_for_symbols; | 7991 Label non_number_comparison; |
| 7902 // Push arguments on stack, for helper functions. | 7992 Label unordered; |
| 7903 FloatingPointHelper::CheckNumberOperands(masm, &check_for_symbols); | 7993 FloatingPointHelper::LoadFloatOperand(masm, rdx, xmm0, |
| 7904 FloatingPointHelper::LoadFloatOperands(masm, rax, rdx); | 7994 &non_number_comparison); |
| 7905 __ FCmp(); | 7995 FloatingPointHelper::LoadFloatOperand(masm, rax, xmm1, |
| 7996 &non_number_comparison); |
| 7906 | 7997 |
| 7907 // Jump to builtin for NaN. | 7998 __ comisd(xmm0, xmm1); |
| 7908 __ j(parity_even, &call_builtin); | |
| 7909 | 7999 |
| 7910 // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up. | 8000 // Don't base result on EFLAGS when a NaN is involved. |
| 7911 Label below_lbl, above_lbl; | 8001 __ j(parity_even, &unordered); |
| 7912 // use rdx, rax to convert unsigned to signed comparison | 8002 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 7913 __ j(below, &below_lbl); | 8003 __ movq(rax, Immediate(0)); // equal |
| 7914 __ j(above, &above_lbl); | 8004 __ movq(rcx, Immediate(1)); |
| 8005 __ cmovq(above, rax, rcx); |
| 8006 __ movq(rcx, Immediate(-1)); |
| 8007 __ cmovq(below, rax, rcx); |
| 8008 __ ret(2 * kPointerSize); // rax, rdx were pushed |
| 7915 | 8009 |
| 7916 __ xor_(rax, rax); // equal | 8010 // If one of the numbers was NaN, then the result is always false. |
| 7917 __ ret(2 * kPointerSize); | 8011 // The cc is never not-equal. |
| 8012 __ bind(&unordered); |
| 8013 ASSERT(cc_ != not_equal); |
| 8014 if (cc_ == less || cc_ == less_equal) { |
| 8015 __ Set(rax, 1); |
| 8016 } else { |
| 8017 __ Set(rax, -1); |
| 8018 } |
| 8019 __ ret(2 * kPointerSize); // rax, rdx were pushed |
| 7918 | 8020 |
| 7919 __ bind(&below_lbl); | 8021 // The number comparison code did not provide a valid result. |
| 7920 __ movq(rax, Immediate(-1)); | 8022 __ bind(&non_number_comparison); |
| 7921 __ ret(2 * kPointerSize); | 8023 } |
| 7922 | |
| 7923 __ bind(&above_lbl); | |
| 7924 __ movq(rax, Immediate(1)); | |
| 7925 __ ret(2 * kPointerSize); // rax, rdx were pushed | |
| 7926 | 8024 |
| 7927 // Fast negative check for symbol-to-symbol equality. | 8025 // Fast negative check for symbol-to-symbol equality. |
| 7928 __ bind(&check_for_symbols); | |
| 7929 Label check_for_strings; | 8026 Label check_for_strings; |
| 7930 if (cc_ == equal) { | 8027 if (cc_ == equal) { |
| 7931 BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); | 8028 BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister); |
| 7932 BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); | 8029 BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister); |
| 7933 | 8030 |
| 7934 // We've already checked for object identity, so if both operands | 8031 // We've already checked for object identity, so if both operands |
| 7935 // are symbols they aren't equal. Register eax (not rax) already holds a | 8032 // are symbols they aren't equal. Register eax (not rax) already holds a |
| 7936 // non-zero value, which indicates not equal, so just return. | 8033 // non-zero value, which indicates not equal, so just return. |
| 7937 __ ret(2 * kPointerSize); | 8034 __ ret(2 * kPointerSize); |
| 7938 } | 8035 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 7961 __ pop(rax); | 8058 __ pop(rax); |
| 7962 __ push(rdx); | 8059 __ push(rdx); |
| 7963 __ push(rax); | 8060 __ push(rax); |
| 7964 | 8061 |
| 7965 // Figure out which native to call and setup the arguments. | 8062 // Figure out which native to call and setup the arguments. |
| 7966 Builtins::JavaScript builtin; | 8063 Builtins::JavaScript builtin; |
| 7967 if (cc_ == equal) { | 8064 if (cc_ == equal) { |
| 7968 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 8065 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
| 7969 } else { | 8066 } else { |
| 7970 builtin = Builtins::COMPARE; | 8067 builtin = Builtins::COMPARE; |
| 7971 int ncr; // NaN compare result | 8068 __ push(Immediate(NegativeComparisonResult(cc_))); |
| 7972 if (cc_ == less || cc_ == less_equal) { | |
| 7973 ncr = GREATER; | |
| 7974 } else { | |
| 7975 ASSERT(cc_ == greater || cc_ == greater_equal); // remaining cases | |
| 7976 ncr = LESS; | |
| 7977 } | |
| 7978 __ Push(Smi::FromInt(ncr)); | |
| 7979 } | 8069 } |
| 7980 | 8070 |
| 7981 // Restore return address on the stack. | 8071 // Restore return address on the stack. |
| 7982 __ push(rcx); | 8072 __ push(rcx); |
| 7983 | 8073 |
| 7984 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 8074 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| 7985 // tagged as a small integer. | 8075 // tagged as a small integer. |
| 7986 __ InvokeBuiltin(builtin, JUMP_FUNCTION); | 8076 __ InvokeBuiltin(builtin, JUMP_FUNCTION); |
| 7987 } | 8077 } |
| 7988 | 8078 |
| (...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8757 __ jmp(&done); | 8847 __ jmp(&done); |
| 8758 | 8848 |
| 8759 __ bind(&load_smi); | 8849 __ bind(&load_smi); |
| 8760 __ SmiToInteger32(src, src); | 8850 __ SmiToInteger32(src, src); |
| 8761 __ cvtlsi2sd(dst, src); | 8851 __ cvtlsi2sd(dst, src); |
| 8762 | 8852 |
| 8763 __ bind(&done); | 8853 __ bind(&done); |
| 8764 } | 8854 } |
| 8765 | 8855 |
| 8766 | 8856 |
| 8857 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| 8858 Register src, |
| 8859 XMMRegister dst, |
| 8860 Label* not_number) { |
| 8861 Label load_smi, done; |
| 8862 ASSERT(!src.is(kScratchRegister)); |
| 8863 __ JumpIfSmi(src, &load_smi); |
| 8864 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); |
| 8865 __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister); |
| 8866 __ j(not_equal, not_number); |
| 8867 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); |
| 8868 __ jmp(&done); |
| 8869 |
| 8870 __ bind(&load_smi); |
| 8871 __ SmiToInteger32(kScratchRegister, src); |
| 8872 __ cvtlsi2sd(dst, kScratchRegister); |
| 8873 |
| 8874 __ bind(&done); |
| 8875 } |
| 8876 |
| 8877 |
| 8767 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 8878 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| 8768 XMMRegister dst1, | 8879 XMMRegister dst1, |
| 8769 XMMRegister dst2) { | 8880 XMMRegister dst2) { |
| 8770 __ movq(kScratchRegister, rdx); | 8881 __ movq(kScratchRegister, rdx); |
| 8771 LoadFloatOperand(masm, kScratchRegister, dst1); | 8882 LoadFloatOperand(masm, kScratchRegister, dst1); |
| 8772 __ movq(kScratchRegister, rax); | 8883 __ movq(kScratchRegister, rax); |
| 8773 LoadFloatOperand(masm, kScratchRegister, dst2); | 8884 LoadFloatOperand(masm, kScratchRegister, dst2); |
| 8774 } | 8885 } |
| 8775 | 8886 |
| 8776 | 8887 |
| (...skipping 1708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10485 // Call the function from C++. | 10596 // Call the function from C++. |
| 10486 return FUNCTION_CAST<ModuloFunction>(buffer); | 10597 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 10487 } | 10598 } |
| 10488 | 10599 |
| 10489 #endif | 10600 #endif |
| 10490 | 10601 |
| 10491 | 10602 |
| 10492 #undef __ | 10603 #undef __ |
| 10493 | 10604 |
| 10494 } } // namespace v8::internal | 10605 } } // namespace v8::internal |
| OLD | NEW |