OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
10 #include "src/regexp/regexp-utils.h" | 10 #include "src/regexp/regexp-utils.h" |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 language_mode); | 243 language_mode); |
244 a->Goto(&out); | 244 a->Goto(&out); |
245 } | 245 } |
246 | 246 |
247 a->Bind(&out); | 247 a->Bind(&out); |
248 } | 248 } |
249 | 249 |
250 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, | 250 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, |
251 CodeStubAssembler* a, | 251 CodeStubAssembler* a, |
252 compiler::Node* context, | 252 compiler::Node* context, |
253 compiler::Node* match_elements, | 253 compiler::Node* match_info, |
254 compiler::Node* string) { | 254 compiler::Node* string) { |
255 typedef CodeStubAssembler::Variable Variable; | 255 typedef CodeStubAssembler::Variable Variable; |
256 typedef CodeStubAssembler::Label Label; | 256 typedef CodeStubAssembler::Label Label; |
257 typedef compiler::Node Node; | 257 typedef compiler::Node Node; |
258 | 258 |
259 Label out(a); | 259 Label out(a); |
260 | 260 |
261 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 261 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
262 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 262 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
263 match_elements, a->IntPtrConstant(RegExpImpl::kLastCaptureCount), 0, | 263 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, |
264 mode)); | 264 mode)); |
265 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); | 265 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); |
266 Node* const start = a->LoadFixedArrayElement( | 266 Node* const start = a->LoadFixedArrayElement( |
267 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture), 0, mode); | 267 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, |
| 268 mode); |
268 Node* const end = a->LoadFixedArrayElement( | 269 Node* const end = a->LoadFixedArrayElement( |
269 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1), 0, | 270 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, |
270 mode); | 271 mode); |
271 | 272 |
272 // Calculate the substring of the first match before creating the result array | 273 // Calculate the substring of the first match before creating the result array |
273 // to avoid an unnecessary write barrier storing the first result. | 274 // to avoid an unnecessary write barrier storing the first result. |
274 Node* const first = a->SubString(context, string, start, end); | 275 Node* const first = a->SubString(context, string, start, end); |
275 | 276 |
276 Node* const result = | 277 Node* const result = |
277 a->AllocateRegExpResult(context, num_results, start, string); | 278 a->AllocateRegExpResult(context, num_results, start, string); |
278 Node* const result_elements = a->LoadElements(result); | 279 Node* const result_elements = a->LoadElements(result); |
279 | 280 |
280 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, | 281 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, |
281 SKIP_WRITE_BARRIER); | 282 SKIP_WRITE_BARRIER); |
282 | 283 |
283 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); | 284 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); |
284 | 285 |
285 // Store all remaining captures. | 286 // Store all remaining captures. |
286 Node* const limit = | 287 Node* const limit = a->IntPtrAdd( |
287 a->IntPtrAdd(a->IntPtrConstant(RegExpImpl::kFirstCapture), num_indices); | 288 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); |
288 | 289 |
289 Variable var_from_cursor(a, MachineType::PointerRepresentation()); | 290 Variable var_from_cursor(a, MachineType::PointerRepresentation()); |
290 Variable var_to_cursor(a, MachineType::PointerRepresentation()); | 291 Variable var_to_cursor(a, MachineType::PointerRepresentation()); |
291 | 292 |
292 var_from_cursor.Bind(a->IntPtrConstant(RegExpImpl::kFirstCapture + 2)); | 293 var_from_cursor.Bind( |
| 294 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); |
293 var_to_cursor.Bind(a->IntPtrConstant(1)); | 295 var_to_cursor.Bind(a->IntPtrConstant(1)); |
294 | 296 |
295 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; | 297 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; |
296 Label loop(a, 2, vars); | 298 Label loop(a, 2, vars); |
297 | 299 |
298 a->Goto(&loop); | 300 a->Goto(&loop); |
299 a->Bind(&loop); | 301 a->Bind(&loop); |
300 { | 302 { |
301 Node* const from_cursor = var_from_cursor.value(); | 303 Node* const from_cursor = var_from_cursor.value(); |
302 Node* const to_cursor = var_to_cursor.value(); | 304 Node* const to_cursor = var_to_cursor.value(); |
303 Node* const start = a->LoadFixedArrayElement(match_elements, from_cursor); | 305 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); |
304 | 306 |
305 Label next_iter(a); | 307 Label next_iter(a); |
306 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); | 308 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); |
307 | 309 |
308 Node* const from_cursor_plus1 = | 310 Node* const from_cursor_plus1 = |
309 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); | 311 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); |
310 Node* const end = | 312 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1); |
311 a->LoadFixedArrayElement(match_elements, from_cursor_plus1); | |
312 | 313 |
313 Node* const capture = a->SubString(context, string, start, end); | 314 Node* const capture = a->SubString(context, string, start, end); |
314 a->StoreFixedArrayElement(result_elements, to_cursor, capture); | 315 a->StoreFixedArrayElement(result_elements, to_cursor, capture); |
315 a->Goto(&next_iter); | 316 a->Goto(&next_iter); |
316 | 317 |
317 a->Bind(&next_iter); | 318 a->Bind(&next_iter); |
318 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); | 319 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); |
319 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); | 320 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); |
320 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 321 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
321 } | 322 } |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 { | 413 { |
413 // Get last match info from the context. | 414 // Get last match info from the context. |
414 Node* const last_match_info = a->LoadContextElement( | 415 Node* const last_match_info = a->LoadContextElement( |
415 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 416 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
416 | 417 |
417 // Call the exec stub. | 418 // Call the exec stub. |
418 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 419 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
419 match_indices = a->CallStub(exec_callable, context, regexp, string, | 420 match_indices = a->CallStub(exec_callable, context, regexp, string, |
420 var_lastindex.value(), last_match_info); | 421 var_lastindex.value(), last_match_info); |
421 | 422 |
422 // {match_indices} is either null or the RegExpLastMatchInfo array. | 423 // {match_indices} is either null or the RegExpMatchInfo array. |
423 // Return early if exec failed, possibly updating last index. | 424 // Return early if exec failed, possibly updating last index. |
424 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 425 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
425 | 426 |
426 Label return_null(a); | 427 Label return_null(a); |
427 a->GotoUnless(should_update_last_index, &return_null); | 428 a->GotoUnless(should_update_last_index, &return_null); |
428 | 429 |
429 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 430 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); |
430 a->Goto(&return_null); | 431 a->Goto(&return_null); |
431 | 432 |
432 a->Bind(&return_null); | 433 a->Bind(&return_null); |
433 a->Return(null); | 434 a->Return(null); |
434 } | 435 } |
435 | 436 |
436 Label construct_result(a); | 437 Label construct_result(a); |
437 a->Bind(&successful_match); | 438 a->Bind(&successful_match); |
438 { | 439 { |
439 Node* const match_elements = a->LoadElements(match_indices); | |
440 | |
441 a->GotoUnless(should_update_last_index, &construct_result); | 440 a->GotoUnless(should_update_last_index, &construct_result); |
442 | 441 |
443 // Update the new last index from {match_indices}. | 442 // Update the new last index from {match_indices}. |
444 Node* const new_lastindex = a->LoadFixedArrayElement( | 443 Node* const new_lastindex = a->LoadFixedArrayElement( |
445 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1)); | 444 match_indices, |
| 445 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
446 | 446 |
447 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 447 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); |
448 a->Goto(&construct_result); | 448 a->Goto(&construct_result); |
449 | 449 |
450 a->Bind(&construct_result); | 450 a->Bind(&construct_result); |
451 { | 451 { |
452 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 452 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
453 match_elements, string); | 453 match_indices, string); |
454 a->Return(result); | 454 a->Return(result); |
455 } | 455 } |
456 } | 456 } |
457 } | 457 } |
458 | 458 |
459 namespace { | 459 namespace { |
460 | 460 |
461 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 461 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
462 compiler::Node* context, | 462 compiler::Node* context, |
463 compiler::Node* value, | 463 compiler::Node* value, |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 DEFINE_CAPTURE_GETTER(8) | 877 DEFINE_CAPTURE_GETTER(8) |
878 DEFINE_CAPTURE_GETTER(9) | 878 DEFINE_CAPTURE_GETTER(9) |
879 #undef DEFINE_CAPTURE_GETTER | 879 #undef DEFINE_CAPTURE_GETTER |
880 | 880 |
881 // The properties `input` and `$_` are aliases for each other. When this | 881 // The properties `input` and `$_` are aliases for each other. When this |
882 // value is set, the value it is set to is coerced to a string. | 882 // value is set, the value it is set to is coerced to a string. |
883 // Getter and setter for the input. | 883 // Getter and setter for the input. |
884 | 884 |
885 BUILTIN(RegExpInputGetter) { | 885 BUILTIN(RegExpInputGetter) { |
886 HandleScope scope(isolate); | 886 HandleScope scope(isolate); |
887 Handle<Object> obj = RegExpUtils::GetLastMatchInput( | 887 Handle<Object> obj(isolate->regexp_last_match_info()->LastInput(), isolate); |
888 isolate, isolate->regexp_last_match_info()); | |
889 return obj->IsUndefined(isolate) ? isolate->heap()->empty_string() | 888 return obj->IsUndefined(isolate) ? isolate->heap()->empty_string() |
890 : String::cast(*obj); | 889 : String::cast(*obj); |
891 } | 890 } |
892 | 891 |
893 BUILTIN(RegExpInputSetter) { | 892 BUILTIN(RegExpInputSetter) { |
894 HandleScope scope(isolate); | 893 HandleScope scope(isolate); |
895 Handle<Object> value = args.atOrUndefined(isolate, 1); | 894 Handle<Object> value = args.atOrUndefined(isolate, 1); |
896 Handle<String> str; | 895 Handle<String> str; |
897 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, | 896 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str, |
898 Object::ToString(isolate, value)); | 897 Object::ToString(isolate, value)); |
899 RegExpUtils::SetLastMatchField(isolate, isolate->regexp_last_match_info(), | 898 isolate->regexp_last_match_info()->SetLastInput(*str); |
900 RegExpImpl::kLastInput, str); | |
901 return isolate->heap()->undefined_value(); | 899 return isolate->heap()->undefined_value(); |
902 } | 900 } |
903 | 901 |
904 // Getters for the static properties lastMatch, lastParen, leftContext, and | 902 // Getters for the static properties lastMatch, lastParen, leftContext, and |
905 // rightContext of the RegExp constructor. The properties are computed based | 903 // rightContext of the RegExp constructor. The properties are computed based |
906 // on the captures array of the last successful match and the subject string | 904 // on the captures array of the last successful match and the subject string |
907 // of the last successful match. | 905 // of the last successful match. |
908 BUILTIN(RegExpLastMatchGetter) { | 906 BUILTIN(RegExpLastMatchGetter) { |
909 HandleScope scope(isolate); | 907 HandleScope scope(isolate); |
910 return *RegExpUtils::GenericCaptureGetter( | 908 return *RegExpUtils::GenericCaptureGetter( |
911 isolate, isolate->regexp_last_match_info(), 0); | 909 isolate, isolate->regexp_last_match_info(), 0); |
912 } | 910 } |
913 | 911 |
914 BUILTIN(RegExpLastParenGetter) { | 912 BUILTIN(RegExpLastParenGetter) { |
915 HandleScope scope(isolate); | 913 HandleScope scope(isolate); |
916 Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 914 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
917 const int length = | 915 const int length = match_info->NumberOfCaptureRegisters(); |
918 RegExpUtils::GetLastMatchNumberOfCaptures(isolate, match_info); | |
919 if (length <= 2) return isolate->heap()->empty_string(); // No captures. | 916 if (length <= 2) return isolate->heap()->empty_string(); // No captures. |
920 | 917 |
921 DCHECK_EQ(0, length % 2); | 918 DCHECK_EQ(0, length % 2); |
922 const int last_capture = (length / 2) - 1; | 919 const int last_capture = (length / 2) - 1; |
923 | 920 |
924 // We match the SpiderMonkey behavior: return the substring defined by the | 921 // We match the SpiderMonkey behavior: return the substring defined by the |
925 // last pair (after the first pair) of elements of the capture array even if | 922 // last pair (after the first pair) of elements of the capture array even if |
926 // it is empty. | 923 // it is empty. |
927 return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); | 924 return *RegExpUtils::GenericCaptureGetter(isolate, match_info, last_capture); |
928 } | 925 } |
929 | 926 |
930 BUILTIN(RegExpLeftContextGetter) { | 927 BUILTIN(RegExpLeftContextGetter) { |
931 HandleScope scope(isolate); | 928 HandleScope scope(isolate); |
932 Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 929 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
933 const int start_index = | 930 const int start_index = match_info->Capture(0); |
934 RegExpUtils::GetLastMatchCapture(isolate, match_info, 0); | 931 Handle<String> last_subject(match_info->LastSubject()); |
935 Handle<String> last_subject = | |
936 RegExpUtils::GetLastMatchSubject(isolate, match_info); | |
937 return *isolate->factory()->NewSubString(last_subject, 0, start_index); | 932 return *isolate->factory()->NewSubString(last_subject, 0, start_index); |
938 } | 933 } |
939 | 934 |
940 BUILTIN(RegExpRightContextGetter) { | 935 BUILTIN(RegExpRightContextGetter) { |
941 HandleScope scope(isolate); | 936 HandleScope scope(isolate); |
942 Handle<JSObject> match_info = isolate->regexp_last_match_info(); | 937 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
943 const int start_index = | 938 const int start_index = match_info->Capture(1); |
944 RegExpUtils::GetLastMatchCapture(isolate, match_info, 1); | 939 Handle<String> last_subject(match_info->LastSubject()); |
945 Handle<String> last_subject = | |
946 RegExpUtils::GetLastMatchSubject(isolate, match_info); | |
947 const int len = last_subject->length(); | 940 const int len = last_subject->length(); |
948 return *isolate->factory()->NewSubString(last_subject, start_index, len); | 941 return *isolate->factory()->NewSubString(last_subject, start_index, len); |
949 } | 942 } |
950 | 943 |
951 // ES#sec-regexp.prototype.test | 944 // ES#sec-regexp.prototype.test |
952 // RegExp.prototype.test ( S ) | 945 // RegExp.prototype.test ( S ) |
953 BUILTIN(RegExpPrototypeTest) { | 946 BUILTIN(RegExpPrototypeTest) { |
954 HandleScope scope(isolate); | 947 HandleScope scope(isolate); |
955 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.test"); | 948 CHECK_RECEIVER(JSReceiver, recv, "RegExp.prototype.test"); |
956 | 949 |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1131 Handle<Object> limit_obj) { | 1124 Handle<Object> limit_obj) { |
1132 Factory* factory = isolate->factory(); | 1125 Factory* factory = isolate->factory(); |
1133 | 1126 |
1134 uint32_t limit; | 1127 uint32_t limit; |
1135 RETURN_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit), JSArray); | 1128 RETURN_ON_EXCEPTION(isolate, ToUint32(isolate, limit_obj, &limit), JSArray); |
1136 | 1129 |
1137 const int length = string->length(); | 1130 const int length = string->length(); |
1138 | 1131 |
1139 if (limit == 0) return factory->NewJSArray(0); | 1132 if (limit == 0) return factory->NewJSArray(0); |
1140 | 1133 |
1141 Handle<JSObject> last_match_info = isolate->regexp_last_match_info(); | 1134 Handle<RegExpMatchInfo> last_match_info = isolate->regexp_last_match_info(); |
1142 | 1135 |
1143 if (length == 0) { | 1136 if (length == 0) { |
1144 Handle<Object> match_indices; | 1137 Handle<Object> match_indices; |
1145 ASSIGN_RETURN_ON_EXCEPTION( | 1138 ASSIGN_RETURN_ON_EXCEPTION( |
1146 isolate, match_indices, | 1139 isolate, match_indices, |
1147 RegExpImpl::Exec(regexp, string, 0, last_match_info), JSArray); | 1140 RegExpImpl::Exec(regexp, string, 0, last_match_info), JSArray); |
1148 | 1141 |
1149 if (!match_indices->IsNull(isolate)) return factory->NewJSArray(0); | 1142 if (!match_indices->IsNull(isolate)) return factory->NewJSArray(0); |
1150 | 1143 |
1151 Handle<FixedArray> elems = factory->NewUninitializedFixedArray(1); | 1144 Handle<FixedArray> elems = factory->NewUninitializedFixedArray(1); |
(...skipping 13 matching lines...) Expand all Loading... |
1165 if (start_index == length) { | 1158 if (start_index == length) { |
1166 Handle<String> substr = | 1159 Handle<String> substr = |
1167 factory->NewSubString(string, current_index, length); | 1160 factory->NewSubString(string, current_index, length); |
1168 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1161 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1169 break; | 1162 break; |
1170 } | 1163 } |
1171 | 1164 |
1172 Handle<Object> match_indices_obj; | 1165 Handle<Object> match_indices_obj; |
1173 ASSIGN_RETURN_ON_EXCEPTION( | 1166 ASSIGN_RETURN_ON_EXCEPTION( |
1174 isolate, match_indices_obj, | 1167 isolate, match_indices_obj, |
1175 RegExpImpl::Exec(regexp, string, start_index, last_match_info), | 1168 RegExpImpl::Exec(regexp, string, start_index, |
| 1169 isolate->regexp_last_match_info()), |
1176 JSArray); | 1170 JSArray); |
1177 | 1171 |
1178 if (match_indices_obj->IsNull(isolate)) { | 1172 if (match_indices_obj->IsNull(isolate)) { |
1179 Handle<String> substr = | 1173 Handle<String> substr = |
1180 factory->NewSubString(string, current_index, length); | 1174 factory->NewSubString(string, current_index, length); |
1181 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1175 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1182 break; | 1176 break; |
1183 } | 1177 } |
1184 | 1178 |
1185 auto match_indices = Handle<JSReceiver>::cast(match_indices_obj); | 1179 auto match_indices = Handle<RegExpMatchInfo>::cast(match_indices_obj); |
1186 | 1180 |
1187 Handle<Object> start_match_obj = | 1181 start_match = match_indices->Capture(0); |
1188 JSReceiver::GetElement(isolate, match_indices, | |
1189 RegExpImpl::kFirstCapture) | |
1190 .ToHandleChecked(); | |
1191 start_match = Handle<Smi>::cast(start_match_obj)->value(); | |
1192 | 1182 |
1193 if (start_match == length) { | 1183 if (start_match == length) { |
1194 Handle<String> substr = | 1184 Handle<String> substr = |
1195 factory->NewSubString(string, current_index, length); | 1185 factory->NewSubString(string, current_index, length); |
1196 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1186 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1197 break; | 1187 break; |
1198 } | 1188 } |
1199 | 1189 |
1200 Handle<Object> end_index_obj = | 1190 const int end_index = match_indices->Capture(1); |
1201 JSReceiver::GetElement(isolate, match_indices, | |
1202 RegExpImpl::kFirstCapture + 1) | |
1203 .ToHandleChecked(); | |
1204 const int end_index = Handle<Smi>::cast(end_index_obj)->value(); | |
1205 | 1191 |
1206 if (start_index == end_index && end_index == current_index) { | 1192 if (start_index == end_index && end_index == current_index) { |
1207 const bool unicode = (regexp->GetFlags() & JSRegExp::kUnicode) != 0; | 1193 const bool unicode = (regexp->GetFlags() & JSRegExp::kUnicode) != 0; |
1208 if (unicode && AtSurrogatePair(isolate, string, start_index)) { | 1194 if (unicode && AtSurrogatePair(isolate, string, start_index)) { |
1209 start_index += 2; | 1195 start_index += 2; |
1210 } else { | 1196 } else { |
1211 start_index += 1; | 1197 start_index += 1; |
1212 } | 1198 } |
1213 continue; | 1199 continue; |
1214 } | 1200 } |
1215 | 1201 |
1216 { | 1202 { |
1217 Handle<String> substr = | 1203 Handle<String> substr = |
1218 factory->NewSubString(string, current_index, start_match); | 1204 factory->NewSubString(string, current_index, start_match); |
1219 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1205 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1220 } | 1206 } |
1221 | 1207 |
1222 if (num_elems == limit) break; | 1208 if (num_elems == limit) break; |
1223 | 1209 |
1224 Handle<Object> num_captures_obj = | 1210 for (int i = 2; i < match_indices->NumberOfCaptureRegisters(); i += 2) { |
1225 JSReceiver::GetElement(isolate, match_indices, | 1211 const int start = match_indices->Capture(i); |
1226 RegExpImpl::kLastCaptureCount) | 1212 const int end = match_indices->Capture(i + 1); |
1227 .ToHandleChecked(); | |
1228 const int match_indices_len = Handle<Smi>::cast(num_captures_obj)->value() + | |
1229 RegExpImpl::kFirstCapture; | |
1230 | |
1231 for (int i = RegExpImpl::kFirstCapture + 2; i < match_indices_len;) { | |
1232 Handle<Object> start_obj = | |
1233 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked(); | |
1234 const int start = Handle<Smi>::cast(start_obj)->value(); | |
1235 | |
1236 Handle<Object> end_obj = | |
1237 JSReceiver::GetElement(isolate, match_indices, i++).ToHandleChecked(); | |
1238 const int end = Handle<Smi>::cast(end_obj)->value(); | |
1239 | 1213 |
1240 if (end != -1) { | 1214 if (end != -1) { |
1241 Handle<String> substr = factory->NewSubString(string, start, end); | 1215 Handle<String> substr = factory->NewSubString(string, start, end); |
1242 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1216 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1243 } else { | 1217 } else { |
1244 elems = FixedArray::SetAndGrow(elems, num_elems++, | 1218 elems = FixedArray::SetAndGrow(elems, num_elems++, |
1245 factory->undefined_value()); | 1219 factory->undefined_value()); |
1246 } | 1220 } |
1247 | 1221 |
1248 if (num_elems == limit) { | 1222 if (num_elems == limit) { |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1524 | 1498 |
1525 a->Bind(&if_didnotmatch); | 1499 a->Bind(&if_didnotmatch); |
1526 { | 1500 { |
1527 FastStoreLastIndex(a, context, regexp, smi_zero); | 1501 FastStoreLastIndex(a, context, regexp, smi_zero); |
1528 var_result.Bind(subject_string); | 1502 var_result.Bind(subject_string); |
1529 a->Goto(&out); | 1503 a->Goto(&out); |
1530 } | 1504 } |
1531 | 1505 |
1532 a->Bind(&if_matched); | 1506 a->Bind(&if_matched); |
1533 { | 1507 { |
1534 Node* const match_elements = a->LoadElements(match_indices); | |
1535 CodeStubAssembler::ParameterMode mode = | 1508 CodeStubAssembler::ParameterMode mode = |
1536 CodeStubAssembler::INTPTR_PARAMETERS; | 1509 CodeStubAssembler::INTPTR_PARAMETERS; |
1537 | 1510 |
1538 Node* const subject_start = smi_zero; | 1511 Node* const subject_start = smi_zero; |
1539 Node* const match_start = a->LoadFixedArrayElement( | 1512 Node* const match_start = a->LoadFixedArrayElement( |
1540 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture), 0, | 1513 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), |
1541 mode); | 1514 0, mode); |
1542 Node* const match_end = a->LoadFixedArrayElement( | 1515 Node* const match_end = a->LoadFixedArrayElement( |
1543 match_elements, a->IntPtrConstant(RegExpImpl::kFirstCapture + 1), 0, | 1516 match_indices, |
1544 mode); | 1517 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); |
1545 Node* const subject_end = a->LoadStringLength(subject_string); | 1518 Node* const subject_end = a->LoadStringLength(subject_string); |
1546 | 1519 |
1547 Label if_replaceisempty(a), if_replaceisnotempty(a); | 1520 Label if_replaceisempty(a), if_replaceisnotempty(a); |
1548 Node* const replace_length = a->LoadStringLength(replace_string); | 1521 Node* const replace_length = a->LoadStringLength(replace_string); |
1549 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, | 1522 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, |
1550 &if_replaceisnotempty); | 1523 &if_replaceisnotempty); |
1551 | 1524 |
1552 a->Bind(&if_replaceisempty); | 1525 a->Bind(&if_replaceisempty); |
1553 { | 1526 { |
1554 // TODO(jgruber): We could skip many of the checks that using SubString | 1527 // TODO(jgruber): We could skip many of the checks that using SubString |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1648 } | 1621 } |
1649 | 1622 |
1650 a->Bind(&runtime); | 1623 a->Bind(&runtime); |
1651 { | 1624 { |
1652 Node* const result = a->CallRuntime(Runtime::kRegExpReplace, context, | 1625 Node* const result = a->CallRuntime(Runtime::kRegExpReplace, context, |
1653 receiver, string, replace_value); | 1626 receiver, string, replace_value); |
1654 a->Return(result); | 1627 a->Return(result); |
1655 } | 1628 } |
1656 } | 1629 } |
1657 | 1630 |
1658 namespace { | |
1659 | |
1660 // TODO(jgruber): Replace this with a FixedArray. | |
1661 compiler::Node* GetInternalMatchInfo(CodeStubAssembler* a, | |
1662 compiler::Node* context) { | |
1663 typedef compiler::Node Node; | |
1664 | |
1665 const ElementsKind elements_kind = FAST_ELEMENTS; | |
1666 Node* const native_context = a->LoadNativeContext(context); | |
1667 Node* const array_map = | |
1668 a->LoadJSArrayElementsMap(elements_kind, native_context); | |
1669 Node* const capacity = a->IntPtrConstant(RegExpImpl::kLastMatchOverhead + 2); | |
1670 Node* const allocation_site = nullptr; | |
1671 | |
1672 Node* const smi_zero = a->SmiConstant(Smi::kZero); | |
1673 | |
1674 return a->AllocateJSArray(elements_kind, array_map, capacity, smi_zero, | |
1675 allocation_site, | |
1676 CodeStubAssembler::INTPTR_PARAMETERS); | |
1677 } | |
1678 | |
1679 } // namespace | |
1680 | |
1681 // Simple string matching functionality for internal use which does not modify | 1631 // Simple string matching functionality for internal use which does not modify |
1682 // the last match info. | 1632 // the last match info. |
1683 void Builtins::Generate_RegExpInternalMatch(CodeStubAssembler* a) { | 1633 void Builtins::Generate_RegExpInternalMatch(CodeStubAssembler* a) { |
1684 typedef CodeStubAssembler::Label Label; | 1634 typedef CodeStubAssembler::Label Label; |
1685 typedef compiler::Node Node; | 1635 typedef compiler::Node Node; |
1686 | 1636 |
1687 Isolate* const isolate = a->isolate(); | 1637 Isolate* const isolate = a->isolate(); |
1688 | 1638 |
1689 Node* const regexp = a->Parameter(1); | 1639 Node* const regexp = a->Parameter(1); |
1690 Node* const string = a->Parameter(2); | 1640 Node* const string = a->Parameter(2); |
1691 Node* const context = a->Parameter(5); | 1641 Node* const context = a->Parameter(5); |
1692 | 1642 |
1693 Node* const null = a->NullConstant(); | 1643 Node* const null = a->NullConstant(); |
1694 Node* const smi_zero = a->SmiConstant(Smi::FromInt(0)); | 1644 Node* const smi_zero = a->SmiConstant(Smi::FromInt(0)); |
1695 Node* const internal_match_info = GetInternalMatchInfo(a, context); | 1645 |
| 1646 Node* const native_context = a->LoadNativeContext(context); |
| 1647 Node* const internal_match_info = a->LoadContextElement( |
| 1648 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); |
1696 | 1649 |
1697 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 1650 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
1698 Node* const match_indices = a->CallStub( | 1651 Node* const match_indices = a->CallStub( |
1699 exec_callable, context, regexp, string, smi_zero, internal_match_info); | 1652 exec_callable, context, regexp, string, smi_zero, internal_match_info); |
1700 | 1653 |
1701 Label if_matched(a), if_didnotmatch(a); | 1654 Label if_matched(a), if_didnotmatch(a); |
1702 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 1655 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
1703 | 1656 |
1704 a->Bind(&if_didnotmatch); | 1657 a->Bind(&if_didnotmatch); |
1705 a->Return(null); | 1658 a->Return(null); |
1706 | 1659 |
1707 a->Bind(&if_matched); | 1660 a->Bind(&if_matched); |
1708 { | 1661 { |
1709 Node* const match_elements = a->LoadElements(match_indices); | |
1710 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 1662 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
1711 match_elements, string); | 1663 match_indices, string); |
1712 a->Return(result); | 1664 a->Return(result); |
1713 } | 1665 } |
1714 } | 1666 } |
1715 | 1667 |
1716 } // namespace internal | 1668 } // namespace internal |
1717 } // namespace v8 | 1669 } // namespace v8 |
OLD | NEW |