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 |
229 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, | 237 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
230 Node* context, Node* match_info, | 238 Node* context, Node* match_info, |
231 Node* string) { | 239 Node* string) { |
232 CLabel out(a); | 240 CLabel out(a); |
233 | 241 |
234 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 242 Node* const num_indices = a->SmiUntag(LoadMatchInfoField( |
235 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 243 a, match_info, RegExpMatchInfo::kNumberOfCapturesIndex)); |
236 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, | |
237 mode)); | |
238 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); | 244 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); |
239 Node* const start = a->LoadFixedArrayElement( | 245 Node* const start = |
240 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, | 246 LoadMatchInfoField(a, match_info, RegExpMatchInfo::kFirstCaptureIndex); |
241 mode); | 247 Node* const end = LoadMatchInfoField(a, match_info, |
242 Node* const end = a->LoadFixedArrayElement( | 248 RegExpMatchInfo::kFirstCaptureIndex + 1); |
243 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, | |
244 mode); | |
245 | 249 |
246 // Calculate the substring of the first match before creating the result array | 250 // Calculate the substring of the first match before creating the result array |
247 // to avoid an unnecessary write barrier storing the first result. | 251 // to avoid an unnecessary write barrier storing the first result. |
248 Node* const first = a->SubString(context, string, start, end); | 252 Node* const first = a->SubString(context, string, start, end); |
249 | 253 |
250 Node* const result = | 254 Node* const result = |
251 a->AllocateRegExpResult(context, num_results, start, string); | 255 a->AllocateRegExpResult(context, num_results, start, string); |
252 Node* const result_elements = a->LoadElements(result); | 256 Node* const result_elements = a->LoadElements(result); |
253 | 257 |
254 a->StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); | 258 a->StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 | 413 |
410 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); | 414 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); |
411 a->Goto(if_didnotmatch); | 415 a->Goto(if_didnotmatch); |
412 } | 416 } |
413 | 417 |
414 a->Bind(&successful_match); | 418 a->Bind(&successful_match); |
415 { | 419 { |
416 a->GotoUnless(should_update_last_index, &out); | 420 a->GotoUnless(should_update_last_index, &out); |
417 | 421 |
418 // Update the new last index from {match_indices}. | 422 // Update the new last index from {match_indices}. |
419 Node* const new_lastindex = a->LoadFixedArrayElement( | 423 Node* const new_lastindex = LoadMatchInfoField( |
420 match_indices, | 424 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
421 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | |
422 | 425 |
423 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); | 426 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); |
424 a->Goto(&out); | 427 a->Goto(&out); |
425 } | 428 } |
426 | 429 |
427 a->Bind(&out); | 430 a->Bind(&out); |
428 return var_result.value(); | 431 return var_result.value(); |
429 } | 432 } |
430 | 433 |
431 // ES#sec-regexp.prototype.exec | 434 // ES#sec-regexp.prototype.exec |
(...skipping 22 matching lines...) Expand all Loading... |
454 a->Bind(&if_didnotmatch); | 457 a->Bind(&if_didnotmatch); |
455 { | 458 { |
456 var_result.Bind(null); | 459 var_result.Bind(null); |
457 a->Goto(&out); | 460 a->Goto(&out); |
458 } | 461 } |
459 | 462 |
460 a->Bind(&out); | 463 a->Bind(&out); |
461 return var_result.value(); | 464 return var_result.value(); |
462 } | 465 } |
463 | 466 |
464 } // namespace | |
465 | |
466 namespace { | |
467 | |
468 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 467 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
469 Node* context, Node* value, | 468 Node* context, Node* value, |
470 MessageTemplate::Template msg_template, | 469 MessageTemplate::Template msg_template, |
471 char const* method_name) { | 470 char const* method_name) { |
472 CLabel out(a), throw_exception(a, CLabel::kDeferred); | 471 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
473 CVariable var_value_map(a, MachineRepresentation::kTagged); | 472 CVariable var_value_map(a, MachineRepresentation::kTagged); |
474 | 473 |
475 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 474 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
476 | 475 |
477 // Load the instance type of the {value}. | 476 // Load the instance type of the {value}. |
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1128 void Builtins::Generate_RegExpPrototypeTest(CodeAssemblerState* state) { | 1127 void Builtins::Generate_RegExpPrototypeTest(CodeAssemblerState* state) { |
1129 CodeStubAssembler a(state); | 1128 CodeStubAssembler a(state); |
1130 | 1129 |
1131 Isolate* const isolate = a.isolate(); | 1130 Isolate* const isolate = a.isolate(); |
1132 | 1131 |
1133 Node* const maybe_receiver = a.Parameter(0); | 1132 Node* const maybe_receiver = a.Parameter(0); |
1134 Node* const maybe_string = a.Parameter(1); | 1133 Node* const maybe_string = a.Parameter(1); |
1135 Node* const context = a.Parameter(4); | 1134 Node* const context = a.Parameter(4); |
1136 | 1135 |
1137 // Ensure {maybe_receiver} is a JSReceiver. | 1136 // Ensure {maybe_receiver} is a JSReceiver. |
1138 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1137 Node* const map = ThrowIfNotJSReceiver( |
1139 MessageTemplate::kIncompatibleMethodReceiver, | 1138 &a, isolate, context, maybe_receiver, |
1140 "RegExp.prototype.test"); | 1139 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.test"); |
1141 Node* const receiver = maybe_receiver; | 1140 Node* const receiver = maybe_receiver; |
1142 | 1141 |
1143 // Convert {maybe_string} to a String. | 1142 // Convert {maybe_string} to a String. |
1144 Node* const string = a.ToString(context, maybe_string); | 1143 Node* const string = a.ToString(context, maybe_string); |
1145 | 1144 |
1146 // Call exec. | 1145 CLabel fast_path(&a), slow_path(&a); |
1147 Node* const match_indices = RegExpExec(&a, context, receiver, string); | 1146 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
1148 | 1147 |
1149 // Return true iff exec matched successfully. | 1148 a.Bind(&fast_path); |
1150 Node* const result = a.Select(a.WordEqual(match_indices, a.NullConstant()), | 1149 { |
1151 a.FalseConstant(), a.TrueConstant()); | 1150 CLabel if_didnotmatch(&a); |
1152 a.Return(result); | 1151 RegExpPrototypeExecBodyWithoutResult(&a, context, receiver, string, |
| 1152 &if_didnotmatch, true); |
| 1153 a.Return(a.TrueConstant()); |
| 1154 |
| 1155 a.Bind(&if_didnotmatch); |
| 1156 a.Return(a.FalseConstant()); |
| 1157 } |
| 1158 |
| 1159 a.Bind(&slow_path); |
| 1160 { |
| 1161 // Call exec. |
| 1162 Node* const match_indices = RegExpExec(&a, context, receiver, string); |
| 1163 |
| 1164 // Return true iff exec matched successfully. |
| 1165 Node* const result = a.Select(a.WordEqual(match_indices, a.NullConstant()), |
| 1166 a.FalseConstant(), a.TrueConstant()); |
| 1167 a.Return(result); |
| 1168 } |
1153 } | 1169 } |
1154 | 1170 |
1155 namespace { | 1171 namespace { |
1156 | 1172 |
1157 Node* AdvanceStringIndex(CodeStubAssembler* a, Node* const string, | 1173 Node* AdvanceStringIndex(CodeStubAssembler* a, Node* const string, |
1158 Node* const index, Node* const is_unicode) { | 1174 Node* const index, Node* const is_unicode) { |
1159 CVariable var_result(a, MachineRepresentation::kTagged); | 1175 CVariable var_result(a, MachineRepresentation::kTagged); |
1160 | 1176 |
1161 // Default to last_index + 1. | 1177 // Default to last_index + 1. |
1162 Node* const index_plus_one = a->SmiAdd(index, a->SmiConstant(1)); | 1178 Node* const index_plus_one = a->SmiAdd(index, a->SmiConstant(1)); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1312 return to_array; | 1328 return to_array; |
1313 } | 1329 } |
1314 | 1330 |
1315 private: | 1331 private: |
1316 CodeStubAssembler* const assembler_; | 1332 CodeStubAssembler* const assembler_; |
1317 CVariable var_array_; | 1333 CVariable var_array_; |
1318 CVariable var_length_; | 1334 CVariable var_length_; |
1319 CVariable var_capacity_; | 1335 CVariable var_capacity_; |
1320 }; | 1336 }; |
1321 | 1337 |
1322 void Generate_RegExpPrototypeMatchBody(CodeStubAssembler* a, | 1338 void RegExpPrototypeMatchBody(CodeStubAssembler* a, Node* const receiver, |
1323 Node* const receiver, Node* const string, | 1339 Node* const string, Node* const context, |
1324 Node* const context, | 1340 const bool is_fastpath) { |
1325 const bool is_fastpath) { | |
1326 Isolate* const isolate = a->isolate(); | 1341 Isolate* const isolate = a->isolate(); |
1327 | 1342 |
1328 Node* const null = a->NullConstant(); | 1343 Node* const null = a->NullConstant(); |
1329 Node* const int_zero = a->IntPtrConstant(0); | 1344 Node* const int_zero = a->IntPtrConstant(0); |
1330 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1345 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1331 | 1346 |
1332 Node* const regexp = receiver; | 1347 Node* const regexp = receiver; |
1333 Node* const is_global = | 1348 Node* const is_global = |
1334 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); | 1349 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); |
1335 | 1350 |
(...skipping 22 matching lines...) Expand all Loading... |
1358 // Loop preparations. Within the loop, collect results from RegExpExec | 1373 // Loop preparations. Within the loop, collect results from RegExpExec |
1359 // and store match strings in the array. | 1374 // and store match strings in the array. |
1360 | 1375 |
1361 CVariable* vars[] = {array.var_array(), array.var_length(), | 1376 CVariable* vars[] = {array.var_array(), array.var_length(), |
1362 array.var_capacity()}; | 1377 array.var_capacity()}; |
1363 CLabel loop(a, 3, vars), out(a); | 1378 CLabel loop(a, 3, vars), out(a); |
1364 a->Goto(&loop); | 1379 a->Goto(&loop); |
1365 | 1380 |
1366 a->Bind(&loop); | 1381 a->Bind(&loop); |
1367 { | 1382 { |
1368 Node* const result = is_fastpath ? RegExpPrototypeExecBody( | 1383 CVariable var_match(a, MachineRepresentation::kTagged); |
1369 a, context, regexp, string, true) | |
1370 : RegExpExec(a, context, regexp, string); | |
1371 | 1384 |
1372 CLabel if_didmatch(a), if_didnotmatch(a); | 1385 CLabel if_didmatch(a), if_didnotmatch(a); |
1373 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); | 1386 if (is_fastpath) { |
| 1387 // On the fast path, grab the matching string from the raw match index |
| 1388 // array. |
| 1389 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( |
| 1390 a, context, regexp, string, &if_didnotmatch, true); |
1374 | 1391 |
1375 a->Bind(&if_didnotmatch); | 1392 Node* const match_from = LoadMatchInfoField( |
1376 { | 1393 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
1377 // Return null if there were no matches, otherwise just exit the loop. | 1394 Node* const match_to = LoadMatchInfoField( |
1378 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); | 1395 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
1379 a->Return(null); | |
1380 } | |
1381 | 1396 |
1382 a->Bind(&if_didmatch); | 1397 Node* match = a->SubString(context, string, match_from, match_to); |
1383 { | 1398 var_match.Bind(match); |
1384 Node* match = nullptr; | |
1385 if (is_fastpath) { | |
1386 // TODO(jgruber): We could optimize further here and in other | |
1387 // methods (e.g. @@search) by bypassing RegExp result construction. | |
1388 Node* const result_fixed_array = a->LoadElements(result); | |
1389 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | |
1390 match = | |
1391 a->LoadFixedArrayElement(result_fixed_array, int_zero, 0, mode); | |
1392 | 1399 |
1393 // The match is guaranteed to be a string on the fast path. | 1400 a->Goto(&if_didmatch); |
1394 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); | 1401 } else { |
1395 } else { | 1402 DCHECK(!is_fastpath); |
1396 DCHECK(!is_fastpath); | 1403 Node* const result = RegExpExec(a, context, regexp, string); |
1397 | 1404 |
1398 CVariable var_match(a, MachineRepresentation::kTagged); | 1405 CLabel load_match(a); |
1399 CLabel fast_result(a), slow_result(a), match_loaded(a); | 1406 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &load_match); |
| 1407 |
| 1408 a->Bind(&load_match); |
| 1409 { |
| 1410 CLabel fast_result(a), slow_result(a); |
1400 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, | 1411 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, |
1401 &slow_result); | 1412 &slow_result); |
1402 | 1413 |
1403 a->Bind(&fast_result); | 1414 a->Bind(&fast_result); |
1404 { | 1415 { |
1405 // TODO(jgruber): We could optimize further here and in other | |
1406 // methods (e.g. @@search) by bypassing RegExp result construction. | |
1407 Node* const result_fixed_array = a->LoadElements(result); | 1416 Node* const result_fixed_array = a->LoadElements(result); |
1408 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1417 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
1409 Node* const match = | 1418 Node* const match = |
1410 a->LoadFixedArrayElement(result_fixed_array, int_zero, 0, mode); | 1419 a->LoadFixedArrayElement(result_fixed_array, int_zero, 0, mode); |
1411 | 1420 |
1412 // The match is guaranteed to be a string on the fast path. | 1421 // The match is guaranteed to be a string on the fast path. |
1413 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); | 1422 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); |
1414 | 1423 |
1415 var_match.Bind(match); | 1424 var_match.Bind(match); |
1416 a->Goto(&match_loaded); | 1425 a->Goto(&if_didmatch); |
1417 } | 1426 } |
1418 | 1427 |
1419 a->Bind(&slow_result); | 1428 a->Bind(&slow_result); |
1420 { | 1429 { |
1421 // TODO(ishell): Use GetElement stub once it's available. | 1430 // TODO(ishell): Use GetElement stub once it's available. |
1422 Node* const name = smi_zero; | 1431 Node* const name = smi_zero; |
1423 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 1432 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
1424 Node* const match = | 1433 Node* const match = |
1425 a->CallStub(getproperty_callable, context, result, name); | 1434 a->CallStub(getproperty_callable, context, result, name); |
1426 | 1435 |
1427 var_match.Bind(match); | 1436 var_match.Bind(a->ToString(context, match)); |
1428 a->Goto(&match_loaded); | 1437 a->Goto(&if_didmatch); |
1429 } | 1438 } |
| 1439 } |
| 1440 } |
1430 | 1441 |
1431 a->Bind(&match_loaded); | 1442 a->Bind(&if_didnotmatch); |
1432 match = a->ToString(context, var_match.value()); | 1443 { |
1433 } | 1444 // Return null if there were no matches, otherwise just exit the loop. |
1434 DCHECK(match != nullptr); | 1445 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); |
| 1446 a->Return(null); |
| 1447 } |
| 1448 |
| 1449 a->Bind(&if_didmatch); |
| 1450 { |
| 1451 Node* match = var_match.value(); |
1435 | 1452 |
1436 // Store the match, growing the fixed array if needed. | 1453 // Store the match, growing the fixed array if needed. |
1437 | 1454 |
1438 array.Push(match); | 1455 array.Push(match); |
1439 | 1456 |
1440 // Advance last index if the match is the empty string. | 1457 // Advance last index if the match is the empty string. |
1441 | 1458 |
1442 Node* const match_length = a->LoadStringLength(match); | 1459 Node* const match_length = a->LoadStringLength(match); |
1443 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); | 1460 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); |
1444 | 1461 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match"); | 1500 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match"); |
1484 Node* const receiver = maybe_receiver; | 1501 Node* const receiver = maybe_receiver; |
1485 | 1502 |
1486 // Convert {maybe_string} to a String. | 1503 // Convert {maybe_string} to a String. |
1487 Node* const string = a.ToString(context, maybe_string); | 1504 Node* const string = a.ToString(context, maybe_string); |
1488 | 1505 |
1489 CLabel fast_path(&a), slow_path(&a); | 1506 CLabel fast_path(&a), slow_path(&a); |
1490 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); | 1507 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
1491 | 1508 |
1492 a.Bind(&fast_path); | 1509 a.Bind(&fast_path); |
1493 Generate_RegExpPrototypeMatchBody(&a, receiver, string, context, true); | 1510 RegExpPrototypeMatchBody(&a, receiver, string, context, true); |
1494 | 1511 |
1495 a.Bind(&slow_path); | 1512 a.Bind(&slow_path); |
1496 Generate_RegExpPrototypeMatchBody(&a, receiver, string, context, false); | 1513 RegExpPrototypeMatchBody(&a, receiver, string, context, false); |
1497 } | 1514 } |
1498 | 1515 |
1499 namespace { | 1516 namespace { |
1500 | 1517 |
1501 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1518 void RegExpPrototypeSearchBodyFast(CodeStubAssembler* a, Node* const receiver, |
1502 Node* const receiver, | 1519 Node* const string, Node* const context) { |
1503 Node* const string, Node* const context, | 1520 // Grab the initial value of last index. |
1504 bool is_fastpath) { | 1521 Node* const previous_last_index = FastLoadLastIndex(a, receiver); |
| 1522 |
| 1523 // Ensure last index is 0. |
| 1524 FastStoreLastIndex(a, receiver, a->SmiConstant(Smi::kZero)); |
| 1525 |
| 1526 // Call exec. |
| 1527 CLabel if_didnotmatch(a); |
| 1528 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( |
| 1529 a, context, receiver, string, &if_didnotmatch, true); |
| 1530 |
| 1531 // Successful match. |
| 1532 { |
| 1533 // Reset last index. |
| 1534 FastStoreLastIndex(a, receiver, previous_last_index); |
| 1535 |
| 1536 // Return the index of the match. |
| 1537 Node* const index = LoadMatchInfoField(a, match_indices, |
| 1538 RegExpMatchInfo::kFirstCaptureIndex); |
| 1539 a->Return(index); |
| 1540 } |
| 1541 |
| 1542 a->Bind(&if_didnotmatch); |
| 1543 { |
| 1544 // Reset last index and return -1. |
| 1545 FastStoreLastIndex(a, receiver, previous_last_index); |
| 1546 a->Return(a->SmiConstant(-1)); |
| 1547 } |
| 1548 } |
| 1549 |
| 1550 void RegExpPrototypeSearchBodySlow(CodeStubAssembler* a, Node* const receiver, |
| 1551 Node* const string, Node* const context) { |
1505 Isolate* const isolate = a->isolate(); | 1552 Isolate* const isolate = a->isolate(); |
1506 | 1553 |
1507 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1554 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1508 | 1555 |
1509 // Grab the initial value of last index. | 1556 // Grab the initial value of last index. |
1510 Node* const previous_last_index = | 1557 Node* const previous_last_index = SlowLoadLastIndex(a, context, receiver); |
1511 LoadLastIndex(a, context, receiver, is_fastpath); | |
1512 | 1558 |
1513 // Ensure last index is 0. | 1559 // Ensure last index is 0. |
1514 if (is_fastpath) { | 1560 { |
1515 FastStoreLastIndex(a, receiver, smi_zero); | |
1516 } else { | |
1517 CLabel next(a); | 1561 CLabel next(a); |
1518 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1562 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
1519 | 1563 |
1520 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1564 SlowStoreLastIndex(a, context, receiver, smi_zero); |
1521 a->Goto(&next); | 1565 a->Goto(&next); |
1522 a->Bind(&next); | 1566 a->Bind(&next); |
1523 } | 1567 } |
1524 | 1568 |
1525 // Call exec. | 1569 // Call exec. |
1526 Node* const match_indices = | 1570 Node* const exec_result = RegExpExec(a, context, receiver, string); |
1527 is_fastpath ? RegExpPrototypeExecBody(a, context, receiver, string, true) | |
1528 : RegExpExec(a, context, receiver, string); | |
1529 | 1571 |
1530 // Reset last index if necessary. | 1572 // Reset last index if necessary. |
1531 if (is_fastpath) { | 1573 { |
1532 FastStoreLastIndex(a, receiver, previous_last_index); | |
1533 } else { | |
1534 CLabel next(a); | 1574 CLabel next(a); |
1535 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1575 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
1536 | 1576 |
1537 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1577 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
1538 &next); | 1578 &next); |
1539 | 1579 |
1540 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1580 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
1541 a->Goto(&next); | 1581 a->Goto(&next); |
| 1582 |
1542 a->Bind(&next); | 1583 a->Bind(&next); |
1543 } | 1584 } |
1544 | 1585 |
1545 // Return -1 if no match was found. | 1586 // Return -1 if no match was found. |
1546 { | 1587 { |
1547 CLabel next(a); | 1588 CLabel next(a); |
1548 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); | 1589 a->GotoUnless(a->WordEqual(exec_result, a->NullConstant()), &next); |
1549 a->Return(a->SmiConstant(-1)); | 1590 a->Return(a->SmiConstant(-1)); |
1550 a->Bind(&next); | 1591 a->Bind(&next); |
1551 } | 1592 } |
1552 | 1593 |
1553 // Return the index of the match. | 1594 // Return the index of the match. |
1554 if (is_fastpath) { | 1595 { |
1555 Node* const index = a->LoadObjectField( | |
1556 match_indices, JSRegExpResult::kIndexOffset, MachineType::AnyTagged()); | |
1557 a->Return(index); | |
1558 } else { | |
1559 DCHECK(!is_fastpath); | |
1560 | |
1561 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); | 1596 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); |
1562 BranchIfFastRegExpResult(a, context, a->LoadMap(match_indices), | 1597 BranchIfFastRegExpResult(a, context, a->LoadMap(exec_result), &fast_result, |
1563 &fast_result, &slow_result); | 1598 &slow_result); |
1564 | 1599 |
1565 a->Bind(&fast_result); | 1600 a->Bind(&fast_result); |
1566 { | 1601 { |
1567 Node* const index = | 1602 Node* const index = |
1568 a->LoadObjectField(match_indices, JSRegExpResult::kIndexOffset, | 1603 a->LoadObjectField(exec_result, JSRegExpResult::kIndexOffset); |
1569 MachineType::AnyTagged()); | |
1570 a->Return(index); | 1604 a->Return(index); |
1571 } | 1605 } |
1572 | 1606 |
1573 a->Bind(&slow_result); | 1607 a->Bind(&slow_result); |
1574 { | 1608 { |
1575 Node* const name = a->HeapConstant(isolate->factory()->index_string()); | 1609 Node* const name = a->HeapConstant(isolate->factory()->index_string()); |
1576 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 1610 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
1577 Node* const index = | 1611 Node* const index = |
1578 a->CallStub(getproperty_callable, context, match_indices, name); | 1612 a->CallStub(getproperty_callable, context, exec_result, name); |
1579 a->Return(index); | 1613 a->Return(index); |
1580 } | 1614 } |
1581 } | 1615 } |
1582 } | 1616 } |
1583 | 1617 |
1584 } // namespace | 1618 } // namespace |
1585 | 1619 |
1586 // ES#sec-regexp.prototype-@@search | 1620 // ES#sec-regexp.prototype-@@search |
1587 // RegExp.prototype [ @@search ] ( string ) | 1621 // RegExp.prototype [ @@search ] ( string ) |
1588 void Builtins::Generate_RegExpPrototypeSearch(CodeAssemblerState* state) { | 1622 void Builtins::Generate_RegExpPrototypeSearch(CodeAssemblerState* state) { |
(...skipping 12 matching lines...) Expand all Loading... |
1601 "RegExp.prototype.@@search"); | 1635 "RegExp.prototype.@@search"); |
1602 Node* const receiver = maybe_receiver; | 1636 Node* const receiver = maybe_receiver; |
1603 | 1637 |
1604 // Convert {maybe_string} to a String. | 1638 // Convert {maybe_string} to a String. |
1605 Node* const string = a.ToString(context, maybe_string); | 1639 Node* const string = a.ToString(context, maybe_string); |
1606 | 1640 |
1607 CLabel fast_path(&a), slow_path(&a); | 1641 CLabel fast_path(&a), slow_path(&a); |
1608 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); | 1642 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
1609 | 1643 |
1610 a.Bind(&fast_path); | 1644 a.Bind(&fast_path); |
1611 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, true); | 1645 RegExpPrototypeSearchBodyFast(&a, receiver, string, context); |
1612 | 1646 |
1613 a.Bind(&slow_path); | 1647 a.Bind(&slow_path); |
1614 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, false); | 1648 RegExpPrototypeSearchBodySlow(&a, receiver, string, context); |
1615 } | 1649 } |
1616 | 1650 |
1617 namespace { | 1651 namespace { |
1618 | 1652 |
1619 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, | 1653 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, |
1620 // {string} is a String, and {limit} is a Smi. | 1654 // {string} is a String, and {limit} is a Smi. |
1621 void Generate_RegExpPrototypeSplitBody(CodeStubAssembler* a, Node* const regexp, | 1655 void Generate_RegExpPrototypeSplitBody(CodeStubAssembler* a, Node* const regexp, |
1622 Node* const string, Node* const limit, | 1656 Node* const string, Node* const limit, |
1623 Node* const context) { | 1657 Node* const context) { |
1624 Isolate* isolate = a->isolate(); | 1658 Isolate* isolate = a->isolate(); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1722 a->CallStub(exec_callable, context, regexp, string, next_search_from, | 1756 a->CallStub(exec_callable, context, regexp, string, next_search_from, |
1723 last_match_info); | 1757 last_match_info); |
1724 | 1758 |
1725 // We're done if no match was found. | 1759 // We're done if no match was found. |
1726 { | 1760 { |
1727 CLabel next(a); | 1761 CLabel next(a); |
1728 a->Branch(a->WordEqual(match_indices, null), &push_suffix_and_out, &next); | 1762 a->Branch(a->WordEqual(match_indices, null), &push_suffix_and_out, &next); |
1729 a->Bind(&next); | 1763 a->Bind(&next); |
1730 } | 1764 } |
1731 | 1765 |
1732 Node* const match_from = a->LoadFixedArrayElement( | 1766 Node* const match_from = LoadMatchInfoField( |
1733 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), | 1767 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
1734 0, mode); | |
1735 | 1768 |
1736 // We're done if the match starts beyond the string. | 1769 // We're done if the match starts beyond the string. |
1737 { | 1770 { |
1738 CLabel next(a); | 1771 CLabel next(a); |
1739 a->Branch(a->WordEqual(match_from, string_length), &push_suffix_and_out, | 1772 a->Branch(a->WordEqual(match_from, string_length), &push_suffix_and_out, |
1740 &next); | 1773 &next); |
1741 a->Bind(&next); | 1774 a->Bind(&next); |
1742 } | 1775 } |
1743 | 1776 |
1744 Node* const match_to = a->LoadFixedArrayElement( | 1777 Node* const match_to = LoadMatchInfoField( |
1745 match_indices, | 1778 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
1746 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); | |
1747 | 1779 |
1748 // Advance index and continue if the match is empty. | 1780 // Advance index and continue if the match is empty. |
1749 { | 1781 { |
1750 CLabel next(a); | 1782 CLabel next(a); |
1751 | 1783 |
1752 a->GotoUnless(a->SmiEqual(match_to, next_search_from), &next); | 1784 a->GotoUnless(a->SmiEqual(match_to, next_search_from), &next); |
1753 a->GotoUnless(a->SmiEqual(match_to, last_matched_until), &next); | 1785 a->GotoUnless(a->SmiEqual(match_to, last_matched_until), &next); |
1754 | 1786 |
1755 Node* const is_unicode = FastFlagGetter(a, regexp, JSRegExp::kUnicode); | 1787 Node* const is_unicode = FastFlagGetter(a, regexp, JSRegExp::kUnicode); |
1756 Node* const new_next_search_from = | 1788 Node* const new_next_search_from = |
(...skipping 10 matching lines...) Expand all Loading... |
1767 Node* const to = match_from; | 1799 Node* const to = match_from; |
1768 | 1800 |
1769 Node* const substr = a->SubString(context, string, from, to); | 1801 Node* const substr = a->SubString(context, string, from, to); |
1770 array.Push(substr); | 1802 array.Push(substr); |
1771 | 1803 |
1772 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); | 1804 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); |
1773 } | 1805 } |
1774 | 1806 |
1775 // Add all captures to the array. | 1807 // Add all captures to the array. |
1776 { | 1808 { |
1777 Node* const num_registers = a->LoadFixedArrayElement( | 1809 Node* const num_registers = LoadMatchInfoField( |
1778 match_indices, | 1810 a, match_indices, RegExpMatchInfo::kNumberOfCapturesIndex); |
1779 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); | |
1780 Node* const int_num_registers = a->SmiUntag(num_registers); | 1811 Node* const int_num_registers = a->SmiUntag(num_registers); |
1781 | 1812 |
1782 CVariable var_reg(a, MachineType::PointerRepresentation()); | 1813 CVariable var_reg(a, MachineType::PointerRepresentation()); |
1783 var_reg.Bind(a->IntPtrConstant(2)); | 1814 var_reg.Bind(a->IntPtrConstant(2)); |
1784 | 1815 |
1785 CVariable* vars[] = {array.var_array(), array.var_length(), | 1816 CVariable* vars[] = {array.var_array(), array.var_length(), |
1786 array.var_capacity(), &var_reg}; | 1817 array.var_capacity(), &var_reg}; |
1787 const int vars_count = sizeof(vars) / sizeof(vars[0]); | 1818 const int vars_count = sizeof(vars) / sizeof(vars[0]); |
1788 CLabel nested_loop(a, vars_count, vars), nested_loop_out(a); | 1819 CLabel nested_loop(a, vars_count, vars), nested_loop_out(a); |
1789 a->Branch(a->IntPtrLessThan(var_reg.value(), int_num_registers), | 1820 a->Branch(a->IntPtrLessThan(var_reg.value(), int_num_registers), |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1987 a->GotoIf(a->WordEqual(res, null), &out); | 2018 a->GotoIf(a->WordEqual(res, null), &out); |
1988 | 2019 |
1989 // Reload last match info since it might have changed. | 2020 // Reload last match info since it might have changed. |
1990 last_match_info = a->LoadContextElement( | 2021 last_match_info = a->LoadContextElement( |
1991 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2022 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1992 | 2023 |
1993 Node* const res_length = a->LoadJSArrayLength(res); | 2024 Node* const res_length = a->LoadJSArrayLength(res); |
1994 Node* const res_elems = a->LoadElements(res); | 2025 Node* const res_elems = a->LoadElements(res); |
1995 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); | 2026 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); |
1996 | 2027 |
1997 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2028 Node* const num_capture_registers = LoadMatchInfoField( |
1998 Node* const num_capture_registers = a->LoadFixedArrayElement( | 2029 a, last_match_info, RegExpMatchInfo::kNumberOfCapturesIndex); |
1999 last_match_info, | |
2000 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); | |
2001 | 2030 |
2002 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); | 2031 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); |
2003 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), | 2032 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), |
2004 &if_noexplicitcaptures, &if_hasexplicitcaptures); | 2033 &if_noexplicitcaptures, &if_hasexplicitcaptures); |
2005 | 2034 |
2006 a->Bind(&if_noexplicitcaptures); | 2035 a->Bind(&if_noexplicitcaptures); |
2007 { | 2036 { |
2008 // If the number of captures is two then there are no explicit captures in | 2037 // If the number of captures is two then there are no explicit captures in |
2009 // the regexp, just the implicit capture that captures the whole match. In | 2038 // the regexp, just the implicit capture that captures the whole match. In |
2010 // this case we can simplify quite a bit and end up with something faster. | 2039 // this case we can simplify quite a bit and end up with something faster. |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2204 | 2233 |
2205 a->Bind(&if_didnotmatch); | 2234 a->Bind(&if_didnotmatch); |
2206 { | 2235 { |
2207 FastStoreLastIndex(a, regexp, smi_zero); | 2236 FastStoreLastIndex(a, regexp, smi_zero); |
2208 var_result.Bind(subject_string); | 2237 var_result.Bind(subject_string); |
2209 a->Goto(&out); | 2238 a->Goto(&out); |
2210 } | 2239 } |
2211 | 2240 |
2212 a->Bind(&if_matched); | 2241 a->Bind(&if_matched); |
2213 { | 2242 { |
2214 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | |
2215 | |
2216 Node* const subject_start = smi_zero; | 2243 Node* const subject_start = smi_zero; |
2217 Node* const match_start = a->LoadFixedArrayElement( | 2244 Node* const match_start = LoadMatchInfoField( |
2218 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), | 2245 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
2219 0, mode); | 2246 Node* const match_end = LoadMatchInfoField( |
2220 Node* const match_end = a->LoadFixedArrayElement( | 2247 a, match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); |
2221 match_indices, | |
2222 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); | |
2223 Node* const subject_end = a->LoadStringLength(subject_string); | 2248 Node* const subject_end = a->LoadStringLength(subject_string); |
2224 | 2249 |
2225 CLabel if_replaceisempty(a), if_replaceisnotempty(a); | 2250 CLabel if_replaceisempty(a), if_replaceisnotempty(a); |
2226 Node* const replace_length = a->LoadStringLength(replace_string); | 2251 Node* const replace_length = a->LoadStringLength(replace_string); |
2227 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, | 2252 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, |
2228 &if_replaceisnotempty); | 2253 &if_replaceisnotempty); |
2229 | 2254 |
2230 a->Bind(&if_replaceisempty); | 2255 a->Bind(&if_replaceisempty); |
2231 { | 2256 { |
2232 // TODO(jgruber): We could skip many of the checks that using SubString | 2257 // 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... |
2387 a.Bind(&if_matched); | 2412 a.Bind(&if_matched); |
2388 { | 2413 { |
2389 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2414 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2390 match_indices, string); | 2415 match_indices, string); |
2391 a.Return(result); | 2416 a.Return(result); |
2392 } | 2417 } |
2393 } | 2418 } |
2394 | 2419 |
2395 } // namespace internal | 2420 } // namespace internal |
2396 } // namespace v8 | 2421 } // namespace v8 |
OLD | NEW |