| 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 |