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()); | |
Igor Sheludko
2017/03/15 00:39:04
I'd rather name the stub and this function the oth
jgruber
2017/03/15 13:43:44
Renamed the function RegExpExecInternal. The stub
| |
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 we force the called regexp to behave | |
Igor Sheludko
2017/03/15 00:39:03
s/we force/the stub forces/ or maybe add a comment
jgruber
2017/03/15 13:43:44
Done.
| |
395 // 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); | |
Igor Sheludko
2017/03/15 00:39:04
Maybe
// Calculate number of capture registers (nu
jgruber
2017/03/15 13:43:44
Done.
| |
417 Node* const register_count = | |
418 SmiShl(SmiAdd(capture_count, SmiConstant(1)), 1); | |
419 GotoIf(SmiGreaterThan(register_count, available_slots), &runtime); | |
420 | |
421 // Fill match_info. | |
422 | |
423 StoreFixedArrayElement(match_info, RegExpMatchInfo::kNumberOfCapturesIndex, | |
424 register_count, SKIP_WRITE_BARRIER); | |
425 StoreFixedArrayElement(match_info, RegExpMatchInfo::kLastSubjectIndex, | |
426 string); | |
427 StoreFixedArrayElement(match_info, RegExpMatchInfo::kLastInputIndex, | |
428 string); | |
429 | |
430 // Fill match and capture offsets in match_info. | |
431 { | |
432 Node* const limit_offset = ElementOffsetFromIndex( | |
433 register_count, INT32_ELEMENTS, SMI_PARAMETERS, 0); | |
434 | |
435 Node* const to_offset = ElementOffsetFromIndex( | |
436 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), FAST_ELEMENTS, | |
437 INTPTR_PARAMETERS, RegExpMatchInfo::kHeaderSize - kHeapObjectTag); | |
438 Variable var_to_offset(this, MachineType::PointerRepresentation(), | |
439 to_offset); | |
440 | |
441 VariableList vars({&var_to_offset}, zone()); | |
442 BuildFastLoop( | |
443 vars, int_zero, limit_offset, | |
444 [this, static_offsets_vector_address, match_info, | |
Igor Sheludko
2017/03/15 00:39:04
[=, &var_to_offset]
jgruber
2017/03/15 13:43:44
Done.
| |
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 | |
Igor Sheludko
2017/03/15 00:39:03
Please reformat the comment.
jgruber
2017/03/15 13:43:44
Done.
| |
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); | |
Igor Sheludko
2017/03/15 00:39:03
AFAICT the only non-gc-safe thing the Irregexp cod
jgruber
2017/03/15 13:43:44
Great find. The initial goal was to completely rem
| |
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(), |
jgruber
2017/03/13 12:27:37
This will add even more to the snapshot size. It's
Igor Sheludko
2017/03/15 00:39:03
Why not leave this code in the stub in this CL?
jgruber
2017/03/15 13:43:44
I have a follow-up CL that sets up a couple more s
| |
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 |