| 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 |