Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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. | |
|
jgruber
2016/10/19 16:39:13
It might not make sense anymore for the result cac
Yang
2016/10/20 09:53:14
I'd simply introduce a version of SBC that only ta
jgruber
2016/10/20 10:58:30
That would work, I'm just not sure what we would g
| |
| 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 Loading... | |
| 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 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1437 Object* result = StringReplaceGlobalRegExpWithString( | 1269 Object* result = StringReplaceGlobalRegExpWithString( |
| 1438 isolate, string, regexp, replace, last_match_info); | 1270 isolate, string, regexp, replace, last_match_info); |
| 1439 if (result->IsString()) { | 1271 if (result->IsString()) { |
| 1440 return handle(String::cast(result), isolate); | 1272 return handle(String::cast(result), isolate); |
| 1441 } else { | 1273 } else { |
| 1442 return MaybeHandle<String>(); | 1274 return MaybeHandle<String>(); |
| 1443 } | 1275 } |
| 1444 } | 1276 } |
| 1445 } else { | 1277 } else { |
| 1446 DCHECK(functional_replace); | 1278 DCHECK(functional_replace); |
| 1447 if (global) { | 1279 DCHECK(!global); // Handled as fast path. |
|
jgruber
2016/10/19 16:39:13
The entire functional_replace branch should be rem
| |
| 1448 // Global regexp search, function replace. | 1280 // Non-global regexp search, function replace. |
| 1449 return StringReplaceGlobalRegExpWithFunction(isolate, string, regexp, | 1281 return StringReplaceNonGlobalRegExpWithFunction(isolate, string, regexp, |
| 1450 replace_obj); | 1282 replace_obj); |
| 1451 } else { | |
| 1452 // Non-global regexp search, function replace. | |
| 1453 return StringReplaceNonGlobalRegExpWithFunction(isolate, string, regexp, | |
| 1454 replace_obj); | |
| 1455 } | |
| 1456 } | 1283 } |
| 1457 | 1284 |
| 1458 UNREACHABLE(); | 1285 UNREACHABLE(); |
| 1459 return MaybeHandle<String>(); | 1286 return MaybeHandle<String>(); |
| 1460 } | 1287 } |
| 1461 | 1288 |
| 1462 } // namespace | 1289 } // namespace |
| 1463 | 1290 |
| 1464 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithFunction) { | 1291 // This is only called for StringReplaceGlobalRegExpWithFunction. |
| 1465 HandleScope scope(isolate); | 1292 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { |
| 1466 DCHECK(args.length() == 3); | 1293 HandleScope handles(isolate); |
| 1294 DCHECK(args.length() == 4); | |
| 1467 | 1295 |
| 1468 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 1296 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); |
| 1469 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 1297 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); |
| 1470 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); | 1298 CONVERT_ARG_HANDLE_CHECKED(RegExpMatchInfo, last_match_info, 2); |
| 1299 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); | |
|
jgruber
2016/10/19 16:39:13
Reusing the result array does not seem to make any
Yang
2016/10/20 09:53:14
I wonder whether we need a JSArray for this at all
jgruber
2016/10/20 10:58:30
Sure. I kept the JSArray return type for now becau
| |
| 1300 CHECK(result_array->HasFastObjectElements()); | |
| 1471 | 1301 |
| 1472 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceGlobalRegExpWithFunction( | 1302 subject = String::Flatten(subject); |
| 1473 isolate, subject, regexp, replace)); | 1303 CHECK(regexp->GetFlags() & JSRegExp::kGlobal); |
| 1304 | |
| 1305 if (regexp->CaptureCount() == 0) { | |
| 1306 return SearchRegExpMultiple<false>(isolate, subject, regexp, | |
| 1307 last_match_info, result_array); | |
| 1308 } else { | |
| 1309 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, | |
| 1310 result_array); | |
| 1311 } | |
| 1474 } | 1312 } |
| 1475 | 1313 |
| 1476 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { | 1314 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { |
| 1477 HandleScope scope(isolate); | 1315 HandleScope scope(isolate); |
| 1478 DCHECK(args.length() == 3); | 1316 DCHECK(args.length() == 3); |
| 1479 | 1317 |
| 1480 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 1318 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
| 1481 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 1319 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |
| 1482 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); | 1320 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); |
| 1483 | 1321 |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1681 | 1519 |
| 1682 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1520 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
| 1683 SealHandleScope shs(isolate); | 1521 SealHandleScope shs(isolate); |
| 1684 DCHECK(args.length() == 1); | 1522 DCHECK(args.length() == 1); |
| 1685 CONVERT_ARG_CHECKED(Object, obj, 0); | 1523 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 1686 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1524 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
| 1687 } | 1525 } |
| 1688 | 1526 |
| 1689 } // namespace internal | 1527 } // namespace internal |
| 1690 } // namespace v8 | 1528 } // namespace v8 |
| OLD | NEW |