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

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

Issue 2433923003: [regexp] Add fast-path for global, callable replace (Closed)
Patch Set: Rebase Created 4 years, 2 months 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 | « src/runtime/runtime.h ('k') | src/string-builder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 1 // Copyright 2014 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/runtime/runtime-utils.h" 5 #include "src/runtime/runtime-utils.h"
6 6
7 #include "src/arguments.h" 7 #include "src/arguments.h"
8 #include "src/conversions-inl.h" 8 #include "src/conversions-inl.h"
9 #include "src/isolate-inl.h" 9 #include "src/isolate-inl.h"
10 #include "src/messages.h" 10 #include "src/messages.h"
(...skipping 955 matching lines...) Expand 10 before | Expand all | Expand 10 after
966 virtual ~VectorBackedMatch() {} 966 virtual ~VectorBackedMatch() {}
967 967
968 private: 968 private:
969 Isolate* isolate_; 969 Isolate* isolate_;
970 Handle<String> subject_; 970 Handle<String> subject_;
971 Handle<String> match_; 971 Handle<String> match_;
972 const int match_position_; 972 const int match_position_;
973 ZoneVector<Handle<Object>>* captures_; 973 ZoneVector<Handle<Object>>* captures_;
974 }; 974 };
975 975
976 // Only called from RegExpExecMultiple so it doesn't need to maintain 976 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
977 // separate last match info. See comment on that function. 977 // separate last match info. See comment on that function.
978 template <bool has_capture> 978 template <bool has_capture>
979 MaybeHandle<Object> SearchRegExpMultiple( 979 static Object* SearchRegExpMultiple(Isolate* isolate, Handle<String> subject,
980 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, 980 Handle<JSRegExp> regexp,
981 Handle<RegExpMatchInfo> last_match_array, 981 Handle<RegExpMatchInfo> last_match_array,
982 Handle<FixedArray> result_elements) { 982 Handle<JSArray> result_array) {
983 DCHECK(subject->IsFlat()); 983 DCHECK(subject->IsFlat());
984 DCHECK_NE(has_capture, regexp->CaptureCount() == 0); 984 DCHECK_NE(has_capture, regexp->CaptureCount() == 0);
985 985
986 int capture_count = regexp->CaptureCount(); 986 int capture_count = regexp->CaptureCount();
987 int subject_length = subject->length(); 987 int subject_length = subject->length();
988 988
989 static const int kMinLengthToCache = 0x1000; 989 static const int kMinLengthToCache = 0x1000;
990 990
991 if (subject_length > kMinLengthToCache) { 991 if (subject_length > kMinLengthToCache) {
992 FixedArray* last_match_cache; 992 FixedArray* last_match_cache;
993 Object* cached_answer = RegExpResultsCache::Lookup( 993 Object* cached_answer = RegExpResultsCache::Lookup(
994 isolate->heap(), *subject, regexp->data(), &last_match_cache, 994 isolate->heap(), *subject, regexp->data(), &last_match_cache,
995 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 995 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
996 if (cached_answer->IsFixedArray()) { 996 if (cached_answer->IsFixedArray()) {
997 int capture_registers = (capture_count + 1) * 2; 997 int capture_registers = (capture_count + 1) * 2;
998 int32_t* last_match = NewArray<int32_t>(capture_registers); 998 int32_t* last_match = NewArray<int32_t>(capture_registers);
999 for (int i = 0; i < capture_registers; i++) { 999 for (int i = 0; i < capture_registers; i++) {
1000 last_match[i] = Smi::cast(last_match_cache->get(i))->value(); 1000 last_match[i] = Smi::cast(last_match_cache->get(i))->value();
1001 } 1001 }
1002 Handle<FixedArray> cached_fixed_array(FixedArray::cast(cached_answer)); 1002 Handle<FixedArray> cached_fixed_array =
1003 Handle<FixedArray>(FixedArray::cast(cached_answer));
1004 // The cache FixedArray is a COW-array and we need to return a copy.
1005 Handle<FixedArray> copied_fixed_array =
1006 isolate->factory()->CopyFixedArrayWithMap(
1007 cached_fixed_array, isolate->factory()->fixed_array_map());
1008 JSArray::SetContent(result_array, copied_fixed_array);
1003 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, 1009 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
1004 last_match); 1010 last_match);
1005 DeleteArray(last_match); 1011 DeleteArray(last_match);
1006 // The cache FixedArray is a COW-array and we need to return a copy. 1012 return *result_array;
1007 return isolate->factory()->CopyFixedArrayWithMap(
1008 cached_fixed_array, isolate->factory()->fixed_array_map());
1009 } 1013 }
1010 } 1014 }
1011 1015
1012 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate); 1016 RegExpImpl::GlobalCache global_cache(regexp, subject, isolate);
1013 if (global_cache.HasException()) return MaybeHandle<Object>(); 1017 if (global_cache.HasException()) return isolate->heap()->exception();
1014 1018
1015 // Ensured in Runtime_RegExpExecMultiple. 1019 // Ensured in Runtime_RegExpExecMultiple.
1020 DCHECK(result_array->HasFastObjectElements());
1021 Handle<FixedArray> result_elements(
1022 FixedArray::cast(result_array->elements()));
1016 if (result_elements->length() < 16) { 1023 if (result_elements->length() < 16) {
1017 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 1024 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
1018 } 1025 }
1019 1026
1020 FixedArrayBuilder builder(result_elements); 1027 FixedArrayBuilder builder(result_elements);
1021 1028
1022 // Position to search from. 1029 // Position to search from.
1023 int match_start = -1; 1030 int match_start = -1;
1024 int match_end = 0; 1031 int match_end = 0;
1025 bool first = true; 1032 bool first = true;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 } 1079 }
1073 elements->set(capture_count + 1, Smi::FromInt(match_start)); 1080 elements->set(capture_count + 1, Smi::FromInt(match_start));
1074 elements->set(capture_count + 2, *subject); 1081 elements->set(capture_count + 2, *subject);
1075 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 1082 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
1076 } else { 1083 } else {
1077 builder.Add(*match); 1084 builder.Add(*match);
1078 } 1085 }
1079 } 1086 }
1080 } 1087 }
1081 1088
1082 if (global_cache.HasException()) return MaybeHandle<Object>(); 1089 if (global_cache.HasException()) return isolate->heap()->exception();
1083 1090
1084 if (match_start >= 0) { 1091 if (match_start >= 0) {
1085 // Finished matching, with at least one match. 1092 // Finished matching, with at least one match.
1086 if (match_end < subject_length) { 1093 if (match_end < subject_length) {
1087 ReplacementStringBuilder::AddSubjectSlice(&builder, match_end, 1094 ReplacementStringBuilder::AddSubjectSlice(&builder, match_end,
1088 subject_length); 1095 subject_length);
1089 } 1096 }
1090 1097
1091 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count, 1098 RegExpImpl::SetLastMatchInfo(last_match_array, subject, capture_count,
1092 global_cache.LastSuccessfulMatch()); 1099 global_cache.LastSuccessfulMatch());
1093 1100
1094 Handle<FixedArray> result_fixed_array = builder.array();
1095 result_fixed_array->Shrink(builder.length());
1096
1097 if (subject_length > kMinLengthToCache) { 1101 if (subject_length > kMinLengthToCache) {
1098 // Store the last successful match into the array for caching. 1102 // Store the last successful match into the array for caching.
1099 // TODO(yangguo): do not expose last match to JS and simplify caching. 1103 // TODO(yangguo): do not expose last match to JS and simplify caching.
1100 int capture_registers = (capture_count + 1) * 2; 1104 int capture_registers = (capture_count + 1) * 2;
1101 Handle<FixedArray> last_match_cache = 1105 Handle<FixedArray> last_match_cache =
1102 isolate->factory()->NewFixedArray(capture_registers); 1106 isolate->factory()->NewFixedArray(capture_registers);
1103 int32_t* last_match = global_cache.LastSuccessfulMatch(); 1107 int32_t* last_match = global_cache.LastSuccessfulMatch();
1104 for (int i = 0; i < capture_registers; i++) { 1108 for (int i = 0; i < capture_registers; i++) {
1105 last_match_cache->set(i, Smi::FromInt(last_match[i])); 1109 last_match_cache->set(i, Smi::FromInt(last_match[i]));
1106 } 1110 }
1107 // Cache the result and turn the FixedArray into a COW array. 1111 Handle<FixedArray> result_fixed_array = builder.array();
1112 result_fixed_array->Shrink(builder.length());
1113 // Cache the result and copy the FixedArray into a COW array.
1114 Handle<FixedArray> copied_fixed_array =
1115 isolate->factory()->CopyFixedArrayWithMap(
1116 result_fixed_array, isolate->factory()->fixed_array_map());
1108 RegExpResultsCache::Enter( 1117 RegExpResultsCache::Enter(
1109 isolate, subject, handle(regexp->data(), isolate), result_fixed_array, 1118 isolate, subject, handle(regexp->data(), isolate), copied_fixed_array,
1110 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 1119 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
1111 } 1120 }
1112 // The cache FixedArray is a COW-array and we need to return a copy. 1121 return *builder.ToJSArray(result_array);
1113 return isolate->factory()->CopyFixedArrayWithMap(
1114 result_fixed_array, isolate->factory()->fixed_array_map());
1115 } else { 1122 } else {
1116 return isolate->factory()->null_value(); // No matches at all. 1123 return isolate->heap()->null_value(); // No matches at all.
1117 } 1124 }
1118 } 1125 }
1119 1126
1120 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
1121 // lastMatchInfoOverride to maintain the last match info, so we don't need to
1122 // set any other last match array info.
1123 MaybeHandle<Object> RegExpExecMultiple(Isolate* isolate,
1124 Handle<JSRegExp> regexp,
1125 Handle<String> subject,
1126 Handle<RegExpMatchInfo> last_match_info,
1127 Handle<FixedArray> result_array) {
1128 subject = String::Flatten(subject);
1129 CHECK(regexp->GetFlags() & JSRegExp::kGlobal);
1130
1131 if (regexp->CaptureCount() == 0) {
1132 return SearchRegExpMultiple<false>(isolate, subject, regexp,
1133 last_match_info, result_array);
1134 } else {
1135 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info,
1136 result_array);
1137 }
1138 }
1139
1140 // Helper function for replacing regular expressions with the result of a
1141 // function application in String.prototype.replace.
1142 MaybeHandle<String> StringReplaceGlobalRegExpWithFunction(
1143 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
1144 Handle<Object> replace_obj) {
1145 Factory* factory = isolate->factory();
1146
1147 // TODO(jgruber): Convert result_array into a List<Handle<Object>> (or
1148 // similar) and adapt / remove FixedArrayBuilder.
1149 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info();
1150 Handle<FixedArray> result_array = factory->NewFixedArrayWithHoles(16);
1151
1152 Handle<Object> res;
1153 ASSIGN_RETURN_ON_EXCEPTION(isolate, res,
1154 RegExpExecMultiple(isolate, regexp, subject,
1155 last_match_info, result_array),
1156 String);
1157
1158 // Reload the last match info since it might have changed in the meantime.
1159 last_match_info = isolate->regexp_last_match_info();
1160
1161 if (res->IsNull(isolate)) return subject; // No matches at all.
1162
1163 result_array = Handle<FixedArray>::cast(res);
1164 const int result_length = result_array->length();
1165
1166 const int num_captures = last_match_info->NumberOfCaptureRegisters() / 2;
1167 if (num_captures == 1) {
1168 // If the number of captures is one then there are no explicit captures in
1169 // the regexp, just the implicit capture that captures the whole match. In
1170 // this case we can simplify quite a bit and end up with something faster.
1171 // The builder will consist of some integers that indicate slices of the
1172 // input string and some replacements that were returned from the replace
1173 // function.
1174 int match_start = 0;
1175 for (int i = 0; i < result_length; i++) {
1176 Handle<Object> elem = FixedArray::get(*result_array, i, isolate);
1177 if (elem->IsSmi()) {
1178 // Integers represent slices of the original string.
1179 // TODO(jgruber): Maybe we don't need this weird encoding anymore (in
1180 // preparation to invoking StringBuilderConcat), but can just copy into
1181 // the result string with the IncrementalStringBuilder as we go?
1182 const int elem_value = Handle<Smi>::cast(elem)->value();
1183 if (elem_value > 0) {
1184 match_start = (elem_value >> 11) + (elem_value & 0x7ff);
1185 } else {
1186 Handle<Object> next_elem =
1187 FixedArray::get(*result_array, ++i, isolate);
1188 const int next_elem_value = Handle<Smi>::cast(next_elem)->value();
1189 match_start = next_elem_value - elem_value;
1190 }
1191 } else {
1192 DCHECK(elem->IsString());
1193 Handle<String> elem_string = Handle<String>::cast(elem);
1194
1195 // Overwrite the i'th element in the results with the string we got
1196 // back from the callback function.
1197 const int argc = 3;
1198 ScopedVector<Handle<Object>> argv(argc);
1199
1200 argv[0] = elem_string;
1201 argv[1] = handle(Smi::FromInt(match_start), isolate);
1202 argv[2] = subject;
1203
1204 Handle<Object> replacement_obj;
1205 ASSIGN_RETURN_ON_EXCEPTION(
1206 isolate, replacement_obj,
1207 Execution::Call(isolate, replace_obj, factory->undefined_value(),
1208 argc, argv.start()),
1209 String);
1210
1211 Handle<String> replacement;
1212 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1213 Object::ToString(isolate, replacement_obj),
1214 String);
1215
1216 result_array->set(i, *replacement);
1217 match_start += elem_string->length();
1218 }
1219 }
1220 } else {
1221 DCHECK(num_captures > 1);
1222 for (int i = 0; i < result_length; i++) {
1223 Handle<Object> elem = FixedArray::get(*result_array, i, isolate);
1224 if (elem->IsSmi()) continue;
1225
1226 // TODO(jgruber): We can skip this whole round-trip through a JS array
1227 // for result_array.
1228 Handle<JSArray> elem_array = Handle<JSArray>::cast(elem);
1229 Handle<FixedArray> elem_array_elems(
1230 FixedArray::cast(elem_array->elements()), isolate);
1231
1232 const int argc = elem_array_elems->length();
1233 ScopedVector<Handle<Object>> argv(argc);
1234
1235 for (int j = 0; j < argc; j++) {
1236 argv[j] = FixedArray::get(*elem_array_elems, j, isolate);
1237 }
1238
1239 // TODO(jgruber): This call is another pattern we could refactor.
1240 Handle<Object> replacement_obj;
1241 ASSIGN_RETURN_ON_EXCEPTION(
1242 isolate, replacement_obj,
1243 Execution::Call(isolate, replace_obj, factory->undefined_value(),
1244 argc, argv.start()),
1245 String);
1246
1247 Handle<String> replacement;
1248 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1249 Object::ToString(isolate, replacement_obj),
1250 String);
1251
1252 result_array->set(i, *replacement);
1253 }
1254 }
1255
1256 if (result_length == 0) {
1257 return factory->empty_string();
1258 } else if (result_length == 1) {
1259 Handle<Object> first = FixedArray::get(*result_array, 0, isolate);
1260 if (first->IsString()) return Handle<String>::cast(first);
1261 }
1262
1263 bool one_byte = subject->HasOnlyOneByteChars();
1264 const int length = StringBuilderConcatLength(subject->length(), *result_array,
1265 result_length, &one_byte);
1266
1267 if (length == -1) {
1268 isolate->Throw(isolate->heap()->illegal_argument_string());
1269 return MaybeHandle<String>();
1270 }
1271
1272 if (one_byte) {
1273 Handle<SeqOneByteString> answer;
1274 ASSIGN_RETURN_ON_EXCEPTION(isolate, answer,
1275 isolate->factory()->NewRawOneByteString(length),
1276 String);
1277 StringBuilderConcatHelper(*subject, answer->GetChars(), *result_array,
1278 result_length);
1279 return answer;
1280 } else {
1281 DCHECK(!one_byte);
1282 Handle<SeqTwoByteString> answer;
1283 ASSIGN_RETURN_ON_EXCEPTION(isolate, answer,
1284 isolate->factory()->NewRawTwoByteString(length),
1285 String);
1286 StringBuilderConcatHelper(*subject, answer->GetChars(), *result_array,
1287 result_length);
1288 return answer;
1289 }
1290
1291 UNREACHABLE();
1292 return MaybeHandle<String>();
1293 }
1294
1295 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( 1127 MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction(
1296 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, 1128 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp,
1297 Handle<Object> replace_obj) { 1129 Handle<Object> replace_obj) {
1298 Factory* factory = isolate->factory(); 1130 Factory* factory = isolate->factory();
1299 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); 1131 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info();
1300 1132
1301 // TODO(jgruber): This is a pattern we could refactor. 1133 // TODO(jgruber): This is a pattern we could refactor.
1302 Handle<Object> match_indices_obj; 1134 Handle<Object> match_indices_obj;
1303 ASSIGN_RETURN_ON_EXCEPTION( 1135 ASSIGN_RETURN_ON_EXCEPTION(
1304 isolate, match_indices_obj, 1136 isolate, match_indices_obj,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
1364 MaybeHandle<String> RegExpReplace(Isolate* isolate, Handle<JSRegExp> regexp, 1196 MaybeHandle<String> RegExpReplace(Isolate* isolate, Handle<JSRegExp> regexp,
1365 Handle<String> string, 1197 Handle<String> string,
1366 Handle<Object> replace_obj) { 1198 Handle<Object> replace_obj) {
1367 Factory* factory = isolate->factory(); 1199 Factory* factory = isolate->factory();
1368 1200
1369 // TODO(jgruber): We need the even stricter guarantee of an unmodified 1201 // TODO(jgruber): We need the even stricter guarantee of an unmodified
1370 // JSRegExp map here for access to GetFlags to be legal. 1202 // JSRegExp map here for access to GetFlags to be legal.
1371 const int flags = regexp->GetFlags(); 1203 const int flags = regexp->GetFlags();
1372 const bool global = (flags & JSRegExp::kGlobal) != 0; 1204 const bool global = (flags & JSRegExp::kGlobal) != 0;
1373 1205
1374 const bool functional_replace = replace_obj->IsCallable(); 1206 // Functional fast-paths are dispatched directly by replace builtin.
1375 if (!functional_replace) { 1207 DCHECK(!replace_obj->IsCallable());
1376 Handle<String> replace;
1377 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace,
1378 Object::ToString(isolate, replace_obj), String);
1379 replace = String::Flatten(replace);
1380 1208
1381 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); 1209 Handle<String> replace;
1210 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace,
1211 Object::ToString(isolate, replace_obj), String);
1212 replace = String::Flatten(replace);
1382 1213
1383 if (!global) { 1214 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info();
1384 // Non-global regexp search, string replace.
1385 1215
1386 Handle<Object> match_indices_obj; 1216 if (!global) {
1387 ASSIGN_RETURN_ON_EXCEPTION( 1217 // Non-global regexp search, string replace.
1388 isolate, match_indices_obj,
1389 RegExpImpl::Exec(regexp, string, 0, last_match_info), String);
1390 1218
1391 if (match_indices_obj->IsNull(isolate)) { 1219 Handle<Object> match_indices_obj;
1392 RETURN_ON_EXCEPTION( 1220 ASSIGN_RETURN_ON_EXCEPTION(
1393 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String); 1221 isolate, match_indices_obj,
1394 return string; 1222 RegExpImpl::Exec(regexp, string, 0, last_match_info), String);
1395 }
1396 1223
1397 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); 1224 if (match_indices_obj->IsNull(isolate)) {
1398
1399 const int start_index = match_indices->Capture(0);
1400 const int end_index = match_indices->Capture(1);
1401
1402 IncrementalStringBuilder builder(isolate);
1403 builder.AppendString(factory->NewSubString(string, 0, start_index));
1404
1405 if (replace->length() > 0) {
1406 MatchInfoBackedMatch m(isolate, string, match_indices);
1407 Handle<String> replacement;
1408 ASSIGN_RETURN_ON_EXCEPTION(
1409 isolate, replacement, String::GetSubstitution(isolate, &m, replace),
1410 String);
1411 builder.AppendString(replacement);
1412 }
1413
1414 builder.AppendString(
1415 factory->NewSubString(string, end_index, string->length()));
1416 return builder.Finish();
1417 } else {
1418 // Global regexp search, string replace.
1419 DCHECK(global);
1420 RETURN_ON_EXCEPTION( 1225 RETURN_ON_EXCEPTION(
1421 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String); 1226 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String);
1227 return string;
1228 }
1422 1229
1423 if (replace->length() == 0) { 1230 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj);
1424 if (string->HasOnlyOneByteChars()) {
1425 Object* result =
1426 StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
1427 isolate, string, regexp, last_match_info);
1428 return handle(String::cast(result), isolate);
1429 } else {
1430 Object* result =
1431 StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
1432 isolate, string, regexp, last_match_info);
1433 return handle(String::cast(result), isolate);
1434 }
1435 }
1436 1231
1437 Object* result = StringReplaceGlobalRegExpWithString( 1232 const int start_index = match_indices->Capture(0);
1438 isolate, string, regexp, replace, last_match_info); 1233 const int end_index = match_indices->Capture(1);
1439 if (result->IsString()) { 1234
1235 IncrementalStringBuilder builder(isolate);
1236 builder.AppendString(factory->NewSubString(string, 0, start_index));
1237
1238 if (replace->length() > 0) {
1239 MatchInfoBackedMatch m(isolate, string, match_indices);
1240 Handle<String> replacement;
1241 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement,
1242 String::GetSubstitution(isolate, &m, replace),
1243 String);
1244 builder.AppendString(replacement);
1245 }
1246
1247 builder.AppendString(
1248 factory->NewSubString(string, end_index, string->length()));
1249 return builder.Finish();
1250 } else {
1251 // Global regexp search, string replace.
1252 DCHECK(global);
1253 RETURN_ON_EXCEPTION(isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0),
1254 String);
1255
1256 if (replace->length() == 0) {
1257 if (string->HasOnlyOneByteChars()) {
1258 Object* result =
1259 StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
1260 isolate, string, regexp, last_match_info);
1440 return handle(String::cast(result), isolate); 1261 return handle(String::cast(result), isolate);
1441 } else { 1262 } else {
1442 return MaybeHandle<String>(); 1263 Object* result =
1264 StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
1265 isolate, string, regexp, last_match_info);
1266 return handle(String::cast(result), isolate);
1443 } 1267 }
1444 } 1268 }
1445 } else { 1269
1446 DCHECK(functional_replace); 1270 Object* result = StringReplaceGlobalRegExpWithString(
1447 if (global) { 1271 isolate, string, regexp, replace, last_match_info);
1448 // Global regexp search, function replace. 1272 if (result->IsString()) {
1449 return StringReplaceGlobalRegExpWithFunction(isolate, string, regexp, 1273 return handle(String::cast(result), isolate);
1450 replace_obj);
1451 } else { 1274 } else {
1452 // Non-global regexp search, function replace. 1275 return MaybeHandle<String>();
1453 return StringReplaceNonGlobalRegExpWithFunction(isolate, string, regexp,
1454 replace_obj);
1455 } 1276 }
1456 } 1277 }
1457 1278
1458 UNREACHABLE(); 1279 UNREACHABLE();
1459 return MaybeHandle<String>(); 1280 return MaybeHandle<String>();
1460 } 1281 }
1461 1282
1462 } // namespace 1283 } // namespace
1463 1284
1464 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithFunction) { 1285 // This is only called for StringReplaceGlobalRegExpWithFunction.
1465 HandleScope scope(isolate); 1286 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) {
1466 DCHECK(args.length() == 3); 1287 HandleScope handles(isolate);
1288 DCHECK(args.length() == 4);
1467 1289
1468 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 1290 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1469 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 1291 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
1470 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); 1292 CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 2);
1293 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
1294 CHECK(result_array->HasFastObjectElements());
1471 1295
1472 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceGlobalRegExpWithFunction( 1296 subject = String::Flatten(subject);
1473 isolate, subject, regexp, replace)); 1297 CHECK(regexp->GetFlags() & JSRegExp::kGlobal);
1298
1299 if (regexp->CaptureCount() == 0) {
1300 return SearchRegExpMultiple<false>(isolate, subject, regexp,
1301 last_match_info, result_array);
1302 } else {
1303 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info,
1304 result_array);
1305 }
1474 } 1306 }
1475 1307
1476 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { 1308 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) {
1477 HandleScope scope(isolate); 1309 HandleScope scope(isolate);
1478 DCHECK(args.length() == 3); 1310 DCHECK(args.length() == 3);
1479 1311
1480 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 1312 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
1481 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 1313 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
1482 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); 1314 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2);
1483 1315
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1667 1499
1668 RUNTIME_FUNCTION(Runtime_IsRegExp) { 1500 RUNTIME_FUNCTION(Runtime_IsRegExp) {
1669 SealHandleScope shs(isolate); 1501 SealHandleScope shs(isolate);
1670 DCHECK(args.length() == 1); 1502 DCHECK(args.length() == 1);
1671 CONVERT_ARG_CHECKED(Object, obj, 0); 1503 CONVERT_ARG_CHECKED(Object, obj, 0);
1672 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); 1504 return isolate->heap()->ToBoolean(obj->IsJSRegExp());
1673 } 1505 }
1674 1506
1675 } // namespace internal 1507 } // namespace internal
1676 } // namespace v8 1508 } // namespace v8
OLDNEW
« no previous file with comments | « src/runtime/runtime.h ('k') | src/string-builder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698