Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: src/builtins/builtins-regexp.cc

Issue 2738413002: [regexp] Port RegExpExecStub to CSA (mostly) (Closed)
Patch Set: Rebase Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins-regexp.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins-regexp.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698