OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
10 #include "src/regexp/regexp-utils.h" | 10 #include "src/regexp/regexp-utils.h" |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 219 |
220 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, | 220 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
221 Node* value, bool is_fastpath) { | 221 Node* value, bool is_fastpath) { |
222 if (is_fastpath) { | 222 if (is_fastpath) { |
223 FastStoreLastIndex(a, regexp, value); | 223 FastStoreLastIndex(a, regexp, value); |
224 } else { | 224 } else { |
225 SlowStoreLastIndex(a, context, regexp, value); | 225 SlowStoreLastIndex(a, context, regexp, value); |
226 } | 226 } |
227 } | 227 } |
228 | 228 |
229 Node* LoadMatchInfoField(CodeStubAssembler* a, Node* const match_info, | |
230 const int index) { | |
231 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | |
232 Node* const result = | |
233 a->LoadFixedArrayElement(match_info, a->IntPtrConstant(index), 0, mode); | |
234 return result; | |
235 } | |
236 | |
237 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, | 229 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
238 Node* context, Node* match_info, | 230 Node* context, Node* match_info, |
239 Node* string) { | 231 Node* string) { |
240 CLabel out(a); | 232 CLabel out(a); |
241 | 233 |
242 Node* const num_indices = a->SmiUntag(LoadMatchInfoField( | 234 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
243 a, match_info, RegExpMatchInfo::kNumberOfCapturesIndex)); | 235 match_info, RegExpMatchInfo::kNumberOfCapturesIndex)); |
244 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); | 236 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); |
245 Node* const start = | 237 Node* const start = |
246 LoadMatchInfoField(a, match_info, RegExpMatchInfo::kFirstCaptureIndex); | 238 a->LoadFixedArrayElement(match_info, RegExpMatchInfo::kFirstCaptureIndex); |
247 Node* const end = LoadMatchInfoField(a, match_info, | 239 Node* const end = a->LoadFixedArrayElement( |
248 RegExpMatchInfo::kFirstCaptureIndex + 1); | 240 match_info, RegExpMatchInfo::kFirstCaptureIndex + 1); |
249 | 241 |
250 // Calculate the substring of the first match before creating the result array | 242 // Calculate the substring of the first match before creating the result array |
251 // to avoid an unnecessary write barrier storing the first result. | 243 // to avoid an unnecessary write barrier storing the first result. |
252 Node* const first = a->SubString(context, string, start, end); | 244 Node* const first = a->SubString(context, string, start, end); |
253 | 245 |
254 Node* const result = | 246 Node* const result = |
255 a->AllocateRegExpResult(context, num_results, start, string); | 247 a->AllocateRegExpResult(context, num_results, start, string); |
256 Node* const result_elements = a->LoadElements(result); | 248 Node* const result_elements = a->LoadElements(result); |
257 | 249 |
258 a->StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); | 250 a->StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
413 | 405 |
414 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); | 406 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
415 a->Goto(if_didnotmatch); | 407 a->Goto(if_didnotmatch); |
416 } | 408 } |
417 | 409 |
418 a->Bind(&successful_match); | 410 a->Bind(&successful_match); |
419 { | 411 { |
420 a->GotoUnless(should_update_last_index, &out); | 412 a->GotoUnless(should_update_last_index, &out); |
421 | 413 |
422 // Update the new last index from {match_indices}. | 414 // Update the new last index from {match_indices}. |
423 Node* const new_lastindex = LoadMatchInfoField( | 415 Node* const new_lastindex = a->LoadFixedArrayElement( |
424 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); | 416 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
425 | 417 |
426 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); | 418 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
427 a->Goto(&out); | 419 a->Goto(&out); |
428 } | 420 } |
429 | 421 |
430 a->Bind(&out); | 422 a->Bind(&out); |
431 return var_result.value(); | 423 return var_result.value(); |
432 } | 424 } |
433 | 425 |
434 // ES#sec-regexp.prototype.exec | 426 // ES#sec-regexp.prototype.exec |
(...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 { | 1374 { |
1383 CVariable var_match(a, MachineRepresentation::kTagged); | 1375 CVariable var_match(a, MachineRepresentation::kTagged); |
1384 | 1376 |
1385 CLabel if_didmatch(a), if_didnotmatch(a); | 1377 CLabel if_didmatch(a), if_didnotmatch(a); |
1386 if (is_fastpath) { | 1378 if (is_fastpath) { |
1387 // On the fast path, grab the matching string from the raw match index | 1379 // On the fast path, grab the matching string from the raw match index |
1388 // array. | 1380 // array. |
1389 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( | 1381 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( |
1390 a, context, regexp, string, &if_didnotmatch, true); | 1382 a, context, regexp, string, &if_didnotmatch, true); |
1391 | 1383 |
1392 Node* const match_from = LoadMatchInfoField( | 1384 Node* const match_from = a->LoadFixedArrayElement( |
1393 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); | 1385 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
1394 Node* const match_to = LoadMatchInfoField( | 1386 Node* const match_to = a->LoadFixedArrayElement( |
1395 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); | 1387 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
1396 | 1388 |
1397 Node* match = a->SubString(context, string, match_from, match_to); | 1389 Node* match = a->SubString(context, string, match_from, match_to); |
1398 var_match.Bind(match); | 1390 var_match.Bind(match); |
1399 | 1391 |
1400 a->Goto(&if_didmatch); | 1392 a->Goto(&if_didmatch); |
1401 } else { | 1393 } else { |
1402 DCHECK(!is_fastpath); | 1394 DCHECK(!is_fastpath); |
1403 Node* const result = RegExpExec(a, context, regexp, string); | 1395 Node* const result = RegExpExec(a, context, regexp, string); |
1404 | 1396 |
1405 CLabel load_match(a); | 1397 CLabel load_match(a); |
1406 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &load_match); | 1398 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &load_match); |
1407 | 1399 |
1408 a->Bind(&load_match); | 1400 a->Bind(&load_match); |
1409 { | 1401 { |
1410 CLabel fast_result(a), slow_result(a); | 1402 CLabel fast_result(a), slow_result(a); |
1411 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, | 1403 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, |
1412 &slow_result); | 1404 &slow_result); |
1413 | 1405 |
1414 a->Bind(&fast_result); | 1406 a->Bind(&fast_result); |
1415 { | 1407 { |
1416 Node* const result_fixed_array = a->LoadElements(result); | 1408 Node* const result_fixed_array = a->LoadElements(result); |
1417 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1409 Node* const match = a->LoadFixedArrayElement(result_fixed_array, 0); |
1418 Node* const match = | |
1419 a->LoadFixedArrayElement(result_fixed_array, int_zero, 0, mode); | |
1420 | 1410 |
1421 // The match is guaranteed to be a string on the fast path. | 1411 // The match is guaranteed to be a string on the fast path. |
1422 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); | 1412 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); |
1423 | 1413 |
1424 var_match.Bind(match); | 1414 var_match.Bind(match); |
1425 a->Goto(&if_didmatch); | 1415 a->Goto(&if_didmatch); |
1426 } | 1416 } |
1427 | 1417 |
1428 a->Bind(&slow_result); | 1418 a->Bind(&slow_result); |
1429 { | 1419 { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1527 CLabel if_didnotmatch(a); | 1517 CLabel if_didnotmatch(a); |
1528 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( | 1518 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( |
1529 a, context, receiver, string, &if_didnotmatch, true); | 1519 a, context, receiver, string, &if_didnotmatch, true); |
1530 | 1520 |
1531 // Successful match. | 1521 // Successful match. |
1532 { | 1522 { |
1533 // Reset last index. | 1523 // Reset last index. |
1534 FastStoreLastIndex(a, receiver, previous_last_index); | 1524 FastStoreLastIndex(a, receiver, previous_last_index); |
1535 | 1525 |
1536 // Return the index of the match. | 1526 // Return the index of the match. |
1537 Node* const index = LoadMatchInfoField(a, match_indices, | 1527 Node* const index = a->LoadFixedArrayElement( |
1538 RegExpMatchInfo::kFirstCaptureIndex); | 1528 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
1539 a->Return(index); | 1529 a->Return(index); |
1540 } | 1530 } |
1541 | 1531 |
1542 a->Bind(&if_didnotmatch); | 1532 a->Bind(&if_didnotmatch); |
1543 { | 1533 { |
1544 // Reset last index and return -1. | 1534 // Reset last index and return -1. |
1545 FastStoreLastIndex(a, receiver, previous_last_index); | 1535 FastStoreLastIndex(a, receiver, previous_last_index); |
1546 a->Return(a->SmiConstant(-1)); | 1536 a->Return(a->SmiConstant(-1)); |
1547 } | 1537 } |
1548 } | 1538 } |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1756 a->CallStub(exec_callable, context, regexp, string, next_search_from, | 1746 a->CallStub(exec_callable, context, regexp, string, next_search_from, |
1757 last_match_info); | 1747 last_match_info); |
1758 | 1748 |
1759 // We're done if no match was found. | 1749 // We're done if no match was found. |
1760 { | 1750 { |
1761 CLabel next(a); | 1751 CLabel next(a); |
1762 a->Branch(a->WordEqual(match_indices, null), &push_suffix_and_out, &next); | 1752 a->Branch(a->WordEqual(match_indices, null), &push_suffix_and_out, &next); |
1763 a->Bind(&next); | 1753 a->Bind(&next); |
1764 } | 1754 } |
1765 | 1755 |
1766 Node* const match_from = LoadMatchInfoField( | 1756 Node* const match_from = a->LoadFixedArrayElement( |
1767 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); | 1757 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
1768 | 1758 |
1769 // We're done if the match starts beyond the string. | 1759 // We're done if the match starts beyond the string. |
1770 { | 1760 { |
1771 CLabel next(a); | 1761 CLabel next(a); |
1772 a->Branch(a->WordEqual(match_from, string_length), &push_suffix_and_out, | 1762 a->Branch(a->WordEqual(match_from, string_length), &push_suffix_and_out, |
1773 &next); | 1763 &next); |
1774 a->Bind(&next); | 1764 a->Bind(&next); |
1775 } | 1765 } |
1776 | 1766 |
1777 Node* const match_to = LoadMatchInfoField( | 1767 Node* const match_to = a->LoadFixedArrayElement( |
1778 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); | 1768 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
1779 | 1769 |
1780 // Advance index and continue if the match is empty. | 1770 // Advance index and continue if the match is empty. |
1781 { | 1771 { |
1782 CLabel next(a); | 1772 CLabel next(a); |
1783 | 1773 |
1784 a->GotoUnless(a->SmiEqual(match_to, next_search_from), &next); | 1774 a->GotoUnless(a->SmiEqual(match_to, next_search_from), &next); |
1785 a->GotoUnless(a->SmiEqual(match_to, last_matched_until), &next); | 1775 a->GotoUnless(a->SmiEqual(match_to, last_matched_until), &next); |
1786 | 1776 |
1787 Node* const is_unicode = FastFlagGetter(a, regexp, JSRegExp::kUnicode); | 1777 Node* const is_unicode = FastFlagGetter(a, regexp, JSRegExp::kUnicode); |
1788 Node* const new_next_search_from = | 1778 Node* const new_next_search_from = |
(...skipping 10 matching lines...) Expand all Loading... |
1799 Node* const to = match_from; | 1789 Node* const to = match_from; |
1800 | 1790 |
1801 Node* const substr = a->SubString(context, string, from, to); | 1791 Node* const substr = a->SubString(context, string, from, to); |
1802 array.Push(substr); | 1792 array.Push(substr); |
1803 | 1793 |
1804 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); | 1794 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); |
1805 } | 1795 } |
1806 | 1796 |
1807 // Add all captures to the array. | 1797 // Add all captures to the array. |
1808 { | 1798 { |
1809 Node* const num_registers = LoadMatchInfoField( | 1799 Node* const num_registers = a->LoadFixedArrayElement( |
1810 a, match_indices, RegExpMatchInfo::kNumberOfCapturesIndex); | 1800 match_indices, RegExpMatchInfo::kNumberOfCapturesIndex); |
1811 Node* const int_num_registers = a->SmiUntag(num_registers); | 1801 Node* const int_num_registers = a->SmiUntag(num_registers); |
1812 | 1802 |
1813 CVariable var_reg(a, MachineType::PointerRepresentation()); | 1803 CVariable var_reg(a, MachineType::PointerRepresentation()); |
1814 var_reg.Bind(a->IntPtrConstant(2)); | 1804 var_reg.Bind(a->IntPtrConstant(2)); |
1815 | 1805 |
1816 CVariable* vars[] = {array.var_array(), array.var_length(), | 1806 CVariable* vars[] = {array.var_array(), array.var_length(), |
1817 array.var_capacity(), &var_reg}; | 1807 array.var_capacity(), &var_reg}; |
1818 const int vars_count = sizeof(vars) / sizeof(vars[0]); | 1808 const int vars_count = sizeof(vars) / sizeof(vars[0]); |
1819 CLabel nested_loop(a, vars_count, vars), nested_loop_out(a); | 1809 CLabel nested_loop(a, vars_count, vars), nested_loop_out(a); |
1820 a->Branch(a->IntPtrLessThan(var_reg.value(), int_num_registers), | 1810 a->Branch(a->IntPtrLessThan(var_reg.value(), int_num_registers), |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2018 a->GotoIf(a->WordEqual(res, null), &out); | 2008 a->GotoIf(a->WordEqual(res, null), &out); |
2019 | 2009 |
2020 // Reload last match info since it might have changed. | 2010 // Reload last match info since it might have changed. |
2021 last_match_info = a->LoadContextElement( | 2011 last_match_info = a->LoadContextElement( |
2022 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2012 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
2023 | 2013 |
2024 Node* const res_length = a->LoadJSArrayLength(res); | 2014 Node* const res_length = a->LoadJSArrayLength(res); |
2025 Node* const res_elems = a->LoadElements(res); | 2015 Node* const res_elems = a->LoadElements(res); |
2026 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); | 2016 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); |
2027 | 2017 |
2028 Node* const num_capture_registers = LoadMatchInfoField( | 2018 Node* const num_capture_registers = a->LoadFixedArrayElement( |
2029 a, last_match_info, RegExpMatchInfo::kNumberOfCapturesIndex); | 2019 last_match_info, RegExpMatchInfo::kNumberOfCapturesIndex); |
2030 | 2020 |
2031 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); | 2021 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); |
2032 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), | 2022 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), |
2033 &if_noexplicitcaptures, &if_hasexplicitcaptures); | 2023 &if_noexplicitcaptures, &if_hasexplicitcaptures); |
2034 | 2024 |
2035 a->Bind(&if_noexplicitcaptures); | 2025 a->Bind(&if_noexplicitcaptures); |
2036 { | 2026 { |
2037 // If the number of captures is two then there are no explicit captures in | 2027 // If the number of captures is two then there are no explicit captures in |
2038 // the regexp, just the implicit capture that captures the whole match. In | 2028 // the regexp, just the implicit capture that captures the whole match. In |
2039 // this case we can simplify quite a bit and end up with something faster. | 2029 // this case we can simplify quite a bit and end up with something faster. |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2234 a->Bind(&if_didnotmatch); | 2224 a->Bind(&if_didnotmatch); |
2235 { | 2225 { |
2236 FastStoreLastIndex(a, regexp, smi_zero); | 2226 FastStoreLastIndex(a, regexp, smi_zero); |
2237 var_result.Bind(subject_string); | 2227 var_result.Bind(subject_string); |
2238 a->Goto(&out); | 2228 a->Goto(&out); |
2239 } | 2229 } |
2240 | 2230 |
2241 a->Bind(&if_matched); | 2231 a->Bind(&if_matched); |
2242 { | 2232 { |
2243 Node* const subject_start = smi_zero; | 2233 Node* const subject_start = smi_zero; |
2244 Node* const match_start = LoadMatchInfoField( | 2234 Node* const match_start = a->LoadFixedArrayElement( |
2245 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); | 2235 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
2246 Node* const match_end = LoadMatchInfoField( | 2236 Node* const match_end = a->LoadFixedArrayElement( |
2247 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); | 2237 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
2248 Node* const subject_end = a->LoadStringLength(subject_string); | 2238 Node* const subject_end = a->LoadStringLength(subject_string); |
2249 | 2239 |
2250 CLabel if_replaceisempty(a), if_replaceisnotempty(a); | 2240 CLabel if_replaceisempty(a), if_replaceisnotempty(a); |
2251 Node* const replace_length = a->LoadStringLength(replace_string); | 2241 Node* const replace_length = a->LoadStringLength(replace_string); |
2252 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, | 2242 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, |
2253 &if_replaceisnotempty); | 2243 &if_replaceisnotempty); |
2254 | 2244 |
2255 a->Bind(&if_replaceisempty); | 2245 a->Bind(&if_replaceisempty); |
2256 { | 2246 { |
2257 // TODO(jgruber): We could skip many of the checks that using SubString | 2247 // TODO(jgruber): We could skip many of the checks that using SubString |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2412 a.Bind(&if_matched); | 2402 a.Bind(&if_matched); |
2413 { | 2403 { |
2414 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2404 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2415 match_indices, string); | 2405 match_indices, string); |
2416 a.Return(result); | 2406 a.Return(result); |
2417 } | 2407 } |
2418 } | 2408 } |
2419 | 2409 |
2420 } // namespace internal | 2410 } // namespace internal |
2421 } // namespace v8 | 2411 } // namespace v8 |
OLD | NEW |