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" |
11 #include "src/string-builder.h" | 11 #include "src/string-builder.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 | 15 |
16 typedef compiler::Node Node; | 16 typedef compiler::Node Node; |
17 typedef CodeStubAssembler::Label CLabel; | 17 typedef CodeStubAssembler::Label CLabel; |
18 typedef CodeStubAssembler::Variable CVariable; | 18 typedef CodeStubAssembler::Variable CVariable; |
19 typedef CodeStubAssembler::ParameterMode ParameterMode; | 19 typedef CodeStubAssembler::ParameterMode ParameterMode; |
20 typedef compiler::CodeAssemblerState CodeAssemblerState; | 20 typedef compiler::CodeAssemblerState CodeAssemblerState; |
21 | 21 |
22 // ----------------------------------------------------------------------------- | 22 // ----------------------------------------------------------------------------- |
23 // ES6 section 21.2 RegExp Objects | 23 // ES6 section 21.2 RegExp Objects |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { | |
28 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; | |
29 char flags_string[kMaxFlagsLength]; | |
30 int i = 0; | |
31 | |
32 const JSRegExp::Flags flags = regexp->GetFlags(); | |
33 | |
34 if ((flags & JSRegExp::kGlobal) != 0) flags_string[i++] = 'g'; | |
35 if ((flags & JSRegExp::kIgnoreCase) != 0) flags_string[i++] = 'i'; | |
36 if ((flags & JSRegExp::kMultiline) != 0) flags_string[i++] = 'm'; | |
37 if ((flags & JSRegExp::kUnicode) != 0) flags_string[i++] = 'u'; | |
38 if ((flags & JSRegExp::kSticky) != 0) flags_string[i++] = 'y'; | |
39 | |
40 DCHECK_LT(i, kMaxFlagsLength); | |
41 memset(&flags_string[i], '\0', kMaxFlagsLength - i); | |
42 | |
43 return isolate->factory()->NewStringFromAsciiChecked(flags_string); | |
44 } | |
45 | |
46 // ES#sec-regexpinitialize | |
47 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) | |
48 MUST_USE_RESULT MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate, | |
49 Handle<JSRegExp> regexp, | |
50 Handle<Object> pattern, | |
51 Handle<Object> flags) { | |
52 Handle<String> pattern_string; | |
53 if (pattern->IsUndefined(isolate)) { | |
54 pattern_string = isolate->factory()->empty_string(); | |
55 } else { | |
56 ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string, | |
57 Object::ToString(isolate, pattern), JSRegExp); | |
58 } | |
59 | |
60 Handle<String> flags_string; | |
61 if (flags->IsUndefined(isolate)) { | |
62 flags_string = isolate->factory()->empty_string(); | |
63 } else { | |
64 ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string, | |
65 Object::ToString(isolate, flags), JSRegExp); | |
66 } | |
67 | |
68 // TODO(jgruber): We could avoid the flags back and forth conversions. | |
69 return JSRegExp::Initialize(regexp, pattern_string, flags_string); | |
70 } | |
71 | |
72 } // namespace | |
73 | |
74 // ES#sec-regexp-pattern-flags | |
75 // RegExp ( pattern, flags ) | |
76 BUILTIN(RegExpConstructor) { | |
77 HandleScope scope(isolate); | |
78 | |
79 Handle<HeapObject> new_target = args.new_target(); | |
80 Handle<Object> pattern = args.atOrUndefined(isolate, 1); | |
81 Handle<Object> flags = args.atOrUndefined(isolate, 2); | |
82 | |
83 Handle<JSFunction> target = isolate->regexp_function(); | |
84 | |
85 bool pattern_is_regexp; | |
86 { | |
87 Maybe<bool> maybe_pattern_is_regexp = | |
88 RegExpUtils::IsRegExp(isolate, pattern); | |
89 if (maybe_pattern_is_regexp.IsNothing()) { | |
90 DCHECK(isolate->has_pending_exception()); | |
91 return isolate->heap()->exception(); | |
92 } | |
93 pattern_is_regexp = maybe_pattern_is_regexp.FromJust(); | |
94 } | |
95 | |
96 if (new_target->IsUndefined(isolate)) { | |
97 new_target = target; | |
98 | |
99 // ES6 section 21.2.3.1 step 3.b | |
100 if (pattern_is_regexp && flags->IsUndefined(isolate)) { | |
101 Handle<Object> pattern_constructor; | |
102 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
103 isolate, pattern_constructor, | |
104 Object::GetProperty(pattern, | |
105 isolate->factory()->constructor_string())); | |
106 | |
107 if (pattern_constructor.is_identical_to(new_target)) { | |
108 return *pattern; | |
109 } | |
110 } | |
111 } | |
112 | |
113 if (pattern->IsJSRegExp()) { | |
114 Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern); | |
115 | |
116 if (flags->IsUndefined(isolate)) { | |
117 flags = PatternFlags(isolate, regexp_pattern); | |
118 } | |
119 pattern = handle(regexp_pattern->source(), isolate); | |
120 } else if (pattern_is_regexp) { | |
121 Handle<Object> pattern_source; | |
122 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
123 isolate, pattern_source, | |
124 Object::GetProperty(pattern, isolate->factory()->source_string())); | |
125 | |
126 if (flags->IsUndefined(isolate)) { | |
127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
128 isolate, flags, | |
129 Object::GetProperty(pattern, isolate->factory()->flags_string())); | |
130 } | |
131 pattern = pattern_source; | |
132 } | |
133 | |
134 Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target); | |
135 | |
136 // TODO(jgruber): Fast-path for target == new_target == unmodified JSRegExp. | |
137 | |
138 Handle<JSObject> object; | |
139 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
140 isolate, object, JSObject::New(target, new_target_receiver)); | |
141 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); | |
142 | |
143 RETURN_RESULT_OR_FAILURE(isolate, | |
144 RegExpInitialize(isolate, regexp, pattern, flags)); | |
145 } | |
146 | |
147 BUILTIN(RegExpPrototypeCompile) { | |
148 HandleScope scope(isolate); | |
149 CHECK_RECEIVER(JSRegExp, regexp, "RegExp.prototype.compile"); | |
150 | |
151 Handle<Object> pattern = args.atOrUndefined(isolate, 1); | |
152 Handle<Object> flags = args.atOrUndefined(isolate, 2); | |
153 | |
154 if (pattern->IsJSRegExp()) { | |
155 Handle<JSRegExp> pattern_regexp = Handle<JSRegExp>::cast(pattern); | |
156 | |
157 if (!flags->IsUndefined(isolate)) { | |
158 THROW_NEW_ERROR_RETURN_FAILURE( | |
159 isolate, NewTypeError(MessageTemplate::kRegExpFlags)); | |
160 } | |
161 | |
162 flags = PatternFlags(isolate, pattern_regexp); | |
163 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
164 isolate, pattern, | |
165 Object::GetProperty(pattern, isolate->factory()->source_string())); | |
166 } | |
167 | |
168 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | |
170 | |
171 // Return undefined for compatibility with JSC. | |
172 // See http://crbug.com/585775 for web compat details. | |
173 | |
174 return isolate->heap()->undefined_value(); | |
175 } | |
176 | |
177 namespace { | |
178 | |
179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) { | 27 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) { |
180 // Load the in-object field. | 28 // Load the in-object field. |
181 static const int field_offset = | 29 static const int field_offset = |
182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 30 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
183 return a->LoadObjectField(regexp, field_offset); | 31 return a->LoadObjectField(regexp, field_offset); |
184 } | 32 } |
185 | 33 |
186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { | 34 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
187 // Load through the GetProperty stub. | 35 // Load through the GetProperty stub. |
188 Node* const name = | 36 Node* const name = |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
572 } | 420 } |
573 | 421 |
574 a.Bind(&if_isslowpath); | 422 a.Bind(&if_isslowpath); |
575 { | 423 { |
576 Node* const result = | 424 Node* const result = |
577 RegExpPrototypeExecBody(&a, context, receiver, string, false); | 425 RegExpPrototypeExecBody(&a, context, receiver, string, false); |
578 a.Return(result); | 426 a.Return(result); |
579 } | 427 } |
580 } | 428 } |
581 | 429 |
582 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | 430 namespace { |
583 CodeStubAssembler a(state); | |
584 | 431 |
585 Node* const receiver = a.Parameter(0); | 432 Node* FlagsGetter(CodeStubAssembler* a, Node* const receiver, |
586 Node* const context = a.Parameter(3); | 433 Node* const context, bool is_fastpath) { |
434 Isolate* isolate = a->isolate(); | |
587 | 435 |
588 Isolate* isolate = a.isolate(); | 436 Node* const int_zero = a->IntPtrConstant(0); |
589 Node* const int_zero = a.IntPtrConstant(0); | 437 Node* const int_one = a->IntPtrConstant(1); |
590 Node* const int_one = a.IntPtrConstant(1); | 438 CVariable var_length(a, MachineType::PointerRepresentation()); |
591 | 439 CVariable var_flags(a, MachineType::PointerRepresentation()); |
592 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver, | |
593 MessageTemplate::kRegExpNonObject, | |
594 "RegExp.prototype.flags"); | |
595 | |
596 CVariable var_length(&a, MachineType::PointerRepresentation()); | |
597 CVariable var_flags(&a, MachineType::PointerRepresentation()); | |
598 | 440 |
599 // First, count the number of characters we will need and check which flags | 441 // First, count the number of characters we will need and check which flags |
600 // are set. | 442 // are set. |
601 | 443 |
602 var_length.Bind(int_zero); | 444 var_length.Bind(int_zero); |
603 | 445 |
604 CLabel if_isunmodifiedjsregexp(&a), | 446 CLabel construct_string(a); |
605 if_isnotunmodifiedjsregexp(&a, CLabel::kDeferred); | 447 if (is_fastpath) { |
606 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, | |
607 &if_isnotunmodifiedjsregexp); | |
608 | |
609 CLabel construct_string(&a); | |
610 a.Bind(&if_isunmodifiedjsregexp); | |
611 { | |
612 // Refer to JSRegExp's flag property on the fast-path. | 448 // Refer to JSRegExp's flag property on the fast-path. |
613 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); | 449 Node* const flags_smi = |
614 Node* const flags_intptr = a.SmiUntag(flags_smi); | 450 a->LoadObjectField(receiver, JSRegExp::kFlagsOffset); |
451 Node* const flags_intptr = a->SmiUntag(flags_smi); | |
615 var_flags.Bind(flags_intptr); | 452 var_flags.Bind(flags_intptr); |
616 | 453 |
617 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), | 454 CLabel label_global(a), label_ignorecase(a), label_multiline(a), |
618 label_unicode(&a), label_sticky(&a); | 455 label_unicode(a), label_sticky(a); |
619 | 456 |
620 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ | 457 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ |
Igor Sheludko
2016/12/05 09:35:51
While you are here, I think you can simplify the m
jgruber
2016/12/05 12:28:48
Done.
| |
621 do { \ | 458 do { \ |
622 a.Bind(&LABEL); \ | 459 a->Bind(&LABEL); \ |
623 Node* const mask = a.IntPtrConstant(FLAG); \ | 460 Node* const mask = a->IntPtrConstant(FLAG); \ |
624 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 461 a->GotoIf(a->WordEqual(a->WordAnd(flags_intptr, mask), int_zero), \ |
Igor Sheludko
2016/12/05 09:35:51
You need something like IsWordSet(flags_intptr, FL
jgruber
2016/12/05 12:28:48
Done.
| |
625 &NEXT_LABEL); \ | 462 &NEXT_LABEL); \ |
626 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 463 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \ |
627 a.Goto(&NEXT_LABEL); \ | 464 a->Goto(&NEXT_LABEL); \ |
628 } while (false) | 465 } while (false) |
629 | 466 |
630 a.Goto(&label_global); | 467 a->Goto(&label_global); |
631 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); | 468 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); |
632 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); | 469 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); |
633 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); | 470 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); |
634 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); | 471 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); |
635 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); | 472 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); |
636 #undef CASE_FOR_FLAG | 473 #undef CASE_FOR_FLAG |
637 } | 474 } else { |
475 DCHECK(!is_fastpath); | |
638 | 476 |
639 a.Bind(&if_isnotunmodifiedjsregexp); | |
640 { | |
641 // Fall back to GetProperty stub on the slow-path. | 477 // Fall back to GetProperty stub on the slow-path. |
642 var_flags.Bind(int_zero); | 478 var_flags.Bind(int_zero); |
643 | 479 |
644 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); | 480 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
645 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), | 481 CLabel label_global(a), label_ignorecase(a), label_multiline(a), |
646 label_unicode(&a), label_sticky(&a); | 482 label_unicode(a), label_sticky(a); |
647 | 483 |
648 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ | 484 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ |
Igor Sheludko
2016/12/05 09:35:51
Same here.
jgruber
2016/12/05 12:28:48
Done.
| |
649 do { \ | 485 do { \ |
650 a.Bind(&LABEL); \ | 486 a->Bind(&LABEL); \ |
651 Node* const name = \ | 487 Node* const name = \ |
652 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ | 488 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ |
Igor Sheludko
2016/12/05 09:35:51
You can speed up the slow lookups a bit if you cre
jgruber
2016/12/05 12:28:48
Done.
| |
653 Node* const flag = \ | 489 Node* const flag = \ |
654 a.CallStub(getproperty_callable, context, receiver, name); \ | 490 a->CallStub(getproperty_callable, context, receiver, name); \ |
655 CLabel if_isflagset(&a); \ | 491 CLabel if_isflagset(a); \ |
656 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ | 492 a->BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ |
657 a.Bind(&if_isflagset); \ | 493 a->Bind(&if_isflagset); \ |
658 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 494 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \ |
659 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ | 495 var_flags.Bind(a->WordOr(var_flags.value(), a->IntPtrConstant(FLAG))); \ |
660 a.Goto(&NEXT_LABEL); \ | 496 a->Goto(&NEXT_LABEL); \ |
661 } while (false) | 497 } while (false) |
662 | 498 |
663 a.Goto(&label_global); | 499 a->Goto(&label_global); |
664 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); | 500 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); |
665 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, | 501 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, |
666 label_multiline); | 502 label_multiline); |
667 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, | 503 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, |
668 label_unicode); | 504 label_unicode); |
669 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); | 505 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); |
670 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); | 506 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); |
671 #undef CASE_FOR_FLAG | 507 #undef CASE_FOR_FLAG |
672 } | 508 } |
673 | 509 |
674 // Allocate a string of the required length and fill it with the corresponding | 510 // Allocate a string of the required length and fill it with the corresponding |
675 // char for each set flag. | 511 // char for each set flag. |
676 | 512 |
677 a.Bind(&construct_string); | 513 a->Bind(&construct_string); |
678 { | 514 { |
679 Node* const result = | 515 Node* const result = |
680 a.AllocateSeqOneByteString(context, var_length.value()); | 516 a->AllocateSeqOneByteString(context, var_length.value()); |
681 Node* const flags_intptr = var_flags.value(); | 517 Node* const flags_intptr = var_flags.value(); |
682 | 518 |
683 CVariable var_offset(&a, MachineType::PointerRepresentation()); | 519 CVariable var_offset(a, MachineType::PointerRepresentation()); |
684 var_offset.Bind( | 520 var_offset.Bind( |
685 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 521 a->IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
686 | 522 |
687 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), | 523 CLabel label_global(a), label_ignorecase(a), label_multiline(a), |
688 label_unicode(&a), label_sticky(&a), out(&a); | 524 label_unicode(a), label_sticky(a), out(a); |
689 | 525 |
690 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ | 526 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ |
Igor Sheludko
2016/12/05 09:35:51
Same here.
jgruber
2016/12/05 12:28:48
Done.
| |
691 do { \ | 527 do { \ |
692 a.Bind(&LABEL); \ | 528 a->Bind(&LABEL); \ |
693 Node* const mask = a.IntPtrConstant(FLAG); \ | 529 Node* const mask = a->IntPtrConstant(FLAG); \ |
694 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 530 a->GotoIf(a->WordEqual(a->WordAnd(flags_intptr, mask), int_zero), \ |
Igor Sheludko
2016/12/05 09:35:51
IsSetWord()
jgruber
2016/12/05 12:28:48
Done.
| |
695 &NEXT_LABEL); \ | 531 &NEXT_LABEL); \ |
696 Node* const value = a.IntPtrConstant(CHAR); \ | 532 Node* const value = a->IntPtrConstant(CHAR); \ |
697 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 533 a->StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
698 var_offset.value(), value); \ | 534 var_offset.value(), value); \ |
699 var_offset.Bind(a.IntPtrAdd(var_offset.value(), int_one)); \ | 535 var_offset.Bind(a->IntPtrAdd(var_offset.value(), int_one)); \ |
700 a.Goto(&NEXT_LABEL); \ | 536 a->Goto(&NEXT_LABEL); \ |
701 } while (false) | 537 } while (false) |
702 | 538 |
703 a.Goto(&label_global); | 539 a->Goto(&label_global); |
704 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase); | 540 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase); |
705 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase, | 541 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase, |
706 label_multiline); | 542 label_multiline); |
707 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode); | 543 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode); |
708 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky); | 544 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky); |
709 CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out); | 545 CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out); |
710 #undef CASE_FOR_FLAG | 546 #undef CASE_FOR_FLAG |
711 | 547 |
712 a.Bind(&out); | 548 a->Bind(&out); |
713 a.Return(result); | 549 return result; |
714 } | 550 } |
551 } | |
552 | |
553 // ES#sec-isregexp IsRegExp ( argument ) | |
554 Node* IsRegExp(CodeStubAssembler* a, Node* const context, | |
555 Node* const maybe_receiver) { | |
556 CLabel out(a), if_isregexp(a); | |
557 | |
558 CVariable var_result(a, MachineType::PointerRepresentation()); | |
559 var_result.Bind(a->IntPtrConstant(0)); | |
560 | |
561 a->GotoIf(a->TaggedIsSmi(maybe_receiver), &out); | |
562 a->GotoUnless(a->IsJSReceiver(maybe_receiver), &out); | |
563 | |
564 Node* const receiver = maybe_receiver; | |
565 | |
566 // Check @@match. | |
567 { | |
568 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | |
569 Node* const name = a->HeapConstant(a->isolate()->factory()->match_symbol()); | |
570 Node* const value = | |
571 a->CallStub(getproperty_callable, context, receiver, name); | |
572 | |
573 CLabel match_isundefined(a), match_isnotundefined(a); | |
574 a->Branch(a->IsUndefined(value), &match_isundefined, &match_isnotundefined); | |
575 | |
576 a->Bind(&match_isundefined); | |
577 a->Branch(a->HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out); | |
578 | |
579 a->Bind(&match_isnotundefined); | |
580 a->BranchIfToBooleanIsTrue(value, &if_isregexp, &out); | |
581 } | |
582 | |
583 a->Bind(&if_isregexp); | |
584 var_result.Bind(a->IntPtrConstant(1)); | |
585 a->Goto(&out); | |
586 | |
587 a->Bind(&out); | |
588 return var_result.value(); | |
589 } | |
590 | |
591 // ES#sec-regexpinitialize | |
592 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) | |
593 Node* RegExpInitialize(CodeStubAssembler* a, Node* const context, | |
594 Node* const regexp, Node* const maybe_pattern, | |
595 Node* const maybe_flags) { | |
596 CVariable var_flags(a, MachineRepresentation::kTagged); | |
597 CVariable var_pattern(a, MachineRepresentation::kTagged); | |
598 | |
599 // Normalize pattern. | |
600 { | |
601 CLabel next(a), if_isundefined(a), if_notundefined(a); | |
602 a->Branch(a->IsUndefined(maybe_pattern), &if_isundefined, &if_notundefined); | |
Igor Sheludko
2016/12/05 09:35:51
Add a comment
// TODO(ishell): Use Select() once
Igor Sheludko
2016/12/05 11:35:14
The new Select() is landed and you can use it!
jgruber
2016/12/05 12:28:48
Nice, I liike!
| |
603 | |
604 a->Bind(&if_isundefined); | |
605 { | |
606 var_pattern.Bind(a->EmptyStringConstant()); | |
607 a->Goto(&next); | |
608 } | |
609 | |
610 a->Bind(&if_notundefined); | |
611 { | |
612 Node* const pattern = a->ToString(context, maybe_pattern); | |
613 var_pattern.Bind(pattern); | |
614 a->Goto(&next); | |
615 } | |
616 | |
617 a->Bind(&next); | |
618 } | |
619 | |
620 // Normalize flags. | |
621 { | |
622 CLabel next(a), if_isundefined(a), if_notundefined(a); | |
623 a->Branch(a->IsUndefined(maybe_flags), &if_isundefined, &if_notundefined); | |
Igor Sheludko
2016/12/05 09:35:51
Same here.
jgruber
2016/12/05 12:28:48
Done.
| |
624 | |
625 a->Bind(&if_isundefined); | |
626 { | |
627 var_flags.Bind(a->EmptyStringConstant()); | |
628 a->Goto(&next); | |
629 } | |
630 | |
631 a->Bind(&if_notundefined); | |
632 { | |
633 Node* const flags = a->ToString(context, maybe_flags); | |
634 var_flags.Bind(flags); | |
635 a->Goto(&next); | |
636 } | |
637 | |
638 a->Bind(&next); | |
639 } | |
640 | |
641 // Initialize. | |
642 | |
643 { | |
644 Node* const result = | |
645 a->CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp, | |
646 var_pattern.value(), var_flags.value()); | |
647 return result; | |
648 } | |
649 } | |
650 | |
651 } // namespace | |
652 | |
653 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { | |
654 CodeStubAssembler a(state); | |
655 | |
656 Isolate* isolate = a.isolate(); | |
657 | |
658 Node* const maybe_receiver = a.Parameter(0); | |
659 Node* const context = a.Parameter(3); | |
660 | |
661 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | |
662 MessageTemplate::kRegExpNonObject, | |
663 "RegExp.prototype.flags"); | |
664 Node* const receiver = maybe_receiver; | |
665 | |
666 CLabel if_isfastpath(&a), if_isslowpath(&a, CLabel::kDeferred); | |
667 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isfastpath, | |
668 &if_isslowpath); | |
669 | |
670 a.Bind(&if_isfastpath); | |
671 a.Return(FlagsGetter(&a, receiver, context, true)); | |
672 | |
673 a.Bind(&if_isslowpath); | |
674 a.Return(FlagsGetter(&a, receiver, context, false)); | |
675 } | |
676 | |
677 // ES#sec-regexp-pattern-flags | |
678 // RegExp ( pattern, flags ) | |
679 void Builtins::Generate_RegExpConstructor(CodeAssemblerState* state) { | |
680 CodeStubAssembler a(state); | |
681 | |
682 Node* const pattern = a.Parameter(1); | |
683 Node* const flags = a.Parameter(2); | |
684 Node* const new_target = a.Parameter(3); | |
685 Node* const context = a.Parameter(5); | |
686 | |
687 Isolate* isolate = a.isolate(); | |
688 | |
689 CVariable var_flags(&a, MachineRepresentation::kTagged); | |
690 CVariable var_pattern(&a, MachineRepresentation::kTagged); | |
691 CVariable var_new_target(&a, MachineRepresentation::kTagged); | |
692 | |
693 var_flags.Bind(flags); | |
694 var_pattern.Bind(pattern); | |
695 var_new_target.Bind(new_target); | |
696 | |
697 Node* const native_context = a.LoadNativeContext(context); | |
698 Node* const regexp_function = | |
699 a.LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | |
700 | |
701 Node* const pattern_is_regexp = IsRegExp(&a, context, pattern); | |
702 | |
703 { | |
704 CLabel next(&a); | |
705 | |
706 a.GotoUnless(a.IsUndefined(new_target), &next); | |
707 var_new_target.Bind(regexp_function); | |
708 | |
709 a.GotoUnless(pattern_is_regexp, &next); | |
710 a.GotoUnless(a.IsUndefined(flags), &next); | |
711 | |
712 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
Igor Sheludko
2016/12/05 11:28:14
I guess you are going to optimize it further in a
jgruber
2016/12/05 12:28:48
Only if it seems necessary. The RegExp constructor
| |
713 Node* const name = a.HeapConstant(isolate->factory()->constructor_string()); | |
714 Node* const value = | |
715 a.CallStub(getproperty_callable, context, pattern, name); | |
716 | |
717 a.GotoUnless(a.WordEqual(value, regexp_function), &next); | |
718 a.Return(pattern); | |
719 | |
720 a.Bind(&next); | |
721 } | |
722 | |
723 { | |
724 CLabel next(&a), if_patternisfastregexp(&a), if_patternisslowregexp(&a); | |
725 a.GotoIf(a.TaggedIsSmi(pattern), &next); | |
726 | |
727 a.GotoIf(a.HasInstanceType(pattern, JS_REGEXP_TYPE), | |
728 &if_patternisfastregexp); | |
Igor Sheludko
2016/12/05 11:28:14
The instance type check only tells you that the pa
jgruber
2016/12/05 12:28:48
Yup, I'm aware of that, and this implements semant
Igor Sheludko
2016/12/05 12:43:40
Ah. Sorry. I missed the fact that they are already
| |
729 | |
730 a.Branch(pattern_is_regexp, &if_patternisslowregexp, &next); | |
731 | |
732 a.Bind(&if_patternisfastregexp); | |
733 { | |
734 Node* const source = a.LoadObjectField(pattern, JSRegExp::kSourceOffset); | |
Igor Sheludko
2016/12/05 11:28:14
Here.
jgruber
2016/12/05 12:28:48
See above.
| |
735 var_pattern.Bind(source); | |
736 | |
737 { | |
738 CLabel inner_next(&a); | |
739 a.GotoUnless(a.IsUndefined(flags), &inner_next); | |
740 | |
741 Node* const value = FlagsGetter(&a, pattern, context, true); | |
Igor Sheludko
2016/12/05 11:28:14
And here.
jgruber
2016/12/05 12:28:47
See above.
| |
742 var_flags.Bind(value); | |
743 a.Goto(&inner_next); | |
744 | |
745 a.Bind(&inner_next); | |
746 } | |
747 | |
748 a.Goto(&next); | |
749 } | |
750 | |
751 a.Bind(&if_patternisslowregexp); | |
752 { | |
753 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
754 | |
755 { | |
756 Node* const name = a.HeapConstant(isolate->factory()->source_string()); | |
757 Node* const value = | |
758 a.CallStub(getproperty_callable, context, pattern, name); | |
759 var_pattern.Bind(value); | |
760 } | |
761 | |
762 { | |
763 CLabel inner_next(&a); | |
764 a.GotoUnless(a.IsUndefined(flags), &inner_next); | |
765 | |
766 Node* const name = a.HeapConstant(isolate->factory()->flags_string()); | |
767 Node* const value = | |
768 a.CallStub(getproperty_callable, context, pattern, name); | |
769 var_flags.Bind(value); | |
770 a.Goto(&inner_next); | |
771 | |
772 a.Bind(&inner_next); | |
773 } | |
774 | |
775 a.Goto(&next); | |
776 } | |
777 | |
778 a.Bind(&next); | |
779 } | |
780 | |
781 // Allocate. | |
782 | |
783 CVariable var_regexp(&a, MachineRepresentation::kTagged); | |
784 { | |
785 CLabel allocate_jsregexp(&a), allocate_generic(&a, CLabel::kDeferred), | |
786 next(&a); | |
787 a.Branch(a.WordEqual(var_new_target.value(), regexp_function), | |
788 &allocate_jsregexp, &allocate_generic); | |
789 | |
790 a.Bind(&allocate_jsregexp); | |
791 { | |
792 Node* const initial_map = a.LoadObjectField( | |
793 regexp_function, JSFunction::kPrototypeOrInitialMapOffset); | |
794 Node* const regexp = a.AllocateJSObjectFromMap(initial_map); | |
795 var_regexp.Bind(regexp); | |
796 a.Goto(&next); | |
797 } | |
798 | |
799 a.Bind(&allocate_generic); | |
800 { | |
801 Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate); | |
802 Node* const regexp = a.CallStub(fastnewobject_callable, context, | |
803 regexp_function, var_new_target.value()); | |
804 var_regexp.Bind(regexp); | |
805 a.Goto(&next); | |
806 } | |
807 | |
808 a.Bind(&next); | |
809 } | |
810 | |
811 Node* const result = RegExpInitialize(&a, context, var_regexp.value(), | |
812 var_pattern.value(), var_flags.value()); | |
813 a.Return(result); | |
814 } | |
815 | |
816 // ES#sec-regexp.prototype.compile | |
817 // RegExp.prototype.compile ( pattern, flags ) | |
818 void Builtins::Generate_RegExpPrototypeCompile(CodeAssemblerState* state) { | |
819 CodeStubAssembler a(state); | |
820 | |
821 Node* const maybe_receiver = a.Parameter(0); | |
822 Node* const maybe_pattern = a.Parameter(1); | |
823 Node* const maybe_flags = a.Parameter(2); | |
824 Node* const context = a.Parameter(5); | |
825 | |
826 a.ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE, | |
827 "RegExp.prototype.compile"); | |
828 Node* const receiver = maybe_receiver; | |
829 | |
830 CVariable var_flags(&a, MachineRepresentation::kTagged); | |
831 CVariable var_pattern(&a, MachineRepresentation::kTagged); | |
832 | |
833 var_flags.Bind(maybe_flags); | |
834 var_pattern.Bind(maybe_pattern); | |
835 | |
836 // Handle a JSRegExp pattern. | |
837 { | |
838 CLabel next(&a); | |
839 | |
840 a.GotoIf(a.TaggedIsSmi(maybe_pattern), &next); | |
841 a.GotoUnless(a.HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next); | |
842 | |
843 Node* const pattern = maybe_pattern; | |
844 | |
845 // {maybe_flags} must be undefined in this case, otherwise throw. | |
846 { | |
847 CLabel next(&a); | |
848 a.GotoIf(a.IsUndefined(maybe_flags), &next); | |
849 | |
850 Node* const message_id = a.SmiConstant(MessageTemplate::kRegExpFlags); | |
851 a.TailCallRuntime(Runtime::kThrowTypeError, context, message_id); | |
852 | |
853 a.Bind(&next); | |
854 } | |
855 | |
856 Node* const new_flags = FlagsGetter(&a, pattern, context, true); | |
Igor Sheludko
2016/12/05 11:28:14
Same here.
jgruber
2016/12/05 12:28:48
See above.
| |
857 Node* const new_pattern = | |
858 a.LoadObjectField(pattern, JSRegExp::kSourceOffset); | |
859 | |
860 var_flags.Bind(new_flags); | |
861 var_pattern.Bind(new_pattern); | |
862 | |
863 a.Goto(&next); | |
864 a.Bind(&next); | |
865 } | |
866 | |
867 RegExpInitialize(&a, context, receiver, var_pattern.value(), | |
868 var_flags.value()); | |
869 | |
870 // Return undefined for compatibility with JSC. | |
871 // See http://crbug.com/585775 for web compat details. | |
872 | |
873 a.Return(a.UndefinedConstant()); | |
715 } | 874 } |
716 | 875 |
717 // ES6 21.2.5.10. | 876 // ES6 21.2.5.10. |
718 void Builtins::Generate_RegExpPrototypeSourceGetter(CodeAssemblerState* state) { | 877 void Builtins::Generate_RegExpPrototypeSourceGetter(CodeAssemblerState* state) { |
719 CodeStubAssembler a(state); | 878 CodeStubAssembler a(state); |
720 Node* const receiver = a.Parameter(0); | 879 Node* const receiver = a.Parameter(0); |
721 Node* const context = a.Parameter(3); | 880 Node* const context = a.Parameter(3); |
722 | 881 |
723 // Check whether we have an unmodified regexp instance. | 882 // Check whether we have an unmodified regexp instance. |
724 CLabel if_isjsregexp(&a), if_isnotjsregexp(&a, CLabel::kDeferred); | 883 CLabel if_isjsregexp(&a), if_isnotjsregexp(&a, CLabel::kDeferred); |
(...skipping 1715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2440 a.Bind(&if_matched); | 2599 a.Bind(&if_matched); |
2441 { | 2600 { |
2442 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2601 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2443 match_indices, string); | 2602 match_indices, string); |
2444 a.Return(result); | 2603 a.Return(result); |
2445 } | 2604 } |
2446 } | 2605 } |
2447 | 2606 |
2448 } // namespace internal | 2607 } // namespace internal |
2449 } // namespace v8 | 2608 } // namespace v8 |
OLD | NEW |