Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 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-regexp-gen.h" | 5 #include "src/builtins/builtins-regexp-gen.h" |
| 6 | 6 |
| 7 #include "src/builtins/builtins-constructor-gen.h" | 7 #include "src/builtins/builtins-constructor-gen.h" |
| 8 #include "src/builtins/builtins-utils-gen.h" | 8 #include "src/builtins/builtins-utils-gen.h" |
| 9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 | 224 |
| 225 Node* const from_offset = ElementOffsetFromIndex( | 225 Node* const from_offset = ElementOffsetFromIndex( |
| 226 IntPtrAdd(offset, last_index), kind, INTPTR_PARAMETERS); | 226 IntPtrAdd(offset, last_index), kind, INTPTR_PARAMETERS); |
| 227 var_string_start->Bind(IntPtrAdd(string_data, from_offset)); | 227 var_string_start->Bind(IntPtrAdd(string_data, from_offset)); |
| 228 | 228 |
| 229 Node* const to_offset = ElementOffsetFromIndex( | 229 Node* const to_offset = ElementOffsetFromIndex( |
| 230 IntPtrAdd(offset, string_length), kind, INTPTR_PARAMETERS); | 230 IntPtrAdd(offset, string_length), kind, INTPTR_PARAMETERS); |
| 231 var_string_end->Bind(IntPtrAdd(string_data, to_offset)); | 231 var_string_end->Bind(IntPtrAdd(string_data, to_offset)); |
| 232 } | 232 } |
| 233 | 233 |
| 234 Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context, | 234 Node* RegExpBuiltinsAssembler::RegExpExecInternal(Node* const context, |
| 235 Node* const regexp, | 235 Node* const regexp, |
| 236 Node* const string, | 236 Node* const string, |
| 237 Node* const last_index, | 237 Node* const last_index, |
| 238 Node* const match_info) { | 238 Node* const match_info) { |
| 239 // Just jump directly to runtime if native RegExp is not selected at compile | 239 // Just jump directly to runtime if native RegExp is not selected at compile |
| 240 // time or if regexp entry in generated code is turned off runtime switch or | 240 // time or if regexp entry in generated code is turned off runtime switch or |
| 241 // at compilation. | 241 // at compilation. |
| 242 #ifdef V8_INTERPRETED_REGEXP | 242 #ifdef V8_INTERPRETED_REGEXP |
| 243 return CallRuntime(Runtime::kRegExpExec, context, regexp, string, last_index, | 243 return CallRuntime(Runtime::kRegExpExec, context, regexp, string, last_index, |
| 244 match_info); | 244 match_info); |
| 245 #else // V8_INTERPRETED_REGEXP | 245 #else // V8_INTERPRETED_REGEXP |
| 246 CSA_ASSERT(this, TaggedIsNotSmi(regexp)); | 246 CSA_ASSERT(this, TaggedIsNotSmi(regexp)); |
| 247 CSA_ASSERT(this, IsJSRegExp(regexp)); | 247 CSA_ASSERT(this, IsJSRegExp(regexp)); |
| 248 | 248 |
| 249 CSA_ASSERT(this, TaggedIsNotSmi(string)); | 249 CSA_ASSERT(this, TaggedIsNotSmi(string)); |
| 250 CSA_ASSERT(this, IsString(string)); | 250 CSA_ASSERT(this, IsString(string)); |
| 251 | 251 |
| 252 CSA_ASSERT(this, IsNumber(last_index)); | 252 CSA_ASSERT(this, IsNumber(last_index)); |
| 253 CSA_ASSERT(this, IsFixedArrayMap(LoadReceiverMap(match_info))); | 253 CSA_ASSERT(this, IsFixedArrayMap(LoadReceiverMap(match_info))); |
| 254 | 254 |
| 255 Node* const int_zero = IntPtrConstant(0); | 255 Node* const int_zero = IntPtrConstant(0); |
| 256 | 256 |
| 257 ToDirectStringAssembler to_direct(state(), string); | 257 ToDirectStringAssembler to_direct(state(), string); |
| 258 | 258 |
| 259 VARIABLE(var_result, MachineRepresentation::kTagged); | 259 VARIABLE(var_result, MachineRepresentation::kTagged); |
| 260 Label out(this), runtime(this, Label::kDeferred); | 260 Label out(this), runtime(this, Label::kDeferred); |
| 261 | 261 |
| 262 // External constants. | 262 // External constants. |
| 263 Node* const isolate_address = | |
| 264 ExternalConstant(ExternalReference::isolate_address(isolate())); | |
| 265 Node* const regexp_stack_memory_address_address = ExternalConstant( | |
| 266 ExternalReference::address_of_regexp_stack_memory_address(isolate())); | |
| 263 Node* const regexp_stack_memory_size_address = ExternalConstant( | 267 Node* const regexp_stack_memory_size_address = ExternalConstant( |
| 264 ExternalReference::address_of_regexp_stack_memory_size(isolate())); | 268 ExternalReference::address_of_regexp_stack_memory_size(isolate())); |
| 265 Node* const static_offsets_vector_address = ExternalConstant( | 269 Node* const static_offsets_vector_address = ExternalConstant( |
| 266 ExternalReference::address_of_static_offsets_vector(isolate())); | 270 ExternalReference::address_of_static_offsets_vector(isolate())); |
| 267 Node* const pending_exception_address = ExternalConstant( | |
| 268 ExternalReference(Isolate::kPendingExceptionAddress, isolate())); | |
| 269 | 271 |
| 270 // Ensure that a RegExp stack is allocated. | 272 // Ensure that a RegExp stack is allocated. |
| 271 { | 273 { |
| 272 Node* const stack_size = | 274 Node* const stack_size = |
| 273 Load(MachineType::IntPtr(), regexp_stack_memory_size_address); | 275 Load(MachineType::IntPtr(), regexp_stack_memory_size_address); |
| 274 GotoIf(IntPtrEqual(stack_size, int_zero), &runtime); | 276 GotoIf(IntPtrEqual(stack_size, int_zero), &runtime); |
| 275 } | 277 } |
| 276 | 278 |
| 277 Node* const data = LoadObjectField(regexp, JSRegExp::kDataOffset); | 279 Node* const data = LoadObjectField(regexp, JSRegExp::kDataOffset); |
| 278 { | 280 { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 | 356 |
| 355 Node* const code = var_code.value(); | 357 Node* const code = var_code.value(); |
| 356 GotoIf(TaggedIsSmi(code), &runtime); | 358 GotoIf(TaggedIsSmi(code), &runtime); |
| 357 CSA_ASSERT(this, HasInstanceType(code, CODE_TYPE)); | 359 CSA_ASSERT(this, HasInstanceType(code, CODE_TYPE)); |
| 358 | 360 |
| 359 Label if_success(this), if_failure(this), | 361 Label if_success(this), if_failure(this), |
| 360 if_exception(this, Label::kDeferred); | 362 if_exception(this, Label::kDeferred); |
| 361 { | 363 { |
| 362 IncrementCounter(isolate()->counters()->regexp_entry_native(), 1); | 364 IncrementCounter(isolate()->counters()->regexp_entry_native(), 1); |
| 363 | 365 |
| 364 Callable exec_callable = CodeFactory::RegExpExec(isolate()); | 366 // Set up args for the final call into generated Irregexp code. |
| 365 Node* const result = CallStub( | 367 |
| 366 exec_callable, context, string, TruncateWordToWord32(int_last_index), | 368 MachineType type_int32 = MachineType::Int32(); |
| 367 var_string_start.value(), var_string_end.value(), code); | 369 MachineType type_tagged = MachineType::AnyTagged(); |
| 370 MachineType type_ptr = MachineType::Pointer(); | |
| 371 | |
| 372 // Result: A NativeRegExpMacroAssembler::Result return code. | |
| 373 MachineType retval_type = type_int32; | |
| 374 | |
| 375 // Argument 0: Original subject string. | |
| 376 MachineType arg0_type = type_tagged; | |
| 377 Node* const arg0 = string; | |
| 378 | |
| 379 // Argument 1: Previous index. | |
| 380 MachineType arg1_type = type_int32; | |
| 381 Node* const arg1 = TruncateWordToWord32(int_last_index); | |
| 382 | |
| 383 // Argument 2: Start of string data. | |
| 384 // Argument 3: End of string data. | |
|
Igor Sheludko
2017/04/20 15:08:07
I'd move this comment down.
jgruber
2017/04/21 10:42:33
Done.
| |
| 385 MachineType arg2_type = type_ptr; | |
| 386 Node* const arg2 = var_string_start.value(); | |
| 387 | |
| 388 MachineType arg3_type = type_ptr; | |
| 389 Node* const arg3 = var_string_end.value(); | |
| 390 | |
| 391 // Argument 4: static offsets vector buffer. | |
| 392 MachineType arg4_type = type_ptr; | |
| 393 Node* const arg4 = static_offsets_vector_address; | |
| 394 | |
| 395 // Argument 5: Set the number of capture registers to zero to force global | |
| 396 // regexps to behave as non-global. This does not affect non-global | |
| 397 // regexps. | |
| 398 MachineType arg5_type = type_int32; | |
| 399 Node* const arg5 = Int32Constant(0); | |
| 400 | |
| 401 // Argument 6: Start (high end) of backtracking stack memory area. | |
| 402 Node* const stack_start = | |
| 403 Load(MachineType::Pointer(), regexp_stack_memory_address_address); | |
| 404 Node* const stack_size = | |
| 405 Load(MachineType::IntPtr(), regexp_stack_memory_size_address); | |
| 406 Node* const stack_end = IntPtrAdd(stack_start, stack_size); | |
| 407 | |
| 408 MachineType arg6_type = type_ptr; | |
| 409 Node* const arg6 = stack_end; | |
| 410 | |
| 411 // Argument 7: Indicate that this is a direct call from JavaScript. | |
| 412 MachineType arg7_type = type_int32; | |
| 413 Node* const arg7 = Int32Constant(1); | |
| 414 | |
| 415 // Argument 8: Pass current isolate address. | |
| 416 MachineType arg8_type = type_ptr; | |
| 417 Node* const arg8 = isolate_address; | |
| 418 | |
| 419 Node* const code_entry = | |
| 420 IntPtrAdd(BitcastTaggedToWord(code), | |
| 421 IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)); | |
| 422 | |
| 423 Node* const result = CallCFunction9( | |
| 424 retval_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type, | |
| 425 arg5_type, arg6_type, arg7_type, arg8_type, code_entry, arg0, arg1, | |
| 426 arg2, arg3, arg4, arg5, arg6, arg7, arg8); | |
| 368 | 427 |
| 369 // Check the result. | 428 // Check the result. |
| 370 // We expect exactly one result since the stub forces the called regexp to | 429 // We expect exactly one result since we force the called regexp to behave |
| 371 // behave as non-global. | 430 // as non-global. |
| 372 GotoIf(SmiEqual(result, SmiConstant(1)), &if_success); | 431 Node* const int_result = ChangeInt32ToIntPtr(result); |
| 373 GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::FAILURE)), | 432 GotoIf(IntPtrEqual(int_result, IntPtrConstant(1)), &if_success); |
|
Igor Sheludko
2017/04/20 15:08:07
s/1/NativeRegExpMacroAssembler::SUCCESS/
jgruber
2017/04/21 10:42:33
Done.
| |
| 433 GotoIf(IntPtrEqual(int_result, | |
| 434 IntPtrConstant(NativeRegExpMacroAssembler::FAILURE)), | |
| 374 &if_failure); | 435 &if_failure); |
| 375 GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::EXCEPTION)), | 436 GotoIf(IntPtrEqual(int_result, |
| 437 IntPtrConstant(NativeRegExpMacroAssembler::EXCEPTION)), | |
| 376 &if_exception); | 438 &if_exception); |
| 377 | 439 |
| 378 CSA_ASSERT( | 440 CSA_ASSERT(this, |
| 379 this, SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::RETRY))); | 441 IntPtrEqual(int_result, |
| 442 IntPtrConstant(NativeRegExpMacroAssembler::RETRY))); | |
| 380 Goto(&runtime); | 443 Goto(&runtime); |
| 381 } | 444 } |
| 382 | 445 |
| 383 BIND(&if_success); | 446 BIND(&if_success); |
| 384 { | 447 { |
| 385 // Check that the last match info has space for the capture registers and | 448 // Check that the last match info has space for the capture registers and |
| 386 // the additional information. Ensure no overflow in add. | 449 // the additional information. Ensure no overflow in add. |
| 387 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 450 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 388 Node* const available_slots = | 451 Node* const available_slots = |
| 389 SmiSub(LoadFixedArrayBaseLength(match_info), | 452 SmiSub(LoadFixedArrayBaseLength(match_info), |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 } | 496 } |
| 434 | 497 |
| 435 BIND(&if_failure); | 498 BIND(&if_failure); |
| 436 { | 499 { |
| 437 var_result.Bind(NullConstant()); | 500 var_result.Bind(NullConstant()); |
| 438 Goto(&out); | 501 Goto(&out); |
| 439 } | 502 } |
| 440 | 503 |
| 441 BIND(&if_exception); | 504 BIND(&if_exception); |
| 442 { | 505 { |
| 443 Node* const pending_exception = | 506 // A stack overflow was detected in RegExp code. |
| 444 Load(MachineType::AnyTagged(), pending_exception_address); | 507 Node* const pending_exception_address = ExternalConstant( |
| 445 | 508 ExternalReference(Isolate::kPendingExceptionAddress, isolate())); |
| 446 // If there is no pending exception, a | 509 CSA_ASSERT(this, IsTheHole(Load(MachineType::AnyTagged(), |
| 447 // stack overflow (on the backtrack stack) was detected in RegExp code. | 510 pending_exception_address))); |
| 448 | 511 USE(pending_exception_address); |
|
Igor Sheludko
2017/04/20 15:08:07
I'd wrap this block in #ifdef DEBUG/#endif instead
jgruber
2017/04/21 10:42:33
Done.
| |
| 449 Label stack_overflow(this), rethrow(this); | |
| 450 Branch(IsTheHole(pending_exception), &stack_overflow, &rethrow); | |
| 451 | |
| 452 BIND(&stack_overflow); | |
| 453 CallRuntime(Runtime::kThrowStackOverflow, context); | 512 CallRuntime(Runtime::kThrowStackOverflow, context); |
| 454 Unreachable(); | 513 Unreachable(); |
| 455 | |
| 456 BIND(&rethrow); | |
| 457 CallRuntime(Runtime::kRegExpExecReThrow, context); | |
| 458 Unreachable(); | |
| 459 } | 514 } |
| 460 | 515 |
| 461 BIND(&runtime); | 516 BIND(&runtime); |
| 462 { | 517 { |
| 463 Node* const result = CallRuntime(Runtime::kRegExpExec, context, regexp, | 518 Node* const result = CallRuntime(Runtime::kRegExpExec, context, regexp, |
| 464 string, last_index, match_info); | 519 string, last_index, match_info); |
| 465 var_result.Bind(result); | 520 var_result.Bind(result); |
| 466 Goto(&out); | 521 Goto(&out); |
| 467 } | 522 } |
| 468 | 523 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 564 Node* match_indices; | 619 Node* match_indices; |
| 565 Label successful_match(this); | 620 Label successful_match(this); |
| 566 BIND(&run_exec); | 621 BIND(&run_exec); |
| 567 { | 622 { |
| 568 // Get last match info from the context. | 623 // Get last match info from the context. |
| 569 Node* const native_context = LoadNativeContext(context); | 624 Node* const native_context = LoadNativeContext(context); |
| 570 Node* const last_match_info = LoadContextElement( | 625 Node* const last_match_info = LoadContextElement( |
| 571 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 626 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 572 | 627 |
| 573 // Call the exec stub. | 628 // Call the exec stub. |
| 574 match_indices = IrregexpExec(context, regexp, string, var_lastindex.value(), | 629 match_indices = RegExpExecInternal(context, regexp, string, |
| 575 last_match_info); | 630 var_lastindex.value(), last_match_info); |
| 576 var_result.Bind(match_indices); | 631 var_result.Bind(match_indices); |
| 577 | 632 |
| 578 // {match_indices} is either null or the RegExpMatchInfo array. | 633 // {match_indices} is either null or the RegExpMatchInfo array. |
| 579 // Return early if exec failed, possibly updating last index. | 634 // Return early if exec failed, possibly updating last index. |
| 580 GotoIfNot(WordEqual(match_indices, null), &successful_match); | 635 GotoIfNot(WordEqual(match_indices, null), &successful_match); |
| 581 | 636 |
| 582 GotoIfNot(should_update_last_index, if_didnotmatch); | 637 GotoIfNot(should_update_last_index, if_didnotmatch); |
| 583 | 638 |
| 584 StoreLastIndex(context, regexp, smi_zero, is_fastpath); | 639 StoreLastIndex(context, regexp, smi_zero, is_fastpath); |
| 585 Goto(if_didnotmatch); | 640 Goto(if_didnotmatch); |
| (...skipping 1511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2097 // array depending on whether the {regexp} matches. | 2152 // array depending on whether the {regexp} matches. |
| 2098 { | 2153 { |
| 2099 Label next(this), if_stringisempty(this, Label::kDeferred); | 2154 Label next(this), if_stringisempty(this, Label::kDeferred); |
| 2100 Branch(SmiEqual(string_length, smi_zero), &if_stringisempty, &next); | 2155 Branch(SmiEqual(string_length, smi_zero), &if_stringisempty, &next); |
| 2101 | 2156 |
| 2102 BIND(&if_stringisempty); | 2157 BIND(&if_stringisempty); |
| 2103 { | 2158 { |
| 2104 Node* const last_match_info = LoadContextElement( | 2159 Node* const last_match_info = LoadContextElement( |
| 2105 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2160 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 2106 | 2161 |
| 2107 Node* const match_indices = | 2162 Node* const match_indices = RegExpExecInternal(context, regexp, string, |
| 2108 IrregexpExec(context, regexp, string, smi_zero, last_match_info); | 2163 smi_zero, last_match_info); |
| 2109 | 2164 |
| 2110 Label return_singleton_array(this); | 2165 Label return_singleton_array(this); |
| 2111 Branch(WordEqual(match_indices, null), &return_singleton_array, | 2166 Branch(WordEqual(match_indices, null), &return_singleton_array, |
| 2112 &return_empty_array); | 2167 &return_empty_array); |
| 2113 | 2168 |
| 2114 BIND(&return_singleton_array); | 2169 BIND(&return_singleton_array); |
| 2115 { | 2170 { |
| 2116 Node* const length = SmiConstant(1); | 2171 Node* const length = SmiConstant(1); |
| 2117 Node* const capacity = IntPtrConstant(1); | 2172 Node* const capacity = IntPtrConstant(1); |
| 2118 Node* const result = AllocateJSArray(kind, array_map, capacity, length, | 2173 Node* const result = AllocateJSArray(kind, array_map, capacity, length, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2159 Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out, | 2214 Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out, |
| 2160 &next); | 2215 &next); |
| 2161 BIND(&next); | 2216 BIND(&next); |
| 2162 } | 2217 } |
| 2163 | 2218 |
| 2164 // Search for the given {regexp}. | 2219 // Search for the given {regexp}. |
| 2165 | 2220 |
| 2166 Node* const last_match_info = LoadContextElement( | 2221 Node* const last_match_info = LoadContextElement( |
| 2167 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2222 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
| 2168 | 2223 |
| 2169 Node* const match_indices = IrregexpExec(context, regexp, string, | 2224 Node* const match_indices = RegExpExecInternal( |
| 2170 next_search_from, last_match_info); | 2225 context, regexp, string, next_search_from, last_match_info); |
| 2171 | 2226 |
| 2172 // We're done if no match was found. | 2227 // We're done if no match was found. |
| 2173 { | 2228 { |
| 2174 Label next(this); | 2229 Label next(this); |
| 2175 Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next); | 2230 Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next); |
| 2176 BIND(&next); | 2231 BIND(&next); |
| 2177 } | 2232 } |
| 2178 | 2233 |
| 2179 Node* const match_from = LoadFixedArrayElement( | 2234 Node* const match_from = LoadFixedArrayElement( |
| 2180 match_indices, RegExpMatchInfo::kFirstCaptureIndex); | 2235 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
| (...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2841 Node* const null = NullConstant(); | 2896 Node* const null = NullConstant(); |
| 2842 Node* const smi_zero = SmiConstant(0); | 2897 Node* const smi_zero = SmiConstant(0); |
| 2843 | 2898 |
| 2844 CSA_ASSERT(this, IsJSRegExp(regexp)); | 2899 CSA_ASSERT(this, IsJSRegExp(regexp)); |
| 2845 CSA_ASSERT(this, IsString(string)); | 2900 CSA_ASSERT(this, IsString(string)); |
| 2846 | 2901 |
| 2847 Node* const native_context = LoadNativeContext(context); | 2902 Node* const native_context = LoadNativeContext(context); |
| 2848 Node* const internal_match_info = LoadContextElement( | 2903 Node* const internal_match_info = LoadContextElement( |
| 2849 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); | 2904 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); |
| 2850 | 2905 |
| 2851 Node* const match_indices = | 2906 Node* const match_indices = RegExpExecInternal(context, regexp, string, |
| 2852 IrregexpExec(context, regexp, string, smi_zero, internal_match_info); | 2907 smi_zero, internal_match_info); |
| 2853 | 2908 |
| 2854 Label if_matched(this), if_didnotmatch(this); | 2909 Label if_matched(this), if_didnotmatch(this); |
| 2855 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2910 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
| 2856 | 2911 |
| 2857 BIND(&if_didnotmatch); | 2912 BIND(&if_didnotmatch); |
| 2858 Return(null); | 2913 Return(null); |
| 2859 | 2914 |
| 2860 BIND(&if_matched); | 2915 BIND(&if_matched); |
| 2861 { | 2916 { |
| 2862 Node* result = | 2917 Node* result = |
| 2863 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2918 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
| 2864 Return(result); | 2919 Return(result); |
| 2865 } | 2920 } |
| 2866 } | 2921 } |
| 2867 | 2922 |
| 2868 } // namespace internal | 2923 } // namespace internal |
| 2869 } // namespace v8 | 2924 } // namespace v8 |
| OLD | NEW |