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/string-builder.h" | |
10 | 11 |
11 namespace v8 { | 12 namespace v8 { |
12 namespace internal { | 13 namespace internal { |
13 | 14 |
15 // ----------------------------------------------------------------------------- | |
16 // ES6 section 21.2 RegExp Objects | |
17 | |
18 namespace { | |
19 | |
20 // ES#sec-isregexp IsRegExp ( argument ) | |
21 Maybe<bool> IsRegExp(Isolate* isolate, Handle<Object> object) { | |
22 if (!object->IsJSReceiver()) return Just(false); | |
23 | |
24 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object); | |
25 | |
26 if (isolate->regexp_function()->initial_map() == receiver->map()) { | |
27 // Fast-path for unmodified JSRegExp instances. | |
28 return Just(true); | |
29 } | |
30 | |
31 Handle<Object> match; | |
32 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
33 isolate, match, | |
34 JSObject::GetProperty(receiver, isolate->factory()->match_symbol()), | |
35 Nothing<bool>()); | |
36 | |
37 if (!match->IsUndefined(isolate)) return Just(match->BooleanValue()); | |
38 return Just(object->IsJSRegExp()); | |
39 } | |
40 | |
41 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { | |
42 IncrementalStringBuilder builder(isolate); | |
Yang
2016/10/05 07:40:34
Using the IncrementalStringBuilder is a bit overki
jgruber
2016/10/05 08:37:03
Good point, done. We could improve this even more
| |
43 const JSRegExp::Flags flags = regexp->GetFlags(); | |
44 | |
45 if ((flags & JSRegExp::kGlobal) != 0) builder.AppendCharacter('g'); | |
46 if ((flags & JSRegExp::kIgnoreCase) != 0) builder.AppendCharacter('i'); | |
47 if ((flags & JSRegExp::kMultiline) != 0) builder.AppendCharacter('m'); | |
48 if ((flags & JSRegExp::kUnicode) != 0) builder.AppendCharacter('u'); | |
49 if ((flags & JSRegExp::kSticky) != 0) builder.AppendCharacter('y'); | |
50 | |
51 return builder.Finish().ToHandleChecked(); | |
52 } | |
53 | |
54 // ES#sec-regexpinitialize | |
55 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) | |
56 MaybeHandle<JSRegExp> RegExpInitialize(Isolate* isolate, | |
57 Handle<JSRegExp> regexp, | |
58 Handle<Object> pattern, | |
59 Handle<Object> flags) { | |
60 Handle<String> pattern_string; | |
61 if (pattern->IsUndefined(isolate)) { | |
62 pattern_string = isolate->factory()->empty_string(); | |
63 } else { | |
64 ASSIGN_RETURN_ON_EXCEPTION(isolate, pattern_string, | |
65 Object::ToString(isolate, pattern), JSRegExp); | |
66 } | |
67 | |
68 Handle<String> flags_string; | |
69 if (flags->IsUndefined(isolate)) { | |
70 flags_string = isolate->factory()->empty_string(); | |
71 } else { | |
72 ASSIGN_RETURN_ON_EXCEPTION(isolate, flags_string, | |
73 Object::ToString(isolate, flags), JSRegExp); | |
74 } | |
75 | |
76 // TODO(jgruber): We could avoid the flags back and forth conversions. | |
77 RETURN_RESULT(isolate, | |
78 JSRegExp::Initialize(regexp, pattern_string, flags_string), | |
79 JSRegExp); | |
80 } | |
81 | |
82 } // namespace | |
83 | |
84 // ES#sec-regexp-pattern-flags | |
85 // RegExp ( pattern, flags ) | |
86 BUILTIN(RegExpConstructor) { | |
87 HandleScope scope(isolate); | |
88 | |
89 Handle<HeapObject> new_target = args.new_target(); | |
90 Handle<Object> pattern = args.atOrUndefined(isolate, 1); | |
91 Handle<Object> flags = args.atOrUndefined(isolate, 2); | |
92 | |
93 Handle<JSFunction> target = isolate->regexp_function(); | |
94 | |
95 bool pattern_is_regexp; | |
96 { | |
97 Maybe<bool> maybe_pattern_is_regexp = IsRegExp(isolate, pattern); | |
98 if (maybe_pattern_is_regexp.IsNothing()) { | |
99 DCHECK(isolate->has_pending_exception()); | |
100 return isolate->heap()->exception(); | |
101 } | |
102 pattern_is_regexp = maybe_pattern_is_regexp.FromJust(); | |
103 } | |
104 | |
105 if (new_target->IsUndefined(isolate)) { | |
106 new_target = target; | |
107 | |
108 // ES6 section 21.2.3.1 step 3.b | |
109 if (pattern_is_regexp && flags->IsUndefined(isolate)) { | |
110 Handle<Object> pattern_constructor; | |
111 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
112 isolate, pattern_constructor, | |
113 Object::GetProperty(pattern, | |
114 isolate->factory()->constructor_string())); | |
115 | |
116 if (pattern_constructor.is_identical_to(new_target)) { | |
117 return *pattern; | |
118 } | |
119 } | |
120 } | |
121 | |
122 if (pattern->IsJSRegExp()) { | |
123 Handle<JSRegExp> regexp_pattern = Handle<JSRegExp>::cast(pattern); | |
124 | |
125 if (flags->IsUndefined(isolate)) { | |
126 flags = PatternFlags(isolate, regexp_pattern); | |
127 } | |
128 pattern = handle(regexp_pattern->source(), isolate); | |
129 } else if (pattern_is_regexp) { | |
130 Handle<Object> pattern_source; | |
131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
132 isolate, pattern_source, | |
133 Object::GetProperty(pattern, isolate->factory()->source_string())); | |
134 | |
135 if (flags->IsUndefined(isolate)) { | |
136 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
137 isolate, flags, | |
138 Object::GetProperty(pattern, isolate->factory()->flags_string())); | |
139 } | |
140 pattern = pattern_source; | |
141 } | |
142 | |
143 Handle<JSReceiver> new_target_receiver = Handle<JSReceiver>::cast(new_target); | |
144 | |
145 // TODO(jgruber): Fast-path for target == new_target == unmodified JSRegExp. | |
146 | |
147 Handle<JSObject> object; | |
148 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
149 isolate, object, JSObject::New(target, new_target_receiver)); | |
150 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object); | |
151 | |
152 RETURN_RESULT_OR_FAILURE(isolate, | |
153 RegExpInitialize(isolate, regexp, pattern, flags)); | |
154 } | |
155 | |
14 namespace { | 156 namespace { |
15 | 157 |
16 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 158 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, |
17 compiler::Node* has_initialmap, | 159 compiler::Node* has_initialmap, |
18 compiler::Node* regexp) { | 160 compiler::Node* regexp) { |
19 typedef CodeStubAssembler::Variable Variable; | 161 typedef CodeStubAssembler::Variable Variable; |
20 typedef CodeStubAssembler::Label Label; | 162 typedef CodeStubAssembler::Label Label; |
21 typedef compiler::Node Node; | 163 typedef compiler::Node Node; |
22 | 164 |
23 Variable var_value(a, MachineRepresentation::kTagged); | 165 Variable var_value(a, MachineRepresentation::kTagged); |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 { | 430 { |
289 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 431 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
290 match_elements, string); | 432 match_elements, string); |
291 a->Return(result); | 433 a->Return(result); |
292 } | 434 } |
293 } | 435 } |
294 } | 436 } |
295 | 437 |
296 } // namespace internal | 438 } // namespace internal |
297 } // namespace v8 | 439 } // namespace v8 |
OLD | NEW |