Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-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 1773 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1784 LikelySmiBinaryOperation(op, operand, &constant_operand, | 1784 LikelySmiBinaryOperation(op, operand, &constant_operand, |
| 1785 overwrite_mode); | 1785 overwrite_mode); |
| 1786 } | 1786 } |
| 1787 break; | 1787 break; |
| 1788 } | 1788 } |
| 1789 } | 1789 } |
| 1790 ASSERT(!operand->is_valid()); | 1790 ASSERT(!operand->is_valid()); |
| 1791 } | 1791 } |
| 1792 | 1792 |
| 1793 | 1793 |
| 1794 void CodeGenerator::Comparison(Condition cc, | 1794 void CodeGenerator::Comparison(AstNode* node, |
| 1795 Condition cc, | |
| 1795 bool strict, | 1796 bool strict, |
| 1796 ControlDestination* dest) { | 1797 ControlDestination* dest) { |
| 1797 // Strict only makes sense for equality comparisons. | 1798 // Strict only makes sense for equality comparisons. |
| 1798 ASSERT(!strict || cc == equal); | 1799 ASSERT(!strict || cc == equal); |
| 1799 | 1800 |
| 1800 Result left_side; | 1801 Result left_side; |
| 1801 Result right_side; | 1802 Result right_side; |
| 1802 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1803 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1803 if (cc == greater || cc == less_equal) { | 1804 if (cc == greater || cc == less_equal) { |
| 1804 cc = ReverseCondition(cc); | 1805 cc = ReverseCondition(cc); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1831 break; | 1832 break; |
| 1832 case equal: | 1833 case equal: |
| 1833 dest->Goto(left_value == right_value); | 1834 dest->Goto(left_value == right_value); |
| 1834 break; | 1835 break; |
| 1835 case greater_equal: | 1836 case greater_equal: |
| 1836 dest->Goto(left_value >= right_value); | 1837 dest->Goto(left_value >= right_value); |
| 1837 break; | 1838 break; |
| 1838 default: | 1839 default: |
| 1839 UNREACHABLE(); | 1840 UNREACHABLE(); |
| 1840 } | 1841 } |
| 1841 } else { // Only one side is a constant Smi. | 1842 } else { |
| 1843 // Only one side is a constant Smi. | |
| 1842 // If left side is a constant Smi, reverse the operands. | 1844 // If left side is a constant Smi, reverse the operands. |
| 1843 // Since one side is a constant Smi, conversion order does not matter. | 1845 // Since one side is a constant Smi, conversion order does not matter. |
| 1844 if (left_side_constant_smi) { | 1846 if (left_side_constant_smi) { |
| 1845 Result temp = left_side; | 1847 Result temp = left_side; |
| 1846 left_side = right_side; | 1848 left_side = right_side; |
| 1847 right_side = temp; | 1849 right_side = temp; |
| 1848 cc = ReverseCondition(cc); | 1850 cc = ReverseCondition(cc); |
| 1849 // This may reintroduce greater or less_equal as the value of cc. | 1851 // This may reintroduce greater or less_equal as the value of cc. |
| 1850 // CompareStub and the inline code both support all values of cc. | 1852 // CompareStub and the inline code both support all values of cc. |
| 1851 } | 1853 } |
| 1852 // Implement comparison against a constant Smi, inlining the case | 1854 // Implement comparison against a constant Smi, inlining the case |
| 1853 // where both sides are Smis. | 1855 // where both sides are Smis. |
| 1854 left_side.ToRegister(); | 1856 left_side.ToRegister(); |
| 1857 Register left_reg = left_side.reg(); | |
| 1858 Handle<Object> right_val = right_side.handle(); | |
| 1855 | 1859 |
| 1856 // Here we split control flow to the stub call and inlined cases | 1860 // Here we split control flow to the stub call and inlined cases |
| 1857 // before finally splitting it to the control destination. We use | 1861 // before finally splitting it to the control destination. We use |
| 1858 // a jump target and branching to duplicate the virtual frame at | 1862 // a jump target and branching to duplicate the virtual frame at |
| 1859 // the first split. We manually handle the off-frame references | 1863 // the first split. We manually handle the off-frame references |
| 1860 // by reconstituting them on the non-fall-through path. | 1864 // by reconstituting them on the non-fall-through path. |
| 1861 JumpTarget is_smi; | 1865 JumpTarget is_smi; |
| 1862 Register left_reg = left_side.reg(); | |
| 1863 Handle<Object> right_val = right_side.handle(); | |
| 1864 __ test(left_side.reg(), Immediate(kSmiTagMask)); | 1866 __ test(left_side.reg(), Immediate(kSmiTagMask)); |
| 1865 is_smi.Branch(zero, taken); | 1867 is_smi.Branch(zero, taken); |
| 1866 | 1868 |
| 1869 bool is_for_loop_compare = node->AsCompareOperation() | |
|
iposva
2009/12/17 21:03:50
Shouldn't you do a " != NULL" here?
bakster
2009/12/18 06:38:47
Done.
| |
| 1870 && node->AsCompareOperation()->is_for_loop_condition(); | |
| 1871 if (!is_for_loop_compare | |
| 1872 && CpuFeatures::IsSupported(SSE2) | |
| 1873 && right_val->IsSmi()) { | |
| 1874 // The right side value is either a smi or heap number. | |
|
iposva
2009/12/17 21:03:50
Comment does not match the check. Right side is a
bakster
2009/12/18 06:38:47
Done.
| |
| 1875 CpuFeatures::Scope use_sse2(SSE2); | |
| 1876 JumpTarget not_number; | |
| 1877 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | |
| 1878 Immediate(Factory::heap_number_map())); | |
| 1879 not_number.Branch(not_equal, &left_side); | |
| 1880 __ movdbl(xmm1, | |
| 1881 FieldOperand(left_reg, HeapNumber::kValueOffset)); | |
| 1882 int value = Smi::cast(*right_val)->value(); | |
| 1883 if (value == 0) { | |
| 1884 __ xorpd(xmm0, xmm0); | |
| 1885 } else { | |
| 1886 Result temp = allocator()->Allocate(); | |
| 1887 __ mov (temp.reg(), Immediate(value)); | |
| 1888 __ cvtsi2sd(xmm0, Operand(temp.reg())); | |
|
iposva
2009/12/17 21:03:50
Why do you keep converting the value to double fro
bakster
2009/12/18 06:38:47
I'm not sure it makes a difference. I'll try the o
| |
| 1889 temp.Unuse(); | |
| 1890 } | |
| 1891 __ comisd(xmm1, xmm0); | |
| 1892 // Jump to builtin for NaN. | |
| 1893 not_number.Branch(parity_even, &left_side); | |
| 1894 left_side.Unuse(); | |
| 1895 Condition double_cc = cc; | |
| 1896 switch (cc) { | |
| 1897 case less: double_cc = below; break; | |
| 1898 case equal: double_cc = equal; break; | |
| 1899 case less_equal: double_cc = below_equal; break; | |
| 1900 case greater: double_cc = above; break; | |
| 1901 case greater_equal: double_cc = above_equal; break; | |
| 1902 default: UNREACHABLE(); | |
| 1903 } | |
| 1904 dest->true_target()->Branch(double_cc); | |
| 1905 dest->false_target()->Jump(); | |
| 1906 not_number.Bind(&left_side); | |
| 1907 } | |
| 1908 | |
| 1867 // Setup and call the compare stub. | 1909 // Setup and call the compare stub. |
| 1868 CompareStub stub(cc, strict); | 1910 CompareStub stub(cc, strict); |
| 1869 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 1911 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
| 1870 result.ToRegister(); | 1912 result.ToRegister(); |
| 1871 __ cmp(result.reg(), 0); | 1913 __ cmp(result.reg(), 0); |
| 1872 result.Unuse(); | 1914 result.Unuse(); |
| 1873 dest->true_target()->Branch(cc); | 1915 dest->true_target()->Branch(cc); |
| 1874 dest->false_target()->Jump(); | 1916 dest->false_target()->Jump(); |
| 1875 | 1917 |
| 1876 is_smi.Bind(); | 1918 is_smi.Bind(); |
| 1877 left_side = Result(left_reg); | 1919 left_side = Result(left_reg); |
| 1878 right_side = Result(right_val); | 1920 right_side = Result(right_val); |
| 1879 // Test smi equality and comparison by signed int comparison. | 1921 // Test smi equality and comparison by signed int comparison. |
| 1880 if (IsUnsafeSmi(right_side.handle())) { | 1922 if (IsUnsafeSmi(right_side.handle())) { |
| 1881 right_side.ToRegister(); | 1923 right_side.ToRegister(); |
| 1882 __ cmp(left_side.reg(), Operand(right_side.reg())); | 1924 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 1883 } else { | 1925 } else { |
| 1884 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); | 1926 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); |
| 1885 } | 1927 } |
| 1886 left_side.Unuse(); | 1928 left_side.Unuse(); |
| 1887 right_side.Unuse(); | 1929 right_side.Unuse(); |
| 1888 dest->Split(cc); | 1930 dest->Split(cc); |
| 1889 } | 1931 } |
| 1932 | |
| 1890 } else if (cc == equal && | 1933 } else if (cc == equal && |
| 1891 (left_side_constant_null || right_side_constant_null)) { | 1934 (left_side_constant_null || right_side_constant_null)) { |
| 1892 // To make null checks efficient, we check if either the left side or | 1935 // To make null checks efficient, we check if either the left side or |
| 1893 // the right side is the constant 'null'. | 1936 // the right side is the constant 'null'. |
| 1894 // If so, we optimize the code by inlining a null check instead of | 1937 // If so, we optimize the code by inlining a null check instead of |
| 1895 // calling the (very) general runtime routine for checking equality. | 1938 // calling the (very) general runtime routine for checking equality. |
| 1896 Result operand = left_side_constant_null ? right_side : left_side; | 1939 Result operand = left_side_constant_null ? right_side : left_side; |
| 1897 right_side.Unuse(); | 1940 right_side.Unuse(); |
| 1898 left_side.Unuse(); | 1941 left_side.Unuse(); |
| 1899 operand.ToRegister(); | 1942 operand.ToRegister(); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1916 ASSERT(temp.is_valid()); | 1959 ASSERT(temp.is_valid()); |
| 1917 __ mov(temp.reg(), | 1960 __ mov(temp.reg(), |
| 1918 FieldOperand(operand.reg(), HeapObject::kMapOffset)); | 1961 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
| 1919 __ movzx_b(temp.reg(), | 1962 __ movzx_b(temp.reg(), |
| 1920 FieldOperand(temp.reg(), Map::kBitFieldOffset)); | 1963 FieldOperand(temp.reg(), Map::kBitFieldOffset)); |
| 1921 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); | 1964 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); |
| 1922 temp.Unuse(); | 1965 temp.Unuse(); |
| 1923 operand.Unuse(); | 1966 operand.Unuse(); |
| 1924 dest->Split(not_zero); | 1967 dest->Split(not_zero); |
| 1925 } | 1968 } |
| 1926 } else { // Neither side is a constant Smi or null. | 1969 } else { |
| 1970 // Neither side is a constant Smi or null. | |
| 1927 // If either side is a non-smi constant, skip the smi check. | 1971 // If either side is a non-smi constant, skip the smi check. |
| 1928 bool known_non_smi = | 1972 bool known_non_smi = |
| 1929 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 1973 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
| 1930 (right_side.is_constant() && !right_side.handle()->IsSmi()); | 1974 (right_side.is_constant() && !right_side.handle()->IsSmi()); |
| 1931 left_side.ToRegister(); | 1975 left_side.ToRegister(); |
| 1932 right_side.ToRegister(); | 1976 right_side.ToRegister(); |
| 1933 | 1977 |
| 1934 if (known_non_smi) { | 1978 if (known_non_smi) { |
| 1935 // When non-smi, call out to the compare stub. | 1979 // When non-smi, call out to the compare stub. |
| 1936 CompareStub stub(cc, strict); | 1980 CompareStub stub(cc, strict); |
| (...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2583 | 2627 |
| 2584 // Duplicate the switch value. | 2628 // Duplicate the switch value. |
| 2585 frame_->Dup(); | 2629 frame_->Dup(); |
| 2586 | 2630 |
| 2587 // Compile the label expression. | 2631 // Compile the label expression. |
| 2588 Load(clause->label()); | 2632 Load(clause->label()); |
| 2589 | 2633 |
| 2590 // Compare and branch to the body if true or the next test if | 2634 // Compare and branch to the body if true or the next test if |
| 2591 // false. Prefer the next test as a fall through. | 2635 // false. Prefer the next test as a fall through. |
| 2592 ControlDestination dest(clause->body_target(), &next_test, false); | 2636 ControlDestination dest(clause->body_target(), &next_test, false); |
| 2593 Comparison(equal, true, &dest); | 2637 Comparison(node, equal, true, &dest); |
| 2594 | 2638 |
| 2595 // If the comparison fell through to the true target, jump to the | 2639 // If the comparison fell through to the true target, jump to the |
| 2596 // actual body. | 2640 // actual body. |
| 2597 if (dest.true_was_fall_through()) { | 2641 if (dest.true_was_fall_through()) { |
| 2598 clause->body_target()->Unuse(); | 2642 clause->body_target()->Unuse(); |
| 2599 clause->body_target()->Jump(); | 2643 clause->body_target()->Jump(); |
| 2600 } | 2644 } |
| 2601 } | 2645 } |
| 2602 | 2646 |
| 2603 // If there was control flow to a next test from the last one | 2647 // If there was control flow to a next test from the last one |
| (...skipping 3392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5996 __ test(answer.reg(), Operand(answer.reg())); | 6040 __ test(answer.reg(), Operand(answer.reg())); |
| 5997 answer.Unuse(); | 6041 answer.Unuse(); |
| 5998 destination()->Split(zero); | 6042 destination()->Split(zero); |
| 5999 return; | 6043 return; |
| 6000 } | 6044 } |
| 6001 default: | 6045 default: |
| 6002 UNREACHABLE(); | 6046 UNREACHABLE(); |
| 6003 } | 6047 } |
| 6004 Load(left); | 6048 Load(left); |
| 6005 Load(right); | 6049 Load(right); |
| 6006 Comparison(cc, strict, destination()); | 6050 Comparison(node, cc, strict, destination()); |
| 6007 } | 6051 } |
| 6008 | 6052 |
| 6009 | 6053 |
| 6010 #ifdef DEBUG | 6054 #ifdef DEBUG |
| 6011 bool CodeGenerator::HasValidEntryRegisters() { | 6055 bool CodeGenerator::HasValidEntryRegisters() { |
| 6012 return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0)) | 6056 return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0)) |
| 6013 && (allocator()->count(ebx) == (frame()->is_used(ebx) ? 1 : 0)) | 6057 && (allocator()->count(ebx) == (frame()->is_used(ebx) ? 1 : 0)) |
| 6014 && (allocator()->count(ecx) == (frame()->is_used(ecx) ? 1 : 0)) | 6058 && (allocator()->count(ecx) == (frame()->is_used(ecx) ? 1 : 0)) |
| 6015 && (allocator()->count(edx) == (frame()->is_used(edx) ? 1 : 0)) | 6059 && (allocator()->count(edx) == (frame()->is_used(edx) ? 1 : 0)) |
| 6016 && (allocator()->count(edi) == (frame()->is_used(edi) ? 1 : 0)); | 6060 && (allocator()->count(edi) == (frame()->is_used(edi) ? 1 : 0)); |
| (...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6795 | 6839 |
| 6796 void GenericBinaryOpStub::GenerateCall( | 6840 void GenericBinaryOpStub::GenerateCall( |
| 6797 MacroAssembler* masm, | 6841 MacroAssembler* masm, |
| 6798 Register left, | 6842 Register left, |
| 6799 Smi* right) { | 6843 Smi* right) { |
| 6800 if (!ArgsInRegistersSupported()) { | 6844 if (!ArgsInRegistersSupported()) { |
| 6801 // Pass arguments on the stack. | 6845 // Pass arguments on the stack. |
| 6802 __ push(left); | 6846 __ push(left); |
| 6803 __ push(Immediate(right)); | 6847 __ push(Immediate(right)); |
| 6804 } else { | 6848 } else { |
| 6805 // The calling convention with registers is left in edx and right in eax. | 6849 // The calling convention with registers is left in edx and right in eax. |
|
iposva
2009/12/17 21:03:50
Unmotivated space?
bakster
2009/12/18 06:38:47
Done.
| |
| 6806 Register left_arg = edx; | 6850 Register left_arg = edx; |
| 6807 Register right_arg = eax; | 6851 Register right_arg = eax; |
| 6808 if (left.is(left_arg)) { | 6852 if (left.is(left_arg)) { |
| 6809 __ mov(right_arg, Immediate(right)); | 6853 __ mov(right_arg, Immediate(right)); |
| 6810 } else if (left.is(right_arg) && IsOperationCommutative()) { | 6854 } else if (left.is(right_arg) && IsOperationCommutative()) { |
| 6811 __ mov(left_arg, Immediate(right)); | 6855 __ mov(left_arg, Immediate(right)); |
| 6812 SetArgsReversed(); | 6856 SetArgsReversed(); |
| 6813 } else { | 6857 } else { |
| 6814 __ mov(left_arg, left); | 6858 __ mov(left_arg, left); |
| 6815 __ mov(right_arg, Immediate(right)); | 6859 __ mov(right_arg, Immediate(right)); |
| (...skipping 1862 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8678 __ add(Operand(dest), Immediate(2)); | 8722 __ add(Operand(dest), Immediate(2)); |
| 8679 } | 8723 } |
| 8680 __ sub(Operand(count), Immediate(1)); | 8724 __ sub(Operand(count), Immediate(1)); |
| 8681 __ j(not_zero, &loop); | 8725 __ j(not_zero, &loop); |
| 8682 } | 8726 } |
| 8683 | 8727 |
| 8684 | 8728 |
| 8685 #undef __ | 8729 #undef __ |
| 8686 | 8730 |
| 8687 } } // namespace v8::internal | 8731 } } // namespace v8::internal |
| OLD | NEW |