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

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

Issue 2551443002: [regexp] Migrate constructor and compile to CSA (Closed)
Patch Set: Remove unused variables Created 4 years 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.h ('k') | src/regexp/regexp-utils.cc » ('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-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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/regexp/regexp-utils.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698