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-regexp.h" | 5 #include "src/builtins/builtins-regexp.h" |
6 | 6 |
7 #include "src/builtins/builtins-constructor.h" | 7 #include "src/builtins/builtins-constructor.h" |
8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.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 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 var_i.Bind(i_plus_2); | 208 var_i.Bind(i_plus_2); |
209 Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), &out, | 209 Branch(IntPtrGreaterThanOrEqual(var_i.value(), names_length), &out, |
210 &loop); | 210 &loop); |
211 } | 211 } |
212 } | 212 } |
213 | 213 |
214 Bind(&out); | 214 Bind(&out); |
215 return result; | 215 return result; |
216 } | 216 } |
217 | 217 |
| 218 void RegExpBuiltinsAssembler::GetStringPointers( |
| 219 Node* const string, Node* const offset, Node* const last_index, |
| 220 Node* const string_length, bool is_one_byte, Variable* var_string_start, |
| 221 Variable* var_string_end) { |
| 222 DCHECK_EQ(var_string_start->rep(), MachineType::PointerRepresentation()); |
| 223 DCHECK_EQ(var_string_end->rep(), MachineType::PointerRepresentation()); |
| 224 |
| 225 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
| 226 const int kHeaderSize = SeqOneByteString::kHeaderSize - kHeapObjectTag; |
| 227 const ElementsKind kind = is_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS; |
| 228 |
| 229 Node* const from_offset = ElementOffsetFromIndex( |
| 230 IntPtrAdd(offset, last_index), kind, INTPTR_PARAMETERS, kHeaderSize); |
| 231 var_string_start->Bind(IntPtrAdd(string, from_offset)); |
| 232 |
| 233 Node* const to_offset = ElementOffsetFromIndex( |
| 234 IntPtrAdd(offset, string_length), kind, INTPTR_PARAMETERS, kHeaderSize); |
| 235 var_string_end->Bind(IntPtrAdd(string, to_offset)); |
| 236 } |
| 237 |
| 238 Node* RegExpBuiltinsAssembler::IrregexpExec(Node* const context, |
| 239 Node* const regexp, |
| 240 Node* const string, |
| 241 Node* const last_index, |
| 242 Node* const match_info) { |
| 243 // Just jump directly to runtime if native RegExp is not selected at compile |
| 244 // time or if regexp entry in generated code is turned off runtime switch or |
| 245 // at compilation. |
| 246 #ifdef V8_INTERPRETED_REGEXP |
| 247 return CallRuntime(Runtime::kRegExpExec, context, regexp, string, last_index, |
| 248 match_info); |
| 249 #else // V8_INTERPRETED_REGEXP |
| 250 CSA_ASSERT(this, TaggedIsNotSmi(regexp)); |
| 251 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); |
| 252 |
| 253 CSA_ASSERT(this, TaggedIsNotSmi(string)); |
| 254 CSA_ASSERT(this, IsString(string)); |
| 255 |
| 256 CSA_ASSERT(this, IsHeapNumberMap(LoadReceiverMap(last_index))); |
| 257 CSA_ASSERT(this, IsFixedArrayMap(LoadReceiverMap(match_info))); |
| 258 |
| 259 Node* const int_zero = IntPtrConstant(0); |
| 260 |
| 261 Variable var_result(this, MachineRepresentation::kTagged); |
| 262 Variable var_string(this, MachineType::PointerRepresentation(), int_zero); |
| 263 Variable var_string_offset(this, MachineType::PointerRepresentation(), |
| 264 int_zero); |
| 265 Variable var_string_instance_type(this, MachineRepresentation::kWord32, |
| 266 Int32Constant(0)); |
| 267 |
| 268 Label out(this), runtime(this, Label::kDeferred); |
| 269 |
| 270 // External constants. |
| 271 Node* const regexp_stack_memory_size_address = ExternalConstant( |
| 272 ExternalReference::address_of_regexp_stack_memory_size(isolate())); |
| 273 Node* const static_offsets_vector_address = ExternalConstant( |
| 274 ExternalReference::address_of_static_offsets_vector(isolate())); |
| 275 Node* const pending_exception_address = ExternalConstant( |
| 276 ExternalReference(Isolate::kPendingExceptionAddress, isolate())); |
| 277 |
| 278 // Ensure that a RegExp stack is allocated. |
| 279 { |
| 280 Node* const stack_size = |
| 281 Load(MachineType::IntPtr(), regexp_stack_memory_size_address); |
| 282 GotoIf(IntPtrEqual(stack_size, int_zero), &runtime); |
| 283 } |
| 284 |
| 285 Node* const data = LoadObjectField(regexp, JSRegExp::kDataOffset); |
| 286 { |
| 287 // Check that the RegExp has been compiled (data contains a fixed array). |
| 288 CSA_ASSERT(this, TaggedIsNotSmi(data)); |
| 289 CSA_ASSERT(this, HasInstanceType(data, FIXED_ARRAY_TYPE)); |
| 290 |
| 291 // Check the type of the RegExp. Only continue if type is |
| 292 // JSRegExp::IRREGEXP. |
| 293 Node* const tag = LoadFixedArrayElement(data, JSRegExp::kTagIndex); |
| 294 GotoIfNot(SmiEqual(tag, SmiConstant(JSRegExp::IRREGEXP)), &runtime); |
| 295 |
| 296 // Check (number_of_captures + 1) * 2 <= offsets vector size |
| 297 // Or number_of_captures <= offsets vector size / 2 - 1 |
| 298 Node* const capture_count = |
| 299 LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureCountIndex); |
| 300 CSA_ASSERT(this, TaggedIsSmi(capture_count)); |
| 301 |
| 302 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
| 303 GotoIf(SmiAbove( |
| 304 capture_count, |
| 305 SmiConstant(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)), |
| 306 &runtime); |
| 307 } |
| 308 |
| 309 // Unpack the string if possible. |
| 310 |
| 311 var_string.Bind(BitcastTaggedToWord(string)); |
| 312 var_string_offset.Bind(int_zero); |
| 313 var_string_instance_type.Bind(LoadInstanceType(string)); |
| 314 |
| 315 { |
| 316 TryUnpackString(&var_string, &var_string_offset, &var_string_instance_type, |
| 317 &runtime); |
| 318 |
| 319 // At this point, {var_string} may contain a faked sequential string (i.e. |
| 320 // an external string with an adjusted offset) so we cannot assert |
| 321 // IsString({var_string}). We also cannot allocate after this point since |
| 322 // GC could move {var_string}'s underlying string. |
| 323 } |
| 324 |
| 325 Node* const smi_string_length = LoadStringLength(string); |
| 326 |
| 327 // Bail out to runtime for invalid {last_index} values. |
| 328 GotoIfNot(TaggedIsSmi(last_index), &runtime); |
| 329 GotoIf(SmiAboveOrEqual(last_index, smi_string_length), &runtime); |
| 330 |
| 331 // Load the irregexp code object and offsets into the subject string. Both |
| 332 // depend on whether the string is one- or two-byte. |
| 333 |
| 334 Node* const int_last_index = SmiUntag(last_index); |
| 335 |
| 336 Variable var_string_start(this, MachineType::PointerRepresentation()); |
| 337 Variable var_string_end(this, MachineType::PointerRepresentation()); |
| 338 Variable var_code(this, MachineRepresentation::kTagged); |
| 339 |
| 340 { |
| 341 Node* const int_string_length = SmiUntag(smi_string_length); |
| 342 |
| 343 Node* const string_instance_type = var_string_instance_type.value(); |
| 344 CSA_ASSERT(this, IsSequentialStringInstanceType(string_instance_type)); |
| 345 |
| 346 Label next(this), if_isonebyte(this), if_istwobyte(this, Label::kDeferred); |
| 347 Branch(IsOneByteStringInstanceType(string_instance_type), &if_isonebyte, |
| 348 &if_istwobyte); |
| 349 |
| 350 Bind(&if_isonebyte); |
| 351 { |
| 352 const bool kIsOneByte = true; |
| 353 GetStringPointers(var_string.value(), var_string_offset.value(), |
| 354 int_last_index, int_string_length, kIsOneByte, |
| 355 &var_string_start, &var_string_end); |
| 356 var_code.Bind( |
| 357 LoadFixedArrayElement(data, JSRegExp::kIrregexpLatin1CodeIndex)); |
| 358 Goto(&next); |
| 359 } |
| 360 |
| 361 Bind(&if_istwobyte); |
| 362 { |
| 363 const bool kIsOneByte = false; |
| 364 GetStringPointers(var_string.value(), var_string_offset.value(), |
| 365 int_last_index, int_string_length, kIsOneByte, |
| 366 &var_string_start, &var_string_end); |
| 367 var_code.Bind( |
| 368 LoadFixedArrayElement(data, JSRegExp::kIrregexpUC16CodeIndex)); |
| 369 Goto(&next); |
| 370 } |
| 371 |
| 372 Bind(&next); |
| 373 } |
| 374 |
| 375 // Check that the irregexp code has been generated for the actual string |
| 376 // encoding. If it has, the field contains a code object otherwise it contains |
| 377 // smi (code flushing support). |
| 378 |
| 379 Node* const code = var_code.value(); |
| 380 GotoIf(TaggedIsSmi(code), &runtime); |
| 381 CSA_ASSERT(this, HasInstanceType(code, CODE_TYPE)); |
| 382 |
| 383 Label if_success(this), if_failure(this), |
| 384 if_exception(this, Label::kDeferred); |
| 385 { |
| 386 IncrementCounter(isolate()->counters()->regexp_entry_native(), 1); |
| 387 |
| 388 Callable exec_callable = CodeFactory::RegExpExec(isolate()); |
| 389 Node* const result = CallStub( |
| 390 exec_callable, context, string, TruncateWordToWord32(int_last_index), |
| 391 var_string_start.value(), var_string_end.value(), code); |
| 392 |
| 393 // Check the result. |
| 394 // We expect exactly one result since the stub forces the called regexp to |
| 395 // behave as non-global. |
| 396 GotoIf(SmiEqual(result, SmiConstant(1)), &if_success); |
| 397 GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::FAILURE)), |
| 398 &if_failure); |
| 399 GotoIf(SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::EXCEPTION)), |
| 400 &if_exception); |
| 401 |
| 402 CSA_ASSERT( |
| 403 this, SmiEqual(result, SmiConstant(NativeRegExpMacroAssembler::RETRY))); |
| 404 Goto(&runtime); |
| 405 } |
| 406 |
| 407 Bind(&if_success); |
| 408 { |
| 409 // Check that the last match info has space for the capture registers and |
| 410 // the additional information. Ensure no overflow in add. |
| 411 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 412 Node* const available_slots = |
| 413 SmiSub(LoadFixedArrayBaseLength(match_info), |
| 414 SmiConstant(RegExpMatchInfo::kLastMatchOverhead)); |
| 415 Node* const capture_count = |
| 416 LoadFixedArrayElement(data, JSRegExp::kIrregexpCaptureCountIndex); |
| 417 // Calculate number of register_count = (capture_count + 1) * 2. |
| 418 Node* const register_count = |
| 419 SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1); |
| 420 GotoIf(SmiGreaterThan(register_count, available_slots), &runtime); |
| 421 |
| 422 // Fill match_info. |
| 423 |
| 424 StoreFixedArrayElement(match_info, RegExpMatchInfo::kNumberOfCapturesIndex, |
| 425 register_count, SKIP_WRITE_BARRIER); |
| 426 StoreFixedArrayElement(match_info, RegExpMatchInfo::kLastSubjectIndex, |
| 427 string); |
| 428 StoreFixedArrayElement(match_info, RegExpMatchInfo::kLastInputIndex, |
| 429 string); |
| 430 |
| 431 // Fill match and capture offsets in match_info. |
| 432 { |
| 433 Node* const limit_offset = ElementOffsetFromIndex( |
| 434 register_count, INT32_ELEMENTS, SMI_PARAMETERS, 0); |
| 435 |
| 436 Node* const to_offset = ElementOffsetFromIndex( |
| 437 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), FAST_ELEMENTS, |
| 438 INTPTR_PARAMETERS, RegExpMatchInfo::kHeaderSize - kHeapObjectTag); |
| 439 Variable var_to_offset(this, MachineType::PointerRepresentation(), |
| 440 to_offset); |
| 441 |
| 442 VariableList vars({&var_to_offset}, zone()); |
| 443 BuildFastLoop( |
| 444 vars, int_zero, limit_offset, |
| 445 [=, &var_to_offset](Node* offset) { |
| 446 Node* const value = Load(MachineType::Int32(), |
| 447 static_offsets_vector_address, offset); |
| 448 Node* const smi_value = SmiFromWord32(value); |
| 449 StoreNoWriteBarrier(MachineRepresentation::kTagged, match_info, |
| 450 var_to_offset.value(), smi_value); |
| 451 Increment(var_to_offset, kPointerSize); |
| 452 }, |
| 453 kInt32Size, INTPTR_PARAMETERS, IndexAdvanceMode::kPost); |
| 454 } |
| 455 |
| 456 var_result.Bind(match_info); |
| 457 Goto(&out); |
| 458 } |
| 459 |
| 460 Bind(&if_failure); |
| 461 { |
| 462 var_result.Bind(NullConstant()); |
| 463 Goto(&out); |
| 464 } |
| 465 |
| 466 Bind(&if_exception); |
| 467 { |
| 468 Node* const pending_exception = |
| 469 Load(MachineType::AnyTagged(), pending_exception_address); |
| 470 |
| 471 // If there is no pending exception, a |
| 472 // stack overflow (on the backtrack stack) was detected in RegExp code. |
| 473 |
| 474 Label stack_overflow(this), rethrow(this); |
| 475 Branch(IsTheHole(pending_exception), &stack_overflow, &rethrow); |
| 476 |
| 477 Bind(&stack_overflow); |
| 478 TailCallRuntime(Runtime::kThrowStackOverflow, context); |
| 479 |
| 480 Bind(&rethrow); |
| 481 TailCallRuntime(Runtime::kRegExpExecReThrow, context); |
| 482 } |
| 483 |
| 484 Bind(&runtime); |
| 485 { |
| 486 Node* const result = CallRuntime(Runtime::kRegExpExec, context, regexp, |
| 487 string, last_index, match_info); |
| 488 var_result.Bind(result); |
| 489 Goto(&out); |
| 490 } |
| 491 |
| 492 Bind(&out); |
| 493 return var_result.value(); |
| 494 #endif // V8_INTERPRETED_REGEXP |
| 495 } |
| 496 |
218 // ES#sec-regexp.prototype.exec | 497 // ES#sec-regexp.prototype.exec |
219 // RegExp.prototype.exec ( string ) | 498 // RegExp.prototype.exec ( string ) |
220 // Implements the core of RegExp.prototype.exec but without actually | 499 // Implements the core of RegExp.prototype.exec but without actually |
221 // constructing the JSRegExpResult. Returns either null (if the RegExp did not | 500 // constructing the JSRegExpResult. Returns either null (if the RegExp did not |
222 // match) or a fixed array containing match indices as returned by | 501 // match) or a fixed array containing match indices as returned by |
223 // RegExpExecStub. | 502 // RegExpExecStub. |
224 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( | 503 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult( |
225 Node* const context, Node* const regexp, Node* const string, | 504 Node* const context, Node* const regexp, Node* const string, |
226 Label* if_didnotmatch, const bool is_fastpath) { | 505 Label* if_didnotmatch, const bool is_fastpath) { |
227 Isolate* const isolate = this->isolate(); | 506 Isolate* const isolate = this->isolate(); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 Node* match_indices; | 583 Node* match_indices; |
305 Label successful_match(this); | 584 Label successful_match(this); |
306 Bind(&run_exec); | 585 Bind(&run_exec); |
307 { | 586 { |
308 // Get last match info from the context. | 587 // Get last match info from the context. |
309 Node* const native_context = LoadNativeContext(context); | 588 Node* const native_context = LoadNativeContext(context); |
310 Node* const last_match_info = LoadContextElement( | 589 Node* const last_match_info = LoadContextElement( |
311 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 590 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
312 | 591 |
313 // Call the exec stub. | 592 // Call the exec stub. |
314 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 593 match_indices = IrregexpExec(context, regexp, string, var_lastindex.value(), |
315 match_indices = CallStub(exec_callable, context, regexp, string, | 594 last_match_info); |
316 var_lastindex.value(), last_match_info); | |
317 var_result.Bind(match_indices); | 595 var_result.Bind(match_indices); |
318 | 596 |
319 // {match_indices} is either null or the RegExpMatchInfo array. | 597 // {match_indices} is either null or the RegExpMatchInfo array. |
320 // Return early if exec failed, possibly updating last index. | 598 // Return early if exec failed, possibly updating last index. |
321 GotoIfNot(WordEqual(match_indices, null), &successful_match); | 599 GotoIfNot(WordEqual(match_indices, null), &successful_match); |
322 | 600 |
323 GotoIfNot(should_update_last_index, if_didnotmatch); | 601 GotoIfNot(should_update_last_index, if_didnotmatch); |
324 | 602 |
325 StoreLastIndex(context, regexp, smi_zero, is_fastpath); | 603 StoreLastIndex(context, regexp, smi_zero, is_fastpath); |
326 Goto(if_didnotmatch); | 604 Goto(if_didnotmatch); |
(...skipping 1476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1803 Bind(&slow_path); | 2081 Bind(&slow_path); |
1804 RegExpPrototypeSearchBodySlow(context, receiver, string); | 2082 RegExpPrototypeSearchBodySlow(context, receiver, string); |
1805 } | 2083 } |
1806 | 2084 |
1807 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, | 2085 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, |
1808 // {string} is a String, and {limit} is a Smi. | 2086 // {string} is a String, and {limit} is a Smi. |
1809 void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, | 2087 void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context, |
1810 Node* const regexp, | 2088 Node* const regexp, |
1811 Node* const string, | 2089 Node* const string, |
1812 Node* const limit) { | 2090 Node* const limit) { |
1813 Isolate* isolate = this->isolate(); | |
1814 | |
1815 Node* const null = NullConstant(); | 2091 Node* const null = NullConstant(); |
1816 Node* const smi_zero = SmiConstant(0); | 2092 Node* const smi_zero = SmiConstant(0); |
1817 Node* const int_zero = IntPtrConstant(0); | 2093 Node* const int_zero = IntPtrConstant(0); |
1818 Node* const int_limit = SmiUntag(limit); | 2094 Node* const int_limit = SmiUntag(limit); |
1819 | 2095 |
1820 const ElementsKind kind = FAST_ELEMENTS; | 2096 const ElementsKind kind = FAST_ELEMENTS; |
1821 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 2097 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
1822 | 2098 |
1823 Node* const allocation_site = nullptr; | 2099 Node* const allocation_site = nullptr; |
1824 Node* const native_context = LoadNativeContext(context); | 2100 Node* const native_context = LoadNativeContext(context); |
(...skipping 14 matching lines...) Expand all Loading... |
1839 // array depending on whether the {regexp} matches. | 2115 // array depending on whether the {regexp} matches. |
1840 { | 2116 { |
1841 Label next(this), if_stringisempty(this, Label::kDeferred); | 2117 Label next(this), if_stringisempty(this, Label::kDeferred); |
1842 Branch(SmiEqual(string_length, smi_zero), &if_stringisempty, &next); | 2118 Branch(SmiEqual(string_length, smi_zero), &if_stringisempty, &next); |
1843 | 2119 |
1844 Bind(&if_stringisempty); | 2120 Bind(&if_stringisempty); |
1845 { | 2121 { |
1846 Node* const last_match_info = LoadContextElement( | 2122 Node* const last_match_info = LoadContextElement( |
1847 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2123 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1848 | 2124 |
1849 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2125 Node* const match_indices = |
1850 Node* const match_indices = CallStub(exec_callable, context, regexp, | 2126 IrregexpExec(context, regexp, string, smi_zero, last_match_info); |
1851 string, smi_zero, last_match_info); | |
1852 | 2127 |
1853 Label return_singleton_array(this); | 2128 Label return_singleton_array(this); |
1854 Branch(WordEqual(match_indices, null), &return_singleton_array, | 2129 Branch(WordEqual(match_indices, null), &return_singleton_array, |
1855 &return_empty_array); | 2130 &return_empty_array); |
1856 | 2131 |
1857 Bind(&return_singleton_array); | 2132 Bind(&return_singleton_array); |
1858 { | 2133 { |
1859 Node* const length = SmiConstant(1); | 2134 Node* const length = SmiConstant(1); |
1860 Node* const capacity = IntPtrConstant(1); | 2135 Node* const capacity = IntPtrConstant(1); |
1861 Node* const result = AllocateJSArray(kind, array_map, capacity, length, | 2136 Node* const result = AllocateJSArray(kind, array_map, capacity, length, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1899 Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out, | 2174 Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out, |
1900 &next); | 2175 &next); |
1901 Bind(&next); | 2176 Bind(&next); |
1902 } | 2177 } |
1903 | 2178 |
1904 // Search for the given {regexp}. | 2179 // Search for the given {regexp}. |
1905 | 2180 |
1906 Node* const last_match_info = LoadContextElement( | 2181 Node* const last_match_info = LoadContextElement( |
1907 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 2182 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1908 | 2183 |
1909 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2184 Node* const match_indices = IrregexpExec(context, regexp, string, |
1910 Node* const match_indices = CallStub(exec_callable, context, regexp, string, | 2185 next_search_from, last_match_info); |
1911 next_search_from, last_match_info); | |
1912 | 2186 |
1913 // We're done if no match was found. | 2187 // We're done if no match was found. |
1914 { | 2188 { |
1915 Label next(this); | 2189 Label next(this); |
1916 Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next); | 2190 Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next); |
1917 Bind(&next); | 2191 Bind(&next); |
1918 } | 2192 } |
1919 | 2193 |
1920 Node* const match_from = LoadFixedArrayElement( | 2194 Node* const match_from = LoadFixedArrayElement( |
1921 match_indices, RegExpMatchInfo::kFirstCaptureIndex); | 2195 match_indices, RegExpMatchInfo::kFirstCaptureIndex); |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2548 Node* const string = Parameter(2); | 2822 Node* const string = Parameter(2); |
2549 Node* const context = Parameter(5); | 2823 Node* const context = Parameter(5); |
2550 | 2824 |
2551 Node* const null = NullConstant(); | 2825 Node* const null = NullConstant(); |
2552 Node* const smi_zero = SmiConstant(Smi::FromInt(0)); | 2826 Node* const smi_zero = SmiConstant(Smi::FromInt(0)); |
2553 | 2827 |
2554 Node* const native_context = LoadNativeContext(context); | 2828 Node* const native_context = LoadNativeContext(context); |
2555 Node* const internal_match_info = LoadContextElement( | 2829 Node* const internal_match_info = LoadContextElement( |
2556 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); | 2830 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); |
2557 | 2831 |
2558 Callable exec_callable = CodeFactory::RegExpExec(isolate()); | 2832 Node* const match_indices = |
2559 Node* const match_indices = CallStub(exec_callable, context, regexp, string, | 2833 IrregexpExec(context, regexp, string, smi_zero, internal_match_info); |
2560 smi_zero, internal_match_info); | |
2561 | 2834 |
2562 Label if_matched(this), if_didnotmatch(this); | 2835 Label if_matched(this), if_didnotmatch(this); |
2563 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2836 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
2564 | 2837 |
2565 Bind(&if_didnotmatch); | 2838 Bind(&if_didnotmatch); |
2566 Return(null); | 2839 Return(null); |
2567 | 2840 |
2568 Bind(&if_matched); | 2841 Bind(&if_matched); |
2569 { | 2842 { |
2570 Node* result = | 2843 Node* result = |
2571 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); | 2844 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); |
2572 Return(result); | 2845 Return(result); |
2573 } | 2846 } |
2574 } | 2847 } |
2575 | 2848 |
2576 } // namespace internal | 2849 } // namespace internal |
2577 } // namespace v8 | 2850 } // namespace v8 |
OLD | NEW |