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 1881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1892 LikelySmiBinaryOperation(op, operand, &constant_operand, | 1892 LikelySmiBinaryOperation(op, operand, &constant_operand, |
1893 overwrite_mode); | 1893 overwrite_mode); |
1894 } | 1894 } |
1895 break; | 1895 break; |
1896 } | 1896 } |
1897 } | 1897 } |
1898 ASSERT(!operand->is_valid()); | 1898 ASSERT(!operand->is_valid()); |
1899 } | 1899 } |
1900 | 1900 |
1901 | 1901 |
| 1902 static bool CouldBeNaN(const Result& result) { |
| 1903 if (!result.is_constant()) return true; |
| 1904 if (!result.handle()->IsHeapNumber()) return false; |
| 1905 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 1906 } |
| 1907 |
| 1908 |
1902 void CodeGenerator::Comparison(AstNode* node, | 1909 void CodeGenerator::Comparison(AstNode* node, |
1903 Condition cc, | 1910 Condition cc, |
1904 bool strict, | 1911 bool strict, |
1905 ControlDestination* dest) { | 1912 ControlDestination* dest) { |
1906 // Strict only makes sense for equality comparisons. | 1913 // Strict only makes sense for equality comparisons. |
1907 ASSERT(!strict || cc == equal); | 1914 ASSERT(!strict || cc == equal); |
1908 | 1915 |
1909 Result left_side; | 1916 Result left_side; |
1910 Result right_side; | 1917 Result right_side; |
1911 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1918 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
1912 if (cc == greater || cc == less_equal) { | 1919 if (cc == greater || cc == less_equal) { |
1913 cc = ReverseCondition(cc); | 1920 cc = ReverseCondition(cc); |
1914 left_side = frame_->Pop(); | 1921 left_side = frame_->Pop(); |
1915 right_side = frame_->Pop(); | 1922 right_side = frame_->Pop(); |
1916 } else { | 1923 } else { |
1917 right_side = frame_->Pop(); | 1924 right_side = frame_->Pop(); |
1918 left_side = frame_->Pop(); | 1925 left_side = frame_->Pop(); |
1919 } | 1926 } |
1920 ASSERT(cc == less || cc == equal || cc == greater_equal); | 1927 ASSERT(cc == less || cc == equal || cc == greater_equal); |
1921 | 1928 |
1922 // If either side is a constant smi, optimize the comparison. | 1929 // If either side is a constant of some sort, we can probably optimize the |
1923 bool left_side_constant_smi = | 1930 // comparison. |
1924 left_side.is_constant() && left_side.handle()->IsSmi(); | 1931 bool left_side_constant_smi = false; |
1925 bool right_side_constant_smi = | 1932 bool left_side_constant_null = false; |
1926 right_side.is_constant() && right_side.handle()->IsSmi(); | 1933 bool left_side_constant_1_char_string = false; |
1927 bool left_side_constant_null = | 1934 if (left_side.is_constant()) { |
1928 left_side.is_constant() && left_side.handle()->IsNull(); | 1935 left_side_constant_smi = left_side.handle()->IsSmi(); |
1929 bool right_side_constant_null = | 1936 left_side_constant_null = left_side.handle()->IsNull(); |
1930 right_side.is_constant() && right_side.handle()->IsNull(); | 1937 left_side_constant_1_char_string = |
| 1938 (left_side.handle()->IsString() && |
| 1939 (String::cast(*left_side.handle())->length() == 1)); |
| 1940 } |
| 1941 bool right_side_constant_smi = false; |
| 1942 bool right_side_constant_null = false; |
| 1943 bool right_side_constant_1_char_string = false; |
| 1944 if (right_side.is_constant()) { |
| 1945 right_side_constant_smi = right_side.handle()->IsSmi(); |
| 1946 right_side_constant_null = right_side.handle()->IsNull(); |
| 1947 right_side_constant_1_char_string = |
| 1948 (right_side.handle()->IsString() && |
| 1949 (String::cast(*right_side.handle())->length() == 1)); |
| 1950 } |
1931 | 1951 |
1932 if (left_side_constant_smi || right_side_constant_smi) { | 1952 if (left_side_constant_smi || right_side_constant_smi) { |
1933 if (left_side_constant_smi && right_side_constant_smi) { | 1953 if (left_side_constant_smi && right_side_constant_smi) { |
1934 // Trivial case, comparing two constants. | 1954 // Trivial case, comparing two constants. |
1935 int left_value = Smi::cast(*left_side.handle())->value(); | 1955 int left_value = Smi::cast(*left_side.handle())->value(); |
1936 int right_value = Smi::cast(*right_side.handle())->value(); | 1956 int right_value = Smi::cast(*right_side.handle())->value(); |
1937 switch (cc) { | 1957 switch (cc) { |
1938 case less: | 1958 case less: |
1939 dest->Goto(left_value < right_value); | 1959 dest->Goto(left_value < right_value); |
1940 break; | 1960 break; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2009 case greater: double_cc = above; break; | 2029 case greater: double_cc = above; break; |
2010 case greater_equal: double_cc = above_equal; break; | 2030 case greater_equal: double_cc = above_equal; break; |
2011 default: UNREACHABLE(); | 2031 default: UNREACHABLE(); |
2012 } | 2032 } |
2013 dest->true_target()->Branch(double_cc); | 2033 dest->true_target()->Branch(double_cc); |
2014 dest->false_target()->Jump(); | 2034 dest->false_target()->Jump(); |
2015 not_number.Bind(&left_side); | 2035 not_number.Bind(&left_side); |
2016 } | 2036 } |
2017 | 2037 |
2018 // Setup and call the compare stub. | 2038 // Setup and call the compare stub. |
2019 CompareStub stub(cc, strict); | 2039 CompareStub stub(cc, strict, CantBothBeNaN); |
2020 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 2040 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
2021 result.ToRegister(); | 2041 result.ToRegister(); |
2022 __ cmp(result.reg(), 0); | 2042 __ cmp(result.reg(), 0); |
2023 result.Unuse(); | 2043 result.Unuse(); |
2024 dest->true_target()->Branch(cc); | 2044 dest->true_target()->Branch(cc); |
2025 dest->false_target()->Jump(); | 2045 dest->false_target()->Jump(); |
2026 | 2046 |
2027 is_smi.Bind(); | 2047 is_smi.Bind(); |
2028 left_side = Result(left_reg); | 2048 left_side = Result(left_reg); |
2029 right_side = Result(right_val); | 2049 right_side = Result(right_val); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2068 ASSERT(temp.is_valid()); | 2088 ASSERT(temp.is_valid()); |
2069 __ mov(temp.reg(), | 2089 __ mov(temp.reg(), |
2070 FieldOperand(operand.reg(), HeapObject::kMapOffset)); | 2090 FieldOperand(operand.reg(), HeapObject::kMapOffset)); |
2071 __ movzx_b(temp.reg(), | 2091 __ movzx_b(temp.reg(), |
2072 FieldOperand(temp.reg(), Map::kBitFieldOffset)); | 2092 FieldOperand(temp.reg(), Map::kBitFieldOffset)); |
2073 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); | 2093 __ test(temp.reg(), Immediate(1 << Map::kIsUndetectable)); |
2074 temp.Unuse(); | 2094 temp.Unuse(); |
2075 operand.Unuse(); | 2095 operand.Unuse(); |
2076 dest->Split(not_zero); | 2096 dest->Split(not_zero); |
2077 } | 2097 } |
| 2098 } else if (left_side_constant_1_char_string || |
| 2099 right_side_constant_1_char_string) { |
| 2100 if (left_side_constant_1_char_string && right_side_constant_1_char_string) { |
| 2101 // Trivial case, comparing two constants. |
| 2102 int left_value = String::cast(*left_side.handle())->Get(0); |
| 2103 int right_value = String::cast(*right_side.handle())->Get(0); |
| 2104 switch (cc) { |
| 2105 case less: |
| 2106 dest->Goto(left_value < right_value); |
| 2107 break; |
| 2108 case equal: |
| 2109 dest->Goto(left_value == right_value); |
| 2110 break; |
| 2111 case greater_equal: |
| 2112 dest->Goto(left_value >= right_value); |
| 2113 break; |
| 2114 default: |
| 2115 UNREACHABLE(); |
| 2116 } |
| 2117 } else { |
| 2118 // Only one side is a constant 1 character string. |
| 2119 // If left side is a constant 1-character string, reverse the operands. |
| 2120 // Since one side is a constant string, conversion order does not matter. |
| 2121 if (left_side_constant_1_char_string) { |
| 2122 Result temp = left_side; |
| 2123 left_side = right_side; |
| 2124 right_side = temp; |
| 2125 cc = ReverseCondition(cc); |
| 2126 // This may reintroduce greater or less_equal as the value of cc. |
| 2127 // CompareStub and the inline code both support all values of cc. |
| 2128 } |
| 2129 // Implement comparison against a constant string, inlining the case |
| 2130 // where both sides are strings. |
| 2131 left_side.ToRegister(); |
| 2132 |
| 2133 // Here we split control flow to the stub call and inlined cases |
| 2134 // before finally splitting it to the control destination. We use |
| 2135 // a jump target and branching to duplicate the virtual frame at |
| 2136 // the first split. We manually handle the off-frame references |
| 2137 // by reconstituting them on the non-fall-through path. |
| 2138 JumpTarget is_not_string, is_string; |
| 2139 Register left_reg = left_side.reg(); |
| 2140 Handle<Object> right_val = right_side.handle(); |
| 2141 __ test(left_side.reg(), Immediate(kSmiTagMask)); |
| 2142 is_not_string.Branch(zero, &left_side); |
| 2143 Result temp = allocator_->Allocate(); |
| 2144 ASSERT(temp.is_valid()); |
| 2145 __ mov(temp.reg(), |
| 2146 FieldOperand(left_side.reg(), HeapObject::kMapOffset)); |
| 2147 __ movzx_b(temp.reg(), |
| 2148 FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
| 2149 // If we are testing for equality then make use of the symbol shortcut. |
| 2150 // Check if the right left hand side has the same type as the left hand |
| 2151 // side (which is always a symbol). |
| 2152 if (cc == equal) { |
| 2153 Label not_a_symbol; |
| 2154 ASSERT(kSymbolTag != 0); |
| 2155 // Ensure that no non-strings have the symbol bit set. |
| 2156 ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); |
| 2157 __ test(temp.reg(), Immediate(kIsSymbolMask)); // Test the symbol bit. |
| 2158 __ j(zero, ¬_a_symbol); |
| 2159 // They are symbols, so do identity compare. |
| 2160 __ cmp(left_side.reg(), right_side.handle()); |
| 2161 dest->true_target()->Branch(equal); |
| 2162 dest->false_target()->Branch(not_equal); |
| 2163 __ bind(¬_a_symbol); |
| 2164 } |
| 2165 // If the receiver is not a string of the type we handle call the stub. |
| 2166 __ and_(temp.reg(), |
| 2167 kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask); |
| 2168 __ cmp(temp.reg(), kStringTag | kSeqStringTag | kAsciiStringTag); |
| 2169 temp.Unuse(); |
| 2170 is_string.Branch(equal, &left_side); |
| 2171 |
| 2172 // Setup and call the compare stub. |
| 2173 is_not_string.Bind(&left_side); |
| 2174 CompareStub stub(cc, strict, CantBothBeNaN); |
| 2175 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
| 2176 result.ToRegister(); |
| 2177 __ cmp(result.reg(), 0); |
| 2178 result.Unuse(); |
| 2179 dest->true_target()->Branch(cc); |
| 2180 dest->false_target()->Jump(); |
| 2181 |
| 2182 is_string.Bind(&left_side); |
| 2183 // Here we know we have a sequential ASCII string. |
| 2184 left_side = Result(left_reg); |
| 2185 right_side = Result(right_val); |
| 2186 Result temp2 = allocator_->Allocate(); |
| 2187 ASSERT(temp2.is_valid()); |
| 2188 // Test string equality and comparison. |
| 2189 if (cc == equal) { |
| 2190 Label comparison_done; |
| 2191 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
| 2192 Immediate(1)); |
| 2193 __ j(not_equal, &comparison_done); |
| 2194 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), |
| 2195 String::cast(*right_side.handle())->Get(0)); |
| 2196 __ bind(&comparison_done); |
| 2197 } else { |
| 2198 __ mov(temp2.reg(), |
| 2199 FieldOperand(left_side.reg(), String::kLengthOffset)); |
| 2200 __ sub(Operand(temp2.reg()), Immediate(1)); |
| 2201 Label comparison; |
| 2202 // If the length is 0 then our subtraction gave -1 which compares less |
| 2203 // than any character. |
| 2204 __ j(negative, &comparison); |
| 2205 // Otherwise load the first character. |
| 2206 __ movzx_b(temp2.reg(), |
| 2207 FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize)); |
| 2208 __ bind(&comparison); |
| 2209 // Compare the first character of the string with out constant |
| 2210 // 1-character string. |
| 2211 __ cmp(Operand(temp2.reg()), |
| 2212 Immediate(String::cast(*right_side.handle())->Get(0))); |
| 2213 Label characters_were_different; |
| 2214 __ j(not_equal, &characters_were_different); |
| 2215 // If the first character is the same then the long string sorts after |
| 2216 // the short one. |
| 2217 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
| 2218 Immediate(1)); |
| 2219 __ bind(&characters_were_different); |
| 2220 } |
| 2221 temp2.Unuse(); |
| 2222 left_side.Unuse(); |
| 2223 right_side.Unuse(); |
| 2224 dest->Split(cc); |
| 2225 } |
2078 } else { | 2226 } else { |
2079 // Neither side is a constant Smi or null. | 2227 // Neither side is a constant Smi or null. |
2080 // If either side is a non-smi constant, skip the smi check. | 2228 // If either side is a non-smi constant, skip the smi check. |
2081 bool known_non_smi = | 2229 bool known_non_smi = |
2082 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2230 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
2083 (right_side.is_constant() && !right_side.handle()->IsSmi()); | 2231 (right_side.is_constant() && !right_side.handle()->IsSmi()); |
| 2232 NaNInformation nan_info = |
| 2233 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
| 2234 BothCouldBeNaN : |
| 2235 CantBothBeNaN; |
2084 left_side.ToRegister(); | 2236 left_side.ToRegister(); |
2085 right_side.ToRegister(); | 2237 right_side.ToRegister(); |
2086 | 2238 |
2087 if (known_non_smi) { | 2239 if (known_non_smi) { |
2088 // When non-smi, call out to the compare stub. | 2240 // When non-smi, call out to the compare stub. |
2089 CompareStub stub(cc, strict); | 2241 CompareStub stub(cc, strict, nan_info); |
2090 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2242 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2091 if (cc == equal) { | 2243 if (cc == equal) { |
2092 __ test(answer.reg(), Operand(answer.reg())); | 2244 __ test(answer.reg(), Operand(answer.reg())); |
2093 } else { | 2245 } else { |
2094 __ cmp(answer.reg(), 0); | 2246 __ cmp(answer.reg(), 0); |
2095 } | 2247 } |
2096 answer.Unuse(); | 2248 answer.Unuse(); |
2097 dest->Split(cc); | 2249 dest->Split(cc); |
2098 } else { | 2250 } else { |
2099 // Here we split control flow to the stub call and inlined cases | 2251 // Here we split control flow to the stub call and inlined cases |
2100 // before finally splitting it to the control destination. We use | 2252 // before finally splitting it to the control destination. We use |
2101 // a jump target and branching to duplicate the virtual frame at | 2253 // a jump target and branching to duplicate the virtual frame at |
2102 // the first split. We manually handle the off-frame references | 2254 // the first split. We manually handle the off-frame references |
2103 // by reconstituting them on the non-fall-through path. | 2255 // by reconstituting them on the non-fall-through path. |
2104 JumpTarget is_smi; | 2256 JumpTarget is_smi; |
2105 Register left_reg = left_side.reg(); | 2257 Register left_reg = left_side.reg(); |
2106 Register right_reg = right_side.reg(); | 2258 Register right_reg = right_side.reg(); |
2107 | 2259 |
2108 Result temp = allocator_->Allocate(); | 2260 Result temp = allocator_->Allocate(); |
2109 ASSERT(temp.is_valid()); | 2261 ASSERT(temp.is_valid()); |
2110 __ mov(temp.reg(), left_side.reg()); | 2262 __ mov(temp.reg(), left_side.reg()); |
2111 __ or_(temp.reg(), Operand(right_side.reg())); | 2263 __ or_(temp.reg(), Operand(right_side.reg())); |
2112 __ test(temp.reg(), Immediate(kSmiTagMask)); | 2264 __ test(temp.reg(), Immediate(kSmiTagMask)); |
2113 temp.Unuse(); | 2265 temp.Unuse(); |
2114 is_smi.Branch(zero, taken); | 2266 is_smi.Branch(zero, taken); |
2115 // When non-smi, call out to the compare stub. | 2267 // When non-smi, call out to the compare stub. |
2116 CompareStub stub(cc, strict); | 2268 CompareStub stub(cc, strict, nan_info); |
2117 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2269 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2118 if (cc == equal) { | 2270 if (cc == equal) { |
2119 __ test(answer.reg(), Operand(answer.reg())); | 2271 __ test(answer.reg(), Operand(answer.reg())); |
2120 } else { | 2272 } else { |
2121 __ cmp(answer.reg(), 0); | 2273 __ cmp(answer.reg(), 0); |
2122 } | 2274 } |
2123 answer.Unuse(); | 2275 answer.Unuse(); |
2124 dest->true_target()->Branch(cc); | 2276 dest->true_target()->Branch(cc); |
2125 dest->false_target()->Jump(); | 2277 dest->false_target()->Jump(); |
2126 | 2278 |
(...skipping 6095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8222 Label slow; // Fallthrough label. | 8374 Label slow; // Fallthrough label. |
8223 // Equality is almost reflexive (everything but NaN), so start by testing | 8375 // Equality is almost reflexive (everything but NaN), so start by testing |
8224 // for "identity and not NaN". | 8376 // for "identity and not NaN". |
8225 { | 8377 { |
8226 Label not_identical; | 8378 Label not_identical; |
8227 __ cmp(eax, Operand(edx)); | 8379 __ cmp(eax, Operand(edx)); |
8228 __ j(not_equal, ¬_identical); | 8380 __ j(not_equal, ¬_identical); |
8229 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 8381 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
8230 // so we do the second best thing - test it ourselves. | 8382 // so we do the second best thing - test it ourselves. |
8231 | 8383 |
8232 Label return_equal; | 8384 if (never_nan_nan_) { |
8233 Label heap_number; | 8385 __ Set(eax, Immediate(0)); |
8234 // If it's not a heap number, then return equal. | 8386 __ ret(0); |
8235 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 8387 } else { |
8236 Immediate(Factory::heap_number_map())); | 8388 Label return_equal; |
8237 __ j(equal, &heap_number); | 8389 Label heap_number; |
8238 __ bind(&return_equal); | 8390 // If it's not a heap number, then return equal. |
8239 __ Set(eax, Immediate(0)); | 8391 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
8240 __ ret(0); | 8392 Immediate(Factory::heap_number_map())); |
| 8393 __ j(equal, &heap_number); |
| 8394 __ bind(&return_equal); |
| 8395 __ Set(eax, Immediate(0)); |
| 8396 __ ret(0); |
8241 | 8397 |
8242 __ bind(&heap_number); | 8398 __ bind(&heap_number); |
8243 // It is a heap number, so return non-equal if it's NaN and equal if it's | 8399 // It is a heap number, so return non-equal if it's NaN and equal if |
8244 // not NaN. | 8400 // it's not NaN. |
8245 // The representation of NaN values has all exponent bits (52..62) set, | 8401 // The representation of NaN values has all exponent bits (52..62) set, |
8246 // and not all mantissa bits (0..51) clear. | 8402 // and not all mantissa bits (0..51) clear. |
8247 // We only accept QNaNs, which have bit 51 set. | 8403 // We only accept QNaNs, which have bit 51 set. |
8248 // Read top bits of double representation (second word of value). | 8404 // Read top bits of double representation (second word of value). |
8249 | 8405 |
8250 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., | 8406 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., |
8251 // all bits in the mask are set. We only need to check the word | 8407 // all bits in the mask are set. We only need to check the word |
8252 // that contains the exponent and high bit of the mantissa. | 8408 // that contains the exponent and high bit of the mantissa. |
8253 ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); | 8409 ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u); |
8254 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 8410 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
8255 __ xor_(eax, Operand(eax)); | 8411 __ xor_(eax, Operand(eax)); |
8256 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost bits. | 8412 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost |
8257 __ add(edx, Operand(edx)); | 8413 // bits. |
8258 __ cmp(edx, kQuietNaNHighBitsMask << 1); | 8414 __ add(edx, Operand(edx)); |
8259 __ setcc(above_equal, eax); | 8415 __ cmp(edx, kQuietNaNHighBitsMask << 1); |
8260 __ ret(0); | 8416 __ setcc(above_equal, eax); |
| 8417 __ ret(0); |
| 8418 } |
8261 | 8419 |
8262 __ bind(¬_identical); | 8420 __ bind(¬_identical); |
8263 } | 8421 } |
8264 | 8422 |
8265 // If we're doing a strict equality comparison, we don't have to do | 8423 // If we're doing a strict equality comparison, we don't have to do |
8266 // type conversion, so we generate code to do fast comparison for objects | 8424 // type conversion, so we generate code to do fast comparison for objects |
8267 // and oddballs. Non-smi numbers and strings still go through the usual | 8425 // and oddballs. Non-smi numbers and strings still go through the usual |
8268 // slow-case code. | 8426 // slow-case code. |
8269 if (strict_) { | 8427 if (strict_) { |
8270 // If either is a Smi (we know that not both are), then they can only | 8428 // If either is a Smi (we know that not both are), then they can only |
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8975 __ bind(&is_not_instance); | 9133 __ bind(&is_not_instance); |
8976 __ Set(eax, Immediate(Smi::FromInt(1))); | 9134 __ Set(eax, Immediate(Smi::FromInt(1))); |
8977 __ ret(2 * kPointerSize); | 9135 __ ret(2 * kPointerSize); |
8978 | 9136 |
8979 // Slow-case: Go through the JavaScript implementation. | 9137 // Slow-case: Go through the JavaScript implementation. |
8980 __ bind(&slow); | 9138 __ bind(&slow); |
8981 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 9139 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
8982 } | 9140 } |
8983 | 9141 |
8984 | 9142 |
| 9143 // Unfortunately you have to run without snapshots to see most of these |
| 9144 // names in the profile since most compare stubs end up in the snapshot. |
| 9145 const char* CompareStub::GetName() { |
| 9146 switch (cc_) { |
| 9147 case less: return "CompareStub_LT"; |
| 9148 case greater: return "CompareStub_GT"; |
| 9149 case less_equal: return "CompareStub_LE"; |
| 9150 case greater_equal: return "CompareStub_GE"; |
| 9151 case not_equal: { |
| 9152 if (strict_) { |
| 9153 if (never_nan_nan_) { |
| 9154 return "CompareStub_NE_STRICT_NO_NAN"; |
| 9155 } else { |
| 9156 return "CompareStub_NE_STRICT"; |
| 9157 } |
| 9158 } else { |
| 9159 if (never_nan_nan_) { |
| 9160 return "CompareStub_NE_NO_NAN"; |
| 9161 } else { |
| 9162 return "CompareStub_NE"; |
| 9163 } |
| 9164 } |
| 9165 } |
| 9166 case equal: { |
| 9167 if (strict_) { |
| 9168 if (never_nan_nan_) { |
| 9169 return "CompareStub_EQ_STRICT_NO_NAN"; |
| 9170 } else { |
| 9171 return "CompareStub_EQ_STRICT"; |
| 9172 } |
| 9173 } else { |
| 9174 if (never_nan_nan_) { |
| 9175 return "CompareStub_EQ_NO_NAN"; |
| 9176 } else { |
| 9177 return "CompareStub_EQ"; |
| 9178 } |
| 9179 } |
| 9180 } |
| 9181 default: return "CompareStub"; |
| 9182 } |
| 9183 } |
| 9184 |
| 9185 |
8985 int CompareStub::MinorKey() { | 9186 int CompareStub::MinorKey() { |
8986 // Encode the two parameters in a unique 16 bit value. | 9187 // Encode the three parameters in a unique 16 bit value. |
8987 ASSERT(static_cast<unsigned>(cc_) < (1 << 15)); | 9188 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
8988 return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); | 9189 int nnn_value = (never_nan_nan_ ? 2 : 0); |
| 9190 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. |
| 9191 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); |
8989 } | 9192 } |
8990 | 9193 |
8991 | 9194 |
8992 void StringAddStub::Generate(MacroAssembler* masm) { | 9195 void StringAddStub::Generate(MacroAssembler* masm) { |
8993 Label string_add_runtime; | 9196 Label string_add_runtime; |
8994 | 9197 |
8995 // Load the two arguments. | 9198 // Load the two arguments. |
8996 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 9199 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
8997 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 9200 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
8998 | 9201 |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9372 __ ret(3 * kPointerSize); | 9575 __ ret(3 * kPointerSize); |
9373 | 9576 |
9374 // Just jump to runtime to create the sub string. | 9577 // Just jump to runtime to create the sub string. |
9375 __ bind(&runtime); | 9578 __ bind(&runtime); |
9376 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); | 9579 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); |
9377 } | 9580 } |
9378 | 9581 |
9379 #undef __ | 9582 #undef __ |
9380 | 9583 |
9381 } } // namespace v8::internal | 9584 } } // namespace v8::internal |
OLD | NEW |