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 |