OLD | NEW |
1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-regexp-gen.h" | 5 #include "src/builtins/builtins-regexp-gen.h" |
6 | 6 |
7 #include "src/builtins/builtins-constructor-gen.h" | 7 #include "src/builtins/builtins-constructor-gen.h" |
8 #include "src/builtins/builtins-utils-gen.h" | 8 #include "src/builtins/builtins-utils-gen.h" |
9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 1517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1528 | 1528 |
1529 // Return true iff exec matched successfully. | 1529 // Return true iff exec matched successfully. |
1530 Node* const result = | 1530 Node* const result = |
1531 SelectBooleanConstant(WordNotEqual(match_indices, NullConstant())); | 1531 SelectBooleanConstant(WordNotEqual(match_indices, NullConstant())); |
1532 Return(result); | 1532 Return(result); |
1533 } | 1533 } |
1534 } | 1534 } |
1535 | 1535 |
1536 Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string, | 1536 Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string, |
1537 Node* const index, | 1537 Node* const index, |
1538 Node* const is_unicode) { | 1538 Node* const is_unicode, |
| 1539 bool is_fastpath) { |
1539 CSA_ASSERT(this, IsString(string)); | 1540 CSA_ASSERT(this, IsString(string)); |
1540 // TODO(jgruber): Handle HeapNumber index. | 1541 CSA_ASSERT(this, IsHeapNumberMap(LoadReceiverMap(index))); |
| 1542 if (is_fastpath) CSA_ASSERT(this, TaggedIsPositiveSmi(index)); |
| 1543 |
| 1544 // TODO(jgruber): If index is a HeapNumber, assert that it is outside the |
| 1545 // Smi range. |
1541 | 1546 |
1542 // Default to last_index + 1. | 1547 // Default to last_index + 1. |
1543 Node* const index_plus_one = SmiAdd(index, SmiConstant(1)); | 1548 Node* const index_plus_one = NumberInc(index); |
1544 Variable var_result(this, MachineRepresentation::kTagged, index_plus_one); | 1549 Variable var_result(this, MachineRepresentation::kTagged, index_plus_one); |
1545 | 1550 |
| 1551 // Advancing the index has some subtle issues involving the distinction |
| 1552 // between Smis and HeapNumbers. There's three cases: |
| 1553 // * {index} is a Smi, {index_plus_one} is a Smi. The standard case. |
| 1554 // * {index} is a Smi, {index_plus_one} overflows into a HeapNumber. |
| 1555 // In this case we can return the result early, because |
| 1556 // {index_plus_one} > {string}.length. |
| 1557 // * {index} is a HeapNumber, {index_plus_one} is a HeapNumber. This can only |
| 1558 // occur when {index} is outside the Smi range since we normalize |
| 1559 // explicitly. Again we can return early. |
| 1560 if (is_fastpath) { |
| 1561 // Must be in Smi range on the fast path. We control the value of {index} |
| 1562 // on all call-sites and can never exceed the length of the string. |
| 1563 STATIC_ASSERT(String::kMaxLength + 2 < Smi::kMaxValue); |
| 1564 CSA_ASSERT(this, TaggedIsPositiveSmi(index_plus_one)); |
| 1565 } |
| 1566 |
1546 Label if_isunicode(this), out(this); | 1567 Label if_isunicode(this), out(this); |
1547 Branch(is_unicode, &if_isunicode, &out); | 1568 GotoIfNot(is_unicode, &out); |
| 1569 |
| 1570 // Keep this unconditional (even on the fast path) just to be safe. |
| 1571 Branch(TaggedIsPositiveSmi(index_plus_one), &if_isunicode, &out); |
1548 | 1572 |
1549 BIND(&if_isunicode); | 1573 BIND(&if_isunicode); |
1550 { | 1574 { |
1551 Node* const string_length = LoadStringLength(string); | 1575 Node* const string_length = LoadStringLength(string); |
1552 GotoIfNot(SmiLessThan(index_plus_one, string_length), &out); | 1576 GotoIfNot(SmiLessThan(index_plus_one, string_length), &out); |
1553 | 1577 |
1554 Node* const lead = StringCharCodeAt(string, index); | 1578 Node* const lead = StringCharCodeAt(string, index); |
1555 GotoIfNot(Word32Equal(Word32And(lead, Int32Constant(0xFC00)), | 1579 GotoIfNot(Word32Equal(Word32And(lead, Int32Constant(0xFC00)), |
1556 Int32Constant(0xD800)), | 1580 Int32Constant(0xD800)), |
1557 &out); | 1581 &out); |
1558 | 1582 |
1559 Node* const trail = StringCharCodeAt(string, index_plus_one); | 1583 Node* const trail = StringCharCodeAt(string, index_plus_one); |
1560 GotoIfNot(Word32Equal(Word32And(trail, Int32Constant(0xFC00)), | 1584 GotoIfNot(Word32Equal(Word32And(trail, Int32Constant(0xFC00)), |
1561 Int32Constant(0xDC00)), | 1585 Int32Constant(0xDC00)), |
1562 &out); | 1586 &out); |
1563 | 1587 |
1564 // At a surrogate pair, return index + 2. | 1588 // At a surrogate pair, return index + 2. |
1565 Node* const index_plus_two = SmiAdd(index, SmiConstant(2)); | 1589 Node* const index_plus_two = NumberInc(index_plus_one); |
1566 var_result.Bind(index_plus_two); | 1590 var_result.Bind(index_plus_two); |
1567 | 1591 |
1568 Goto(&out); | 1592 Goto(&out); |
1569 } | 1593 } |
1570 | 1594 |
1571 BIND(&out); | 1595 BIND(&out); |
1572 return var_result.value(); | 1596 return var_result.value(); |
1573 } | 1597 } |
1574 | 1598 |
1575 namespace { | 1599 namespace { |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1844 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); | 1868 GotoIfNot(SmiEqual(match_length, smi_zero), &loop); |
1845 | 1869 |
1846 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); | 1870 Node* last_index = LoadLastIndex(context, regexp, is_fastpath); |
1847 if (is_fastpath) { | 1871 if (is_fastpath) { |
1848 CSA_ASSERT(this, TaggedIsPositiveSmi(last_index)); | 1872 CSA_ASSERT(this, TaggedIsPositiveSmi(last_index)); |
1849 } else { | 1873 } else { |
1850 last_index = CallBuiltin(Builtins::kToLength, context, last_index); | 1874 last_index = CallBuiltin(Builtins::kToLength, context, last_index); |
1851 } | 1875 } |
1852 | 1876 |
1853 Node* const new_last_index = | 1877 Node* const new_last_index = |
1854 AdvanceStringIndex(string, last_index, is_unicode); | 1878 AdvanceStringIndex(string, last_index, is_unicode, is_fastpath); |
1855 | 1879 |
1856 if (is_fastpath) { | 1880 if (is_fastpath) { |
1857 // On the fast path, we can be certain that lastIndex can never be | 1881 // On the fast path, we can be certain that lastIndex can never be |
1858 // incremented to overflow the Smi range since the maximal string | 1882 // incremented to overflow the Smi range since the maximal string |
1859 // length is less than the maximal Smi value. | 1883 // length is less than the maximal Smi value. |
1860 STATIC_ASSERT(String::kMaxLength < Smi::kMaxValue); | 1884 STATIC_ASSERT(String::kMaxLength < Smi::kMaxValue); |
1861 CSA_ASSERT(this, TaggedIsPositiveSmi(new_last_index)); | 1885 CSA_ASSERT(this, TaggedIsPositiveSmi(new_last_index)); |
1862 } | 1886 } |
1863 | 1887 |
1864 StoreLastIndex(context, regexp, new_last_index, is_fastpath); | 1888 StoreLastIndex(context, regexp, new_last_index, is_fastpath); |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2162 | 2186 |
2163 // Advance index and continue if the match is empty. | 2187 // Advance index and continue if the match is empty. |
2164 { | 2188 { |
2165 Label next(this); | 2189 Label next(this); |
2166 | 2190 |
2167 GotoIfNot(SmiEqual(match_to, next_search_from), &next); | 2191 GotoIfNot(SmiEqual(match_to, next_search_from), &next); |
2168 GotoIfNot(SmiEqual(match_to, last_matched_until), &next); | 2192 GotoIfNot(SmiEqual(match_to, last_matched_until), &next); |
2169 | 2193 |
2170 Node* const is_unicode = FastFlagGetter(regexp, JSRegExp::kUnicode); | 2194 Node* const is_unicode = FastFlagGetter(regexp, JSRegExp::kUnicode); |
2171 Node* const new_next_search_from = | 2195 Node* const new_next_search_from = |
2172 AdvanceStringIndex(string, next_search_from, is_unicode); | 2196 AdvanceStringIndex(string, next_search_from, is_unicode, true); |
2173 var_next_search_from.Bind(new_next_search_from); | 2197 var_next_search_from.Bind(new_next_search_from); |
2174 Goto(&loop); | 2198 Goto(&loop); |
2175 | 2199 |
2176 BIND(&next); | 2200 BIND(&next); |
2177 } | 2201 } |
2178 | 2202 |
2179 // A valid match was found, add the new substring to the array. | 2203 // A valid match was found, add the new substring to the array. |
2180 { | 2204 { |
2181 Node* const from = last_matched_until; | 2205 Node* const from = last_matched_until; |
2182 Node* const to = match_from; | 2206 Node* const to = match_from; |
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2831 BIND(&if_matched); | 2855 BIND(&if_matched); |
2832 { | 2856 { |
2833 Node* result = | 2857 Node* result = |
2834 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2858 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2835 Return(result); | 2859 Return(result); |
2836 } | 2860 } |
2837 } | 2861 } |
2838 | 2862 |
2839 } // namespace internal | 2863 } // namespace internal |
2840 } // namespace v8 | 2864 } // namespace v8 |
OLD | NEW |