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