Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: src/builtins/builtins-regexp.cc

Issue 2543483003: [regexp] Skip result construction in test, @@match, @@search (Closed)
Patch Set: Remove unused variables Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698