| 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 1066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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( | 1081 MUST_USE_RESULT MaybeHandle<String> StringReplaceNonGlobalRegExpWithFunction( |
| 1082 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, | 1082 Isolate* isolate, Handle<String> subject, Handle<JSRegExp> regexp, |
| 1083 Handle<Object> replace_obj) { | 1083 Handle<Object> replace_obj) { |
| 1084 Factory* factory = isolate->factory(); | 1084 Factory* factory = isolate->factory(); |
| 1085 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | 1085 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1086 | 1086 |
| 1087 // TODO(jgruber): This is a pattern we could refactor. | 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 |
| 1088 Handle<Object> match_indices_obj; | 1106 Handle<Object> match_indices_obj; |
| 1089 ASSIGN_RETURN_ON_EXCEPTION( | 1107 ASSIGN_RETURN_ON_EXCEPTION( |
| 1090 isolate, match_indices_obj, | 1108 isolate, match_indices_obj, |
| 1091 RegExpImpl::Exec(regexp, subject, 0, last_match_info), String); | 1109 RegExpImpl::Exec(regexp, subject, last_index, last_match_info), String); |
| 1092 | 1110 |
| 1093 if (match_indices_obj->IsNull(isolate)) { | 1111 if (match_indices_obj->IsNull(isolate)) { |
| 1094 RETURN_ON_EXCEPTION(isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), | 1112 if (sticky) regexp->SetLastIndex(0); |
| 1095 String); | |
| 1096 return subject; | 1113 return subject; |
| 1097 } | 1114 } |
| 1098 | 1115 |
| 1099 Handle<RegExpMatchInfo> match_indices = | 1116 Handle<RegExpMatchInfo> match_indices = |
| 1100 Handle<RegExpMatchInfo>::cast(match_indices_obj); | 1117 Handle<RegExpMatchInfo>::cast(match_indices_obj); |
| 1101 | 1118 |
| 1102 const int index = match_indices->Capture(0); | 1119 const int index = match_indices->Capture(0); |
| 1103 const int end_of_match = match_indices->Capture(1); | 1120 const int end_of_match = match_indices->Capture(1); |
| 1104 | 1121 |
| 1122 if (sticky) regexp->SetLastIndex(end_of_match); |
| 1123 |
| 1105 IncrementalStringBuilder builder(isolate); | 1124 IncrementalStringBuilder builder(isolate); |
| 1106 builder.AppendString(factory->NewSubString(subject, 0, index)); | 1125 builder.AppendString(factory->NewSubString(subject, 0, index)); |
| 1107 | 1126 |
| 1108 // Compute the parameter list consisting of the match, captures, index, | 1127 // Compute the parameter list consisting of the match, captures, index, |
| 1109 // and subject for the replace function invocation. | 1128 // and subject for the replace function invocation. |
| 1110 // The number of captures plus one for the match. | 1129 // The number of captures plus one for the match. |
| 1111 const int m = match_indices->NumberOfCaptureRegisters() / 2; | 1130 const int m = match_indices->NumberOfCaptureRegisters() / 2; |
| 1112 | 1131 |
| 1113 const int argc = m + 2; | 1132 const int argc = m + 2; |
| 1114 ScopedVector<Handle<Object>> argv(argc); | 1133 ScopedVector<Handle<Object>> argv(argc); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 } | 1165 } |
| 1147 | 1166 |
| 1148 // Legacy implementation of RegExp.prototype[Symbol.replace] which | 1167 // Legacy implementation of RegExp.prototype[Symbol.replace] which |
| 1149 // doesn't properly call the underlying exec method. | 1168 // doesn't properly call the underlying exec method. |
| 1150 MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, | 1169 MUST_USE_RESULT MaybeHandle<String> RegExpReplace(Isolate* isolate, |
| 1151 Handle<JSRegExp> regexp, | 1170 Handle<JSRegExp> regexp, |
| 1152 Handle<String> string, | 1171 Handle<String> string, |
| 1153 Handle<Object> replace_obj) { | 1172 Handle<Object> replace_obj) { |
| 1154 Factory* factory = isolate->factory(); | 1173 Factory* factory = isolate->factory(); |
| 1155 | 1174 |
| 1156 // TODO(jgruber): We need the even stricter guarantee of an unmodified | |
| 1157 // JSRegExp map here for access to GetFlags to be legal. | |
| 1158 const int flags = regexp->GetFlags(); | 1175 const int flags = regexp->GetFlags(); |
| 1159 const bool global = (flags & JSRegExp::kGlobal) != 0; | 1176 const bool global = (flags & JSRegExp::kGlobal) != 0; |
| 1177 const bool sticky = (flags & JSRegExp::kSticky) != 0; |
| 1160 | 1178 |
| 1161 // Functional fast-paths are dispatched directly by replace builtin. | 1179 // Functional fast-paths are dispatched directly by replace builtin. |
| 1162 DCHECK(!replace_obj->IsCallable()); | 1180 DCHECK(!replace_obj->IsCallable()); |
| 1163 | 1181 |
| 1164 Handle<String> replace; | 1182 Handle<String> replace; |
| 1165 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, | 1183 ASSIGN_RETURN_ON_EXCEPTION(isolate, replace, |
| 1166 Object::ToString(isolate, replace_obj), String); | 1184 Object::ToString(isolate, replace_obj), String); |
| 1167 replace = String::Flatten(replace); | 1185 replace = String::Flatten(replace); |
| 1168 | 1186 |
| 1169 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); | 1187 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
| 1170 | 1188 |
| 1171 if (!global) { | 1189 if (!global) { |
| 1172 // Non-global regexp search, string replace. | 1190 // Non-global regexp search, string replace. |
| 1173 | 1191 |
| 1192 uint32_t last_index = 0; |
| 1193 if (sticky) { |
| 1194 Handle<Object> last_index_obj(regexp->LastIndex(), isolate); |
| 1195 ASSIGN_RETURN_ON_EXCEPTION(isolate, last_index_obj, |
| 1196 Object::ToLength(isolate, last_index_obj), |
| 1197 String); |
| 1198 last_index = PositiveNumberToUint32(*last_index_obj); |
| 1199 |
| 1200 if (static_cast<int>(last_index) > string->length()) last_index = 0; |
| 1201 } |
| 1202 |
| 1174 Handle<Object> match_indices_obj; | 1203 Handle<Object> match_indices_obj; |
| 1175 ASSIGN_RETURN_ON_EXCEPTION( | 1204 ASSIGN_RETURN_ON_EXCEPTION( |
| 1176 isolate, match_indices_obj, | 1205 isolate, match_indices_obj, |
| 1177 RegExpImpl::Exec(regexp, string, 0, last_match_info), String); | 1206 RegExpImpl::Exec(regexp, string, last_index, last_match_info), String); |
| 1178 | 1207 |
| 1179 if (match_indices_obj->IsNull(isolate)) { | 1208 if (match_indices_obj->IsNull(isolate)) { |
| 1180 RETURN_ON_EXCEPTION( | 1209 if (sticky) regexp->SetLastIndex(0); |
| 1181 isolate, RegExpUtils::SetLastIndex(isolate, regexp, 0), String); | |
| 1182 return string; | 1210 return string; |
| 1183 } | 1211 } |
| 1184 | 1212 |
| 1185 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); | 1213 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); |
| 1186 | 1214 |
| 1187 const int start_index = match_indices->Capture(0); | 1215 const int start_index = match_indices->Capture(0); |
| 1188 const int end_index = match_indices->Capture(1); | 1216 const int end_index = match_indices->Capture(1); |
| 1189 | 1217 |
| 1218 if (sticky) regexp->SetLastIndex(end_index); |
| 1219 |
| 1190 IncrementalStringBuilder builder(isolate); | 1220 IncrementalStringBuilder builder(isolate); |
| 1191 builder.AppendString(factory->NewSubString(string, 0, start_index)); | 1221 builder.AppendString(factory->NewSubString(string, 0, start_index)); |
| 1192 | 1222 |
| 1193 if (replace->length() > 0) { | 1223 if (replace->length() > 0) { |
| 1194 MatchInfoBackedMatch m(isolate, string, match_indices); | 1224 MatchInfoBackedMatch m(isolate, string, match_indices); |
| 1195 Handle<String> replacement; | 1225 Handle<String> replacement; |
| 1196 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement, | 1226 ASSIGN_RETURN_ON_EXCEPTION(isolate, replacement, |
| 1197 String::GetSubstitution(isolate, &m, replace), | 1227 String::GetSubstitution(isolate, &m, replace), |
| 1198 String); | 1228 String); |
| 1199 builder.AppendString(replacement); | 1229 builder.AppendString(replacement); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1261 } | 1291 } |
| 1262 | 1292 |
| 1263 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { | 1293 RUNTIME_FUNCTION(Runtime_StringReplaceNonGlobalRegExpWithFunction) { |
| 1264 HandleScope scope(isolate); | 1294 HandleScope scope(isolate); |
| 1265 DCHECK_EQ(3, args.length()); | 1295 DCHECK_EQ(3, args.length()); |
| 1266 | 1296 |
| 1267 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); | 1297 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); |
| 1268 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); | 1298 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); |
| 1269 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); | 1299 CONVERT_ARG_HANDLE_CHECKED(JSObject, replace, 2); |
| 1270 | 1300 |
| 1301 DCHECK(RegExpUtils::IsUnmodifiedRegExp(isolate, regexp)); |
| 1302 |
| 1271 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceNonGlobalRegExpWithFunction( | 1303 RETURN_RESULT_OR_FAILURE(isolate, StringReplaceNonGlobalRegExpWithFunction( |
| 1272 isolate, subject, regexp, replace)); | 1304 isolate, subject, regexp, replace)); |
| 1273 } | 1305 } |
| 1274 | 1306 |
| 1275 namespace { | 1307 namespace { |
| 1276 | 1308 |
| 1277 // ES##sec-speciesconstructor | 1309 // ES##sec-speciesconstructor |
| 1278 // SpeciesConstructor ( O, defaultConstructor ) | 1310 // SpeciesConstructor ( O, defaultConstructor ) |
| 1279 MUST_USE_RESULT MaybeHandle<Object> SpeciesConstructor( | 1311 MUST_USE_RESULT MaybeHandle<Object> SpeciesConstructor( |
| 1280 Isolate* isolate, Handle<JSReceiver> recv, | 1312 Isolate* isolate, Handle<JSReceiver> recv, |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1681 | 1713 |
| 1682 RUNTIME_FUNCTION(Runtime_IsRegExp) { | 1714 RUNTIME_FUNCTION(Runtime_IsRegExp) { |
| 1683 SealHandleScope shs(isolate); | 1715 SealHandleScope shs(isolate); |
| 1684 DCHECK_EQ(1, args.length()); | 1716 DCHECK_EQ(1, args.length()); |
| 1685 CONVERT_ARG_CHECKED(Object, obj, 0); | 1717 CONVERT_ARG_CHECKED(Object, obj, 0); |
| 1686 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); | 1718 return isolate->heap()->ToBoolean(obj->IsJSRegExp()); |
| 1687 } | 1719 } |
| 1688 | 1720 |
| 1689 } // namespace internal | 1721 } // namespace internal |
| 1690 } // namespace v8 | 1722 } // namespace v8 |
| OLD | NEW |