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 5690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5701 __ cmpb(temp.reg(), | 5701 __ cmpb(temp.reg(), |
5702 Immediate(kStringTag | kSeqStringTag | kAsciiStringTag)); | 5702 Immediate(kStringTag | kSeqStringTag | kAsciiStringTag)); |
5703 temp.Unuse(); | 5703 temp.Unuse(); |
5704 is_string.Branch(equal, &left_side); | 5704 is_string.Branch(equal, &left_side); |
5705 | 5705 |
5706 // Setup and call the compare stub. | 5706 // Setup and call the compare stub. |
5707 is_not_string.Bind(&left_side); | 5707 is_not_string.Bind(&left_side); |
5708 CompareStub stub(cc, strict, kCantBothBeNaN); | 5708 CompareStub stub(cc, strict, kCantBothBeNaN); |
5709 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 5709 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
5710 result.ToRegister(); | 5710 result.ToRegister(); |
5711 __ SmiCompare(result.reg(), Smi::FromInt(0)); | 5711 __ testq(result.reg(), result.reg()); |
5712 result.Unuse(); | 5712 result.Unuse(); |
5713 dest->true_target()->Branch(cc); | 5713 dest->true_target()->Branch(cc); |
5714 dest->false_target()->Jump(); | 5714 dest->false_target()->Jump(); |
5715 | 5715 |
5716 is_string.Bind(&left_side); | 5716 is_string.Bind(&left_side); |
5717 // left_side is a sequential ASCII string. | 5717 // left_side is a sequential ASCII string. |
5718 ASSERT(left_side.reg().is(left_reg)); | 5718 ASSERT(left_side.reg().is(left_reg)); |
5719 right_side = Result(right_val); | 5719 right_side = Result(right_val); |
5720 Result temp2 = allocator_->Allocate(); | 5720 Result temp2 = allocator_->Allocate(); |
5721 ASSERT(temp2.is_valid()); | 5721 ASSERT(temp2.is_valid()); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5798 if (nan_info == kCantBothBeNaN && cc == equal) { | 5798 if (nan_info == kCantBothBeNaN && cc == equal) { |
5799 __ cmpq(left_side.reg(), right_side.reg()); | 5799 __ cmpq(left_side.reg(), right_side.reg()); |
5800 dest->true_target()->Branch(equal); | 5800 dest->true_target()->Branch(equal); |
5801 } | 5801 } |
5802 | 5802 |
5803 // Inlined number comparison: | 5803 // Inlined number comparison: |
5804 if (inline_number_compare) { | 5804 if (inline_number_compare) { |
5805 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 5805 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
5806 } | 5806 } |
5807 | 5807 |
5808 // Call the compare stub. | 5808 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
5809 // TODO(whesse@chromium.org): Enable the inlining flag once | |
5810 // GenerateInlineNumberComparison is implemented. | |
5811 CompareStub stub(cc, strict, nan_info, true || !inline_number_compare); | |
5812 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 5809 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
5813 // The result is a Smi, which is negative, zero, or positive. | 5810 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flag. |
5814 __ SmiTest(answer.reg()); // Sets both zero and sign flag. | |
5815 answer.Unuse(); | 5811 answer.Unuse(); |
5816 dest->Split(cc); | 5812 dest->Split(cc); |
5817 } else { | 5813 } else { |
5818 // Here we split control flow to the stub call and inlined cases | 5814 // Here we split control flow to the stub call and inlined cases |
5819 // before finally splitting it to the control destination. We use | 5815 // before finally splitting it to the control destination. We use |
5820 // a jump target and branching to duplicate the virtual frame at | 5816 // a jump target and branching to duplicate the virtual frame at |
5821 // the first split. We manually handle the off-frame references | 5817 // the first split. We manually handle the off-frame references |
5822 // by reconstituting them on the non-fall-through path. | 5818 // by reconstituting them on the non-fall-through path. |
5823 JumpTarget is_smi; | 5819 JumpTarget is_smi; |
5824 Register left_reg = left_side.reg(); | 5820 Register left_reg = left_side.reg(); |
5825 Register right_reg = right_side.reg(); | 5821 Register right_reg = right_side.reg(); |
5826 | 5822 |
5827 Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); | 5823 Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg); |
5828 is_smi.Branch(both_smi); | 5824 is_smi.Branch(both_smi); |
5829 | 5825 |
5830 // Inline the equality check if both operands can't be a NaN. If both | 5826 // Inline the equality check if both operands can't be a NaN. If both |
5831 // objects are the same they are equal. | 5827 // objects are the same they are equal. |
5832 if (nan_info == kCantBothBeNaN && cc == equal) { | 5828 if (nan_info == kCantBothBeNaN && cc == equal) { |
5833 __ cmpq(left_side.reg(), right_side.reg()); | 5829 __ cmpq(left_side.reg(), right_side.reg()); |
5834 dest->true_target()->Branch(equal); | 5830 dest->true_target()->Branch(equal); |
5835 } | 5831 } |
5836 | 5832 |
5837 // Inlined number comparison: | 5833 // Inlined number comparison: |
5838 if (inline_number_compare) { | 5834 if (inline_number_compare) { |
5839 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 5835 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
5840 } | 5836 } |
5841 | 5837 |
5842 // Call the compare stub. | 5838 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
5843 // TODO(whesse@chromium.org): Enable the inlining flag once | |
5844 // GenerateInlineNumberComparison is implemented. | |
5845 CompareStub stub(cc, strict, nan_info, true || !inline_number_compare); | |
5846 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 5839 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
5847 __ SmiTest(answer.reg()); // Sets both zero and sign flags. | 5840 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flags. |
5848 answer.Unuse(); | 5841 answer.Unuse(); |
5849 dest->true_target()->Branch(cc); | 5842 dest->true_target()->Branch(cc); |
5850 dest->false_target()->Jump(); | 5843 dest->false_target()->Jump(); |
5851 | 5844 |
5852 is_smi.Bind(); | 5845 is_smi.Bind(); |
5853 left_side = Result(left_reg); | 5846 left_side = Result(left_reg); |
5854 right_side = Result(right_reg); | 5847 right_side = Result(right_reg); |
5855 __ SmiCompare(left_side.reg(), right_side.reg()); | 5848 __ SmiCompare(left_side.reg(), right_side.reg()); |
5856 right_side.Unuse(); | 5849 right_side.Unuse(); |
5857 left_side.Unuse(); | 5850 left_side.Unuse(); |
5858 dest->Split(cc); | 5851 dest->Split(cc); |
5859 } | 5852 } |
5860 } | 5853 } |
5861 } | 5854 } |
5862 | 5855 |
5863 | 5856 |
| 5857 // Load a comparison operand into into a XMM register. Jump to not_numbers jump |
| 5858 // target passing the left and right result if the operand is not a number. |
| 5859 static void LoadComparisonOperand(MacroAssembler* masm_, |
| 5860 Result* operand, |
| 5861 XMMRegister xmm_reg, |
| 5862 Result* left_side, |
| 5863 Result* right_side, |
| 5864 JumpTarget* not_numbers) { |
| 5865 Label done; |
| 5866 if (operand->type_info().IsDouble()) { |
| 5867 // Operand is known to be a heap number, just load it. |
| 5868 __ movsd(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 5869 } else if (operand->type_info().IsSmi()) { |
| 5870 // Operand is known to be a smi. Convert it to double and keep the original |
| 5871 // smi. |
| 5872 __ SmiToInteger32(kScratchRegister, operand->reg()); |
| 5873 __ cvtlsi2sd(xmm_reg, kScratchRegister); |
| 5874 } else { |
| 5875 // Operand type not known, check for smi or heap number. |
| 5876 Label smi; |
| 5877 __ JumpIfSmi(operand->reg(), &smi); |
| 5878 if (!operand->type_info().IsNumber()) { |
| 5879 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex); |
| 5880 __ cmpq(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
| 5881 kScratchRegister); |
| 5882 not_numbers->Branch(not_equal, left_side, right_side, taken); |
| 5883 } |
| 5884 __ movsd(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 5885 __ jmp(&done); |
| 5886 |
| 5887 __ bind(&smi); |
| 5888 // Comvert smi to float and keep the original smi. |
| 5889 __ SmiToInteger32(kScratchRegister, operand->reg()); |
| 5890 __ cvtlsi2sd(xmm_reg, kScratchRegister); |
| 5891 __ jmp(&done); |
| 5892 } |
| 5893 __ bind(&done); |
| 5894 } |
| 5895 |
| 5896 |
5864 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | 5897 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
5865 Result* right_side, | 5898 Result* right_side, |
5866 Condition cc, | 5899 Condition cc, |
5867 ControlDestination* dest) { | 5900 ControlDestination* dest) { |
5868 ASSERT(left_side->is_register()); | 5901 ASSERT(left_side->is_register()); |
5869 ASSERT(right_side->is_register()); | 5902 ASSERT(right_side->is_register()); |
5870 // TODO(whesse@chromium.org): Implement this function, and enable the | 5903 |
5871 // corresponding flags in the CompareStub. | 5904 JumpTarget not_numbers; |
| 5905 // Load left and right operand into registers xmm0 and xmm1 and compare. |
| 5906 LoadComparisonOperand(masm_, left_side, xmm0, left_side, right_side, |
| 5907 ¬_numbers); |
| 5908 LoadComparisonOperand(masm_, right_side, xmm1, left_side, right_side, |
| 5909 ¬_numbers); |
| 5910 __ comisd(xmm0, xmm1); |
| 5911 // Bail out if a NaN is involved. |
| 5912 not_numbers.Branch(parity_even, left_side, right_side); |
| 5913 |
| 5914 // Split to destination targets based on comparison. |
| 5915 left_side->Unuse(); |
| 5916 right_side->Unuse(); |
| 5917 dest->true_target()->Branch(DoubleCondition(cc)); |
| 5918 dest->false_target()->Jump(); |
| 5919 |
| 5920 not_numbers.Bind(left_side, right_side); |
5872 } | 5921 } |
5873 | 5922 |
5874 | 5923 |
5875 class DeferredInlineBinaryOperation: public DeferredCode { | 5924 class DeferredInlineBinaryOperation: public DeferredCode { |
5876 public: | 5925 public: |
5877 DeferredInlineBinaryOperation(Token::Value op, | 5926 DeferredInlineBinaryOperation(Token::Value op, |
5878 Register dst, | 5927 Register dst, |
5879 Register left, | 5928 Register left, |
5880 Register right, | 5929 Register right, |
5881 OverwriteMode mode) | 5930 OverwriteMode mode) |
(...skipping 2102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7984 | 8033 |
7985 static int NegativeComparisonResult(Condition cc) { | 8034 static int NegativeComparisonResult(Condition cc) { |
7986 ASSERT(cc != equal); | 8035 ASSERT(cc != equal); |
7987 ASSERT((cc == less) || (cc == less_equal) | 8036 ASSERT((cc == less) || (cc == less_equal) |
7988 || (cc == greater) || (cc == greater_equal)); | 8037 || (cc == greater) || (cc == greater_equal)); |
7989 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 8038 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
7990 } | 8039 } |
7991 | 8040 |
7992 void CompareStub::Generate(MacroAssembler* masm) { | 8041 void CompareStub::Generate(MacroAssembler* masm) { |
7993 Label call_builtin, done; | 8042 Label call_builtin, done; |
7994 | 8043 // The compare stub returns a positive, negative, or zero 64-bit |
| 8044 // integer value in rax, corresponding to the relation of the two objects. |
7995 // NOTICE! This code is only reached after a smi-fast-case check, so | 8045 // NOTICE! This code is only reached after a smi-fast-case check, so |
7996 // it is certain that at least one operand isn't a smi. | 8046 // it is certain that at least one operand isn't a smi. |
7997 | 8047 |
7998 // Identical objects can be compared fast, but there are some tricky cases | 8048 // Two identical objects are equal unless they are both NaN or undefined. |
7999 // for NaN and undefined. | |
8000 { | 8049 { |
8001 Label not_identical; | 8050 Label not_identical; |
8002 __ cmpq(rax, rdx); | 8051 __ cmpq(rax, rdx); |
8003 __ j(not_equal, ¬_identical); | 8052 __ j(not_equal, ¬_identical); |
8004 | 8053 |
8005 if (cc_ != equal) { | 8054 if (cc_ != equal) { |
8006 // Check for undefined. undefined OP undefined is false even though | 8055 // Check for undefined. undefined OP undefined is false even though |
8007 // undefined == undefined. | 8056 // undefined == undefined. |
8008 Label check_for_nan; | 8057 Label check_for_nan; |
8009 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | 8058 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); |
(...skipping 2867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10877 // Call the function from C++. | 10926 // Call the function from C++. |
10878 return FUNCTION_CAST<ModuloFunction>(buffer); | 10927 return FUNCTION_CAST<ModuloFunction>(buffer); |
10879 } | 10928 } |
10880 | 10929 |
10881 #endif | 10930 #endif |
10882 | 10931 |
10883 | 10932 |
10884 #undef __ | 10933 #undef __ |
10885 | 10934 |
10886 } } // namespace v8::internal | 10935 } } // namespace v8::internal |
OLD | NEW |