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 1060 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1071 RegExpResultsCache::Enter( | 1071 RegExpResultsCache::Enter( |
1072 isolate, subject, handle(regexp->data(), isolate), copied_fixed_array, | 1072 isolate, subject, handle(regexp->data(), isolate), copied_fixed_array, |
1073 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES); | 1073 last_match_cache, RegExpResultsCache::REGEXP_MULTIPLE_INDICES); |
1074 } | 1074 } |
1075 return *builder.ToJSArray(result_array); | 1075 return *builder.ToJSArray(result_array); |
1076 } else { | 1076 } else { |
1077 return isolate->heap()->null_value(); // No matches at all. | 1077 return isolate->heap()->null_value(); // No matches at all. |
1078 } | 1078 } |
1079 } | 1079 } |
1080 | 1080 |
1081 MUST_USE_RESULT MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( | |
1082 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | |
1083 Handle<Object> replace_obj) { | |
1084 Factory* factory = isolate->factory(); | |
1085 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | |
1086 | |
1087 const int flags = regexp->GetFlags(); | |
1088 | |
1089 DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); | |
1090 DCHECK_EQ(flags & JSRegExp::kGlobal, 0); | |
1091 | |
1092 // TODO(jgruber): This should be an easy port to CSA with massive payback. | |
1093 | |
1094 const bool sticky = (flags & JSRegExp::kSticky) != 0; | |
1095 uint32_t last_index = 0; | |
1096 if (sticky) { | |
1097 Handle<Object> last_index_obj(regexp->LastIndex(), isolate); | |
1098 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, | |
1099 Object::ToLength(isolate, last_index_obj), | |
1100 String); | |
1101 last_index = PositiveNumberToUint32(*last_index_obj); | |
1102 | |
1103 if (static_cast<int>(last_index) > subject->length()) last_index = 0; | |
1104 } | |
1105 | |
1106 Handle<Object> match_indices_obj; | |
1107 ASSIGN_RETURN_ON_EXCEPTION( | |
1108 isolate, match_indices_obj, | |
1109 RegExpImpl::Exec(regexp, subject, last_index, last_match_info), String); | |
1110 | |
1111 if (match_indices_obj->IsNull(isolate)) { | |
1112 if (sticky) regexp->SetLastIndex(0); | |
1113 return subject; | |
1114 } | |
1115 | |
1116 Handle<RegExpMatchInfo> match_indices = | |
1117 Handle<RegExpMatchInfo>::cast(match_indices_obj); | |
1118 | |
1119 const int index = match_indices->Capture(0); | |
1120 const int end_of_match = match_indices->Capture(1); | |
1121 | |
1122 if (sticky) regexp->SetLastIndex(end_of_match); | |
1123 | |
1124 IncrementalStringBuilder builder(isolate); | |
1125 builder.AppendString(factory->NewSubString(subject, 0, index)); | |
1126 | |
1127 // Compute the parameter list consisting of the match, captures, index, | |
1128 // and subject for the replace function invocation. | |
1129 // The number of captures plus one for the match. | |
1130 const int m = match_indices->NumberOfCaptureRegisters() / 2; | |
1131 | |
1132 const int argc = m + 2; | |
1133 ScopedVector<Handle<Object>> argv(argc); | |
1134 | |
1135 for (int j = 0; j < m; j++) { | |
1136 bool ok; | |
1137 Handle<String> capture = | |
1138 RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); | |
1139 if (ok) { | |
1140 argv[j] = capture; | |
1141 } else { | |
1142 argv[j] = factory->undefined_value(); | |
1143 } | |
1144 } | |
1145 | |
1146 argv[argc - 2] = handle(Smi::FromInt(index), isolate); | |
1147 argv[argc - 1] = subject; | |
1148 | |
1149 Handle<Object> replacement_obj; | |
1150 ASSIGN_RETURN_ON_EXCEPTION( | |
1151 isolate, replacement_obj, | |
1152 Execution::Call(isolate, replace_obj, factory->undefined_value(), argc, | |
1153 argv.start()), | |
1154 String); | |
1155 | |
1156 Handle<String> replacement; | |
1157 ASSIGN_RETURN_ON_EXCEPTION( | |
1158 isolate, replacement, Object::ToString(isolate, replacement_obj), String); | |
1159 | |
1160 builder.AppendString(replacement); | |
1161 builder.AppendString( | |
1162 factory->NewSubString(subject, end_of_match, subject->length())); | |
1163 | |
1164 return builder.Finish(); | |
1165 } | |
1166 | |
1167 // Legacy implementation of RegExp.prototype[Symbol.replace] which | 1081 // Legacy implementation of RegExp.prototype[Symbol.replace] which |
1168 // doesn't properly call the underlying exec method. | 1082 // doesn't properly call the underlying exec method. |
1169 MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, | 1083 MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, |
1170 Handle<JSRegExp> regexp, | 1084 Handle<JSRegExp> regexp, |
1171 Handle<String> string, | 1085 Handle<String> string, |
1172 Handle<Object> replace_obj) { | 1086 Handle<Object> replace_obj) { |
1173 Factory* factory = isolate->factory(); | 1087 Factory* factory = isolate->factory(); |
1174 | 1088 |
1175 const int flags = regexp->GetFlags(); | 1089 const int flags = regexp->GetFlags(); |
1176 const bool global = (flags & JSRegExp::kGlobal) != 0; | 1090 const bool global = (flags & JSRegExp::kGlobal) != 0; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1286 last_match_info, result_array); | 1200 last_match_info, result_array); |
1287 } else { | 1201 } else { |
1288 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, | 1202 return SearchRegExpMultiple<true>(isolate, subject, regexp, last_match_info, |
1289 result_array); | 1203 result_array); |
1290 } | 1204 } |
1291 } | 1205 } |
1292 | 1206 |
1293 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { | 1207 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { |
1294 HandleScope scope(isolate); | 1208 HandleScope scope(isolate); |
1295 DCHECK_EQ(3, args.length()); | 1209 DCHECK_EQ(3, args.length()); |
1296 | |
1297 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 1210 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
1298 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 1211 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |
1299 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); | 1212 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace_obj, 2); |
1300 | 1213 |
1301 DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); | 1214 DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); |
1302 | 1215 |
1303 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceNonGlobalRegExpWithFunction( | 1216 Factory* factory = isolate->factory(); |
1304 isolate, subject, regexp, replace)); | 1217 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1218 |
| 1219 const int flags = regexp->GetFlags(); |
| 1220 DCHECK_EQ(flags & JSRegExp::kGlobal, 0); |
| 1221 |
| 1222 // TODO(jgruber): This should be an easy port to CSA with massive payback. |
| 1223 |
| 1224 const bool sticky = (flags & JSRegExp::kSticky) != 0; |
| 1225 uint32_t last_index = 0; |
| 1226 if (sticky) { |
| 1227 Handle<Object> last_index_obj(regexp->LastIndex(), isolate); |
| 1228 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1229 isolate, last_index_obj, Object::ToLength(isolate, last_index_obj)); |
| 1230 last_index = PositiveNumberToUint32(*last_index_obj); |
| 1231 |
| 1232 if (static_cast<int>(last_index) > subject->length()) last_index = 0; |
| 1233 } |
| 1234 |
| 1235 Handle<Object> match_indices_obj; |
| 1236 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1237 isolate, match_indices_obj, |
| 1238 RegExpImpl::Exec(regexp, subject, last_index, last_match_info)); |
| 1239 |
| 1240 if (match_indices_obj->IsNull(isolate)) { |
| 1241 if (sticky) regexp->SetLastIndex(0); |
| 1242 return *subject; |
| 1243 } |
| 1244 |
| 1245 Handle<RegExpMatchInfo> match_indices = |
| 1246 Handle<RegExpMatchInfo>::cast(match_indices_obj); |
| 1247 |
| 1248 const int index = match_indices->Capture(0); |
| 1249 const int end_of_match = match_indices->Capture(1); |
| 1250 |
| 1251 if (sticky) regexp->SetLastIndex(end_of_match); |
| 1252 |
| 1253 IncrementalStringBuilder builder(isolate); |
| 1254 builder.AppendString(factory->NewSubString(subject, 0, index)); |
| 1255 |
| 1256 // Compute the parameter list consisting of the match, captures, index, |
| 1257 // and subject for the replace function invocation. |
| 1258 // The number of captures plus one for the match. |
| 1259 const int m = match_indices->NumberOfCaptureRegisters() / 2; |
| 1260 |
| 1261 const int argc = m + 2; |
| 1262 ScopedVector<Handle<Object>> argv(argc); |
| 1263 |
| 1264 for (int j = 0; j < m; j++) { |
| 1265 bool ok; |
| 1266 Handle<String> capture = |
| 1267 RegExpUtils::GenericCaptureGetter(isolate, match_indices, j, &ok); |
| 1268 if (ok) { |
| 1269 argv[j] = capture; |
| 1270 } else { |
| 1271 argv[j] = factory->undefined_value(); |
| 1272 } |
| 1273 } |
| 1274 |
| 1275 argv[argc - 2] = handle(Smi::FromInt(index), isolate); |
| 1276 argv[argc - 1] = subject; |
| 1277 |
| 1278 Handle<Object> replacement_obj; |
| 1279 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1280 isolate, replacement_obj, |
| 1281 Execution::Call(isolate, replace_obj, factory->undefined_value(), argc, |
| 1282 argv.start())); |
| 1283 |
| 1284 Handle<String> replacement; |
| 1285 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 1286 isolate, replacement, Object::ToString(isolate, replacement_obj)); |
| 1287 |
| 1288 builder.AppendString(replacement); |
| 1289 builder.AppendString( |
| 1290 factory->NewSubString(subject, end_of_match, subject->length())); |
| 1291 |
| 1292 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); |
1305 } | 1293 } |
1306 | 1294 |
1307 namespace { | 1295 namespace { |
1308 | 1296 |
1309 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, | 1297 MUST_USE_RESULT MaybeHandle<Object> ToUint32(Isolate* isolate, |
1310 Handle<Object> object, | 1298 Handle<Object> object, |
1311 uint32_t* out) { | 1299 uint32_t* out) { |
1312 if (object->IsUndefined(isolate)) { | 1300 if (object->IsUndefined(isolate)) { |
1313 *out = kMaxUInt32; | 1301 *out = kMaxUInt32; |
1314 return object; | 1302 return object; |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1676 | 1664 |
1677 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1665 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
1678 SealHandleScope shs(isolate); | 1666 SealHandleScope shs(isolate); |
1679 DCHECK_EQ(1, args.length()); | 1667 DCHECK_EQ(1, args.length()); |
1680 CONVERT_ARG_CHECKED(Object, obj, 0); | 1668 CONVERT_ARG_CHECKED(Object, obj, 0); |
1681 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1669 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
1682 } | 1670 } |
1683 | 1671 |
1684 } // namespace internal | 1672 } // namespace internal |
1685 } // namespace v8 | 1673 } // namespace v8 |
OLD | NEW |