34constexpr int kStaticVectorSlots = 8;
37uint32_t GetArgcForReplaceCallable(uint32_t num_captures,
38 bool has_named_captures) {
39 const uint32_t kAdditionalArgsWithoutNamedCaptures = 2;
40 const uint32_t kAdditionalArgsWithNamedCaptures = 3;
42 uint32_t argc = has_named_captures
43 ? num_captures + kAdditionalArgsWithNamedCaptures
44 : num_captures + kAdditionalArgsWithoutNamedCaptures;
45 static_assert(Code::kMaxArguments < std::numeric_limits<uint32_t>::max() -
46 kAdditionalArgsWithNamedCaptures);
55template <
typename Matcher,
typename = std::enable_if<std::is_invocable_r_v<
57int LookupNamedCapture(Matcher name_matches,
63 int maybe_capture_index = -1;
65 DCHECK_LE(*index_in_out, named_capture_count);
66 for (
int j = *index_in_out; j < named_capture_count; j++) {
69 const int name_ix = j * 2;
70 const int index_ix = j * 2 + 1;
73 if (!name_matches(capture_name))
continue;
76 *index_in_out = j + 1;
80 return maybe_capture_index;
163 template <
typename Char>
166 int capture_count,
int subject_length) {
170 int length = characters.
length();
173 Char c = characters[
i];
175 int next_index =
i + 1;
176 if (next_index == length) {
179 Char c2 = characters[next_index];
186 last = next_index + 1;
230 int capture_ref = c2 -
'0';
231 if (capture_ref > capture_count) {
235 int second_digit_index = next_index + 1;
236 if (second_digit_index < length) {
238 Char c3 = characters[second_digit_index];
239 if (
'0' <= c3 && c3 <=
'9') {
240 int double_digit_ref = capture_ref * 10 + c3 -
'0';
241 if (double_digit_ref <= capture_count) {
242 next_index = second_digit_index;
243 capture_ref = double_digit_ref;
247 if (capture_ref > 0) {
252 DCHECK(capture_ref <= capture_count);
254 last = next_index + 1;
268 const int name_start_index = next_index + 1;
269 int closing_bracket_index = -1;
270 for (
int j = name_start_index; j <
length; j++) {
271 if (characters[j] ==
'>') {
272 closing_bracket_index = j;
279 if (closing_bracket_index == -1) {
290 characters.
SubVector(name_start_index, closing_bracket_index);
301 int capture_index = 0;
302 int capture_name_map_index = 0;
303 while (capture_index != -1) {
304 capture_index = LookupNamedCapture(
306 return capture_name->IsEqualTo(requested_name);
309 DCHECK(capture_index == -1 ||
310 (1 <= capture_index && capture_index <= capture_count));
318 last = closing_bracket_index + 1;
319 i = closing_bracket_index;
348 int capture_count,
int subject_length) {
355 if (capture_count > 0) {
361 Tagged<Object> maybe_capture_name_map = re_data->capture_name_map();
362 if (IsFixedArray(maybe_capture_name_map)) {
371 capture_count, subject_length);
375 capture_count, subject_length);
377 if (simple)
return true;
382 int substring_index = 0;
389 isolate->factory()->NewSubString(replacement, from, to));
391 part.data = substring_index;
395 part.data = substring_index;
403 int match_from,
int match_to, int32_t* match) {
411 int subject_length = part.data;
412 if (match_to < subject_length) {
418 int capture = part.data;
419 int from = match[capture * 2];
420 int to = match[capture * 2 + 1];
421 if (from >= 0 && to > from) {
439 uint8_t
pattern, std::vector<int>* indices,
440 unsigned int limit) {
444 const uint8_t* subject_start = subject.
begin();
445 const uint8_t* subject_end = subject_start + subject.
length();
446 const uint8_t*
pos = subject_start;
448 pos =
reinterpret_cast<const uint8_t*
>(
450 if (
pos ==
nullptr)
return;
451 indices->push_back(
static_cast<int>(
pos - subject_start));
459 unsigned int limit) {
466 indices->push_back(
static_cast<int>(
pos - subject_start));
472template <
typename SubjectChar,
typename PatternChar>
476 std::vector<int>* indices,
unsigned int limit) {
480 int pattern_length =
pattern.length();
484 index = search.
Search(subject, index);
485 if (index < 0)
return;
486 indices->push_back(index);
487 index += pattern_length;
494 std::vector<int>* indices,
unsigned int limit) {
507 if (pattern_vector.
length() == 1) {
524 if (pattern_vector.
length() == 1) {
534 if (pattern_vector.
length() == 1) {
547std::vector<int>* GetRewoundRegexpIndicesList(
Isolate* isolate) {
548 std::vector<int>* list = isolate->regexp_indices();
553void TruncateRegexpIndicesList(Isolate* isolate) {
559 static const int kMaxRegexpIndicesListCapacity = 8 * KB /
kIntSize;
560 std::vector<int>* indices = isolate->regexp_indices();
561 if (indices->capacity() > kMaxRegexpIndicesListCapacity) {
564 indices->shrink_to_fit();
569template <
typename ResultSeqString>
576 DCHECK(subject->IsFlat());
577 DCHECK(replacement->IsFlat());
579 std::vector<int>* indices = GetRewoundRegexpIndicesList(isolate);
582 int subject_len = subject->length();
583 int pattern_len =
pattern->length();
584 int replacement_len = replacement->length();
588 if (indices->empty())
return *subject;
591 int64_t result_len_64 = (
static_cast<int64_t
>(replacement_len) -
592 static_cast<int64_t
>(pattern_len)) *
593 static_cast<int64_t
>(indices->size()) +
594 static_cast<int64_t
>(subject_len);
600 result_len =
static_cast<int>(result_len_64);
602 if (result_len == 0) {
610 if (ResultSeqString::kHasOneByteEncoding) {
611 maybe_res = isolate->factory()->NewRawOneByteString(result_len);
613 maybe_res = isolate->factory()->NewRawTwoByteString(result_len);
620 for (
int index : *indices) {
622 if (subject_pos < index) {
624 subject_pos, index - subject_pos);
625 result_pos += index - subject_pos;
629 if (replacement_len > 0) {
632 result_pos += replacement_len;
635 subject_pos = index + pattern_len;
638 if (subject_pos < subject_len) {
640 subject_pos, subject_len - subject_pos);
643 int32_t match_indices[] = {indices->back(), indices->back() + pattern_len};
646 TruncateRegexpIndicesList(isolate);
656 DCHECK(subject->IsFlat());
657 DCHECK(replacement->IsFlat());
659 int capture_count = regexp_data->capture_count();
660 int subject_length = subject->length();
668 const bool simple_replace = compiled_replacement.
Compile(
669 isolate, regexp, regexp_data, replacement, capture_count, subject_length);
673 if (subject->IsOneByteRepresentation() &&
674 replacement->IsOneByteRepresentation()) {
676 isolate, subject, regexp, replacement, last_match_info,
680 isolate, subject, regexp, replacement, last_match_info,
687 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
689 int32_t* current_match = runner.FetchNext();
690 if (current_match ==
nullptr) {
691 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
698 int expected_parts = (compiled_replacement.
parts() + 1) * 4 + 1;
706 int start = current_match[0];
707 int end = current_match[1];
713 if (simple_replace) {
716 compiled_replacement.
Apply(&builder,
start,
end, current_match);
720 current_match = runner.FetchNext();
721 }
while (current_match !=
nullptr);
723 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
725 if (prev < subject_length) {
730 runner.LastSuccessfulMatch());
735template <
typename ResultSeqString>
741 DCHECK(subject->IsFlat());
746 if (subject->IsOneByteRepresentation()) {
748 isolate, subject, regexp, empty_string, last_match_info,
752 isolate, subject, regexp, empty_string, last_match_info,
759 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
761 int32_t* current_match = runner.FetchNext();
762 if (current_match ==
nullptr) {
763 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
767 int start = current_match[0];
768 int end = current_match[1];
769 int capture_count = regexp_data->capture_count();
770 int subject_length = subject->length();
776 if (ResultSeqString::kHasOneByteEncoding) {
778 isolate->factory()->NewRawOneByteString(
new_length).ToHandleChecked());
781 isolate->factory()->NewRawTwoByteString(
new_length).ToHandleChecked());
789 start = current_match[0];
790 end = current_match[1];
799 current_match = runner.FetchNext();
800 }
while (current_match !=
nullptr);
802 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
805 runner.LastSuccessfulMatch());
807 if (prev < subject_length) {
810 subject_length - prev);
817 int string_size = ResultSeqString::SizeFor(
position);
818 int allocated_string_size = ResultSeqString::SizeFor(
new_length);
819 int delta = allocated_string_size - string_size;
822 if (delta == 0)
return *answer;
833 if (!
heap->IsLargeObject(*answer)) {
834 heap->CreateFillerObjectAt(end_of_string, delta);
847 int subject_length = subject->length();
848 int pattern_length =
pattern->length();
851 if (limit == 0xFFFFFFFFu) {
855 &last_match_cache_unused,
873 std::vector<int>* indices = GetRewoundRegexpIndicesList(isolate);
877 if (
static_cast<uint32_t
>(indices->size()) < limit) {
878 indices->push_back(subject_length);
884 int part_count =
static_cast<int>(indices->size());
895 if (part_count == 1 && indices->at(0) == subject_length) {
896 elements->set(0, *subject);
900 int part_end = indices->at(
i);
902 isolate->factory()->NewProperSubString(subject, part_start, part_end);
903 elements->set(
i, *substring);
904 part_start = part_end + pattern_length;
908 if (limit == 0xFFFFFFFFu) {
909 if (
result->HasObjectElements()) {
911 isolate->factory()->empty_fixed_array(),
916 TruncateRegexpIndicesList(isolate);
923std::optional<int> RegExpExec(
Isolate* isolate, DirectHandle<JSRegExp> regexp,
924 DirectHandle<String> subject, int32_t index,
925 int32_t* result_offsets_vector,
926 uint32_t result_offsets_vector_length) {
931 isolate->counters()->regexp_entry_runtime()->Increment();
932 return RegExp::Exec(isolate, regexp, subject, index, result_offsets_vector,
933 result_offsets_vector_length);
936std::optional<int> ExperimentalOneshotExec(
937 Isolate* isolate, DirectHandle<JSRegExp> regexp,
938 DirectHandle<String> subject, int32_t index, int32_t* result_offsets_vector,
939 uint32_t result_offsets_vector_length) {
940 CHECK_GE(result_offsets_vector_length,
942 regexp->data(isolate)->capture_count()));
947 isolate->counters()->regexp_entry_runtime()->Increment();
949 result_offsets_vector,
950 result_offsets_vector_length);
962 uint32_t result_offsets_vector_length = 0;
966 int32_t* result_offsets_vector =
reinterpret_cast<int32_t*
>(
967 isolate->isolate_data()->regexp_exec_vector_argument());
970 std::optional<int>
result =
971 RegExpExec(isolate, regexp, subject, index, result_offsets_vector,
972 result_offsets_vector_length);
982 int32_t register_count;
986 DCHECK_EQ(*match_info, *isolate->regexp_last_match_info());
990 if (*
result != *match_info) {
991 isolate->native_context()->set_regexp_last_match_info(*
result);
1004 uint32_t result_offsets_vector_length = 0;
1008 int32_t* result_offsets_vector =
reinterpret_cast<int32_t*
>(
1009 isolate->isolate_data()->regexp_exec_vector_argument());
1012 std::optional<int>
result = ExperimentalOneshotExec(
1013 isolate, regexp, subject, index, result_offsets_vector,
1014 result_offsets_vector_length);
1027 DCHECK(regexp->flags() & JSRegExp::kHasIndices);
1035class MatchInfoBackedMatch :
public String::Match {
1037 MatchInfoBackedMatch(
Isolate* isolate, DirectHandle<JSRegExp> regexp,
1038 DirectHandle<RegExpData> regexp_data,
1039 DirectHandle<String> subject,
1040 DirectHandle<RegExpMatchInfo> match_info)
1048 if (has_named_captures_) {
1056 DirectHandle<String> GetMatch()
override {
1060 DirectHandle<String> GetPrefix()
override {
1062 return isolate_->factory()->NewSubString(subject_, 0, match_start);
1065 DirectHandle<String> GetSuffix()
override {
1067 return isolate_->factory()->NewSubString(subject_, match_end,
1073 int CaptureCount()
override {
1074 return match_info_->number_of_capture_registers() / 2;
1077 MaybeDirectHandle<String> GetCapture(
int i,
bool* capture_exists)
override {
1079 isolate_, match_info_,
i, capture_exists);
1081 :
isolate_->factory()->empty_string();
1084 MaybeDirectHandle<String> GetNamedCapture(DirectHandle<String> name,
1085 CaptureState* state)
override {
1086 DCHECK(has_named_captures_);
1087 int capture_index = 0;
1088 int capture_name_map_index = 0;
1090 capture_index = LookupNamedCapture(
1092 return capture_name->Equals(*name);
1095 if (capture_index == -1) {
1097 return isolate_->factory()->empty_string();
1100 DirectHandle<String> capture_value;
1102 isolate_, capture_value,
1105 isolate_, match_info_, capture_index)));
1107 return capture_value;
1121class VectorBackedMatch :
public String::Match {
1123 VectorBackedMatch(Isolate* isolate, DirectHandle<String> subject,
1124 DirectHandle<String> match, uint32_t match_position,
1125 base::Vector<DirectHandle<Object>> captures,
1126 DirectHandle<Object> groups_obj)
1133 DCHECK(IsUndefined(*groups_obj, isolate) || IsJSReceiver(*groups_obj));
1138 DirectHandle<String> GetMatch()
override {
return match_; }
1140 DirectHandle<String> GetPrefix()
override {
1143 uint32_t
end = std::min(
subject_->length(), match_position_);
1144 return isolate_->factory()->NewSubString(subject_, 0,
end);
1147 DirectHandle<String> GetSuffix()
override {
1151 std::min(
subject_->length(), match_position_ +
match_->length());
1158 int CaptureCount()
override {
return captures_.length(); }
1160 MaybeDirectHandle<String> GetCapture(
int i,
bool* capture_exists)
override {
1161 DirectHandle<Object> capture_obj =
captures_[
i];
1162 if (IsUndefined(*capture_obj, isolate_)) {
1163 *capture_exists =
false;
1164 return isolate_->factory()->empty_string();
1166 *capture_exists =
true;
1170 MaybeDirectHandle<String> GetNamedCapture(DirectHandle<String> name,
1171 CaptureState* state)
override {
1172 DCHECK(has_named_captures_);
1178 if (name->AsIntegerIndex(&unused)) {
1180 return isolate_->factory()->empty_string();
1183 DirectHandle<Object> capture_obj;
1185 isolate_, capture_obj,
1187 if (IsUndefined(*capture_obj, isolate_)) {
1189 return isolate_->factory()->empty_string();
1212 typename = std::enable_if_t<std::is_function_v<Tagged<Object>(
int)>>>
1213DirectHandle<JSObject> ConstructNamedCaptureGroupsObject(
1214 Isolate* isolate, DirectHandle<FixedArray> capture_map,
1216 DirectHandle<JSObject> groups =
1217 isolate->factory()->NewJSObjectWithNullProto();
1219 const int named_capture_count = capture_map->length() >> 1;
1220 for (
int i = 0;
i < named_capture_count;
i++) {
1221 const int name_ix =
i * 2;
1222 const int index_ix =
i * 2 + 1;
1224 DirectHandle<String> capture_name(
Cast<String>(capture_map->get(name_ix)),
1226 const int capture_ix =
Smi::ToInt(capture_map->get(index_ix));
1229 DirectHandle<Object> capture_value(f_get_capture(capture_ix), isolate);
1230 DCHECK(IsUndefined(*capture_value, isolate) || IsString(*capture_value));
1232 LookupIterator it(isolate, groups, capture_name, groups,
1236 if (!IsUndefined(*capture_value, isolate)) {
1237 DCHECK(IsUndefined(*it.GetDataValue(), isolate));
1253template <
bool has_capture>
1255 Isolate* isolate, DirectHandle<String> subject,
1256 DirectHandle<JSRegExp> regexp, DirectHandle<RegExpData> regexp_data,
1257 DirectHandle<RegExpMatchInfo> last_match_array) {
1259 DCHECK_NE(has_capture, regexp_data->capture_count() == 0);
1261 DCHECK(subject->IsFlat());
1271 if (
v8_flags.trace_regexp_tier_up) {
1272 PrintF(
"Forcing tier-up of JSRegExp object %p in SearchRegExpMultiple\n",
1273 reinterpret_cast<void*
>(regexp->ptr()));
1277 int capture_count = regexp_data->capture_count();
1278 int subject_length = subject->length();
1280 static const int kMinLengthToCache = 0x1000;
1282 if (subject_length > kMinLengthToCache) {
1285 isolate->heap(), *subject, regexp_data->wrapper(), &last_match_cache,
1287 if (IsFixedArray(cached_answer)) {
1289 std::unique_ptr<int32_t[]> last_match(
new int32_t[capture_registers]);
1290 int32_t* raw_last_match = last_match.get();
1291 for (
int i = 0;
i < capture_registers;
i++) {
1292 raw_last_match[
i] =
Smi::ToInt(last_match_cache->get(
i));
1294 DirectHandle<FixedArray> cached_fixed_array(
1297 DirectHandle<FixedArray> copied_fixed_array =
1298 isolate->factory()->CopyFixedArrayWithMap(
1299 cached_fixed_array, isolate->factory()->fixed_array_map());
1301 capture_count, raw_last_match);
1302 return *copied_fixed_array;
1306 RegExpGlobalExecRunner runner(
direct_handle(*regexp_data, isolate), subject,
1308 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
1313 int match_start = -1;
1318 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
1321 int32_t* current_match = runner.FetchNext();
1322 if (current_match ==
nullptr)
break;
1323 match_start = current_match[0];
1324 builder.EnsureCapacity(isolate, kMaxBuilderEntriesPerRegExpMatch);
1325 if (match_end < match_start) {
1329 match_end = current_match[1];
1332 HandleScope temp_scope(isolate);
1333 DirectHandle<String> match;
1335 match = isolate->factory()->NewProperSubString(subject, match_start,
1339 isolate->factory()->NewSubString(subject, match_start, match_end);
1350 DirectHandle<Object> maybe_capture_map(re_data->capture_name_map(),
1352 const bool has_named_captures = IsFixedArray(*maybe_capture_map);
1355 has_named_captures ? 4 + capture_count : 3 + capture_count;
1357 DirectHandle<FixedArray> elements =
1358 isolate->factory()->NewFixedArray(argc);
1361 elements->set(cursor++, *match);
1362 for (
int i = 1;
i <= capture_count;
i++) {
1363 int start = current_match[
i * 2];
1365 int end = current_match[
i * 2 + 1];
1367 DirectHandle<String> substring =
1368 isolate->factory()->NewSubString(subject,
start,
end);
1369 elements->set(cursor++, *substring);
1372 elements->set(cursor++, ReadOnlyRoots(isolate).undefined_value());
1377 elements->set(cursor++, *subject);
1379 if (has_named_captures) {
1380 DirectHandle<FixedArray> capture_map =
1382 DirectHandle<JSObject> groups = ConstructNamedCaptureGroupsObject(
1383 isolate, capture_map, [=](
int ix) {
return elements->get(ix); });
1384 elements->set(cursor++, *groups);
1388 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
1390 builder.Add(*match);
1395 if (runner.HasException())
return ReadOnlyRoots(isolate).exception();
1397 if (match_start >= 0) {
1399 if (match_end < subject_length) {
1405 runner.LastSuccessfulMatch());
1407 if (subject_length > kMinLengthToCache) {
1410 DirectHandle<FixedArray> last_match_cache =
1411 isolate->factory()->NewFixedArray(capture_registers);
1412 int32_t* last_match = runner.LastSuccessfulMatch();
1413 for (
int i = 0;
i < capture_registers;
i++) {
1416 DirectHandle<FixedArray> result_fixed_array =
1420 DirectHandle<FixedArray> copied_fixed_array =
1421 isolate->factory()->CopyFixedArrayWithMap(
1422 result_fixed_array, isolate->factory()->fixed_array_map());
1426 copied_fixed_array, last_match_cache,
1429 return *builder.array();
1431 return ReadOnlyRoots(isolate).null_value();
1438 Isolate* isolate, DirectHandle<JSRegExp> regexp,
1439 DirectHandle<String>
string, DirectHandle<String> replace) {
1443 Factory* factory = isolate->factory();
1445 const int flags = regexp->flags();
1446 const bool global = (flags & JSRegExp::kGlobal) != 0;
1447 const bool sticky = (flags & JSRegExp::kSticky) != 0;
1451 DirectHandle<RegExpMatchInfo> last_match_info =
1452 isolate->regexp_last_match_info();
1453 DirectHandle<RegExpData>
data(regexp->data(isolate), isolate);
1458 uint32_t last_index = 0;
1460 DirectHandle<Object> last_index_obj(regexp->last_index(), isolate);
1466 DirectHandle<Object> match_indices_obj(ReadOnlyRoots(isolate).null_value(),
1471 if (last_index <=
static_cast<uint32_t
>(string->length())) {
1473 isolate, match_indices_obj,
1478 if (
IsNull(*match_indices_obj, isolate)) {
1485 const int start_index = match_indices->capture(0);
1486 const int end_index = match_indices->capture(1);
1492 IncrementalStringBuilder builder(isolate);
1493 builder.AppendString(factory->NewSubString(
string, 0, start_index));
1495 if (replace->length() > 0) {
1496 MatchInfoBackedMatch
m(isolate, regexp, data,
string, match_indices);
1497 DirectHandle<String> replacement;
1500 builder.AppendString(replacement);
1503 builder.AppendString(
1504 factory->NewSubString(
string, end_index, string->length()));
1505 return builder.Finish();
1519 if (
v8_flags.trace_regexp_tier_up) {
1520 PrintF(
"Forcing tier-up of JSRegExp object %p in RegExpReplace\n",
1521 reinterpret_cast<void*
>(regexp->ptr()));
1525 if (replace->length() == 0) {
1526 if (string->IsOneByteRepresentation()) {
1529 isolate,
string, regexp, data, last_match_info);
1534 isolate,
string, regexp, data, last_match_info);
1540 isolate,
string, regexp, data, replace, last_match_info);
1544 return MaybeDirectHandle<String>();
1566 CHECK(regexp->flags() & JSRegExp::kGlobal);
1569 if (regexp_data->capture_count() == 0) {
1570 result = SearchRegExpMultiple<false>(isolate, subject, regexp, regexp_data,
1573 result = SearchRegExpMultiple<true>(isolate, subject, regexp, regexp_data,
1588 DCHECK(replace_obj->map()->is_callable());
1590 Factory* factory = isolate->factory();
1592 isolate->regexp_last_match_info();
1595 const int flags = regexp->flags();
1596 DCHECK_EQ(flags & JSRegExp::kGlobal, 0);
1600 const bool sticky = (flags & JSRegExp::kSticky) != 0;
1601 uint32_t last_index = 0;
1614 if (last_index <=
static_cast<uint32_t
>(subject->length())) {
1616 isolate, match_indices_obj,
1621 if (
IsNull(*match_indices_obj, isolate)) {
1628 const int index = match_indices->capture(0);
1629 const int end_of_match = match_indices->capture(1);
1643 const int m = match_indices->number_of_capture_registers() / 2;
1645 bool has_named_captures =
false;
1652 if (IsFixedArray(maybe_capture_map)) {
1653 has_named_captures =
true;
1658 const uint32_t argc = GetArgcForReplaceCallable(
m, has_named_captures);
1659 if (argc ==
static_cast<uint32_t
>(-1)) {
1661 isolate, NewRangeError(MessageTemplate::kTooManyArguments));
1666 for (
int j = 0; j <
m; j++) {
1671 arguments[cursor++] = capture;
1673 arguments[cursor++] = factory->undefined_value();
1678 arguments[cursor++] = subject;
1680 if (has_named_captures) {
1681 arguments[cursor++] = ConstructNamedCaptureGroupsObject(
1682 isolate, capture_map, [&arguments](
int ix) {
return *arguments[ix]; });
1689 isolate, replacement_obj,
1699 factory->
NewSubString(subject, end_of_match, subject->length()));
1707 Isolate* isolate, DirectHandle<Object>
object, uint32_t* out) {
1708 if (IsUndefined(*
object, isolate)) {
1713 DirectHandle<Object> number;
1720DirectHandle<JSArray> NewJSArrayWithElements(Isolate* isolate,
1721 DirectHandle<FixedArray> elems,
1723 return isolate->factory()->NewJSArrayWithElements(
1740 Factory* factory = isolate->factory();
1750 JSObject::GetProperty(isolate, recv, factory->flags_string()));
1758 const bool unicode = (
String::IndexOf(isolate, flags, u_str, 0) >= 0);
1772 constexpr int argc = 2;
1773 std::array<DirectHandle<Object>, argc> ctor_args = {recv, new_flags};
1777 isolate, splitter_obj,
1786 const uint32_t length =
string->length();
1788 if (limit == 0)
return *factory->
NewJSArray(0);
1794 factory->undefined_value()));
1799 elems->set(0, *
string);
1803 static const int kInitialArraySize = 8;
1806 uint32_t num_elems = 0;
1808 uint32_t string_index = 0;
1809 uint32_t prev_string_index = 0;
1810 while (string_index < length) {
1817 factory->undefined_value()));
1820 string_index =
static_cast<uint32_t
>(
1832 const uint32_t
end =
1834 if (
end == prev_string_index) {
1835 string_index =
static_cast<uint32_t
>(
1842 factory->
NewSubString(
string, prev_string_index, string_index);
1844 if (num_elems == limit) {
1845 return *NewJSArrayWithElements(isolate, elems, num_elems);
1849 prev_string_index =
end;
1853 isolate, num_captures_obj,
1855 isolate->factory()->length_string()));
1861 for (uint32_t
i = 1;
i < num_captures;
i++) {
1866 if (num_elems == limit) {
1867 return *NewJSArrayWithElements(isolate, elems, num_elems);
1871 string_index = prev_string_index;
1876 factory->
NewSubString(
string, prev_string_index, length);
1880 return *NewJSArrayWithElements(isolate, elems, num_elems);
1885template <
typename Char>
1890 return search.Search(flags, 0) >= 0;
1893inline bool IsContainFlag(Isolate* isolate, String::FlatContent& flags,
1896 return flags.IsOneByte()
1897 ? IsContainFlagImpl<uint8_t>(isolate, flags.ToOneByteVector(),
1899 : IsContainFlagImpl<
base::uc16>(isolate, flags.ToUC16Vector(),
1916 Factory* factory = isolate->factory();
1920 const bool functional_replace = IsCallable(*replace_obj);
1923 if (!functional_replace) {
1932 CHECK(!functional_replace);
1941 const uint32_t length =
string->length();
1942 bool global =
false;
1943 bool fullUnicode =
false;
1962 global = IsContainFlag(isolate, flat_flag,
"g", no_gc);
1967 fullUnicode = IsContainFlag(isolate, flat_flag,
"u", no_gc) ||
1968 IsContainFlag(isolate, flat_flag,
"v", no_gc);
1986 factory->undefined_value()));
2006 if (match->length() == 0) {
2016 uint32_t next_source_position = 0;
2018 for (
const auto&
result : results) {
2022 isolate, captures_length_obj,
2026 isolate, captures_length_obj,
2028 const uint32_t captures_length =
2039 const int match_length = match->length();
2043 isolate, position_obj,
2055 for (uint32_t n = 1; n < captures_length; n++) {
2060 if (!IsUndefined(*capture, isolate)) {
2069 isolate, groups_obj,
2072 const bool has_named_captures = !IsUndefined(*groups_obj, isolate);
2075 if (functional_replace) {
2078 const uint32_t argc = GetArgcForReplaceCallable(
2079 static_cast<uint32_t
>(captures.
size()), has_named_captures);
2080 if (argc ==
static_cast<uint32_t
>(-1)) {
2082 isolate, NewRangeError(MessageTemplate::kTooManyArguments));
2088 for (uint32_t j = 0; j < captures.
size(); j++) {
2089 call_args[cursor++] = captures[j];
2093 call_args[cursor++] =
string;
2094 if (has_named_captures) call_args[cursor++] = groups_obj;
2100 isolate, replacement_obj,
2107 DCHECK(!functional_replace);
2108 if (!IsUndefined(*groups_obj, isolate)) {
2112 VectorBackedMatch
m(isolate,
string, match,
position,
2118 if (
position >= next_source_position) {
2123 next_source_position =
position + match_length;
2127 if (next_source_position < length) {
2129 factory->
NewSubString(
string, next_source_position, length));
2162template <
typename SChar,
typename PChar>
2163inline void RegExpMatchGlobalAtom_OneCharPattern(
2165 int start_index,
int* number_of_matches,
int* last_match_index,
2167 for (
int i = start_index;
i < subject.
length();
i++) {
2171 if (subject[
i] !=
static_cast<const SChar
>(
pattern))
continue;
2172 (*number_of_matches)++;
2173 (*last_match_index) =
i;
2179inline void RegExpMatchGlobalAtom_OneCharPattern(
2180 Isolate* isolate, base::Vector<const uint8_t> subject,
2184template <
typename Char>
2185inline int AdvanceStringIndex(base::Vector<const Char> subject,
int index,
2189 const int subject_length = subject.length();
2190 if (is_unicode && index < subject_length) {
2192 if (first >= 0xD800 && first <= 0xDBFF && index + 1 < subject_length) {
2193 DCHECK_LT(index, std::numeric_limits<int>::max());
2204template <
typename SChar,
typename PChar>
2205inline void RegExpMatchGlobalAtom_Generic(
2206 Isolate* isolate, base::Vector<const SChar> subject,
2207 base::Vector<const PChar>
pattern,
bool is_unicode,
int start_index,
2208 int* number_of_matches,
int* last_match_index,
2210 const int pattern_length =
pattern.length();
2211 StringSearch<PChar, SChar> search(isolate,
pattern);
2215 found_at_index = search.Search(subject, start_index);
2216 if (found_at_index == -1)
return;
2218 (*number_of_matches)++;
2219 (*last_match_index) = found_at_index;
2220 start_index = pattern_length > 0
2221 ? found_at_index + pattern_length
2222 : AdvanceStringIndex(subject, start_index, is_unicode);
2226inline void RegExpMatchGlobalAtom_Dispatch(
2227 Isolate* isolate,
const String::FlatContent& subject,
2228 const String::FlatContent&
pattern,
bool is_unicode,
int start_index,
2229 int* number_of_matches,
int* last_match_index,
2231#define CALL_Generic() \
2232 RegExpMatchGlobalAtom_Generic(isolate, sv, pv, is_unicode, start_index, \
2233 number_of_matches, last_match_index, no_gc);
2234#define CALL_OneCharPattern() \
2235 RegExpMatchGlobalAtom_OneCharPattern(isolate, sv, pv[0], start_index, \
2236 number_of_matches, last_match_index, \
2241 auto pv =
pattern.ToOneByteVector();
2242 if (subject.IsOneByte()) {
2243 auto sv = subject.ToOneByteVector();
2250 auto sv = subject.ToUC16Vector();
2258 auto pv =
pattern.ToUC16Vector();
2259 if (subject.IsOneByte()) {
2260 auto sv = subject.ToOneByteVector();
2263 auto sv = subject.ToUC16Vector();
2271#undef CALL_OneCharPattern
2287 DCHECK(regexp_handle->flags() & JSRegExp::kGlobal);
2294 int number_of_matches = 0;
2295 int last_match_index = -1;
2306 pattern_length =
pattern->length();
2312 int start_index = 0;
2314 isolate, subject,
pattern, &number_of_matches, &last_match_index)) {
2317 start_index = last_match_index + pattern_length;
2320 const bool is_unicode = (regexp->flags() & JSRegExp::kUnicode) != 0;
2323 RegExpMatchGlobalAtom_Dispatch(isolate, subject_content, pattern_content,
2324 is_unicode, start_index, &number_of_matches,
2325 &last_match_index, no_gc);
2327 if (last_match_index == -1) {
2337 isolate, subject,
pattern, number_of_matches, last_match_index);
2341 static constexpr int kNumberOfCaptures = 0;
2342 int32_t match_indices[] = {last_match_index,
2343 last_match_index + pattern_length};
2345 isolate->regexp_last_match_info();
2347 kNumberOfCaptures, match_indices);
2350 auto elems = isolate->factory()->NewFixedArray(number_of_matches);
2351 ObjectSlot dst_slot = elems->RawFieldOfFirstElement();
2352 MemsetTagged(dst_slot, *pattern_handle, number_of_matches);
2355 dst_slot + number_of_matches);
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
#define SBXCHECK(condition)
Vector< T > SubVector(size_t from, size_t to) const
constexpr T * begin() const
static const int kMaxArguments
CompiledReplacement(Isolate *isolate)
base::SmallVector< ReplacementPart, kStaticVectorSlots > parts_
bool Compile(Isolate *isolate, DirectHandle< JSRegExp > regexp, DirectHandle< RegExpData > regexp_data, DirectHandle< String > replacement, int capture_count, int subject_length)
bool ParseReplacementPattern(base::Vector< Char > characters, Tagged< FixedArray > capture_name_map, int capture_count, int subject_length)
DirectHandleSmallVector< String, kStaticVectorSlots > replacement_substrings_
void Apply(ReplacementStringBuilder *builder, int match_from, int match_to, int32_t *match)
void emplace_back(Args &&... args)
size_t size() const noexcept
V8_INLINE Address address() const
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSReceiver > New(Isolate *isolate, DirectHandle< Object > constructor, base::Vector< const DirectHandle< Object > > args)
V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType NewConsString(HandleType< String > left, HandleType< String > right, AllocationType allocation=AllocationType::kYoung)
Handle< String > LookupSingleCharacterStringFromCode(uint16_t code)
Handle< FixedArray > NewFixedArrayWithHoles(int length, AllocationType allocation=AllocationType::kYoung)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< JSArray > NewJSArray(ElementsKind elements_kind, int length, int capacity, ArrayStorageAllocationMode mode=ArrayStorageAllocationMode::DONT_INITIALIZE_ARRAY_ELEMENTS, AllocationType allocation=AllocationType::kYoung)
Handle< JSArray > NewJSArrayWithElements(DirectHandle< FixedArrayBase > elements, ElementsKind elements_kind, int length, AllocationType allocation=AllocationType::kYoung)
HandleType< String > NewSubString(HandleType< T > str, uint32_t begin, uint32_t end)
static FixedArrayBuilder Lazy(Isolate *isolate)
static HandleType< FixedArray > RightTrimOrEmpty(Isolate *isolate, HandleType< FixedArray > array, int new_length)
static V8_EXPORT_PRIVATE HandleType< FixedArray > SetAndGrow(Isolate *isolate, HandleType< FixedArray > array, int index, DirectHandle< Object > value)
HandleType< T > CloseAndEscape(HandleType< T > handle_value)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
MaybeDirectHandle< String > Finish()
V8_INLINE void AppendString(std::string_view str)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(Isolate *isolate, DirectHandle< JSReceiver > receiver, const char *key)
static DirectHandle< JSRegExpResultIndices > BuildIndices(Isolate *isolate, DirectHandle< RegExpMatchInfo > match_info, DirectHandle< Object > maybe_names)
static MaybeDirectHandle< JSRegExp > Initialize(DirectHandle< JSRegExp > regexp, DirectHandle< String > source, Flags flags, uint32_t backtrack_limit=kNoBacktrackLimit)
static V8_EXPORT_PRIVATE DirectHandle< String > StringFromFlags(Isolate *isolate, Flags flags)
static constexpr int CaptureCountForRegisters(int register_count)
static constexpr int RegistersForCaptureCount(int count)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > ToLength(Isolate *isolate, DirectHandle< Object > input)
static V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType ToString(Isolate *isolate, HandleType< T > input)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > AddDataProperty(LookupIterator *it, DirectHandle< Object > value, PropertyAttributes attributes, Maybe< ShouldThrow > should_throw, StoreOrigin store_origin, EnforceDefineSemantics semantics=EnforceDefineSemantics::kSet)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToNumber(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToInteger(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT HandleType< JSReceiver >::MaybeType ToObject(Isolate *isolate, HandleType< T > object, const char *method_name=nullptr)
static V8_EXPORT_PRIVATE bool ToInt32(Tagged< Object > obj, int32_t *value)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SpeciesConstructor(Isolate *isolate, DirectHandle< JSReceiver > recv, DirectHandle< JSFunction > default_ctor)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetProperty(LookupIterator *it, bool is_global_reference=false)
static bool ToUint32(Tagged< Object > obj, uint32_t *value)
static V8_WARN_UNUSED_RESULT Maybe< bool > SetDataProperty(LookupIterator *it, DirectHandle< Object > value)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetElement(Isolate *isolate, DirectHandle< JSAny > object, uint32_t index)
static constexpr bool TypeSupportsCaptures(Type t)
static DirectHandle< RegExpMatchInfo > ReserveCaptures(Isolate *isolate, DirectHandle< RegExpMatchInfo > match_info, int capture_count)
static bool TryGet(Isolate *isolate, Tagged< String > subject, Tagged< String > pattern, int *number_of_matches_out, int *last_match_index_out)
static void TryInsert(Isolate *isolate, Tagged< String > subject, Tagged< String > pattern, int number_of_matches, int last_match_index)
@ REGEXP_MULTIPLE_INDICES
@ STRING_SPLIT_SUBSTRINGS
static void Enter(Isolate *isolate, DirectHandle< String > key_string, DirectHandle< Object > key_pattern, DirectHandle< FixedArray > value_array, DirectHandle< FixedArray > last_match_cache, ResultsCacheType type)
static Tagged< Object > Lookup(Heap *heap, Tagged< String > key_string, Tagged< Object > key_pattern, Tagged< FixedArray > *last_match_out, ResultsCacheType type)
static Handle< String > GenericCaptureGetter(Isolate *isolate, DirectHandle< RegExpMatchInfo > match_info, int capture, bool *ok=nullptr)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetLastIndex(Isolate *isolate, DirectHandle< JSReceiver > recv)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetAdvancedStringIndex(Isolate *isolate, DirectHandle< JSReceiver > regexp, DirectHandle< String > string, bool unicode)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > SetLastIndex(Isolate *isolate, DirectHandle< JSReceiver > regexp, uint64_t value)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSAny > RegExpExec(Isolate *isolate, DirectHandle< JSReceiver > regexp, DirectHandle< String > string, DirectHandle< Object > exec)
static uint64_t AdvanceStringIndex(Tagged< String > string, uint64_t index, bool unicode)
static bool IsMatchedCapture(Tagged< RegExpMatchInfo > match_info, int capture)
static bool IsUnmodifiedRegExp(Isolate *isolate, DirectHandle< Object > obj)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT std::optional< int > ExperimentalOneshotExec(Isolate *isolate, DirectHandle< JSRegExp > regexp, DirectHandle< String > subject, int index, int32_t *result_offsets_vector, uint32_t result_offsets_vector_length)
static DirectHandle< RegExpMatchInfo > SetLastMatchInfo(Isolate *isolate, DirectHandle< RegExpMatchInfo > last_match_info, DirectHandle< String > subject, int capture_count, int32_t *match)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT std::optional< int > Exec(Isolate *isolate, DirectHandle< JSRegExp > regexp, DirectHandle< String > subject, int index, int32_t *result_offsets_vector, uint32_t result_offsets_vector_length)
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > Exec_Single(Isolate *isolate, DirectHandle< JSRegExp > regexp, DirectHandle< String > subject, int index, DirectHandle< RegExpMatchInfo > last_match_info)
static V8_WARN_UNUSED_RESULT bool EnsureFullyCompiled(Isolate *isolate, DirectHandle< RegExpData > re_data, DirectHandle< String > subject)
static void AddSubjectSlice(FixedArrayBuilder *builder, int from, int to)
MaybeDirectHandle< String > ToString()
void AddString(DirectHandle< String > string)
static constexpr int ToInt(const Tagged< Object > object)
static constexpr Tagged< Smi > FromInt(int value)
static constexpr Tagged< Smi > zero()
int Search(base::Vector< const SubjectChar > subject, int index)
base::Vector< const uint8_t > ToOneByteVector() const
base::Vector< const base::uc16 > ToUC16Vector() const
static void WriteToFlat(Tagged< String > source, SinkCharT *sink, uint32_t start, uint32_t length)
static const uint32_t kMaxLength
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
static Tagged< Object > IndexOf(Isolate *isolate, DirectHandle< Object > receiver, DirectHandle< Object > search, DirectHandle< Object > position)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > GetSubstitution(Isolate *isolate, Match *match, DirectHandle< String > replacement, uint32_t start_index=0)
static void ForRange(Heap *heap, Tagged< HeapObject > object, TSlot start, TSlot end)
#define RUNTIME_FUNCTION(Name)
#define RETURN_ON_EXCEPTION(isolate, call)
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
#define RETURN_FAILURE_ON_EXCEPTION(isolate, call)
#define FOR_WITH_HANDLE_SCOPE(isolate, loop_var_type, init, loop_var, limit_check, increment, body)
#define RETURN_RESULT_OR_FAILURE(isolate, call)
base::Vector< const DirectHandle< Object > > args
DirectHandle< FixedArray > capture_name_map
ZoneVector< RpoNumber > & result
constexpr Vector< T > VectorOf(T *start, size_t size)
Vector< const uint8_t > OneByteVector(const char *data, size_t length)
bool(* FunctionType)(const Operation &op, Zone *zone)
void FindOneByteStringIndices(base::Vector< const uint8_t > subject, uint8_t pattern, std::vector< int > *indices, unsigned int limit)
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
uint32_t PositiveNumberToUint32(Tagged< Object > number)
bool Is(IndirectHandle< U > value)
void PrintF(const char *format,...)
void FindStringIndicesDispatch(Isolate *isolate, Tagged< String > subject, Tagged< String > pattern, std::vector< int > *indices, unsigned int limit)
Tagged(T object) -> Tagged< T >
static V8_WARN_UNUSED_RESULT Tagged< Object > StringReplaceGlobalRegExpWithEmptyString(Isolate *isolate, DirectHandle< String > subject, DirectHandle< JSRegExp > regexp, DirectHandle< RegExpData > regexp_data, DirectHandle< RegExpMatchInfo > last_match_info)
kStaticElementsTemplateOffset kInstancePropertiesTemplateOffset Tagged< FixedArray >
void MemsetTagged(Tagged_t *start, Tagged< MaybeObject > value, size_t counter)
@ TERMINAL_FAST_ELEMENTS_KIND
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
static V8_WARN_UNUSED_RESULT Tagged< Object > StringReplaceGlobalAtomRegExpWithString(Isolate *isolate, DirectHandle< String > subject, DirectHandle< JSRegExp > pattern_regexp, DirectHandle< String > replacement, DirectHandle< RegExpMatchInfo > last_match_info, DirectHandle< AtomRegExpData > regexp_data)
uint32_t NumberToUint32(Tagged< Object > number)
V8_EXPORT_PRIVATE FlagValues v8_flags
void FindStringIndices(Isolate *isolate, base::Vector< const SubjectChar > subject, base::Vector< const PatternChar > pattern, std::vector< int > *indices, unsigned int limit)
void FindTwoByteStringIndices(const base::Vector< const base::uc16 > subject, base::uc16 pattern, std::vector< int > *indices, unsigned int limit)
constexpr uint32_t kMaxUInt32
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
@ INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
template const char * string
static V8_WARN_UNUSED_RESULT Tagged< Object > StringReplaceGlobalRegExpWithString(Isolate *isolate, DirectHandle< String > subject, DirectHandle< JSRegExp > regexp, DirectHandle< RegExpData > regexp_data, DirectHandle< String > replacement, DirectHandle< RegExpMatchInfo > last_match_info)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Maybe< T > Just(const T &t)
ZoneList< RegExpCapture * > * captures_
#define CALL_OneCharPattern()
DirectHandle< String > subject_
DirectHandle< String > match_
DirectHandle< FixedArray > capture_name_map_
DirectHandle< JSReceiver > groups_obj_
const uint32_t match_position_
DirectHandle< RegExpMatchInfo > match_info_
#define DCHECK_LE(v1, v2)
#define CHECK_GE(lhs, rhs)
#define CHECK_LT(lhs, rhs)
#define CHECK_LE(lhs, rhs)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
#define DCHECK_GT(v1, v2)
static ReplacementPart ReplacementString()
ReplacementPart(int tag, int data)
static ReplacementPart ReplacementSubString(int from, int to)
static ReplacementPart EmptyReplacement()
static ReplacementPart SubjectSuffix(int subject_length)
static ReplacementPart SubjectMatch()
static ReplacementPart SubjectPrefix()
static ReplacementPart SubjectCapture(int capture_index)
#define V8_WARN_UNUSED_RESULT