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

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

Issue 2551443002: [regexp] Migrate constructor and compile to CSA (Closed)
Patch Set: Address comments 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/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-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
430 namespace {
431
432 Node* FlagsGetter(CodeStubAssembler* a, Node* const receiver,
433 Node* const context, bool is_fastpath) {
434 Isolate* isolate = a->isolate();
435
436 Node* const int_zero = a->IntPtrConstant(0);
437 Node* const int_one = a->IntPtrConstant(1);
438 CVariable var_length(a, MachineType::PointerRepresentation());
439 CVariable var_flags(a, MachineType::PointerRepresentation());
440
441 // First, count the number of characters we will need and check which flags
442 // are set.
443
444 var_length.Bind(int_zero);
445
446 if (is_fastpath) {
447 // Refer to JSRegExp's flag property on the fast-path.
448 Node* const flags_smi =
449 a->LoadObjectField(receiver, JSRegExp::kFlagsOffset);
450 Node* const flags_intptr = a->SmiUntag(flags_smi);
451 var_flags.Bind(flags_intptr);
452
453 #define CASE_FOR_FLAG(FLAG) \
454 do { \
455 CLabel next(a); \
456 a->GotoUnless(a->IsSetWord(flags_intptr, FLAG), &next); \
457 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \
458 a->Goto(&next); \
459 a->Bind(&next); \
460 } while (false)
461
462 CASE_FOR_FLAG(JSRegExp::kGlobal);
463 CASE_FOR_FLAG(JSRegExp::kIgnoreCase);
464 CASE_FOR_FLAG(JSRegExp::kMultiline);
465 CASE_FOR_FLAG(JSRegExp::kUnicode);
466 CASE_FOR_FLAG(JSRegExp::kSticky);
467 #undef CASE_FOR_FLAG
468 } else {
469 DCHECK(!is_fastpath);
470
471 // Fall back to GetProperty stub on the slow-path.
472 var_flags.Bind(int_zero);
473
474 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
475
476 #define CASE_FOR_FLAG(NAME, FLAG) \
477 do { \
478 CLabel next(a); \
479 Node* const name = \
480 a->HeapConstant(isolate->factory()->InternalizeUtf8String(NAME)); \
481 Node* const flag = \
482 a->CallStub(getproperty_callable, context, receiver, name); \
483 CLabel if_isflagset(a); \
484 a->BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
485 a->Bind(&if_isflagset); \
486 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \
487 var_flags.Bind(a->WordOr(var_flags.value(), a->IntPtrConstant(FLAG))); \
488 a->Goto(&next); \
489 a->Bind(&next); \
490 } while (false)
491
492 CASE_FOR_FLAG("global", JSRegExp::kGlobal);
493 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase);
494 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline);
495 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode);
496 CASE_FOR_FLAG("sticky", JSRegExp::kSticky);
497 #undef CASE_FOR_FLAG
498 }
499
500 // Allocate a string of the required length and fill it with the corresponding
501 // char for each set flag.
502
503 {
504 Node* const result =
505 a->AllocateSeqOneByteString(context, var_length.value());
506 Node* const flags_intptr = var_flags.value();
507
508 CVariable var_offset(a, MachineType::PointerRepresentation());
509 var_offset.Bind(
510 a->IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
511
512 #define CASE_FOR_FLAG(FLAG, CHAR) \
513 do { \
514 CLabel next(a); \
515 a->GotoUnless(a->IsSetWord(flags_intptr, FLAG), &next); \
516 Node* const value = a->IntPtrConstant(CHAR); \
517 a->StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \
518 var_offset.value(), value); \
519 var_offset.Bind(a->IntPtrAdd(var_offset.value(), int_one)); \
520 a->Goto(&next); \
521 a->Bind(&next); \
522 } while (false)
523
524 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g');
525 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i');
526 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm');
527 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u');
528 CASE_FOR_FLAG(JSRegExp::kSticky, 'y');
529 #undef CASE_FOR_FLAG
530
531 return result;
532 }
533 }
534
535 // ES#sec-isregexp IsRegExp ( argument )
536 Node* IsRegExp(CodeStubAssembler* a, Node* const context,
537 Node* const maybe_receiver) {
538 CLabel out(a), if_isregexp(a);
539
540 CVariable var_result(a, MachineType::PointerRepresentation());
541 var_result.Bind(a->IntPtrConstant(0));
542
543 a->GotoIf(a->TaggedIsSmi(maybe_receiver), &out);
544 a->GotoUnless(a->IsJSReceiver(maybe_receiver), &out);
545
546 Node* const receiver = maybe_receiver;
547
548 // Check @@match.
549 {
550 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
551 Node* const name = a->HeapConstant(a->isolate()->factory()->match_symbol());
552 Node* const value =
553 a->CallStub(getproperty_callable, context, receiver, name);
554
555 CLabel match_isundefined(a), match_isnotundefined(a);
556 a->Branch(a->IsUndefined(value), &match_isundefined, &match_isnotundefined);
557
558 a->Bind(&match_isundefined);
559 a->Branch(a->HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out);
560
561 a->Bind(&match_isnotundefined);
562 a->BranchIfToBooleanIsTrue(value, &if_isregexp, &out);
563 }
564
565 a->Bind(&if_isregexp);
566 var_result.Bind(a->IntPtrConstant(1));
567 a->Goto(&out);
568
569 a->Bind(&out);
570 return var_result.value();
571 }
572
573 // ES#sec-regexpinitialize
574 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
575 Node* RegExpInitialize(CodeStubAssembler* a, Node* const context,
576 Node* const regexp, Node* const maybe_pattern,
577 Node* const maybe_flags) {
578 // Normalize pattern.
579 Node* const pattern = a->Select(
580 a->IsUndefined(maybe_pattern), [&] { return a->EmptyStringConstant(); },
Igor Sheludko 2016/12/05 12:43:41 You don't need reference access to the captured va
jgruber 2016/12/05 13:27:14 Done.
581 [&] { return a->ToString(context, maybe_pattern); },
Igor Sheludko 2016/12/05 12:43:40 Same here.
jgruber 2016/12/05 13:27:14 Done.
582 MachineRepresentation::kTagged);
583
584 // Normalize flags.
585 Node* const flags = a->Select(
586 a->IsUndefined(maybe_flags), [&] { return a->EmptyStringConstant(); },
Igor Sheludko 2016/12/05 12:43:40 Same here.
jgruber 2016/12/05 13:27:14 Done.
587 [&] { return a->ToString(context, maybe_flags); },
Igor Sheludko 2016/12/05 12:43:40 And here.
jgruber 2016/12/05 13:27:14 Done.
588 MachineRepresentation::kTagged);
589
590 // Initialize.
591
592 return a->CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp,
593 pattern, flags);
594 }
595
596 } // namespace
597
582 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { 598 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) {
583 CodeStubAssembler a(state); 599 CodeStubAssembler a(state);
584 600
585 Node* const receiver = a.Parameter(0); 601 Isolate* isolate = a.isolate();
602
603 Node* const maybe_receiver = a.Parameter(0);
586 Node* const context = a.Parameter(3); 604 Node* const context = a.Parameter(3);
587 605
588 Isolate* isolate = a.isolate(); 606 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver,
589 Node* const int_zero = a.IntPtrConstant(0);
590 Node* const int_one = a.IntPtrConstant(1);
591
592 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver,
593 MessageTemplate::kRegExpNonObject, 607 MessageTemplate::kRegExpNonObject,
594 "RegExp.prototype.flags"); 608 "RegExp.prototype.flags");
595 609 Node* const receiver = maybe_receiver;
596 CVariable var_length(&a, MachineType::PointerRepresentation()); 610
597 CVariable var_flags(&a, MachineType::PointerRepresentation()); 611 CLabel if_isfastpath(&a), if_isslowpath(&a, CLabel::kDeferred);
598 612 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isfastpath,
599 // First, count the number of characters we will need and check which flags 613 &if_isslowpath);
600 // are set. 614
601 615 a.Bind(&if_isfastpath);
602 var_length.Bind(int_zero); 616 a.Return(FlagsGetter(&a, receiver, context, true));
603 617
604 CLabel if_isunmodifiedjsregexp(&a), 618 a.Bind(&if_isslowpath);
605 if_isnotunmodifiedjsregexp(&a, CLabel::kDeferred); 619 a.Return(FlagsGetter(&a, receiver, context, false));
606 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, 620 }
607 &if_isnotunmodifiedjsregexp); 621
608 622 // ES#sec-regexp-pattern-flags
609 CLabel construct_string(&a); 623 // RegExp ( pattern, flags )
610 a.Bind(&if_isunmodifiedjsregexp); 624 void Builtins::Generate_RegExpConstructor(CodeAssemblerState* state) {
611 { 625 CodeStubAssembler a(state);
612 // Refer to JSRegExp's flag property on the fast-path. 626
613 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); 627 Node* const pattern = a.Parameter(1);
614 Node* const flags_intptr = a.SmiUntag(flags_smi); 628 Node* const flags = a.Parameter(2);
615 var_flags.Bind(flags_intptr); 629 Node* const new_target = a.Parameter(3);
616 630 Node* const context = a.Parameter(5);
617 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), 631
618 label_unicode(&a), label_sticky(&a); 632 Isolate* isolate = a.isolate();
619 633
620 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ 634 CVariable var_flags(&a, MachineRepresentation::kTagged);
621 do { \ 635 CVariable var_pattern(&a, MachineRepresentation::kTagged);
622 a.Bind(&LABEL); \ 636 CVariable var_new_target(&a, MachineRepresentation::kTagged);
623 Node* const mask = a.IntPtrConstant(FLAG); \ 637
624 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ 638 var_flags.Bind(flags);
625 &NEXT_LABEL); \ 639 var_pattern.Bind(pattern);
626 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ 640 var_new_target.Bind(new_target);
627 a.Goto(&NEXT_LABEL); \ 641
628 } while (false) 642 Node* const native_context = a.LoadNativeContext(context);
629 643 Node* const regexp_function =
630 a.Goto(&label_global); 644 a.LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
631 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); 645
632 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); 646 Node* const pattern_is_regexp = IsRegExp(&a, context, pattern);
633 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); 647
634 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); 648 {
635 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); 649 CLabel next(&a);
636 #undef CASE_FOR_FLAG 650
637 } 651 a.GotoUnless(a.IsUndefined(new_target), &next);
638 652 var_new_target.Bind(regexp_function);
639 a.Bind(&if_isnotunmodifiedjsregexp); 653
640 { 654 a.GotoUnless(pattern_is_regexp, &next);
641 // Fall back to GetProperty stub on the slow-path. 655 a.GotoUnless(a.IsUndefined(flags), &next);
642 var_flags.Bind(int_zero); 656
643 657 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
644 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); 658 Node* const name = a.HeapConstant(isolate->factory()->constructor_string());
645 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), 659 Node* const value =
646 label_unicode(&a), label_sticky(&a); 660 a.CallStub(getproperty_callable, context, pattern, name);
647 661
648 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ 662 a.GotoUnless(a.WordEqual(value, regexp_function), &next);
649 do { \ 663 a.Return(pattern);
650 a.Bind(&LABEL); \ 664
651 Node* const name = \ 665 a.Bind(&next);
652 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ 666 }
653 Node* const flag = \ 667
654 a.CallStub(getproperty_callable, context, receiver, name); \ 668 {
655 CLabel if_isflagset(&a); \ 669 CLabel next(&a), if_patternisfastregexp(&a), if_patternisslowregexp(&a);
656 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ 670 a.GotoIf(a.TaggedIsSmi(pattern), &next);
657 a.Bind(&if_isflagset); \ 671
658 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ 672 a.GotoIf(a.HasInstanceType(pattern, JS_REGEXP_TYPE),
659 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ 673 &if_patternisfastregexp);
660 a.Goto(&NEXT_LABEL); \ 674
661 } while (false) 675 a.Branch(pattern_is_regexp, &if_patternisslowregexp, &next);
662 676
663 a.Goto(&label_global); 677 a.Bind(&if_patternisfastregexp);
664 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); 678 {
665 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, 679 Node* const source = a.LoadObjectField(pattern, JSRegExp::kSourceOffset);
666 label_multiline); 680 var_pattern.Bind(source);
667 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, 681
668 label_unicode); 682 {
669 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); 683 CLabel inner_next(&a);
670 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); 684 a.GotoUnless(a.IsUndefined(flags), &inner_next);
671 #undef CASE_FOR_FLAG 685
672 } 686 Node* const value = FlagsGetter(&a, pattern, context, true);
673 687 var_flags.Bind(value);
674 // Allocate a string of the required length and fill it with the corresponding 688 a.Goto(&inner_next);
675 // char for each set flag. 689
676 690 a.Bind(&inner_next);
677 a.Bind(&construct_string); 691 }
678 { 692
679 Node* const result = 693 a.Goto(&next);
680 a.AllocateSeqOneByteString(context, var_length.value()); 694 }
681 Node* const flags_intptr = var_flags.value(); 695
682 696 a.Bind(&if_patternisslowregexp);
683 CVariable var_offset(&a, MachineType::PointerRepresentation()); 697 {
684 var_offset.Bind( 698 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
685 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 699
686 700 {
687 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), 701 Node* const name = a.HeapConstant(isolate->factory()->source_string());
688 label_unicode(&a), label_sticky(&a), out(&a); 702 Node* const value =
689 703 a.CallStub(getproperty_callable, context, pattern, name);
690 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ 704 var_pattern.Bind(value);
691 do { \ 705 }
692 a.Bind(&LABEL); \ 706
693 Node* const mask = a.IntPtrConstant(FLAG); \ 707 {
694 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ 708 CLabel inner_next(&a);
695 &NEXT_LABEL); \ 709 a.GotoUnless(a.IsUndefined(flags), &inner_next);
696 Node* const value = a.IntPtrConstant(CHAR); \ 710
697 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ 711 Node* const name = a.HeapConstant(isolate->factory()->flags_string());
698 var_offset.value(), value); \ 712 Node* const value =
699 var_offset.Bind(a.IntPtrAdd(var_offset.value(), int_one)); \ 713 a.CallStub(getproperty_callable, context, pattern, name);
700 a.Goto(&NEXT_LABEL); \ 714 var_flags.Bind(value);
701 } while (false) 715 a.Goto(&inner_next);
702 716
703 a.Goto(&label_global); 717 a.Bind(&inner_next);
704 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase); 718 }
705 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase, 719
706 label_multiline); 720 a.Goto(&next);
707 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode); 721 }
708 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky); 722
709 CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out); 723 a.Bind(&next);
710 #undef CASE_FOR_FLAG 724 }
711 725
712 a.Bind(&out); 726 // Allocate.
713 a.Return(result); 727
714 } 728 CVariable var_regexp(&a, MachineRepresentation::kTagged);
729 {
730 CLabel allocate_jsregexp(&a), allocate_generic(&a, CLabel::kDeferred),
731 next(&a);
732 a.Branch(a.WordEqual(var_new_target.value(), regexp_function),
733 &allocate_jsregexp, &allocate_generic);
734
735 a.Bind(&allocate_jsregexp);
736 {
737 Node* const initial_map = a.LoadObjectField(
738 regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
739 Node* const regexp = a.AllocateJSObjectFromMap(initial_map);
740 var_regexp.Bind(regexp);
741 a.Goto(&next);
742 }
743
744 a.Bind(&allocate_generic);
745 {
746 Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate);
747 Node* const regexp = a.CallStub(fastnewobject_callable, context,
748 regexp_function, var_new_target.value());
749 var_regexp.Bind(regexp);
750 a.Goto(&next);
751 }
752
753 a.Bind(&next);
754 }
755
756 Node* const result = RegExpInitialize(&a, context, var_regexp.value(),
757 var_pattern.value(), var_flags.value());
758 a.Return(result);
759 }
760
761 // ES#sec-regexp.prototype.compile
762 // RegExp.prototype.compile ( pattern, flags )
763 void Builtins::Generate_RegExpPrototypeCompile(CodeAssemblerState* state) {
764 CodeStubAssembler a(state);
765
766 Node* const maybe_receiver = a.Parameter(0);
767 Node* const maybe_pattern = a.Parameter(1);
768 Node* const maybe_flags = a.Parameter(2);
769 Node* const context = a.Parameter(5);
770
771 a.ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
772 "RegExp.prototype.compile");
773 Node* const receiver = maybe_receiver;
774
775 CVariable var_flags(&a, MachineRepresentation::kTagged);
776 CVariable var_pattern(&a, MachineRepresentation::kTagged);
777
778 var_flags.Bind(maybe_flags);
779 var_pattern.Bind(maybe_pattern);
780
781 // Handle a JSRegExp pattern.
782 {
783 CLabel next(&a);
784
785 a.GotoIf(a.TaggedIsSmi(maybe_pattern), &next);
786 a.GotoUnless(a.HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next);
787
788 Node* const pattern = maybe_pattern;
789
790 // {maybe_flags} must be undefined in this case, otherwise throw.
791 {
792 CLabel next(&a);
793 a.GotoIf(a.IsUndefined(maybe_flags), &next);
794
795 Node* const message_id = a.SmiConstant(MessageTemplate::kRegExpFlags);
796 a.TailCallRuntime(Runtime::kThrowTypeError, context, message_id);
797
798 a.Bind(&next);
799 }
800
801 Node* const new_flags = FlagsGetter(&a, pattern, context, true);
802 Node* const new_pattern =
803 a.LoadObjectField(pattern, JSRegExp::kSourceOffset);
804
805 var_flags.Bind(new_flags);
806 var_pattern.Bind(new_pattern);
807
808 a.Goto(&next);
809 a.Bind(&next);
810 }
811
812 RegExpInitialize(&a, context, receiver, var_pattern.value(),
813 var_flags.value());
814
815 // Return undefined for compatibility with JSC.
816 // See http://crbug.com/585775 for web compat details.
817
818 a.Return(a.UndefinedConstant());
715 } 819 }
716 820
717 // ES6 21.2.5.10. 821 // ES6 21.2.5.10.
718 void Builtins::Generate_RegExpPrototypeSourceGetter(CodeAssemblerState* state) { 822 void Builtins::Generate_RegExpPrototypeSourceGetter(CodeAssemblerState* state) {
719 CodeStubAssembler a(state); 823 CodeStubAssembler a(state);
720 Node* const receiver = a.Parameter(0); 824 Node* const receiver = a.Parameter(0);
721 Node* const context = a.Parameter(3); 825 Node* const context = a.Parameter(3);
722 826
723 // Check whether we have an unmodified regexp instance. 827 // Check whether we have an unmodified regexp instance.
724 CLabel if_isjsregexp(&a), if_isnotjsregexp(&a, CLabel::kDeferred); 828 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); 2544 a.Bind(&if_matched);
2441 { 2545 {
2442 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, 2546 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context,
2443 match_indices, string); 2547 match_indices, string);
2444 a.Return(result); 2548 a.Return(result);
2445 } 2549 }
2446 } 2550 }
2447 2551
2448 } // namespace internal 2552 } // namespace internal
2449 } // namespace v8 2553 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698