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

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

Issue 2554453003: [regexp] Move helper functions to custom assembler (Closed)
Patch Set: 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 | « no previous file | no next file » | 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;
18 typedef CodeStubAssembler::Variable CVariable;
19 typedef CodeStubAssembler::ParameterMode ParameterMode; 17 typedef CodeStubAssembler::ParameterMode ParameterMode;
20 typedef compiler::CodeAssemblerState CodeAssemblerState; 18 typedef compiler::CodeAssemblerState CodeAssemblerState;
21 19
22 class RegExpBuiltinsAssembler : public CodeStubAssembler { 20 class RegExpBuiltinsAssembler : public CodeStubAssembler {
23 public: 21 public:
24 explicit RegExpBuiltinsAssembler(compiler::CodeAssemblerState* state) 22 explicit RegExpBuiltinsAssembler(CodeAssemblerState* state)
25 : CodeStubAssembler(state) {} 23 : CodeStubAssembler(state) {}
26 24
27 protected: 25 protected:
26 Node* FastLoadLastIndex(Node* regexp);
27 Node* SlowLoadLastIndex(Node* context, Node* regexp);
28 Node* LoadLastIndex(Node* context, Node* regexp, bool is_fastpath);
29
30 void FastStoreLastIndex(Node* regexp, Node* value);
31 void SlowStoreLastIndex(Node* context, Node* regexp, Node* value);
32 void StoreLastIndex(Node* context, Node* regexp, Node* value,
33 bool is_fastpath);
34
35 Node* ConstructNewResultFromMatchInfo(Node* context, Node* match_info,
36 Node* string);
37
38 Node* RegExpPrototypeExecBodyWithoutResult(Node* const context,
39 Node* const regexp,
40 Node* const string,
41 Label* if_didnotmatch,
42 const bool is_fastpath);
43 Node* RegExpPrototypeExecBody(Node* const context, Node* const regexp,
44 Node* const string, const bool is_fastpath);
45
46 Node* ThrowIfNotJSReceiver(Node* context, Node* maybe_receiver,
47 MessageTemplate::Template msg_template,
48 char const* method_name);
49
50 Node* IsInitialRegExpMap(Node* context, Node* map);
51 void BranchIfFastRegExp(Node* context, Node* map, Label* if_isunmodified,
52 Label* if_ismodified);
53 void BranchIfFastRegExpResult(Node* context, Node* map,
54 Label* if_isunmodified, Label* if_ismodified);
55
56 Node* FlagsGetter(Node* const context, Node* const regexp, bool is_fastpath);
57
58 Node* FastFlagGetter(Node* const regexp, JSRegExp::Flag flag);
59 Node* SlowFlagGetter(Node* const context, Node* const regexp,
60 JSRegExp::Flag flag);
61 Node* FlagGetter(Node* const context, Node* const regexp, JSRegExp::Flag flag,
62 bool is_fastpath);
63 void FlagGetter(JSRegExp::Flag flag, v8::Isolate::UseCounterFeature counter,
64 const char* method_name);
65
66 Node* IsRegExp(Node* const context, Node* const maybe_receiver);
67 Node* RegExpInitialize(Node* const context, Node* const regexp,
68 Node* const maybe_pattern, Node* const maybe_flags);
69
70 Node* RegExpExec(Node* context, Node* regexp, Node* string);
71
72 Node* AdvanceStringIndex(Node* const string, Node* const index,
73 Node* const is_unicode);
74
75 void RegExpPrototypeMatchBody(Node* const context, Node* const regexp,
76 Node* const string, const bool is_fastpath);
77
78 void RegExpPrototypeSearchBodyFast(Node* const context, Node* const regexp,
79 Node* const string);
80 void RegExpPrototypeSearchBodySlow(Node* const context, Node* const regexp,
81 Node* const string);
82
83 void RegExpPrototypeSplitBody(Node* const context, Node* const regexp,
84 Node* const string, Node* const limit);
85
86 Node* ReplaceGlobalCallableFastPath(Node* context, Node* regexp, Node* string,
87 Node* replace_callable);
88 Node* ReplaceSimpleStringFastPath(Node* context, Node* regexp, Node* string,
89 Node* replace_string);
28 }; 90 };
29 91
30 // ----------------------------------------------------------------------------- 92 // -----------------------------------------------------------------------------
31 // ES6 section 21.2 RegExp Objects 93 // ES6 section 21.2 RegExp Objects
32 94
33 namespace { 95 Node* RegExpBuiltinsAssembler::FastLoadLastIndex(Node* regexp) {
Camillo Bruni 2016/12/05 09:52:10 I'd directly define them inline to avoid declaring
34
35 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) {
36 // Load the in-object field. 96 // Load the in-object field.
37 static const int field_offset = 97 static const int field_offset =
38 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 98 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
39 return a->LoadObjectField(regexp, field_offset); 99 return LoadObjectField(regexp, field_offset);
40 } 100 }
41 101
42 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { 102 Node* RegExpBuiltinsAssembler::SlowLoadLastIndex(Node* context, Node* regexp) {
43 // Load through the GetProperty stub. 103 // Load through the GetProperty stub.
44 Node* const name = 104 Node* const name = HeapConstant(isolate()->factory()->lastIndex_string());
45 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 105 Callable getproperty_callable = CodeFactory::GetProperty(isolate());
46 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 106 return CallStub(getproperty_callable, context, regexp, name);
47 return a->CallStub(getproperty_callable, context, regexp, name);
48 } 107 }
49 108
50 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, 109 Node* RegExpBuiltinsAssembler::LoadLastIndex(Node* context, Node* regexp,
51 bool is_fastpath) { 110 bool is_fastpath) {
52 return is_fastpath ? FastLoadLastIndex(a, regexp) 111 return is_fastpath ? FastLoadLastIndex(regexp)
53 : SlowLoadLastIndex(a, context, regexp); 112 : SlowLoadLastIndex(context, regexp);
54 } 113 }
55 114
56 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified 115 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified
57 // JSRegExp instance. 116 // JSRegExp instance.
58 void FastStoreLastIndex(CodeStubAssembler* a, Node* regexp, Node* value) { 117 void RegExpBuiltinsAssembler::FastStoreLastIndex(Node* regexp, Node* value) {
59 // Store the in-object field. 118 // Store the in-object field.
60 static const int field_offset = 119 static const int field_offset =
61 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 120 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
62 a->StoreObjectField(regexp, field_offset, value); 121 StoreObjectField(regexp, field_offset, value);
63 } 122 }
64 123
65 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, 124 void RegExpBuiltinsAssembler::SlowStoreLastIndex(Node* context, Node* regexp,
66 Node* value) { 125 Node* value) {
67 // Store through runtime. 126 // Store through runtime.
68 // TODO(ishell): Use SetPropertyStub here once available. 127 // TODO(ishell): Use SetPropertyStub here once available.
69 Node* const name = 128 Node* const name = HeapConstant(isolate()->factory()->lastIndex_string());
70 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 129 Node* const language_mode = SmiConstant(Smi::FromInt(STRICT));
71 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); 130 CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
72 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, 131 language_mode);
73 language_mode);
74 } 132 }
75 133
76 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, 134 void RegExpBuiltinsAssembler::StoreLastIndex(Node* context, Node* regexp,
77 Node* value, bool is_fastpath) { 135 Node* value, bool is_fastpath) {
78 if (is_fastpath) { 136 if (is_fastpath) {
79 FastStoreLastIndex(a, regexp, value); 137 FastStoreLastIndex(regexp, value);
80 } else { 138 } else {
81 SlowStoreLastIndex(a, context, regexp, value); 139 SlowStoreLastIndex(context, regexp, value);
82 } 140 }
83 } 141 }
84 142
85 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, 143 Node* RegExpBuiltinsAssembler::ConstructNewResultFromMatchInfo(Node* context,
86 Node* context, Node* match_info, 144 Node* match_info,
87 Node* string) { 145 Node* string) {
88 CLabel out(a); 146 Label out(this);
89 147
90 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( 148 Node* const num_indices = SmiUntag(LoadFixedArrayElement(
91 match_info, RegExpMatchInfo::kNumberOfCapturesIndex)); 149 match_info, RegExpMatchInfo::kNumberOfCapturesIndex));
92 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); 150 Node* const num_results = SmiTag(WordShr(num_indices, 1));
93 Node* const start = 151 Node* const start =
94 a->LoadFixedArrayElement(match_info, RegExpMatchInfo::kFirstCaptureIndex); 152 LoadFixedArrayElement(match_info, RegExpMatchInfo::kFirstCaptureIndex);
95 Node* const end = a->LoadFixedArrayElement( 153 Node* const end = LoadFixedArrayElement(
96 match_info, RegExpMatchInfo::kFirstCaptureIndex + 1); 154 match_info, RegExpMatchInfo::kFirstCaptureIndex + 1);
97 155
98 // Calculate the substring of the first match before creating the result array 156 // Calculate the substring of the first match before creating the result array
99 // to avoid an unnecessary write barrier storing the first result. 157 // to avoid an unnecessary write barrier storing the first result.
100 Node* const first = a->SubString(context, string, start, end); 158 Node* const first = SubString(context, string, start, end);
101 159
102 Node* const result = 160 Node* const result =
103 a->AllocateRegExpResult(context, num_results, start, string); 161 AllocateRegExpResult(context, num_results, start, string);
104 Node* const result_elements = a->LoadElements(result); 162 Node* const result_elements = LoadElements(result);
105 163
106 a->StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER); 164 StoreFixedArrayElement(result_elements, 0, first, SKIP_WRITE_BARRIER);
107 165
108 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); 166 GotoIf(SmiEqual(num_results, SmiConstant(Smi::FromInt(1))), &out);
109 167
110 // Store all remaining captures. 168 // Store all remaining captures.
111 Node* const limit = a->IntPtrAdd( 169 Node* const limit = IntPtrAdd(
112 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); 170 IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices);
113 171
114 CVariable var_from_cursor(a, MachineType::PointerRepresentation()); 172 Variable var_from_cursor(this, MachineType::PointerRepresentation());
115 CVariable var_to_cursor(a, MachineType::PointerRepresentation()); 173 Variable var_to_cursor(this, MachineType::PointerRepresentation());
116 174
117 var_from_cursor.Bind( 175 var_from_cursor.Bind(IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2));
118 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); 176 var_to_cursor.Bind(IntPtrConstant(1));
119 var_to_cursor.Bind(a->IntPtrConstant(1));
120 177
121 CVariable* vars[] = {&var_from_cursor, &var_to_cursor}; 178 Variable* vars[] = {&var_from_cursor, &var_to_cursor};
122 CLabel loop(a, 2, vars); 179 Label loop(this, 2, vars);
123 180
124 a->Goto(&loop); 181 Goto(&loop);
125 a->Bind(&loop); 182 Bind(&loop);
126 { 183 {
127 Node* const from_cursor = var_from_cursor.value(); 184 Node* const from_cursor = var_from_cursor.value();
128 Node* const to_cursor = var_to_cursor.value(); 185 Node* const to_cursor = var_to_cursor.value();
129 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); 186 Node* const start = LoadFixedArrayElement(match_info, from_cursor);
130 187
131 CLabel next_iter(a); 188 Label next_iter(this);
132 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); 189 GotoIf(SmiEqual(start, SmiConstant(Smi::FromInt(-1))), &next_iter);
133 190
134 Node* const from_cursor_plus1 = 191 Node* const from_cursor_plus1 = IntPtrAdd(from_cursor, IntPtrConstant(1));
135 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); 192 Node* const end = LoadFixedArrayElement(match_info, from_cursor_plus1);
136 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1);
137 193
138 Node* const capture = a->SubString(context, string, start, end); 194 Node* const capture = SubString(context, string, start, end);
139 a->StoreFixedArrayElement(result_elements, to_cursor, capture); 195 StoreFixedArrayElement(result_elements, to_cursor, capture);
140 a->Goto(&next_iter); 196 Goto(&next_iter);
141 197
142 a->Bind(&next_iter); 198 Bind(&next_iter);
143 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); 199 var_from_cursor.Bind(IntPtrAdd(from_cursor, IntPtrConstant(2)));
144 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); 200 var_to_cursor.Bind(IntPtrAdd(to_cursor, IntPtrConstant(1)));
145 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); 201 Branch(UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out);
146 } 202 }
147 203
148 a->Bind(&out); 204 Bind(&out);
149 return result; 205 return result;
150 } 206 }
151 207
152 // ES#sec-regexp.prototype.exec 208 // ES#sec-regexp.prototype.exec
153 // RegExp.prototype.exec ( string ) 209 // RegExp.prototype.exec ( string )
154 // Implements the core of RegExp.prototype.exec but without actually 210 // Implements the core of RegExp.prototype.exec but without actually
155 // constructing the JSRegExpResult. Returns either null (if the RegExp did not 211 // constructing the JSRegExpResult. Returns either null (if the RegExp did not
156 // match) or a fixed array containing match indices as returned by 212 // match) or a fixed array containing match indices as returned by
157 // RegExpExecStub. 213 // RegExpExecStub.
158 Node* RegExpPrototypeExecBodyWithoutResult( 214 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
159 CodeStubAssembler* a, Node* const context, Node* const regexp, 215 Node* const context, Node* const regexp, Node* const string,
160 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) { 216 Label* if_didnotmatch, const bool is_fastpath) {
161 Isolate* const isolate = a->isolate(); 217 Isolate* const isolate = this->isolate();
162 218
163 Node* const null = a->NullConstant(); 219 Node* const null = NullConstant();
164 Node* const int_zero = a->IntPtrConstant(0); 220 Node* const int_zero = IntPtrConstant(0);
165 Node* const smi_zero = a->SmiConstant(Smi::kZero); 221 Node* const smi_zero = SmiConstant(Smi::kZero);
166 222
167 if (!is_fastpath) { 223 if (!is_fastpath) {
168 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, 224 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
169 "RegExp.prototype.exec"); 225 "RegExp.prototype.exec");
170 } 226 }
171 227
172 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string))); 228 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string)));
173 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE)); 229 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE));
174 230
175 CVariable var_result(a, MachineRepresentation::kTagged); 231 Variable var_result(this, MachineRepresentation::kTagged);
176 CLabel out(a); 232 Label out(this);
177 233
178 Node* const native_context = a->LoadNativeContext(context); 234 Node* const native_context = LoadNativeContext(context);
179 Node* const string_length = a->LoadStringLength(string); 235 Node* const string_length = LoadStringLength(string);
180 236
181 // Check whether the regexp is global or sticky, which determines whether we 237 // Check whether the regexp is global or sticky, which determines whether we
182 // update last index later on. 238 // update last index later on.
183 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 239 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
184 Node* const is_global_or_sticky = 240 Node* const is_global_or_sticky = WordAnd(
185 a->WordAnd(a->SmiUntag(flags), 241 SmiUntag(flags), IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky));
186 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky));
187 Node* const should_update_last_index = 242 Node* const should_update_last_index =
188 a->WordNotEqual(is_global_or_sticky, int_zero); 243 WordNotEqual(is_global_or_sticky, int_zero);
189 244
190 // Grab and possibly update last index. 245 // Grab and possibly update last index.
191 CLabel run_exec(a); 246 Label run_exec(this);
192 CVariable var_lastindex(a, MachineRepresentation::kTagged); 247 Variable var_lastindex(this, MachineRepresentation::kTagged);
193 { 248 {
194 CLabel if_doupdate(a), if_dontupdate(a); 249 Label if_doupdate(this), if_dontupdate(this);
195 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); 250 Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
196 251
197 a->Bind(&if_doupdate); 252 Bind(&if_doupdate);
198 { 253 {
199 Node* const regexp_lastindex = 254 Node* const regexp_lastindex =
200 LoadLastIndex(a, context, regexp, is_fastpath); 255 LoadLastIndex(context, regexp, is_fastpath);
201 var_lastindex.Bind(regexp_lastindex); 256 var_lastindex.Bind(regexp_lastindex);
202 257
203 // Omit ToLength if lastindex is a non-negative smi. 258 // Omit ToLength if lastindex is a non-negative smi.
204 { 259 {
205 CLabel call_tolength(a, CLabel::kDeferred), next(a); 260 Label call_tolength(this, Label::kDeferred), next(this);
206 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next, 261 Branch(WordIsPositiveSmi(regexp_lastindex), &next, &call_tolength);
207 &call_tolength); 262
208 263 Bind(&call_tolength);
209 a->Bind(&call_tolength);
210 { 264 {
211 Callable tolength_callable = CodeFactory::ToLength(isolate); 265 Callable tolength_callable = CodeFactory::ToLength(isolate);
212 var_lastindex.Bind( 266 var_lastindex.Bind(
213 a->CallStub(tolength_callable, context, regexp_lastindex)); 267 CallStub(tolength_callable, context, regexp_lastindex));
214 a->Goto(&next); 268 Goto(&next);
215 } 269 }
216 270
217 a->Bind(&next); 271 Bind(&next);
218 } 272 }
219 273
220 Node* const lastindex = var_lastindex.value(); 274 Node* const lastindex = var_lastindex.value();
221 275
222 CLabel if_isoob(a, CLabel::kDeferred); 276 Label if_isoob(this, Label::kDeferred);
223 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); 277 GotoUnless(TaggedIsSmi(lastindex), &if_isoob);
224 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); 278 GotoUnless(SmiLessThanOrEqual(lastindex, string_length), &if_isoob);
225 a->Goto(&run_exec); 279 Goto(&run_exec);
226 280
227 a->Bind(&if_isoob); 281 Bind(&if_isoob);
228 { 282 {
229 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); 283 StoreLastIndex(context, regexp, smi_zero, is_fastpath);
230 var_result.Bind(null); 284 var_result.Bind(null);
231 a->Goto(if_didnotmatch); 285 Goto(if_didnotmatch);
232 } 286 }
233 } 287 }
234 288
235 a->Bind(&if_dontupdate); 289 Bind(&if_dontupdate);
236 { 290 {
237 var_lastindex.Bind(smi_zero); 291 var_lastindex.Bind(smi_zero);
238 a->Goto(&run_exec); 292 Goto(&run_exec);
239 } 293 }
240 } 294 }
241 295
242 Node* match_indices; 296 Node* match_indices;
243 CLabel successful_match(a); 297 Label successful_match(this);
244 a->Bind(&run_exec); 298 Bind(&run_exec);
245 { 299 {
246 // Get last match info from the context. 300 // Get last match info from the context.
247 Node* const last_match_info = a->LoadContextElement( 301 Node* const last_match_info = LoadContextElement(
248 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 302 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
249 303
250 // Call the exec stub. 304 // Call the exec stub.
251 Callable exec_callable = CodeFactory::RegExpExec(isolate); 305 Callable exec_callable = CodeFactory::RegExpExec(isolate);
252 match_indices = a->CallStub(exec_callable, context, regexp, string, 306 match_indices = CallStub(exec_callable, context, regexp, string,
253 var_lastindex.value(), last_match_info); 307 var_lastindex.value(), last_match_info);
254 var_result.Bind(match_indices); 308 var_result.Bind(match_indices);
255 309
256 // {match_indices} is either null or the RegExpMatchInfo array. 310 // {match_indices} is either null or the RegExpMatchInfo array.
257 // Return early if exec failed, possibly updating last index. 311 // Return early if exec failed, possibly updating last index.
258 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); 312 GotoUnless(WordEqual(match_indices, null), &successful_match);
259 313
260 a->GotoUnless(should_update_last_index, if_didnotmatch); 314 GotoUnless(should_update_last_index, if_didnotmatch);
261 315
262 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); 316 StoreLastIndex(context, regexp, smi_zero, is_fastpath);
263 a->Goto(if_didnotmatch); 317 Goto(if_didnotmatch);
264 } 318 }
265 319
266 a->Bind(&successful_match); 320 Bind(&successful_match);
267 { 321 {
268 a->GotoUnless(should_update_last_index, &out); 322 GotoUnless(should_update_last_index, &out);
269 323
270 // Update the new last index from {match_indices}. 324 // Update the new last index from {match_indices}.
271 Node* const new_lastindex = a->LoadFixedArrayElement( 325 Node* const new_lastindex = LoadFixedArrayElement(
272 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); 326 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
273 327
274 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath); 328 StoreLastIndex(context, regexp, new_lastindex, is_fastpath);
275 a->Goto(&out); 329 Goto(&out);
276 } 330 }
277 331
278 a->Bind(&out); 332 Bind(&out);
279 return var_result.value(); 333 return var_result.value();
280 } 334 }
281 335
282 // ES#sec-regexp.prototype.exec 336 // ES#sec-regexp.prototype.exec
283 // RegExp.prototype.exec ( string ) 337 // RegExp.prototype.exec ( string )
284 Node* RegExpPrototypeExecBody(CodeStubAssembler* a, Node* const context, 338 Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(Node* const context,
285 Node* const regexp, Node* const string, 339 Node* const regexp,
286 const bool is_fastpath) { 340 Node* const string,
287 Isolate* const isolate = a->isolate(); 341 const bool is_fastpath) {
288 Node* const null = a->NullConstant(); 342 Node* const null = NullConstant();
289 343
290 CVariable var_result(a, MachineRepresentation::kTagged); 344 Variable var_result(this, MachineRepresentation::kTagged);
291 345
292 CLabel if_didnotmatch(a), out(a); 346 Label if_didnotmatch(this), out(this);
293 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult( 347 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult(
294 a, context, regexp, string, &if_didnotmatch, is_fastpath); 348 context, regexp, string, &if_didnotmatch, is_fastpath);
295 349
296 // Successful match. 350 // Successful match.
297 { 351 {
298 Node* const match_indices = indices_or_null; 352 Node* const match_indices = indices_or_null;
299 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context, 353 Node* const result =
300 match_indices, string); 354 ConstructNewResultFromMatchInfo(context, match_indices, string);
301 var_result.Bind(result); 355 var_result.Bind(result);
302 a->Goto(&out); 356 Goto(&out);
303 } 357 }
304 358
305 a->Bind(&if_didnotmatch); 359 Bind(&if_didnotmatch);
306 { 360 {
307 var_result.Bind(null); 361 var_result.Bind(null);
308 a->Goto(&out); 362 Goto(&out);
309 } 363 }
310 364
311 a->Bind(&out); 365 Bind(&out);
312 return var_result.value(); 366 return var_result.value();
313 } 367 }
314 368
315 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, 369 Node* RegExpBuiltinsAssembler::ThrowIfNotJSReceiver(
316 Node* context, Node* value, 370 Node* context, Node* maybe_receiver, MessageTemplate::Template msg_template,
317 MessageTemplate::Template msg_template, 371 char const* method_name) {
318 char const* method_name) { 372 Label out(this), throw_exception(this, Label::kDeferred);
319 CLabel out(a), throw_exception(a, CLabel::kDeferred); 373 Variable var_value_map(this, MachineRepresentation::kTagged);
320 CVariable var_value_map(a, MachineRepresentation::kTagged); 374
321 375 GotoIf(TaggedIsSmi(maybe_receiver), &throw_exception);
322 a->GotoIf(a->TaggedIsSmi(value), &throw_exception);
323 376
324 // Load the instance type of the {value}. 377 // Load the instance type of the {value}.
325 var_value_map.Bind(a->LoadMap(value)); 378 var_value_map.Bind(LoadMap(maybe_receiver));
326 Node* const value_instance_type = 379 Node* const value_instance_type = LoadMapInstanceType(var_value_map.value());
327 a->LoadMapInstanceType(var_value_map.value()); 380
328 381 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
329 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out,
330 &throw_exception);
331 382
332 // The {value} is not a compatible receiver for this method. 383 // The {value} is not a compatible receiver for this method.
333 a->Bind(&throw_exception); 384 Bind(&throw_exception);
334 { 385 {
335 Node* const message_id = a->SmiConstant(Smi::FromInt(msg_template)); 386 Node* const message_id = SmiConstant(Smi::FromInt(msg_template));
336 Node* const method_name_str = a->HeapConstant( 387 Node* const method_name_str = HeapConstant(
337 isolate->factory()->NewStringFromAsciiChecked(method_name, TENURED)); 388 isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED));
338 389
339 Callable callable = CodeFactory::ToString(isolate); 390 Callable callable = CodeFactory::ToString(isolate());
340 Node* const value_str = a->CallStub(callable, context, value); 391 Node* const value_str = CallStub(callable, context, maybe_receiver);
341 392
342 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, 393 CallRuntime(Runtime::kThrowTypeError, context, message_id, method_name_str,
343 method_name_str, value_str); 394 value_str);
344 var_value_map.Bind(a->UndefinedConstant()); 395 var_value_map.Bind(UndefinedConstant());
345 a->Goto(&out); // Never reached. 396 Goto(&out); // Never reached.
346 } 397 }
347 398
348 a->Bind(&out); 399 Bind(&out);
349 return var_value_map.value(); 400 return var_value_map.value();
350 } 401 }
351 402
352 Node* IsInitialRegExpMap(CodeStubAssembler* a, Node* context, Node* map) { 403 Node* RegExpBuiltinsAssembler::IsInitialRegExpMap(Node* context, Node* map) {
353 Node* const native_context = a->LoadNativeContext(context); 404 Node* const native_context = LoadNativeContext(context);
354 Node* const regexp_fun = 405 Node* const regexp_fun =
355 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 406 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
356 Node* const initial_map = 407 Node* const initial_map =
357 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 408 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
358 Node* const has_initialmap = a->WordEqual(map, initial_map); 409 Node* const has_initialmap = WordEqual(map, initial_map);
359 410
360 return has_initialmap; 411 return has_initialmap;
361 } 412 }
362 413
363 // RegExp fast path implementations rely on unmodified JSRegExp instances. 414 // RegExp fast path implementations rely on unmodified JSRegExp instances.
364 // We use a fairly coarse granularity for this and simply check whether both 415 // We use a fairly coarse granularity for this and simply check whether both
365 // the regexp itself is unmodified (i.e. its map has not changed) and its 416 // the regexp itself is unmodified (i.e. its map has not changed) and its
366 // prototype is unmodified. 417 // prototype is unmodified.
367 void BranchIfFastPath(CodeStubAssembler* a, Node* context, Node* map, 418 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* context, Node* map,
368 CLabel* if_isunmodified, CLabel* if_ismodified) { 419 Label* if_isunmodified,
369 Node* const native_context = a->LoadNativeContext(context); 420 Label* if_ismodified) {
421 Node* const native_context = LoadNativeContext(context);
370 Node* const regexp_fun = 422 Node* const regexp_fun =
371 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 423 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
372 Node* const initial_map = 424 Node* const initial_map =
373 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 425 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
374 Node* const has_initialmap = a->WordEqual(map, initial_map); 426 Node* const has_initialmap = WordEqual(map, initial_map);
375 427
376 a->GotoUnless(has_initialmap, if_ismodified); 428 GotoUnless(has_initialmap, if_ismodified);
377 429
378 Node* const initial_proto_initial_map = a->LoadContextElement( 430 Node* const initial_proto_initial_map =
379 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); 431 LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX);
380 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); 432 Node* const proto_map = LoadMap(LoadMapPrototype(map));
381 Node* const proto_has_initialmap = 433 Node* const proto_has_initialmap =
382 a->WordEqual(proto_map, initial_proto_initial_map); 434 WordEqual(proto_map, initial_proto_initial_map);
383 435
384 // TODO(ishell): Update this check once map changes for constant field 436 // TODO(ishell): Update this check once map changes for constant field
385 // tracking are landing. 437 // tracking are landing.
386 438
387 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); 439 Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
388 } 440 }
389 441
390 void BranchIfFastRegExpResult(CodeStubAssembler* a, Node* context, Node* map, 442 void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* context, Node* map,
391 CLabel* if_isunmodified, CLabel* if_ismodified) { 443 Label* if_isunmodified,
392 Node* const native_context = a->LoadNativeContext(context); 444 Label* if_ismodified) {
445 Node* const native_context = LoadNativeContext(context);
393 Node* const initial_regexp_result_map = 446 Node* const initial_regexp_result_map =
394 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); 447 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
395 448
396 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, 449 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified,
397 if_ismodified); 450 if_ismodified);
398 } 451 }
399 452
400 } // namespace
401
402 // ES#sec-regexp.prototype.exec 453 // ES#sec-regexp.prototype.exec
403 // RegExp.prototype.exec ( string ) 454 // RegExp.prototype.exec ( string )
404 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) { 455 TF_BUILTIN(RegExpPrototypeExec, RegExpBuiltinsAssembler) {
405 Node* const maybe_receiver = Parameter(0); 456 Node* const maybe_receiver = Parameter(0);
406 Node* const maybe_string = Parameter(1); 457 Node* const maybe_string = Parameter(1);
407 Node* const context = Parameter(4); 458 Node* const context = Parameter(4);
408 459
409 // Ensure {maybe_receiver} is a JSRegExp. 460 // Ensure {maybe_receiver} is a JSRegExp.
410 Node* const regexp_map = ThrowIfNotInstanceType( 461 Node* const regexp_map = ThrowIfNotInstanceType(
411 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); 462 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec");
412 Node* const receiver = maybe_receiver; 463 Node* const receiver = maybe_receiver;
413 464
414 // Convert {maybe_string} to a String. 465 // Convert {maybe_string} to a String.
415 Node* const string = ToString(context, maybe_string); 466 Node* const string = ToString(context, maybe_string);
416 467
417 CLabel if_isfastpath(this), if_isslowpath(this); 468 Label if_isfastpath(this), if_isslowpath(this);
418 Branch(IsInitialRegExpMap(this, context, regexp_map), &if_isfastpath, 469 Branch(IsInitialRegExpMap(context, regexp_map), &if_isfastpath,
419 &if_isslowpath); 470 &if_isslowpath);
420 471
421 Bind(&if_isfastpath); 472 Bind(&if_isfastpath);
422 { 473 {
423 Node* const result = 474 Node* const result =
424 RegExpPrototypeExecBody(this, context, receiver, string, true); 475 RegExpPrototypeExecBody(context, receiver, string, true);
425 Return(result); 476 Return(result);
426 } 477 }
427 478
428 Bind(&if_isslowpath); 479 Bind(&if_isslowpath);
429 { 480 {
430 Node* const result = 481 Node* const result =
431 RegExpPrototypeExecBody(this, context, receiver, string, false); 482 RegExpPrototypeExecBody(context, receiver, string, false);
432 Return(result); 483 Return(result);
433 } 484 }
434 } 485 }
435 486
436 namespace { 487 Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
488 Node* const regexp,
489 bool is_fastpath) {
490 Isolate* isolate = this->isolate();
437 491
438 Node* FlagsGetter(CodeStubAssembler* a, Node* const receiver, 492 Node* const int_zero = IntPtrConstant(0);
439 Node* const context, bool is_fastpath) { 493 Node* const int_one = IntPtrConstant(1);
440 Isolate* isolate = a->isolate(); 494 Variable var_length(this, MachineType::PointerRepresentation());
441 495 Variable var_flags(this, MachineType::PointerRepresentation());
442 Node* const int_zero = a->IntPtrConstant(0);
443 Node* const int_one = a->IntPtrConstant(1);
444 CVariable var_length(a, MachineType::PointerRepresentation());
445 CVariable var_flags(a, MachineType::PointerRepresentation());
446 496
447 // First, count the number of characters we will need and check which flags 497 // First, count the number of characters we will need and check which flags
448 // are set. 498 // are set.
449 499
450 var_length.Bind(int_zero); 500 var_length.Bind(int_zero);
451 501
452 CLabel construct_string(a); 502 Label construct_string(this);
453 if (is_fastpath) { 503 if (is_fastpath) {
454 // Refer to JSRegExp's flag property on the fast-path. 504 // Refer to JSRegExp's flag property on the fast-path.
455 Node* const flags_smi = 505 Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
456 a->LoadObjectField(receiver, JSRegExp::kFlagsOffset); 506 Node* const flags_intptr = SmiUntag(flags_smi);
457 Node* const flags_intptr = a->SmiUntag(flags_smi);
458 var_flags.Bind(flags_intptr); 507 var_flags.Bind(flags_intptr);
459 508
460 CLabel label_global(a), label_ignorecase(a), label_multiline(a), 509 Label label_global(this), label_ignorecase(this), label_multiline(this),
461 label_unicode(a), label_sticky(a); 510 label_unicode(this), label_sticky(this);
462 511
463 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ 512 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \
464 do { \ 513 do { \
465 a->Bind(&LABEL); \ 514 Bind(&LABEL); \
466 Node* const mask = a->IntPtrConstant(FLAG); \ 515 Node* const mask = IntPtrConstant(FLAG); \
467 a->GotoIf(a->WordEqual(a->WordAnd(flags_intptr, mask), int_zero), \ 516 GotoIf(WordEqual(WordAnd(flags_intptr, mask), int_zero), &NEXT_LABEL); \
468 &NEXT_LABEL); \ 517 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \
469 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \ 518 Goto(&NEXT_LABEL); \
470 a->Goto(&NEXT_LABEL); \
471 } while (false) 519 } while (false)
472 520
473 a->Goto(&label_global); 521 Goto(&label_global);
474 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); 522 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase);
475 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); 523 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline);
476 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); 524 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode);
477 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); 525 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky);
478 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); 526 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string);
479 #undef CASE_FOR_FLAG 527 #undef CASE_FOR_FLAG
480 } else { 528 } else {
481 DCHECK(!is_fastpath); 529 DCHECK(!is_fastpath);
482 530
483 // Fall back to GetProperty stub on the slow-path. 531 // Fall back to GetProperty stub on the slow-path.
484 var_flags.Bind(int_zero); 532 var_flags.Bind(int_zero);
485 533
486 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 534 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
487 CLabel label_global(a), label_ignorecase(a), label_multiline(a), 535 Label label_global(this), label_ignorecase(this), label_multiline(this),
488 label_unicode(a), label_sticky(a); 536 label_unicode(this), label_sticky(this);
489 537
490 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ 538 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \
491 do { \ 539 do { \
492 a->Bind(&LABEL); \ 540 Bind(&LABEL); \
493 Node* const name = \ 541 Node* const name = \
494 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ 542 HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \
495 Node* const flag = \ 543 Node* const flag = CallStub(getproperty_callable, context, regexp, name); \
496 a->CallStub(getproperty_callable, context, receiver, name); \ 544 Label if_isflagset(this); \
497 CLabel if_isflagset(a); \ 545 BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \
498 a->BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ 546 Bind(&if_isflagset); \
499 a->Bind(&if_isflagset); \ 547 var_length.Bind(IntPtrAdd(var_length.value(), int_one)); \
500 var_length.Bind(a->IntPtrAdd(var_length.value(), int_one)); \ 548 var_flags.Bind(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \
501 var_flags.Bind(a->WordOr(var_flags.value(), a->IntPtrConstant(FLAG))); \ 549 Goto(&NEXT_LABEL); \
502 a->Goto(&NEXT_LABEL); \
503 } while (false) 550 } while (false)
504 551
505 a->Goto(&label_global); 552 Goto(&label_global);
506 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); 553 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase);
507 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, 554 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase,
508 label_multiline); 555 label_multiline);
509 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, 556 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline,
510 label_unicode); 557 label_unicode);
511 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); 558 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky);
512 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); 559 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string);
513 #undef CASE_FOR_FLAG 560 #undef CASE_FOR_FLAG
514 } 561 }
515 562
516 // Allocate a string of the required length and fill it with the corresponding 563 // Allocate a string of the required length and fill it with the corresponding
517 // char for each set flag. 564 // char for each set flag.
518 565
519 a->Bind(&construct_string); 566 Bind(&construct_string);
520 { 567 {
521 Node* const result = 568 Node* const result = AllocateSeqOneByteString(context, var_length.value());
522 a->AllocateSeqOneByteString(context, var_length.value());
523 Node* const flags_intptr = var_flags.value(); 569 Node* const flags_intptr = var_flags.value();
524 570
525 CVariable var_offset(a, MachineType::PointerRepresentation()); 571 Variable var_offset(this, MachineType::PointerRepresentation());
526 var_offset.Bind( 572 var_offset.Bind(
527 a->IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); 573 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
528 574
529 CLabel label_global(a), label_ignorecase(a), label_multiline(a), 575 Label label_global(this), label_ignorecase(this), label_multiline(this),
530 label_unicode(a), label_sticky(a), out(a); 576 label_unicode(this), label_sticky(this), out(this);
531 577
532 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ 578 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \
533 do { \ 579 do { \
534 a->Bind(&LABEL); \ 580 Bind(&LABEL); \
535 Node* const mask = a->IntPtrConstant(FLAG); \ 581 Node* const mask = IntPtrConstant(FLAG); \
536 a->GotoIf(a->WordEqual(a->WordAnd(flags_intptr, mask), int_zero), \ 582 GotoIf(WordEqual(WordAnd(flags_intptr, mask), int_zero), &NEXT_LABEL); \
537 &NEXT_LABEL); \ 583 Node* const value = IntPtrConstant(CHAR); \
538 Node* const value = a->IntPtrConstant(CHAR); \ 584 StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \
539 a->StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ 585 var_offset.value(), value); \
540 var_offset.value(), value); \ 586 var_offset.Bind(IntPtrAdd(var_offset.value(), int_one)); \
541 var_offset.Bind(a->IntPtrAdd(var_offset.value(), int_one)); \ 587 Goto(&NEXT_LABEL); \
542 a->Goto(&NEXT_LABEL); \
543 } while (false) 588 } while (false)
544 589
545 a->Goto(&label_global); 590 Goto(&label_global);
546 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase); 591 CASE_FOR_FLAG(JSRegExp::kGlobal, 'g', label_global, label_ignorecase);
547 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase, 592 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, 'i', label_ignorecase,
548 label_multiline); 593 label_multiline);
549 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode); 594 CASE_FOR_FLAG(JSRegExp::kMultiline, 'm', label_multiline, label_unicode);
550 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky); 595 CASE_FOR_FLAG(JSRegExp::kUnicode, 'u', label_unicode, label_sticky);
551 CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out); 596 CASE_FOR_FLAG(JSRegExp::kSticky, 'y', label_sticky, out);
552 #undef CASE_FOR_FLAG 597 #undef CASE_FOR_FLAG
553 598
554 a->Bind(&out); 599 Bind(&out);
555 return result; 600 return result;
556 } 601 }
557 } 602 }
558 603
559 // ES#sec-isregexp IsRegExp ( argument ) 604 // ES#sec-isregexp IsRegExp ( argument )
560 Node* IsRegExp(CodeStubAssembler* a, Node* const context, 605 Node* RegExpBuiltinsAssembler::IsRegExp(Node* const context,
561 Node* const maybe_receiver) { 606 Node* const maybe_receiver) {
562 CLabel out(a), if_isregexp(a); 607 Label out(this), if_isregexp(this);
563 608
564 CVariable var_result(a, MachineType::PointerRepresentation()); 609 Variable var_result(this, MachineType::PointerRepresentation());
565 var_result.Bind(a->IntPtrConstant(0)); 610 var_result.Bind(IntPtrConstant(0));
566 611
567 a->GotoIf(a->TaggedIsSmi(maybe_receiver), &out); 612 GotoIf(TaggedIsSmi(maybe_receiver), &out);
568 a->GotoUnless(a->IsJSReceiver(maybe_receiver), &out); 613 GotoUnless(IsJSReceiver(maybe_receiver), &out);
569 614
570 Node* const receiver = maybe_receiver; 615 Node* const receiver = maybe_receiver;
571 616
572 // Check @@match. 617 // Check @@match.
573 { 618 {
574 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 619 Callable getproperty_callable = CodeFactory::GetProperty(isolate());
575 Node* const name = a->HeapConstant(a->isolate()->factory()->match_symbol()); 620 Node* const name = HeapConstant(isolate()->factory()->match_symbol());
576 Node* const value = 621 Node* const value = CallStub(getproperty_callable, context, receiver, name);
577 a->CallStub(getproperty_callable, context, receiver, name);
578 622
579 CLabel match_isundefined(a), match_isnotundefined(a); 623 Label match_isundefined(this), match_isnotundefined(this);
580 a->Branch(a->IsUndefined(value), &match_isundefined, &match_isnotundefined); 624 Branch(IsUndefined(value), &match_isundefined, &match_isnotundefined);
581 625
582 a->Bind(&match_isundefined); 626 Bind(&match_isundefined);
583 a->Branch(a->HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out); 627 Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isregexp, &out);
584 628
585 a->Bind(&match_isnotundefined); 629 Bind(&match_isnotundefined);
586 a->BranchIfToBooleanIsTrue(value, &if_isregexp, &out); 630 BranchIfToBooleanIsTrue(value, &if_isregexp, &out);
587 } 631 }
588 632
589 a->Bind(&if_isregexp); 633 Bind(&if_isregexp);
590 var_result.Bind(a->IntPtrConstant(1)); 634 var_result.Bind(IntPtrConstant(1));
591 a->Goto(&out); 635 Goto(&out);
592 636
593 a->Bind(&out); 637 Bind(&out);
594 return var_result.value(); 638 return var_result.value();
595 } 639 }
596 640
597 // ES#sec-regexpinitialize 641 // ES#sec-regexpinitialize
598 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags ) 642 // Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
599 Node* RegExpInitialize(CodeStubAssembler* a, Node* const context, 643 Node* RegExpBuiltinsAssembler::RegExpInitialize(Node* const context,
600 Node* const regexp, Node* const maybe_pattern, 644 Node* const regexp,
601 Node* const maybe_flags) { 645 Node* const maybe_pattern,
602 CVariable var_flags(a, MachineRepresentation::kTagged); 646 Node* const maybe_flags) {
603 CVariable var_pattern(a, MachineRepresentation::kTagged); 647 Variable var_flags(this, MachineRepresentation::kTagged);
648 Variable var_pattern(this, MachineRepresentation::kTagged);
604 649
605 // Normalize pattern. 650 // Normalize pattern.
606 { 651 {
607 CLabel next(a), if_isundefined(a), if_notundefined(a); 652 Label next(this), if_isundefined(this), if_notundefined(this);
608 a->Branch(a->IsUndefined(maybe_pattern), &if_isundefined, &if_notundefined); 653 Branch(IsUndefined(maybe_pattern), &if_isundefined, &if_notundefined);
609 654
610 a->Bind(&if_isundefined); 655 Bind(&if_isundefined);
611 { 656 {
612 var_pattern.Bind(a->EmptyStringConstant()); 657 var_pattern.Bind(EmptyStringConstant());
613 a->Goto(&next); 658 Goto(&next);
614 } 659 }
615 660
616 a->Bind(&if_notundefined); 661 Bind(&if_notundefined);
617 { 662 {
618 Node* const pattern = a->ToString(context, maybe_pattern); 663 Node* const pattern = ToString(context, maybe_pattern);
619 var_pattern.Bind(pattern); 664 var_pattern.Bind(pattern);
620 a->Goto(&next); 665 Goto(&next);
621 } 666 }
622 667
623 a->Bind(&next); 668 Bind(&next);
624 } 669 }
625 670
626 // Normalize flags. 671 // Normalize flags.
627 { 672 {
628 CLabel next(a), if_isundefined(a), if_notundefined(a); 673 Label next(this), if_isundefined(this), if_notundefined(this);
629 a->Branch(a->IsUndefined(maybe_flags), &if_isundefined, &if_notundefined); 674 Branch(IsUndefined(maybe_flags), &if_isundefined, &if_notundefined);
630 675
631 a->Bind(&if_isundefined); 676 Bind(&if_isundefined);
632 { 677 {
633 var_flags.Bind(a->EmptyStringConstant()); 678 var_flags.Bind(EmptyStringConstant());
634 a->Goto(&next); 679 Goto(&next);
635 } 680 }
636 681
637 a->Bind(&if_notundefined); 682 Bind(&if_notundefined);
638 { 683 {
639 Node* const flags = a->ToString(context, maybe_flags); 684 Node* const flags = ToString(context, maybe_flags);
640 var_flags.Bind(flags); 685 var_flags.Bind(flags);
641 a->Goto(&next); 686 Goto(&next);
642 } 687 }
643 688
644 a->Bind(&next); 689 Bind(&next);
645 } 690 }
646 691
647 // Initialize. 692 // Initialize.
648 693
649 { 694 {
650 Node* const result = 695 Node* const result =
651 a->CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp, 696 CallRuntime(Runtime::kRegExpInitializeAndCompile, context, regexp,
652 var_pattern.value(), var_flags.value()); 697 var_pattern.value(), var_flags.value());
653 return result; 698 return result;
654 } 699 }
655 } 700 }
656 701
657 } // namespace
658
659 TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) { 702 TF_BUILTIN(RegExpPrototypeFlagsGetter, RegExpBuiltinsAssembler) {
660 Isolate* isolate = this->isolate();
661
662 Node* const maybe_receiver = Parameter(0); 703 Node* const maybe_receiver = Parameter(0);
663 Node* const context = Parameter(3); 704 Node* const context = Parameter(3);
664 705
665 Node* const map = ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver, 706 Node* const map = ThrowIfNotJSReceiver(context, maybe_receiver,
666 MessageTemplate::kRegExpNonObject, 707 MessageTemplate::kRegExpNonObject,
667 "RegExp.prototype.flags"); 708 "RegExp.prototype.flags");
668 Node* const receiver = maybe_receiver; 709 Node* const receiver = maybe_receiver;
669 710
670 CLabel if_isfastpath(this), if_isslowpath(this, CLabel::kDeferred); 711 Label if_isfastpath(this), if_isslowpath(this, Label::kDeferred);
671 Branch(IsInitialRegExpMap(this, context, map), &if_isfastpath, 712 Branch(IsInitialRegExpMap(context, map), &if_isfastpath, &if_isslowpath);
672 &if_isslowpath);
673 713
674 Bind(&if_isfastpath); 714 Bind(&if_isfastpath);
675 Return(FlagsGetter(this, receiver, context, true)); 715 Return(FlagsGetter(context, receiver, true));
676 716
677 Bind(&if_isslowpath); 717 Bind(&if_isslowpath);
678 Return(FlagsGetter(this, receiver, context, false)); 718 Return(FlagsGetter(context, receiver, false));
679 } 719 }
680 720
681 // ES#sec-regexp-pattern-flags 721 // ES#sec-regexp-pattern-flags
682 // RegExp ( pattern, flags ) 722 // RegExp ( pattern, flags )
683 TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) { 723 TF_BUILTIN(RegExpConstructor, RegExpBuiltinsAssembler) {
684 Node* const pattern = Parameter(1); 724 Node* const pattern = Parameter(1);
685 Node* const flags = Parameter(2); 725 Node* const flags = Parameter(2);
686 Node* const new_target = Parameter(3); 726 Node* const new_target = Parameter(3);
687 Node* const context = Parameter(5); 727 Node* const context = Parameter(5);
688 728
689 Isolate* isolate = this->isolate(); 729 Isolate* isolate = this->isolate();
690 730
691 CVariable var_flags(this, MachineRepresentation::kTagged); 731 Variable var_flags(this, MachineRepresentation::kTagged);
692 CVariable var_pattern(this, MachineRepresentation::kTagged); 732 Variable var_pattern(this, MachineRepresentation::kTagged);
693 CVariable var_new_target(this, MachineRepresentation::kTagged); 733 Variable var_new_target(this, MachineRepresentation::kTagged);
694 734
695 var_flags.Bind(flags); 735 var_flags.Bind(flags);
696 var_pattern.Bind(pattern); 736 var_pattern.Bind(pattern);
697 var_new_target.Bind(new_target); 737 var_new_target.Bind(new_target);
698 738
699 Node* const native_context = LoadNativeContext(context); 739 Node* const native_context = LoadNativeContext(context);
700 Node* const regexp_function = 740 Node* const regexp_function =
701 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 741 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
702 742
703 Node* const pattern_is_regexp = IsRegExp(this, context, pattern); 743 Node* const pattern_is_regexp = IsRegExp(context, pattern);
704 744
705 { 745 {
706 CLabel next(this); 746 Label next(this);
707 747
708 GotoUnless(IsUndefined(new_target), &next); 748 GotoUnless(IsUndefined(new_target), &next);
709 var_new_target.Bind(regexp_function); 749 var_new_target.Bind(regexp_function);
710 750
711 GotoUnless(pattern_is_regexp, &next); 751 GotoUnless(pattern_is_regexp, &next);
712 GotoUnless(IsUndefined(flags), &next); 752 GotoUnless(IsUndefined(flags), &next);
713 753
714 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 754 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
715 Node* const name = HeapConstant(isolate->factory()->constructor_string()); 755 Node* const name = HeapConstant(isolate->factory()->constructor_string());
716 Node* const value = CallStub(getproperty_callable, context, pattern, name); 756 Node* const value = CallStub(getproperty_callable, context, pattern, name);
717 757
718 GotoUnless(WordEqual(value, regexp_function), &next); 758 GotoUnless(WordEqual(value, regexp_function), &next);
719 Return(pattern); 759 Return(pattern);
720 760
721 Bind(&next); 761 Bind(&next);
722 } 762 }
723 763
724 { 764 {
725 CLabel next(this), if_patternisfastregexp(this), 765 Label next(this), if_patternisfastregexp(this),
726 if_patternisslowregexp(this); 766 if_patternisslowregexp(this);
727 GotoIf(TaggedIsSmi(pattern), &next); 767 GotoIf(TaggedIsSmi(pattern), &next);
728 768
729 GotoIf(HasInstanceType(pattern, JS_REGEXP_TYPE), &if_patternisfastregexp); 769 GotoIf(HasInstanceType(pattern, JS_REGEXP_TYPE), &if_patternisfastregexp);
730 770
731 Branch(pattern_is_regexp, &if_patternisslowregexp, &next); 771 Branch(pattern_is_regexp, &if_patternisslowregexp, &next);
732 772
733 Bind(&if_patternisfastregexp); 773 Bind(&if_patternisfastregexp);
734 { 774 {
735 Node* const source = LoadObjectField(pattern, JSRegExp::kSourceOffset); 775 Node* const source = LoadObjectField(pattern, JSRegExp::kSourceOffset);
736 var_pattern.Bind(source); 776 var_pattern.Bind(source);
737 777
738 { 778 {
739 CLabel inner_next(this); 779 Label inner_next(this);
740 GotoUnless(IsUndefined(flags), &inner_next); 780 GotoUnless(IsUndefined(flags), &inner_next);
741 781
742 Node* const value = FlagsGetter(this, pattern, context, true); 782 Node* const value = FlagsGetter(context, pattern, true);
743 var_flags.Bind(value); 783 var_flags.Bind(value);
744 Goto(&inner_next); 784 Goto(&inner_next);
745 785
746 Bind(&inner_next); 786 Bind(&inner_next);
747 } 787 }
748 788
749 Goto(&next); 789 Goto(&next);
750 } 790 }
751 791
752 Bind(&if_patternisslowregexp); 792 Bind(&if_patternisslowregexp);
753 { 793 {
754 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 794 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
755 795
756 { 796 {
757 Node* const name = HeapConstant(isolate->factory()->source_string()); 797 Node* const name = HeapConstant(isolate->factory()->source_string());
758 Node* const value = 798 Node* const value =
759 CallStub(getproperty_callable, context, pattern, name); 799 CallStub(getproperty_callable, context, pattern, name);
760 var_pattern.Bind(value); 800 var_pattern.Bind(value);
761 } 801 }
762 802
763 { 803 {
764 CLabel inner_next(this); 804 Label inner_next(this);
765 GotoUnless(IsUndefined(flags), &inner_next); 805 GotoUnless(IsUndefined(flags), &inner_next);
766 806
767 Node* const name = HeapConstant(isolate->factory()->flags_string()); 807 Node* const name = HeapConstant(isolate->factory()->flags_string());
768 Node* const value = 808 Node* const value =
769 CallStub(getproperty_callable, context, pattern, name); 809 CallStub(getproperty_callable, context, pattern, name);
770 var_flags.Bind(value); 810 var_flags.Bind(value);
771 Goto(&inner_next); 811 Goto(&inner_next);
772 812
773 Bind(&inner_next); 813 Bind(&inner_next);
774 } 814 }
775 815
776 Goto(&next); 816 Goto(&next);
777 } 817 }
778 818
779 Bind(&next); 819 Bind(&next);
780 } 820 }
781 821
782 // Allocate. 822 // Allocate.
783 823
784 CVariable var_regexp(this, MachineRepresentation::kTagged); 824 Variable var_regexp(this, MachineRepresentation::kTagged);
785 { 825 {
786 CLabel allocate_jsregexp(this), allocate_generic(this, CLabel::kDeferred), 826 Label allocate_jsregexp(this), allocate_generic(this, Label::kDeferred),
787 next(this); 827 next(this);
788 Branch(WordEqual(var_new_target.value(), regexp_function), 828 Branch(WordEqual(var_new_target.value(), regexp_function),
789 &allocate_jsregexp, &allocate_generic); 829 &allocate_jsregexp, &allocate_generic);
790 830
791 Bind(&allocate_jsregexp); 831 Bind(&allocate_jsregexp);
792 { 832 {
793 Node* const initial_map = LoadObjectField( 833 Node* const initial_map = LoadObjectField(
794 regexp_function, JSFunction::kPrototypeOrInitialMapOffset); 834 regexp_function, JSFunction::kPrototypeOrInitialMapOffset);
795 Node* const regexp = AllocateJSObjectFromMap(initial_map); 835 Node* const regexp = AllocateJSObjectFromMap(initial_map);
796 var_regexp.Bind(regexp); 836 var_regexp.Bind(regexp);
797 Goto(&next); 837 Goto(&next);
798 } 838 }
799 839
800 Bind(&allocate_generic); 840 Bind(&allocate_generic);
801 { 841 {
802 Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate); 842 Callable fastnewobject_callable = CodeFactory::FastNewObject(isolate);
803 Node* const regexp = CallStub(fastnewobject_callable, context, 843 Node* const regexp = CallStub(fastnewobject_callable, context,
804 regexp_function, var_new_target.value()); 844 regexp_function, var_new_target.value());
805 var_regexp.Bind(regexp); 845 var_regexp.Bind(regexp);
806 Goto(&next); 846 Goto(&next);
807 } 847 }
808 848
809 Bind(&next); 849 Bind(&next);
810 } 850 }
811 851
812 Node* const result = RegExpInitialize(this, context, var_regexp.value(), 852 Node* const result = RegExpInitialize(context, var_regexp.value(),
813 var_pattern.value(), var_flags.value()); 853 var_pattern.value(), var_flags.value());
814 Return(result); 854 Return(result);
815 } 855 }
816 856
817 // ES#sec-regexp.prototype.compile 857 // ES#sec-regexp.prototype.compile
818 // RegExp.prototype.compile ( pattern, flags ) 858 // RegExp.prototype.compile ( pattern, flags )
819 TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) { 859 TF_BUILTIN(RegExpPrototypeCompile, RegExpBuiltinsAssembler) {
820 Node* const maybe_receiver = Parameter(0); 860 Node* const maybe_receiver = Parameter(0);
821 Node* const maybe_pattern = Parameter(1); 861 Node* const maybe_pattern = Parameter(1);
822 Node* const maybe_flags = Parameter(2); 862 Node* const maybe_flags = Parameter(2);
823 Node* const context = Parameter(5); 863 Node* const context = Parameter(5);
824 864
825 ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE, 865 ThrowIfNotInstanceType(context, maybe_receiver, JS_REGEXP_TYPE,
826 "RegExp.prototype.compile"); 866 "RegExp.prototype.compile");
827 Node* const receiver = maybe_receiver; 867 Node* const receiver = maybe_receiver;
828 868
829 CVariable var_flags(this, MachineRepresentation::kTagged); 869 Variable var_flags(this, MachineRepresentation::kTagged);
830 CVariable var_pattern(this, MachineRepresentation::kTagged); 870 Variable var_pattern(this, MachineRepresentation::kTagged);
831 871
832 var_flags.Bind(maybe_flags); 872 var_flags.Bind(maybe_flags);
833 var_pattern.Bind(maybe_pattern); 873 var_pattern.Bind(maybe_pattern);
834 874
835 // Handle a JSRegExp pattern. 875 // Handle a JSRegExp pattern.
836 { 876 {
837 CLabel next(this); 877 Label next(this);
838 878
839 GotoIf(TaggedIsSmi(maybe_pattern), &next); 879 GotoIf(TaggedIsSmi(maybe_pattern), &next);
840 GotoUnless(HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next); 880 GotoUnless(HasInstanceType(maybe_pattern, JS_REGEXP_TYPE), &next);
841 881
842 Node* const pattern = maybe_pattern; 882 Node* const pattern = maybe_pattern;
843 883
844 // {maybe_flags} must be undefined in this case, otherwise throw. 884 // {maybe_flags} must be undefined in this case, otherwise throw.
845 { 885 {
846 CLabel next(this); 886 Label next(this);
847 GotoIf(IsUndefined(maybe_flags), &next); 887 GotoIf(IsUndefined(maybe_flags), &next);
848 888
849 Node* const message_id = SmiConstant(MessageTemplate::kRegExpFlags); 889 Node* const message_id = SmiConstant(MessageTemplate::kRegExpFlags);
850 TailCallRuntime(Runtime::kThrowTypeError, context, message_id); 890 TailCallRuntime(Runtime::kThrowTypeError, context, message_id);
851 891
852 Bind(&next); 892 Bind(&next);
853 } 893 }
854 894
855 Node* const new_flags = FlagsGetter(this, pattern, context, true); 895 Node* const new_flags = FlagsGetter(context, pattern, true);
856 Node* const new_pattern = LoadObjectField(pattern, JSRegExp::kSourceOffset); 896 Node* const new_pattern = LoadObjectField(pattern, JSRegExp::kSourceOffset);
857 897
858 var_flags.Bind(new_flags); 898 var_flags.Bind(new_flags);
859 var_pattern.Bind(new_pattern); 899 var_pattern.Bind(new_pattern);
860 900
861 Goto(&next); 901 Goto(&next);
862 Bind(&next); 902 Bind(&next);
863 } 903 }
864 904
865 RegExpInitialize(this, context, receiver, var_pattern.value(), 905 RegExpInitialize(context, receiver, var_pattern.value(), var_flags.value());
866 var_flags.value());
867 906
868 // Return undefined for compatibility with JSC. 907 // Return undefined for compatibility with JSC.
869 // See http://crbug.com/585775 for web compat details. 908 // See http://crbug.com/585775 for web compat details.
870 909
871 Return(UndefinedConstant()); 910 Return(UndefinedConstant());
872 } 911 }
873 912
874 // ES6 21.2.5.10. 913 // ES6 21.2.5.10.
875 TF_BUILTIN(RegExpPrototypeSourceGetter, RegExpBuiltinsAssembler) { 914 TF_BUILTIN(RegExpPrototypeSourceGetter, RegExpBuiltinsAssembler) {
876 Node* const receiver = Parameter(0); 915 Node* const receiver = Parameter(0);
877 Node* const context = Parameter(3); 916 Node* const context = Parameter(3);
878 917
879 // Check whether we have an unmodified regexp instance. 918 // Check whether we have an unmodified regexp instance.
880 CLabel if_isjsregexp(this), if_isnotjsregexp(this, CLabel::kDeferred); 919 Label if_isjsregexp(this), if_isnotjsregexp(this, Label::kDeferred);
881 920
882 GotoIf(TaggedIsSmi(receiver), &if_isnotjsregexp); 921 GotoIf(TaggedIsSmi(receiver), &if_isnotjsregexp);
883 Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isjsregexp, 922 Branch(HasInstanceType(receiver, JS_REGEXP_TYPE), &if_isjsregexp,
884 &if_isnotjsregexp); 923 &if_isnotjsregexp);
885 924
886 Bind(&if_isjsregexp); 925 Bind(&if_isjsregexp);
887 { 926 {
888 Node* const source = LoadObjectField(receiver, JSRegExp::kSourceOffset); 927 Node* const source = LoadObjectField(receiver, JSRegExp::kSourceOffset);
889 Return(source); 928 Return(source);
890 } 929 }
891 930
892 Bind(&if_isnotjsregexp); 931 Bind(&if_isnotjsregexp);
893 { 932 {
894 Isolate* isolate = this->isolate(); 933 Isolate* isolate = this->isolate();
895 Node* const native_context = LoadNativeContext(context); 934 Node* const native_context = LoadNativeContext(context);
896 Node* const regexp_fun = 935 Node* const regexp_fun =
897 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 936 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
898 Node* const initial_map = 937 Node* const initial_map =
899 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 938 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
900 Node* const initial_prototype = LoadMapPrototype(initial_map); 939 Node* const initial_prototype = LoadMapPrototype(initial_map);
901 940
902 CLabel if_isprototype(this), if_isnotprototype(this); 941 Label if_isprototype(this), if_isnotprototype(this);
903 Branch(WordEqual(receiver, initial_prototype), &if_isprototype, 942 Branch(WordEqual(receiver, initial_prototype), &if_isprototype,
904 &if_isnotprototype); 943 &if_isnotprototype);
905 944
906 Bind(&if_isprototype); 945 Bind(&if_isprototype);
907 { 946 {
908 const int counter = v8::Isolate::kRegExpPrototypeSourceGetter; 947 const int counter = v8::Isolate::kRegExpPrototypeSourceGetter;
909 Node* const counter_smi = SmiConstant(counter); 948 Node* const counter_smi = SmiConstant(counter);
910 CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); 949 CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
911 950
912 Node* const result = 951 Node* const result =
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
963 1002
964 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish()); 1003 RETURN_RESULT_OR_FAILURE(isolate, builder.Finish());
965 } 1004 }
966 1005
967 // ES6 21.2.4.2. 1006 // ES6 21.2.4.2.
968 TF_BUILTIN(RegExpPrototypeSpeciesGetter, RegExpBuiltinsAssembler) { 1007 TF_BUILTIN(RegExpPrototypeSpeciesGetter, RegExpBuiltinsAssembler) {
969 Node* const receiver = Parameter(0); 1008 Node* const receiver = Parameter(0);
970 Return(receiver); 1009 Return(receiver);
971 } 1010 }
972 1011
973 namespace {
974
975 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. 1012 // Fast-path implementation for flag checks on an unmodified JSRegExp instance.
976 Node* FastFlagGetter(CodeStubAssembler* a, Node* const regexp, 1013 Node* RegExpBuiltinsAssembler::FastFlagGetter(Node* const regexp,
977 JSRegExp::Flag flag) { 1014 JSRegExp::Flag flag) {
978 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1015 Node* const smi_zero = SmiConstant(Smi::kZero);
979 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 1016 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
980 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); 1017 Node* const mask = SmiConstant(Smi::FromInt(flag));
981 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); 1018 Node* const is_flag_set = WordNotEqual(WordAnd(flags, mask), smi_zero);
982 1019
983 return is_flag_set; 1020 return is_flag_set;
984 } 1021 }
985 1022
986 // Load through the GetProperty stub. 1023 // Load through the GetProperty stub.
987 compiler::Node* SlowFlagGetter(CodeStubAssembler* a, 1024 Node* RegExpBuiltinsAssembler::SlowFlagGetter(Node* const context,
988 compiler::Node* const context, 1025 Node* const regexp,
989 compiler::Node* const regexp, 1026 JSRegExp::Flag flag) {
990 JSRegExp::Flag flag) { 1027 Factory* factory = isolate()->factory();
991 Factory* factory = a->isolate()->factory();
992 1028
993 CLabel out(a); 1029 Label out(this);
994 CVariable var_result(a, MachineType::PointerRepresentation()); 1030 Variable var_result(this, MachineType::PointerRepresentation());
995 1031
996 Node* name; 1032 Node* name;
997 1033
998 switch (flag) { 1034 switch (flag) {
999 case JSRegExp::kGlobal: 1035 case JSRegExp::kGlobal:
1000 name = a->HeapConstant(factory->global_string()); 1036 name = HeapConstant(factory->global_string());
1001 break; 1037 break;
1002 case JSRegExp::kIgnoreCase: 1038 case JSRegExp::kIgnoreCase:
1003 name = a->HeapConstant(factory->ignoreCase_string()); 1039 name = HeapConstant(factory->ignoreCase_string());
1004 break; 1040 break;
1005 case JSRegExp::kMultiline: 1041 case JSRegExp::kMultiline:
1006 name = a->HeapConstant(factory->multiline_string()); 1042 name = HeapConstant(factory->multiline_string());
1007 break; 1043 break;
1008 case JSRegExp::kSticky: 1044 case JSRegExp::kSticky:
1009 name = a->HeapConstant(factory->sticky_string()); 1045 name = HeapConstant(factory->sticky_string());
1010 break; 1046 break;
1011 case JSRegExp::kUnicode: 1047 case JSRegExp::kUnicode:
1012 name = a->HeapConstant(factory->unicode_string()); 1048 name = HeapConstant(factory->unicode_string());
1013 break; 1049 break;
1014 default: 1050 default:
1015 UNREACHABLE(); 1051 UNREACHABLE();
1016 } 1052 }
1017 1053
1018 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 1054 Callable getproperty_callable = CodeFactory::GetProperty(isolate());
1019 Node* const value = a->CallStub(getproperty_callable, context, regexp, name); 1055 Node* const value = CallStub(getproperty_callable, context, regexp, name);
1020 1056
1021 CLabel if_true(a), if_false(a); 1057 Label if_true(this), if_false(this);
1022 a->BranchIfToBooleanIsTrue(value, &if_true, &if_false); 1058 BranchIfToBooleanIsTrue(value, &if_true, &if_false);
1023 1059
1024 a->Bind(&if_true); 1060 Bind(&if_true);
1025 { 1061 {
1026 var_result.Bind(a->IntPtrConstant(1)); 1062 var_result.Bind(IntPtrConstant(1));
1027 a->Goto(&out); 1063 Goto(&out);
1028 } 1064 }
1029 1065
1030 a->Bind(&if_false); 1066 Bind(&if_false);
1031 { 1067 {
1032 var_result.Bind(a->IntPtrConstant(0)); 1068 var_result.Bind(IntPtrConstant(0));
1033 a->Goto(&out); 1069 Goto(&out);
1034 } 1070 }
1035 1071
1036 a->Bind(&out); 1072 Bind(&out);
1037 return var_result.value(); 1073 return var_result.value();
1038 } 1074 }
1039 1075
1040 compiler::Node* FlagGetter(CodeStubAssembler* a, compiler::Node* const context, 1076 Node* RegExpBuiltinsAssembler::FlagGetter(Node* const context,
1041 compiler::Node* const regexp, JSRegExp::Flag flag, 1077 Node* const regexp,
1042 bool is_fastpath) { 1078 JSRegExp::Flag flag,
1043 return is_fastpath ? FastFlagGetter(a, regexp, flag) 1079 bool is_fastpath) {
1044 : SlowFlagGetter(a, context, regexp, flag); 1080 return is_fastpath ? FastFlagGetter(regexp, flag)
1081 : SlowFlagGetter(context, regexp, flag);
1045 } 1082 }
1046 1083
1047 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, 1084 void RegExpBuiltinsAssembler::FlagGetter(JSRegExp::Flag flag,
1048 v8::Isolate::UseCounterFeature counter, 1085 v8::Isolate::UseCounterFeature counter,
1049 const char* method_name) { 1086 const char* method_name) {
1050 Node* const receiver = a->Parameter(0); 1087 Node* const receiver = Parameter(0);
1051 Node* const context = a->Parameter(3); 1088 Node* const context = Parameter(3);
1052 1089
1053 Isolate* isolate = a->isolate(); 1090 Isolate* isolate = this->isolate();
1054 1091
1055 // Check whether we have an unmodified regexp instance. 1092 // Check whether we have an unmodified regexp instance.
1056 CLabel if_isunmodifiedjsregexp(a), 1093 Label if_isunmodifiedjsregexp(this),
1057 if_isnotunmodifiedjsregexp(a, CLabel::kDeferred); 1094 if_isnotunmodifiedjsregexp(this, Label::kDeferred);
1058 1095
1059 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); 1096 GotoIf(TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp);
1060 1097
1061 Node* const receiver_map = a->LoadMap(receiver); 1098 Node* const receiver_map = LoadMap(receiver);
1062 Node* const instance_type = a->LoadMapInstanceType(receiver_map); 1099 Node* const instance_type = LoadMapInstanceType(receiver_map);
1063 1100
1064 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), 1101 Branch(Word32Equal(instance_type, Int32Constant(JS_REGEXP_TYPE)),
1065 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); 1102 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp);
1066 1103
1067 a->Bind(&if_isunmodifiedjsregexp); 1104 Bind(&if_isunmodifiedjsregexp);
1068 { 1105 {
1069 // Refer to JSRegExp's flag property on the fast-path. 1106 // Refer to JSRegExp's flag property on the fast-path.
1070 Node* const is_flag_set = FastFlagGetter(a, receiver, flag); 1107 Node* const is_flag_set = FastFlagGetter(receiver, flag);
1071 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant())); 1108 Return(Select(is_flag_set, TrueConstant(), FalseConstant()));
1072 } 1109 }
1073 1110
1074 a->Bind(&if_isnotunmodifiedjsregexp); 1111 Bind(&if_isnotunmodifiedjsregexp);
1075 { 1112 {
1076 Node* const native_context = a->LoadNativeContext(context); 1113 Node* const native_context = LoadNativeContext(context);
1077 Node* const regexp_fun = 1114 Node* const regexp_fun =
1078 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 1115 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
1079 Node* const initial_map = a->LoadObjectField( 1116 Node* const initial_map =
1080 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 1117 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
1081 Node* const initial_prototype = a->LoadMapPrototype(initial_map); 1118 Node* const initial_prototype = LoadMapPrototype(initial_map);
1082 1119
1083 CLabel if_isprototype(a), if_isnotprototype(a); 1120 Label if_isprototype(this), if_isnotprototype(this);
1084 a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype, 1121 Branch(WordEqual(receiver, initial_prototype), &if_isprototype,
1085 &if_isnotprototype); 1122 &if_isnotprototype);
1086 1123
1087 a->Bind(&if_isprototype); 1124 Bind(&if_isprototype);
1088 { 1125 {
1089 Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter)); 1126 Node* const counter_smi = SmiConstant(Smi::FromInt(counter));
1090 a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); 1127 CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi);
1091 a->Return(a->UndefinedConstant()); 1128 Return(UndefinedConstant());
1092 } 1129 }
1093 1130
1094 a->Bind(&if_isnotprototype); 1131 Bind(&if_isnotprototype);
1095 { 1132 {
1096 Node* const message_id = 1133 Node* const message_id =
1097 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); 1134 SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp));
1098 Node* const method_name_str = a->HeapConstant( 1135 Node* const method_name_str = HeapConstant(
1099 isolate->factory()->NewStringFromAsciiChecked(method_name)); 1136 isolate->factory()->NewStringFromAsciiChecked(method_name));
1100 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, 1137 CallRuntime(Runtime::kThrowTypeError, context, message_id,
1101 method_name_str); 1138 method_name_str);
1102 a->Return(a->UndefinedConstant()); // Never reached. 1139 Return(UndefinedConstant()); // Never reached.
1103 } 1140 }
1104 } 1141 }
1105 } 1142 }
1106 1143
1107 } // namespace
1108
1109 // ES6 21.2.5.4. 1144 // ES6 21.2.5.4.
1110 TF_BUILTIN(RegExpPrototypeGlobalGetter, RegExpBuiltinsAssembler) { 1145 TF_BUILTIN(RegExpPrototypeGlobalGetter, RegExpBuiltinsAssembler) {
1111 Generate_FlagGetter(this, JSRegExp::kGlobal, 1146 FlagGetter(JSRegExp::kGlobal, v8::Isolate::kRegExpPrototypeOldFlagGetter,
1112 v8::Isolate::kRegExpPrototypeOldFlagGetter, 1147 "RegExp.prototype.global");
1113 "RegExp.prototype.global");
1114 } 1148 }
1115 1149
1116 // ES6 21.2.5.5. 1150 // ES6 21.2.5.5.
1117 TF_BUILTIN(RegExpPrototypeIgnoreCaseGetter, RegExpBuiltinsAssembler) { 1151 TF_BUILTIN(RegExpPrototypeIgnoreCaseGetter, RegExpBuiltinsAssembler) {
1118 Generate_FlagGetter(this, JSRegExp::kIgnoreCase, 1152 FlagGetter(JSRegExp::kIgnoreCase, v8::Isolate::kRegExpPrototypeOldFlagGetter,
1119 v8::Isolate::kRegExpPrototypeOldFlagGetter, 1153 "RegExp.prototype.ignoreCase");
1120 "RegExp.prototype.ignoreCase");
1121 } 1154 }
1122 1155
1123 // ES6 21.2.5.7. 1156 // ES6 21.2.5.7.
1124 TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) { 1157 TF_BUILTIN(RegExpPrototypeMultilineGetter, RegExpBuiltinsAssembler) {
1125 Generate_FlagGetter(this, JSRegExp::kMultiline, 1158 FlagGetter(JSRegExp::kMultiline, v8::Isolate::kRegExpPrototypeOldFlagGetter,
1126 v8::Isolate::kRegExpPrototypeOldFlagGetter, 1159 "RegExp.prototype.multiline");
1127 "RegExp.prototype.multiline");
1128 } 1160 }
1129 1161
1130 // ES6 21.2.5.12. 1162 // ES6 21.2.5.12.
1131 TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) { 1163 TF_BUILTIN(RegExpPrototypeStickyGetter, RegExpBuiltinsAssembler) {
1132 Generate_FlagGetter(this, JSRegExp::kSticky, 1164 FlagGetter(JSRegExp::kSticky, v8::Isolate::kRegExpPrototypeStickyGetter,
1133 v8::Isolate::kRegExpPrototypeStickyGetter, 1165 "RegExp.prototype.sticky");
1134 "RegExp.prototype.sticky");
1135 } 1166 }
1136 1167
1137 // ES6 21.2.5.15. 1168 // ES6 21.2.5.15.
1138 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) { 1169 TF_BUILTIN(RegExpPrototypeUnicodeGetter, RegExpBuiltinsAssembler) {
1139 Generate_FlagGetter(this, JSRegExp::kUnicode, 1170 FlagGetter(JSRegExp::kUnicode, v8::Isolate::kRegExpPrototypeUnicodeGetter,
1140 v8::Isolate::kRegExpPrototypeUnicodeGetter, 1171 "RegExp.prototype.unicode");
1141 "RegExp.prototype.unicode");
1142 } 1172 }
1143 1173
1144 // The properties $1..$9 are the first nine capturing substrings of the last 1174 // The properties $1..$9 are the first nine capturing substrings of the last
1145 // successful match, or ''. The function RegExpMakeCaptureGetter will be 1175 // successful match, or ''. The function RegExpMakeCaptureGetter will be
1146 // called with indices from 1 to 9. 1176 // called with indices from 1 to 9.
1147 #define DEFINE_CAPTURE_GETTER(i) \ 1177 #define DEFINE_CAPTURE_GETTER(i) \
1148 BUILTIN(RegExpCapture##i##Getter) { \ 1178 BUILTIN(RegExpCapture##i##Getter) { \
1149 HandleScope scope(isolate); \ 1179 HandleScope scope(isolate); \
1150 return *RegExpUtils::GenericCaptureGetter( \ 1180 return *RegExpUtils::GenericCaptureGetter( \
1151 isolate, isolate->regexp_last_match_info(), i); \ 1181 isolate, isolate->regexp_last_match_info(), i); \
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 1247
1218 BUILTIN(RegExpRightContextGetter) { 1248 BUILTIN(RegExpRightContextGetter) {
1219 HandleScope scope(isolate); 1249 HandleScope scope(isolate);
1220 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); 1250 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info();
1221 const int start_index = match_info->Capture(1); 1251 const int start_index = match_info->Capture(1);
1222 Handle<String> last_subject(match_info->LastSubject()); 1252 Handle<String> last_subject(match_info->LastSubject());
1223 const int len = last_subject->length(); 1253 const int len = last_subject->length();
1224 return *isolate->factory()->NewSubString(last_subject, start_index, len); 1254 return *isolate->factory()->NewSubString(last_subject, start_index, len);
1225 } 1255 }
1226 1256
1227 namespace { 1257 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
1258 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
1259 Node* string) {
1260 Isolate* isolate = this->isolate();
1228 1261
1229 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) 1262 Node* const null = NullConstant();
1230 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv,
1231 Node* string) {
1232 Isolate* isolate = a->isolate();
1233 1263
1234 Node* const null = a->NullConstant(); 1264 Variable var_result(this, MachineRepresentation::kTagged);
1265 Label out(this), if_isfastpath(this), if_isslowpath(this);
1235 1266
1236 CVariable var_result(a, MachineRepresentation::kTagged); 1267 Node* const map = LoadMap(regexp);
1237 CLabel out(a), if_isfastpath(a), if_isslowpath(a); 1268 BranchIfFastRegExp(context, map, &if_isfastpath, &if_isslowpath);
1238 1269
1239 Node* const map = a->LoadMap(recv); 1270 Bind(&if_isfastpath);
1240 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath);
1241
1242 a->Bind(&if_isfastpath);
1243 { 1271 {
1244 Node* const result = 1272 Node* const result = RegExpPrototypeExecBody(context, regexp, string, true);
1245 RegExpPrototypeExecBody(a, context, recv, string, true);
1246 var_result.Bind(result); 1273 var_result.Bind(result);
1247 a->Goto(&out); 1274 Goto(&out);
1248 } 1275 }
1249 1276
1250 a->Bind(&if_isslowpath); 1277 Bind(&if_isslowpath);
1251 { 1278 {
1252 // Take the slow path of fetching the exec property, calling it, and 1279 // Take the slow path of fetching the exec property, calling it, and
1253 // verifying its return value. 1280 // verifying its return value.
1254 1281
1255 // Get the exec property. 1282 // Get the exec property.
1256 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); 1283 Node* const name = HeapConstant(isolate->factory()->exec_string());
1257 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 1284 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1258 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); 1285 Node* const exec = CallStub(getproperty_callable, context, regexp, name);
1259 1286
1260 // Is {exec} callable? 1287 // Is {exec} callable?
1261 CLabel if_iscallable(a), if_isnotcallable(a); 1288 Label if_iscallable(this), if_isnotcallable(this);
1262 1289
1263 a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable); 1290 GotoIf(TaggedIsSmi(exec), &if_isnotcallable);
1264 1291
1265 Node* const exec_map = a->LoadMap(exec); 1292 Node* const exec_map = LoadMap(exec);
1266 a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); 1293 Branch(IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable);
1267 1294
1268 a->Bind(&if_iscallable); 1295 Bind(&if_iscallable);
1269 { 1296 {
1270 Callable call_callable = CodeFactory::Call(isolate); 1297 Callable call_callable = CodeFactory::Call(isolate);
1271 Node* const result = 1298 Node* const result = CallJS(call_callable, context, exec, regexp, string);
1272 a->CallJS(call_callable, context, exec, recv, string);
1273 1299
1274 var_result.Bind(result); 1300 var_result.Bind(result);
1275 a->GotoIf(a->WordEqual(result, null), &out); 1301 GotoIf(WordEqual(result, null), &out);
1276 1302
1277 ThrowIfNotJSReceiver(a, isolate, context, result, 1303 ThrowIfNotJSReceiver(context, result,
1278 MessageTemplate::kInvalidRegExpExecResult, "unused"); 1304 MessageTemplate::kInvalidRegExpExecResult, "unused");
1279 1305
1280 a->Goto(&out); 1306 Goto(&out);
1281 } 1307 }
1282 1308
1283 a->Bind(&if_isnotcallable); 1309 Bind(&if_isnotcallable);
1284 { 1310 {
1285 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, 1311 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
1286 "RegExp.prototype.exec"); 1312 "RegExp.prototype.exec");
1287 1313
1288 Node* const result = 1314 Node* const result =
1289 RegExpPrototypeExecBody(a, context, recv, string, false); 1315 RegExpPrototypeExecBody(context, regexp, string, false);
1290 var_result.Bind(result); 1316 var_result.Bind(result);
1291 a->Goto(&out); 1317 Goto(&out);
1292 } 1318 }
1293 } 1319 }
1294 1320
1295 a->Bind(&out); 1321 Bind(&out);
1296 return var_result.value(); 1322 return var_result.value();
1297 } 1323 }
1298 1324
1299 } // namespace
1300
1301 // ES#sec-regexp.prototype.test 1325 // ES#sec-regexp.prototype.test
1302 // RegExp.prototype.test ( S ) 1326 // RegExp.prototype.test ( S )
1303 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) { 1327 TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
1304 Isolate* const isolate = this->isolate();
1305
1306 Node* const maybe_receiver = Parameter(0); 1328 Node* const maybe_receiver = Parameter(0);
1307 Node* const maybe_string = Parameter(1); 1329 Node* const maybe_string = Parameter(1);
1308 Node* const context = Parameter(4); 1330 Node* const context = Parameter(4);
1309 1331
1310 // Ensure {maybe_receiver} is a JSReceiver. 1332 // Ensure {maybe_receiver} is a JSReceiver.
1311 Node* const map = ThrowIfNotJSReceiver( 1333 Node* const map = ThrowIfNotJSReceiver(
1312 this, isolate, context, maybe_receiver, 1334 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1313 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.test"); 1335 "RegExp.prototype.test");
1314 Node* const receiver = maybe_receiver; 1336 Node* const receiver = maybe_receiver;
1315 1337
1316 // Convert {maybe_string} to a String. 1338 // Convert {maybe_string} to a String.
1317 Node* const string = ToString(context, maybe_string); 1339 Node* const string = ToString(context, maybe_string);
1318 1340
1319 CLabel fast_path(this), slow_path(this); 1341 Label fast_path(this), slow_path(this);
1320 BranchIfFastPath(this, context, map, &fast_path, &slow_path); 1342 BranchIfFastRegExp(context, map, &fast_path, &slow_path);
1321 1343
1322 Bind(&fast_path); 1344 Bind(&fast_path);
1323 { 1345 {
1324 CLabel if_didnotmatch(this); 1346 Label if_didnotmatch(this);
1325 RegExpPrototypeExecBodyWithoutResult(this, context, receiver, string, 1347 RegExpPrototypeExecBodyWithoutResult(context, receiver, string,
1326 &if_didnotmatch, true); 1348 &if_didnotmatch, true);
1327 Return(TrueConstant()); 1349 Return(TrueConstant());
1328 1350
1329 Bind(&if_didnotmatch); 1351 Bind(&if_didnotmatch);
1330 Return(FalseConstant()); 1352 Return(FalseConstant());
1331 } 1353 }
1332 1354
1333 Bind(&slow_path); 1355 Bind(&slow_path);
1334 { 1356 {
1335 // Call exec. 1357 // Call exec.
1336 Node* const match_indices = RegExpExec(this, context, receiver, string); 1358 Node* const match_indices = RegExpExec(context, receiver, string);
1337 1359
1338 // Return true iff exec matched successfully. 1360 // Return true iff exec matched successfully.
1339 Node* const result = Select(WordEqual(match_indices, NullConstant()), 1361 Node* const result = Select(WordEqual(match_indices, NullConstant()),
1340 FalseConstant(), TrueConstant()); 1362 FalseConstant(), TrueConstant());
1341 Return(result); 1363 Return(result);
1342 } 1364 }
1343 } 1365 }
1344 1366
1367 Node* RegExpBuiltinsAssembler::AdvanceStringIndex(Node* const string,
1368 Node* const index,
1369 Node* const is_unicode) {
1370 Variable var_result(this, MachineRepresentation::kTagged);
1371
1372 // Default to last_index + 1.
1373 Node* const index_plus_one = SmiAdd(index, SmiConstant(1));
1374 var_result.Bind(index_plus_one);
1375
1376 Label if_isunicode(this), out(this);
1377 Branch(is_unicode, &if_isunicode, &out);
1378
1379 Bind(&if_isunicode);
1380 {
1381 Node* const string_length = LoadStringLength(string);
1382 GotoUnless(SmiLessThan(index_plus_one, string_length), &out);
1383
1384 Node* const lead = StringCharCodeAt(string, index);
1385 GotoUnless(Word32Equal(Word32And(lead, Int32Constant(0xFC00)),
1386 Int32Constant(0xD800)),
1387 &out);
1388
1389 Node* const trail = StringCharCodeAt(string, index_plus_one);
1390 GotoUnless(Word32Equal(Word32And(trail, Int32Constant(0xFC00)),
1391 Int32Constant(0xDC00)),
1392 &out);
1393
1394 // At a surrogate pair, return index + 2.
1395 Node* const index_plus_two = SmiAdd(index, SmiConstant(2));
1396 var_result.Bind(index_plus_two);
1397
1398 Goto(&out);
1399 }
1400
1401 Bind(&out);
1402 return var_result.value();
1403 }
1404
1345 namespace { 1405 namespace {
1346 1406
1347 Node* AdvanceStringIndex(CodeStubAssembler* a, Node* const string,
1348 Node* const index, Node* const is_unicode) {
1349 CVariable var_result(a, MachineRepresentation::kTagged);
1350
1351 // Default to last_index + 1.
1352 Node* const index_plus_one = a->SmiAdd(index, a->SmiConstant(1));
1353 var_result.Bind(index_plus_one);
1354
1355 CLabel if_isunicode(a), out(a);
1356 a->Branch(is_unicode, &if_isunicode, &out);
1357
1358 a->Bind(&if_isunicode);
1359 {
1360 Node* const string_length = a->LoadStringLength(string);
1361 a->GotoUnless(a->SmiLessThan(index_plus_one, string_length), &out);
1362
1363 Node* const lead = a->StringCharCodeAt(string, index);
1364 a->GotoUnless(a->Word32Equal(a->Word32And(lead, a->Int32Constant(0xFC00)),
1365 a->Int32Constant(0xD800)),
1366 &out);
1367
1368 Node* const trail = a->StringCharCodeAt(string, index_plus_one);
1369 a->GotoUnless(a->Word32Equal(a->Word32And(trail, a->Int32Constant(0xFC00)),
1370 a->Int32Constant(0xDC00)),
1371 &out);
1372
1373 // At a surrogate pair, return index + 2.
1374 Node* const index_plus_two = a->SmiAdd(index, a->SmiConstant(2));
1375 var_result.Bind(index_plus_two);
1376
1377 a->Goto(&out);
1378 }
1379
1380 a->Bind(&out);
1381 return var_result.value();
1382 }
1383
1384 // Utility class implementing a growable fixed array through CSA. 1407 // Utility class implementing a growable fixed array through CSA.
1385 class GrowableFixedArray { 1408 class GrowableFixedArray {
1409 typedef CodeStubAssembler::Label Label;
1410 typedef CodeStubAssembler::Variable Variable;
1411
1386 public: 1412 public:
1387 explicit GrowableFixedArray(CodeStubAssembler* a) 1413 explicit GrowableFixedArray(CodeStubAssembler* a)
1388 : assembler_(a), 1414 : assembler_(a),
1389 var_array_(a, MachineRepresentation::kTagged), 1415 var_array_(a, MachineRepresentation::kTagged),
1390 var_length_(a, MachineType::PointerRepresentation()), 1416 var_length_(a, MachineType::PointerRepresentation()),
1391 var_capacity_(a, MachineType::PointerRepresentation()) { 1417 var_capacity_(a, MachineType::PointerRepresentation()) {
1392 Initialize(); 1418 Initialize();
1393 } 1419 }
1394 1420
1395 Node* length() const { return var_length_.value(); } 1421 Node* length() const { return var_length_.value(); }
1396 1422
1397 CVariable* var_array() { return &var_array_; } 1423 Variable* var_array() { return &var_array_; }
1398 CVariable* var_length() { return &var_length_; } 1424 Variable* var_length() { return &var_length_; }
1399 CVariable* var_capacity() { return &var_capacity_; } 1425 Variable* var_capacity() { return &var_capacity_; }
1400 1426
1401 void Push(Node* const value) { 1427 void Push(Node* const value) {
1402 CodeStubAssembler* a = assembler_; 1428 CodeStubAssembler* a = assembler_;
1403 1429
1404 const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; 1430 const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER;
1405 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 1431 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
1406 1432
1407 Node* const length = var_length_.value(); 1433 Node* const length = var_length_.value();
1408 Node* const capacity = var_capacity_.value(); 1434 Node* const capacity = var_capacity_.value();
1409 1435
1410 CLabel grow(a), store(a); 1436 Label grow(a), store(a);
1411 a->Branch(a->IntPtrEqual(capacity, length), &grow, &store); 1437 a->Branch(a->IntPtrEqual(capacity, length), &grow, &store);
1412 1438
1413 a->Bind(&grow); 1439 a->Bind(&grow);
1414 { 1440 {
1415 Node* const new_capacity = NewCapacity(a, capacity); 1441 Node* const new_capacity = NewCapacity(a, capacity);
1416 Node* const new_array = GrowFixedArray(capacity, new_capacity, mode); 1442 Node* const new_array = GrowFixedArray(capacity, new_capacity, mode);
1417 1443
1418 var_capacity_.Bind(new_capacity); 1444 var_capacity_.Bind(new_capacity);
1419 var_array_.Bind(new_array); 1445 var_array_.Bind(new_array);
1420 a->Goto(&store); 1446 a->Goto(&store);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1497 Node* const to_array = a->AllocateFixedArray(kind, new_capacity, mode); 1523 Node* const to_array = a->AllocateFixedArray(kind, new_capacity, mode);
1498 a->CopyFixedArrayElements(kind, from_array, kind, to_array, 1524 a->CopyFixedArrayElements(kind, from_array, kind, to_array,
1499 current_capacity, new_capacity, barrier_mode, 1525 current_capacity, new_capacity, barrier_mode,
1500 mode); 1526 mode);
1501 1527
1502 return to_array; 1528 return to_array;
1503 } 1529 }
1504 1530
1505 private: 1531 private:
1506 CodeStubAssembler* const assembler_; 1532 CodeStubAssembler* const assembler_;
1507 CVariable var_array_; 1533 Variable var_array_;
1508 CVariable var_length_; 1534 Variable var_length_;
1509 CVariable var_capacity_; 1535 Variable var_capacity_;
1510 }; 1536 };
1511 1537
1512 void RegExpPrototypeMatchBody(CodeStubAssembler* a, Node* const receiver, 1538 } // namespace
1513 Node* const string, Node* const context,
1514 const bool is_fastpath) {
1515 Isolate* const isolate = a->isolate();
1516 1539
1517 Node* const null = a->NullConstant(); 1540 void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
1518 Node* const int_zero = a->IntPtrConstant(0); 1541 Node* const regexp,
1519 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1542 Node* const string,
1543 const bool is_fastpath) {
1544 Isolate* const isolate = this->isolate();
1520 1545
1521 Node* const regexp = receiver; 1546 Node* const null = NullConstant();
1547 Node* const int_zero = IntPtrConstant(0);
1548 Node* const smi_zero = SmiConstant(Smi::kZero);
1549
1522 Node* const is_global = 1550 Node* const is_global =
1523 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); 1551 FlagGetter(context, regexp, JSRegExp::kGlobal, is_fastpath);
1524 1552
1525 CLabel if_isglobal(a), if_isnotglobal(a); 1553 Label if_isglobal(this), if_isnotglobal(this);
1526 a->Branch(is_global, &if_isglobal, &if_isnotglobal); 1554 Branch(is_global, &if_isglobal, &if_isnotglobal);
1527 1555
1528 a->Bind(&if_isnotglobal); 1556 Bind(&if_isnotglobal);
1529 { 1557 {
1530 Node* const result = 1558 Node* const result =
1531 is_fastpath ? RegExpPrototypeExecBody(a, context, regexp, string, true) 1559 is_fastpath ? RegExpPrototypeExecBody(context, regexp, string, true)
1532 : RegExpExec(a, context, regexp, string); 1560 : RegExpExec(context, regexp, string);
1533 a->Return(result); 1561 Return(result);
1534 } 1562 }
1535 1563
1536 a->Bind(&if_isglobal); 1564 Bind(&if_isglobal);
1537 { 1565 {
1538 Node* const is_unicode = 1566 Node* const is_unicode =
1539 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); 1567 FlagGetter(context, regexp, JSRegExp::kUnicode, is_fastpath);
1540 1568
1541 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath); 1569 StoreLastIndex(context, regexp, smi_zero, is_fastpath);
1542 1570
1543 // Allocate an array to store the resulting match strings. 1571 // Allocate an array to store the resulting match strings.
1544 1572
1545 GrowableFixedArray array(a); 1573 GrowableFixedArray array(this);
1546 1574
1547 // Loop preparations. Within the loop, collect results from RegExpExec 1575 // Loop preparations. Within the loop, collect results from RegExpExec
1548 // and store match strings in the array. 1576 // and store match strings in the array.
1549 1577
1550 CVariable* vars[] = {array.var_array(), array.var_length(), 1578 Variable* vars[] = {array.var_array(), array.var_length(),
1551 array.var_capacity()}; 1579 array.var_capacity()};
1552 CLabel loop(a, 3, vars), out(a); 1580 Label loop(this, 3, vars), out(this);
1553 a->Goto(&loop); 1581 Goto(&loop);
1554 1582
1555 a->Bind(&loop); 1583 Bind(&loop);
1556 { 1584 {
1557 CVariable var_match(a, MachineRepresentation::kTagged); 1585 Variable var_match(this, MachineRepresentation::kTagged);
1558 1586
1559 CLabel if_didmatch(a), if_didnotmatch(a); 1587 Label if_didmatch(this), if_didnotmatch(this);
1560 if (is_fastpath) { 1588 if (is_fastpath) {
1561 // On the fast path, grab the matching string from the raw match index 1589 // On the fast path, grab the matching string from the raw match index
1562 // array. 1590 // array.
1563 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( 1591 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult(
1564 a, context, regexp, string, &if_didnotmatch, true); 1592 context, regexp, string, &if_didnotmatch, true);
1565 1593
1566 Node* const match_from = a->LoadFixedArrayElement( 1594 Node* const match_from = LoadFixedArrayElement(
1567 match_indices, RegExpMatchInfo::kFirstCaptureIndex); 1595 match_indices, RegExpMatchInfo::kFirstCaptureIndex);
1568 Node* const match_to = a->LoadFixedArrayElement( 1596 Node* const match_to = LoadFixedArrayElement(
1569 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); 1597 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
1570 1598
1571 Node* match = a->SubString(context, string, match_from, match_to); 1599 Node* match = SubString(context, string, match_from, match_to);
1572 var_match.Bind(match); 1600 var_match.Bind(match);
1573 1601
1574 a->Goto(&if_didmatch); 1602 Goto(&if_didmatch);
1575 } else { 1603 } else {
1576 DCHECK(!is_fastpath); 1604 DCHECK(!is_fastpath);
1577 Node* const result = RegExpExec(a, context, regexp, string); 1605 Node* const result = RegExpExec(context, regexp, string);
1578 1606
1579 CLabel load_match(a); 1607 Label load_match(this);
1580 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &load_match); 1608 Branch(WordEqual(result, null), &if_didnotmatch, &load_match);
1581 1609
1582 a->Bind(&load_match); 1610 Bind(&load_match);
1583 { 1611 {
1584 CLabel fast_result(a), slow_result(a); 1612 Label fast_result(this), slow_result(this);
1585 BranchIfFastRegExpResult(a, context, a->LoadMap(result), &fast_result, 1613 BranchIfFastRegExpResult(context, LoadMap(result), &fast_result,
1586 &slow_result); 1614 &slow_result);
1587 1615
1588 a->Bind(&fast_result); 1616 Bind(&fast_result);
1589 { 1617 {
1590 Node* const result_fixed_array = a->LoadElements(result); 1618 Node* const result_fixed_array = LoadElements(result);
1591 Node* const match = a->LoadFixedArrayElement(result_fixed_array, 0); 1619 Node* const match = LoadFixedArrayElement(result_fixed_array, 0);
1592 1620
1593 // The match is guaranteed to be a string on the fast path. 1621 // The match is guaranteed to be a string on the fast path.
1594 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(match))); 1622 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(match)));
1595 1623
1596 var_match.Bind(match); 1624 var_match.Bind(match);
1597 a->Goto(&if_didmatch); 1625 Goto(&if_didmatch);
1598 } 1626 }
1599 1627
1600 a->Bind(&slow_result); 1628 Bind(&slow_result);
1601 { 1629 {
1602 // TODO(ishell): Use GetElement stub once it's available. 1630 // TODO(ishell): Use GetElement stub once it's available.
1603 Node* const name = smi_zero; 1631 Node* const name = smi_zero;
1604 Callable getproperty_callable = CodeFactory::GetProperty(isolate); 1632 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1605 Node* const match = 1633 Node* const match =
1606 a->CallStub(getproperty_callable, context, result, name); 1634 CallStub(getproperty_callable, context, result, name);
1607 1635
1608 var_match.Bind(a->ToString(context, match)); 1636 var_match.Bind(ToString(context, match));
1609 a->Goto(&if_didmatch); 1637 Goto(&if_didmatch);
1610 } 1638 }
1611 } 1639 }
1612 } 1640 }
1613 1641
1614 a->Bind(&if_didnotmatch); 1642 Bind(&if_didnotmatch);
1615 { 1643 {
1616 // Return null if there were no matches, otherwise just exit the loop. 1644 // Return null if there were no matches, otherwise just exit the loop.
1617 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); 1645 GotoUnless(IntPtrEqual(array.length(), int_zero), &out);
1618 a->Return(null); 1646 Return(null);
1619 } 1647 }
1620 1648
1621 a->Bind(&if_didmatch); 1649 Bind(&if_didmatch);
1622 { 1650 {
1623 Node* match = var_match.value(); 1651 Node* match = var_match.value();
1624 1652
1625 // Store the match, growing the fixed array if needed. 1653 // Store the match, growing the fixed array if needed.
1626 1654
1627 array.Push(match); 1655 array.Push(match);
1628 1656
1629 // Advance last index if the match is the empty string. 1657 // Advance last index if the match is the empty string.
1630 1658
1631 Node* const match_length = a->LoadStringLength(match); 1659 Node* const match_length = LoadStringLength(match);
1632 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); 1660 GotoUnless(SmiEqual(match_length, smi_zero), &loop);
1633 1661
1634 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath); 1662 Node* last_index = LoadLastIndex(context, regexp, is_fastpath);
1635 1663
1636 Callable tolength_callable = CodeFactory::ToLength(isolate); 1664 Callable tolength_callable = CodeFactory::ToLength(isolate);
1637 last_index = a->CallStub(tolength_callable, context, last_index); 1665 last_index = CallStub(tolength_callable, context, last_index);
1638 1666
1639 Node* const new_last_index = 1667 Node* const new_last_index =
1640 AdvanceStringIndex(a, string, last_index, is_unicode); 1668 AdvanceStringIndex(string, last_index, is_unicode);
1641 1669
1642 StoreLastIndex(a, context, regexp, new_last_index, is_fastpath); 1670 StoreLastIndex(context, regexp, new_last_index, is_fastpath);
1643 1671
1644 a->Goto(&loop); 1672 Goto(&loop);
1645 } 1673 }
1646 } 1674 }
1647 1675
1648 a->Bind(&out); 1676 Bind(&out);
1649 { 1677 {
1650 // Wrap the match in a JSArray. 1678 // Wrap the match in a JSArray.
1651 1679
1652 Node* const result = array.ToJSArray(context); 1680 Node* const result = array.ToJSArray(context);
1653 a->Return(result); 1681 Return(result);
1654 } 1682 }
1655 } 1683 }
1656 } 1684 }
1657 1685
1658 } // namespace
1659
1660 // ES#sec-regexp.prototype-@@match 1686 // ES#sec-regexp.prototype-@@match
1661 // RegExp.prototype [ @@match ] ( string ) 1687 // RegExp.prototype [ @@match ] ( string )
1662 TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) { 1688 TF_BUILTIN(RegExpPrototypeMatch, RegExpBuiltinsAssembler) {
1663 Node* const maybe_receiver = Parameter(0); 1689 Node* const maybe_receiver = Parameter(0);
1664 Node* const maybe_string = Parameter(1); 1690 Node* const maybe_string = Parameter(1);
1665 Node* const context = Parameter(4); 1691 Node* const context = Parameter(4);
1666 1692
1667 // Ensure {maybe_receiver} is a JSReceiver. 1693 // Ensure {maybe_receiver} is a JSReceiver.
1668 Node* const map = ThrowIfNotJSReceiver( 1694 Node* const map = ThrowIfNotJSReceiver(
1669 this, isolate(), context, maybe_receiver, 1695 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1670 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@match"); 1696 "RegExp.prototype.@@match");
1671 Node* const receiver = maybe_receiver; 1697 Node* const receiver = maybe_receiver;
1672 1698
1673 // Convert {maybe_string} to a String. 1699 // Convert {maybe_string} to a String.
1674 Node* const string = ToString(context, maybe_string); 1700 Node* const string = ToString(context, maybe_string);
1675 1701
1676 CLabel fast_path(this), slow_path(this); 1702 Label fast_path(this), slow_path(this);
1677 BranchIfFastPath(this, context, map, &fast_path, &slow_path); 1703 BranchIfFastRegExp(context, map, &fast_path, &slow_path);
1678 1704
1679 Bind(&fast_path); 1705 Bind(&fast_path);
1680 RegExpPrototypeMatchBody(this, receiver, string, context, true); 1706 RegExpPrototypeMatchBody(context, receiver, string, true);
1681 1707
1682 Bind(&slow_path); 1708 Bind(&slow_path);
1683 RegExpPrototypeMatchBody(this, receiver, string, context, false); 1709 RegExpPrototypeMatchBody(context, receiver, string, false);
1684 } 1710 }
1685 1711
1686 namespace { 1712 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
1687 1713 Node* const context, Node* const regexp, Node* const string) {
1688 void RegExpPrototypeSearchBodyFast(CodeStubAssembler* a, Node* const receiver,
1689 Node* const string, Node* const context) {
1690 // Grab the initial value of last index. 1714 // Grab the initial value of last index.
1691 Node* const previous_last_index = FastLoadLastIndex(a, receiver); 1715 Node* const previous_last_index = FastLoadLastIndex(regexp);
1692 1716
1693 // Ensure last index is 0. 1717 // Ensure last index is 0.
1694 FastStoreLastIndex(a, receiver, a->SmiConstant(Smi::kZero)); 1718 FastStoreLastIndex(regexp, SmiConstant(Smi::kZero));
1695 1719
1696 // Call exec. 1720 // Call exec.
1697 CLabel if_didnotmatch(a); 1721 Label if_didnotmatch(this);
1698 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult( 1722 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult(
1699 a, context, receiver, string, &if_didnotmatch, true); 1723 context, regexp, string, &if_didnotmatch, true);
1700 1724
1701 // Successful match. 1725 // Successful match.
1702 { 1726 {
1703 // Reset last index. 1727 // Reset last index.
1704 FastStoreLastIndex(a, receiver, previous_last_index); 1728 FastStoreLastIndex(regexp, previous_last_index);
1705 1729
1706 // Return the index of the match. 1730 // Return the index of the match.
1707 Node* const index = a->LoadFixedArrayElement( 1731 Node* const index = LoadFixedArrayElement(
1708 match_indices, RegExpMatchInfo::kFirstCaptureIndex); 1732 match_indices, RegExpMatchInfo::kFirstCaptureIndex);
1709 a->Return(index); 1733 Return(index);
1710 } 1734 }
1711 1735
1712 a->Bind(&if_didnotmatch); 1736 Bind(&if_didnotmatch);
1713 { 1737 {
1714 // Reset last index and return -1. 1738 // Reset last index and return -1.
1715 FastStoreLastIndex(a, receiver, previous_last_index); 1739 FastStoreLastIndex(regexp, previous_last_index);
1716 a->Return(a->SmiConstant(-1)); 1740 Return(SmiConstant(-1));
1717 } 1741 }
1718 } 1742 }
1719 1743
1720 void RegExpPrototypeSearchBodySlow(CodeStubAssembler* a, Node* const receiver, 1744 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
1721 Node* const string, Node* const context) { 1745 Node* const context, Node* const regexp, Node* const string) {
1722 Isolate* const isolate = a->isolate(); 1746 Isolate* const isolate = this->isolate();
1723 1747
1724 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1748 Node* const smi_zero = SmiConstant(Smi::kZero);
1725 1749
1726 // Grab the initial value of last index. 1750 // Grab the initial value of last index.
1727 Node* const previous_last_index = SlowLoadLastIndex(a, context, receiver); 1751 Node* const previous_last_index = SlowLoadLastIndex(context, regexp);
1728 1752
1729 // Ensure last index is 0. 1753 // Ensure last index is 0.
1730 { 1754 {
1731 CLabel next(a); 1755 Label next(this);
1732 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); 1756 GotoIf(SameValue(previous_last_index, smi_zero, context), &next);
1733 1757
1734 SlowStoreLastIndex(a, context, receiver, smi_zero); 1758 SlowStoreLastIndex(context, regexp, smi_zero);
1735 a->Goto(&next); 1759 Goto(&next);
1736 a->Bind(&next); 1760 Bind(&next);
1737 } 1761 }
1738 1762
1739 // Call exec. 1763 // Call exec.
1740 Node* const exec_result = RegExpExec(a, context, receiver, string); 1764 Node* const exec_result = RegExpExec(context, regexp, string);
1741 1765
1742 // Reset last index if necessary. 1766 // Reset last index if necessary.
1743 { 1767 {
1744 CLabel next(a); 1768 Label next(this);
1745 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); 1769 Node* const current_last_index = SlowLoadLastIndex(context, regexp);
1746 1770
1747 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), 1771 GotoIf(SameValue(current_last_index, previous_last_index, context), &next);
1748 &next); 1772
1749 1773 SlowStoreLastIndex(context, regexp, previous_last_index);
1750 SlowStoreLastIndex(a, context, receiver, previous_last_index); 1774 Goto(&next);
1751 a->Goto(&next); 1775
1752 1776 Bind(&next);
1753 a->Bind(&next);
1754 } 1777 }
1755 1778
1756 // Return -1 if no match was found. 1779 // Return -1 if no match was found.
1757 { 1780 {
1758 CLabel next(a); 1781 Label next(this);
1759 a->GotoUnless(a->WordEqual(exec_result, a->NullConstant()), &next); 1782 GotoUnless(WordEqual(exec_result, NullConstant()), &next);
1760 a->Return(a->SmiConstant(-1)); 1783 Return(SmiConstant(-1));
1761 a->Bind(&next); 1784 Bind(&next);
1762 } 1785 }
1763 1786
1764 // Return the index of the match. 1787 // Return the index of the match.
1765 { 1788 {
1766 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); 1789 Label fast_result(this), slow_result(this, Label::kDeferred);
1767 BranchIfFastRegExpResult(a, context, a->LoadMap(exec_result), &fast_result, 1790 BranchIfFastRegExpResult(context, LoadMap(exec_result), &fast_result,
1768 &slow_result); 1791 &slow_result);
1769 1792
1770 a->Bind(&fast_result); 1793 Bind(&fast_result);
1771 { 1794 {
1772 Node* const index = 1795 Node* const index =
1773 a->LoadObjectField(exec_result, JSRegExpResult::kIndexOffset); 1796 LoadObjectField(exec_result, JSRegExpResult::kIndexOffset);
1774 a->Return(index); 1797 Return(index);
1775 } 1798 }
1776 1799
1777 a->Bind(&slow_result); 1800 Bind(&slow_result);
1778 { 1801 {
1779 Node* const name = a->HeapConstant(isolate->factory()->index_string()); 1802 Node* const name = HeapConstant(isolate->factory()->index_string());
1780 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 1803 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1781 Node* const index = 1804 Node* const index =
1782 a->CallStub(getproperty_callable, context, exec_result, name); 1805 CallStub(getproperty_callable, context, exec_result, name);
1783 a->Return(index); 1806 Return(index);
1784 } 1807 }
1785 } 1808 }
1786 } 1809 }
1787
1788 } // namespace
1789 1810
1790 // ES#sec-regexp.prototype-@@search 1811 // ES#sec-regexp.prototype-@@search
1791 // RegExp.prototype [ @@search ] ( string ) 1812 // RegExp.prototype [ @@search ] ( string )
1792 TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) { 1813 TF_BUILTIN(RegExpPrototypeSearch, RegExpBuiltinsAssembler) {
1793 Isolate* const isolate = this->isolate();
1794
1795 Node* const maybe_receiver = Parameter(0); 1814 Node* const maybe_receiver = Parameter(0);
1796 Node* const maybe_string = Parameter(1); 1815 Node* const maybe_string = Parameter(1);
1797 Node* const context = Parameter(4); 1816 Node* const context = Parameter(4);
1798 1817
1799 // Ensure {maybe_receiver} is a JSReceiver. 1818 // Ensure {maybe_receiver} is a JSReceiver.
1800 Node* const map = 1819 Node* const map = ThrowIfNotJSReceiver(
1801 ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver, 1820 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1802 MessageTemplate::kIncompatibleMethodReceiver, 1821 "RegExp.prototype.@@search");
1803 "RegExp.prototype.@@search");
1804 Node* const receiver = maybe_receiver; 1822 Node* const receiver = maybe_receiver;
1805 1823
1806 // Convert {maybe_string} to a String. 1824 // Convert {maybe_string} to a String.
1807 Node* const string = ToString(context, maybe_string); 1825 Node* const string = ToString(context, maybe_string);
1808 1826
1809 CLabel fast_path(this), slow_path(this); 1827 Label fast_path(this), slow_path(this);
1810 BranchIfFastPath(this, context, map, &fast_path, &slow_path); 1828 BranchIfFastRegExp(context, map, &fast_path, &slow_path);
1811 1829
1812 Bind(&fast_path); 1830 Bind(&fast_path);
1813 RegExpPrototypeSearchBodyFast(this, receiver, string, context); 1831 RegExpPrototypeSearchBodyFast(context, receiver, string);
1814 1832
1815 Bind(&slow_path); 1833 Bind(&slow_path);
1816 RegExpPrototypeSearchBodySlow(this, receiver, string, context); 1834 RegExpPrototypeSearchBodySlow(context, receiver, string);
1817 } 1835 }
1818
1819 namespace {
1820 1836
1821 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, 1837 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp,
1822 // {string} is a String, and {limit} is a Smi. 1838 // {string} is a String, and {limit} is a Smi.
1823 void Generate_RegExpPrototypeSplitBody(CodeStubAssembler* a, Node* const regexp, 1839 void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
1824 Node* const string, Node* const limit, 1840 Node* const regexp,
1825 Node* const context) { 1841 Node* const string,
1826 Isolate* isolate = a->isolate(); 1842 Node* const limit) {
1827 1843 Isolate* isolate = this->isolate();
1828 Node* const null = a->NullConstant(); 1844
1829 Node* const smi_zero = a->SmiConstant(0); 1845 Node* const null = NullConstant();
1830 Node* const int_zero = a->IntPtrConstant(0); 1846 Node* const smi_zero = SmiConstant(0);
1831 Node* const int_limit = a->SmiUntag(limit); 1847 Node* const int_zero = IntPtrConstant(0);
1848 Node* const int_limit = SmiUntag(limit);
1832 1849
1833 const ElementsKind kind = FAST_ELEMENTS; 1850 const ElementsKind kind = FAST_ELEMENTS;
1834 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 1851 const ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
1835 1852
1836 Node* const allocation_site = nullptr; 1853 Node* const allocation_site = nullptr;
1837 Node* const native_context = a->LoadNativeContext(context); 1854 Node* const native_context = LoadNativeContext(context);
1838 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); 1855 Node* const array_map = LoadJSArrayElementsMap(kind, native_context);
1839 1856
1840 CLabel return_empty_array(a, CLabel::kDeferred); 1857 Label return_empty_array(this, Label::kDeferred);
1841 1858
1842 // If limit is zero, return an empty array. 1859 // If limit is zero, return an empty array.
1843 { 1860 {
1844 CLabel next(a), if_limitiszero(a, CLabel::kDeferred); 1861 Label next(this), if_limitiszero(this, Label::kDeferred);
1845 a->Branch(a->SmiEqual(limit, smi_zero), &return_empty_array, &next); 1862 Branch(SmiEqual(limit, smi_zero), &return_empty_array, &next);
1846 a->Bind(&next); 1863 Bind(&next);
1847 } 1864 }
1848 1865
1849 Node* const string_length = a->LoadStringLength(string); 1866 Node* const string_length = LoadStringLength(string);
1850 1867
1851 // If passed the empty {string}, return either an empty array or a singleton 1868 // If passed the empty {string}, return either an empty array or a singleton
1852 // array depending on whether the {regexp} matches. 1869 // array depending on whether the {regexp} matches.
1853 { 1870 {
1854 CLabel next(a), if_stringisempty(a, CLabel::kDeferred); 1871 Label next(this), if_stringisempty(this, Label::kDeferred);
1855 a->Branch(a->SmiEqual(string_length, smi_zero), &if_stringisempty, &next); 1872 Branch(SmiEqual(string_length, smi_zero), &if_stringisempty, &next);
1856 1873
1857 a->Bind(&if_stringisempty); 1874 Bind(&if_stringisempty);
1858 { 1875 {
1859 Node* const last_match_info = a->LoadContextElement( 1876 Node* const last_match_info = LoadContextElement(
1860 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1877 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1861 1878
1862 Callable exec_callable = CodeFactory::RegExpExec(isolate); 1879 Callable exec_callable = CodeFactory::RegExpExec(isolate);
1863 Node* const match_indices = a->CallStub( 1880 Node* const match_indices = CallStub(exec_callable, context, regexp,
1864 exec_callable, context, regexp, string, smi_zero, last_match_info); 1881 string, smi_zero, last_match_info);
1865 1882
1866 CLabel return_singleton_array(a); 1883 Label return_singleton_array(this);
1867 a->Branch(a->WordEqual(match_indices, null), &return_singleton_array, 1884 Branch(WordEqual(match_indices, null), &return_singleton_array,
1868 &return_empty_array); 1885 &return_empty_array);
1869 1886
1870 a->Bind(&return_singleton_array); 1887 Bind(&return_singleton_array);
1871 { 1888 {
1872 Node* const length = a->SmiConstant(1); 1889 Node* const length = SmiConstant(1);
1873 Node* const capacity = a->IntPtrConstant(1); 1890 Node* const capacity = IntPtrConstant(1);
1874 Node* const result = a->AllocateJSArray(kind, array_map, capacity, 1891 Node* const result = AllocateJSArray(kind, array_map, capacity, length,
1875 length, allocation_site, mode); 1892 allocation_site, mode);
1876 1893
1877 Node* const fixed_array = a->LoadElements(result); 1894 Node* const fixed_array = LoadElements(result);
1878 a->StoreFixedArrayElement(fixed_array, 0, string); 1895 StoreFixedArrayElement(fixed_array, 0, string);
1879 1896
1880 a->Return(result); 1897 Return(result);
1881 } 1898 }
1882 } 1899 }
1883 1900
1884 a->Bind(&next); 1901 Bind(&next);
1885 } 1902 }
1886 1903
1887 // Loop preparations. 1904 // Loop preparations.
1888 1905
1889 GrowableFixedArray array(a); 1906 GrowableFixedArray array(this);
1890 1907
1891 CVariable var_last_matched_until(a, MachineRepresentation::kTagged); 1908 Variable var_last_matched_until(this, MachineRepresentation::kTagged);
1892 CVariable var_next_search_from(a, MachineRepresentation::kTagged); 1909 Variable var_next_search_from(this, MachineRepresentation::kTagged);
1893 1910
1894 var_last_matched_until.Bind(smi_zero); 1911 var_last_matched_until.Bind(smi_zero);
1895 var_next_search_from.Bind(smi_zero); 1912 var_next_search_from.Bind(smi_zero);
1896 1913
1897 CVariable* vars[] = {array.var_array(), array.var_length(), 1914 Variable* vars[] = {array.var_array(), array.var_length(),
1898 array.var_capacity(), &var_last_matched_until, 1915 array.var_capacity(), &var_last_matched_until,
1899 &var_next_search_from}; 1916 &var_next_search_from};
1900 const int vars_count = sizeof(vars) / sizeof(vars[0]); 1917 const int vars_count = sizeof(vars) / sizeof(vars[0]);
1901 CLabel loop(a, vars_count, vars), push_suffix_and_out(a), out(a); 1918 Label loop(this, vars_count, vars), push_suffix_and_out(this), out(this);
1902 a->Goto(&loop); 1919 Goto(&loop);
1903 1920
1904 a->Bind(&loop); 1921 Bind(&loop);
1905 { 1922 {
1906 Node* const next_search_from = var_next_search_from.value(); 1923 Node* const next_search_from = var_next_search_from.value();
1907 Node* const last_matched_until = var_last_matched_until.value(); 1924 Node* const last_matched_until = var_last_matched_until.value();
1908 1925
1909 // We're done if we've reached the end of the string. 1926 // We're done if we've reached the end of the string.
1910 { 1927 {
1911 CLabel next(a); 1928 Label next(this);
1912 a->Branch(a->SmiEqual(next_search_from, string_length), 1929 Branch(SmiEqual(next_search_from, string_length), &push_suffix_and_out,
1913 &push_suffix_and_out, &next); 1930 &next);
1914 a->Bind(&next); 1931 Bind(&next);
1915 } 1932 }
1916 1933
1917 // Search for the given {regexp}. 1934 // Search for the given {regexp}.
1918 1935
1919 Node* const last_match_info = a->LoadContextElement( 1936 Node* const last_match_info = LoadContextElement(
1920 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1937 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1921 1938
1922 Callable exec_callable = CodeFactory::RegExpExec(isolate); 1939 Callable exec_callable = CodeFactory::RegExpExec(isolate);
1923 Node* const match_indices = 1940 Node* const match_indices = CallStub(exec_callable, context, regexp, string,
1924 a->CallStub(exec_callable, context, regexp, string, next_search_from, 1941 next_search_from, last_match_info);
1925 last_match_info);
1926 1942
1927 // We're done if no match was found. 1943 // We're done if no match was found.
1928 { 1944 {
1929 CLabel next(a); 1945 Label next(this);
1930 a->Branch(a->WordEqual(match_indices, null), &push_suffix_and_out, &next); 1946 Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next);
1931 a->Bind(&next); 1947 Bind(&next);
1932 } 1948 }
1933 1949
1934 Node* const match_from = a->LoadFixedArrayElement( 1950 Node* const match_from = LoadFixedArrayElement(
1935 match_indices, RegExpMatchInfo::kFirstCaptureIndex); 1951 match_indices, RegExpMatchInfo::kFirstCaptureIndex);
1936 1952
1937 // We're done if the match starts beyond the string. 1953 // We're done if the match starts beyond the string.
1938 { 1954 {
1939 CLabel next(a); 1955 Label next(this);
1940 a->Branch(a->WordEqual(match_from, string_length), &push_suffix_and_out, 1956 Branch(WordEqual(match_from, string_length), &push_suffix_and_out, &next);
1941 &next); 1957 Bind(&next);
1942 a->Bind(&next); 1958 }
1943 } 1959
1944 1960 Node* const match_to = LoadFixedArrayElement(
1945 Node* const match_to = a->LoadFixedArrayElement(
1946 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); 1961 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
1947 1962
1948 // Advance index and continue if the match is empty. 1963 // Advance index and continue if the match is empty.
1949 { 1964 {
1950 CLabel next(a); 1965 Label next(this);
1951 1966
1952 a->GotoUnless(a->SmiEqual(match_to, next_search_from), &next); 1967 GotoUnless(SmiEqual(match_to, next_search_from), &next);
1953 a->GotoUnless(a->SmiEqual(match_to, last_matched_until), &next); 1968 GotoUnless(SmiEqual(match_to, last_matched_until), &next);
1954 1969
1955 Node* const is_unicode = FastFlagGetter(a, regexp, JSRegExp::kUnicode); 1970 Node* const is_unicode = FastFlagGetter(regexp, JSRegExp::kUnicode);
1956 Node* const new_next_search_from = 1971 Node* const new_next_search_from =
1957 AdvanceStringIndex(a, string, next_search_from, is_unicode); 1972 AdvanceStringIndex(string, next_search_from, is_unicode);
1958 var_next_search_from.Bind(new_next_search_from); 1973 var_next_search_from.Bind(new_next_search_from);
1959 a->Goto(&loop); 1974 Goto(&loop);
1960 1975
1961 a->Bind(&next); 1976 Bind(&next);
1962 } 1977 }
1963 1978
1964 // A valid match was found, add the new substring to the array. 1979 // A valid match was found, add the new substring to the array.
1965 { 1980 {
1966 Node* const from = last_matched_until; 1981 Node* const from = last_matched_until;
1967 Node* const to = match_from; 1982 Node* const to = match_from;
1968 1983
1969 Node* const substr = a->SubString(context, string, from, to); 1984 Node* const substr = SubString(context, string, from, to);
1970 array.Push(substr); 1985 array.Push(substr);
1971 1986
1972 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); 1987 GotoIf(WordEqual(array.length(), int_limit), &out);
1973 } 1988 }
1974 1989
1975 // Add all captures to the array. 1990 // Add all captures to the array.
1976 { 1991 {
1977 Node* const num_registers = a->LoadFixedArrayElement( 1992 Node* const num_registers = LoadFixedArrayElement(
1978 match_indices, RegExpMatchInfo::kNumberOfCapturesIndex); 1993 match_indices, RegExpMatchInfo::kNumberOfCapturesIndex);
1979 Node* const int_num_registers = a->SmiUntag(num_registers); 1994 Node* const int_num_registers = SmiUntag(num_registers);
1980 1995
1981 CVariable var_reg(a, MachineType::PointerRepresentation()); 1996 Variable var_reg(this, MachineType::PointerRepresentation());
1982 var_reg.Bind(a->IntPtrConstant(2)); 1997 var_reg.Bind(IntPtrConstant(2));
1983 1998
1984 CVariable* vars[] = {array.var_array(), array.var_length(), 1999 Variable* vars[] = {array.var_array(), array.var_length(),
1985 array.var_capacity(), &var_reg}; 2000 array.var_capacity(), &var_reg};
1986 const int vars_count = sizeof(vars) / sizeof(vars[0]); 2001 const int vars_count = sizeof(vars) / sizeof(vars[0]);
1987 CLabel nested_loop(a, vars_count, vars), nested_loop_out(a); 2002 Label nested_loop(this, vars_count, vars), nested_loop_out(this);
1988 a->Branch(a->IntPtrLessThan(var_reg.value(), int_num_registers), 2003 Branch(IntPtrLessThan(var_reg.value(), int_num_registers), &nested_loop,
1989 &nested_loop, &nested_loop_out); 2004 &nested_loop_out);
1990 2005
1991 a->Bind(&nested_loop); 2006 Bind(&nested_loop);
1992 { 2007 {
1993 Node* const reg = var_reg.value(); 2008 Node* const reg = var_reg.value();
1994 Node* const from = a->LoadFixedArrayElement( 2009 Node* const from = LoadFixedArrayElement(
1995 match_indices, reg, 2010 match_indices, reg,
1996 RegExpMatchInfo::kFirstCaptureIndex * kPointerSize, mode); 2011 RegExpMatchInfo::kFirstCaptureIndex * kPointerSize, mode);
1997 Node* const to = a->LoadFixedArrayElement( 2012 Node* const to = LoadFixedArrayElement(
1998 match_indices, reg, 2013 match_indices, reg,
1999 (RegExpMatchInfo::kFirstCaptureIndex + 1) * kPointerSize, mode); 2014 (RegExpMatchInfo::kFirstCaptureIndex + 1) * kPointerSize, mode);
2000 2015
2001 CLabel select_capture(a), select_undefined(a), store_value(a); 2016 Label select_capture(this), select_undefined(this), store_value(this);
2002 CVariable var_value(a, MachineRepresentation::kTagged); 2017 Variable var_value(this, MachineRepresentation::kTagged);
2003 a->Branch(a->SmiEqual(to, a->SmiConstant(-1)), &select_undefined, 2018 Branch(SmiEqual(to, SmiConstant(-1)), &select_undefined,
2004 &select_capture); 2019 &select_capture);
2005 2020
2006 a->Bind(&select_capture); 2021 Bind(&select_capture);
2007 { 2022 {
2008 Node* const substr = a->SubString(context, string, from, to); 2023 Node* const substr = SubString(context, string, from, to);
2009 var_value.Bind(substr); 2024 var_value.Bind(substr);
2010 a->Goto(&store_value); 2025 Goto(&store_value);
2011 } 2026 }
2012 2027
2013 a->Bind(&select_undefined); 2028 Bind(&select_undefined);
2014 { 2029 {
2015 Node* const undefined = a->UndefinedConstant(); 2030 Node* const undefined = UndefinedConstant();
2016 var_value.Bind(undefined); 2031 var_value.Bind(undefined);
2017 a->Goto(&store_value); 2032 Goto(&store_value);
2018 } 2033 }
2019 2034
2020 a->Bind(&store_value); 2035 Bind(&store_value);
2021 { 2036 {
2022 array.Push(var_value.value()); 2037 array.Push(var_value.value());
2023 a->GotoIf(a->WordEqual(array.length(), int_limit), &out); 2038 GotoIf(WordEqual(array.length(), int_limit), &out);
2024 2039
2025 Node* const new_reg = a->IntPtrAdd(reg, a->IntPtrConstant(2)); 2040 Node* const new_reg = IntPtrAdd(reg, IntPtrConstant(2));
2026 var_reg.Bind(new_reg); 2041 var_reg.Bind(new_reg);
2027 2042
2028 a->Branch(a->IntPtrLessThan(new_reg, int_num_registers), &nested_loop, 2043 Branch(IntPtrLessThan(new_reg, int_num_registers), &nested_loop,
2029 &nested_loop_out); 2044 &nested_loop_out);
2030 } 2045 }
2031 } 2046 }
2032 2047
2033 a->Bind(&nested_loop_out); 2048 Bind(&nested_loop_out);
2034 } 2049 }
2035 2050
2036 var_last_matched_until.Bind(match_to); 2051 var_last_matched_until.Bind(match_to);
2037 var_next_search_from.Bind(match_to); 2052 var_next_search_from.Bind(match_to);
2038 a->Goto(&loop); 2053 Goto(&loop);
2039 } 2054 }
2040 2055
2041 a->Bind(&push_suffix_and_out); 2056 Bind(&push_suffix_and_out);
2042 { 2057 {
2043 Node* const from = var_last_matched_until.value(); 2058 Node* const from = var_last_matched_until.value();
2044 Node* const to = string_length; 2059 Node* const to = string_length;
2045 2060
2046 Node* const substr = a->SubString(context, string, from, to); 2061 Node* const substr = SubString(context, string, from, to);
2047 array.Push(substr); 2062 array.Push(substr);
2048 2063
2049 a->Goto(&out); 2064 Goto(&out);
2050 } 2065 }
2051 2066
2052 a->Bind(&out); 2067 Bind(&out);
2053 { 2068 {
2054 Node* const result = array.ToJSArray(context); 2069 Node* const result = array.ToJSArray(context);
2055 a->Return(result); 2070 Return(result);
2056 } 2071 }
2057 2072
2058 a->Bind(&return_empty_array); 2073 Bind(&return_empty_array);
2059 { 2074 {
2060 Node* const length = smi_zero; 2075 Node* const length = smi_zero;
2061 Node* const capacity = int_zero; 2076 Node* const capacity = int_zero;
2062 Node* const result = a->AllocateJSArray(kind, array_map, capacity, length, 2077 Node* const result = AllocateJSArray(kind, array_map, capacity, length,
2063 allocation_site, mode); 2078 allocation_site, mode);
2064 a->Return(result); 2079 Return(result);
2065 } 2080 }
2066 } 2081 }
2067 2082
2068 } // namespace
2069
2070 // ES#sec-regexp.prototype-@@split 2083 // ES#sec-regexp.prototype-@@split
2071 // RegExp.prototype [ @@split ] ( string, limit ) 2084 // RegExp.prototype [ @@split ] ( string, limit )
2072 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { 2085 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
2073 Isolate* const isolate = this->isolate();
2074
2075 Node* const undefined = UndefinedConstant();
2076
2077 Node* const maybe_receiver = Parameter(0); 2086 Node* const maybe_receiver = Parameter(0);
2078 Node* const maybe_string = Parameter(1); 2087 Node* const maybe_string = Parameter(1);
2079 Node* const maybe_limit = Parameter(2); 2088 Node* const maybe_limit = Parameter(2);
2080 Node* const context = Parameter(5); 2089 Node* const context = Parameter(5);
2081 2090
2082 // Ensure {maybe_receiver} is a JSReceiver. 2091 // Ensure {maybe_receiver} is a JSReceiver.
2083 Node* const map = ThrowIfNotJSReceiver( 2092 Node* const map = ThrowIfNotJSReceiver(
2084 this, isolate, context, maybe_receiver, 2093 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
2085 MessageTemplate::kIncompatibleMethodReceiver, "RegExp.prototype.@@split"); 2094 "RegExp.prototype.@@split");
2086 Node* const receiver = maybe_receiver; 2095 Node* const receiver = maybe_receiver;
2087 2096
2088 // Convert {maybe_string} to a String. 2097 // Convert {maybe_string} to a String.
2089 Node* const string = ToString(context, maybe_string); 2098 Node* const string = ToString(context, maybe_string);
2090 2099
2091 CLabel fast_path(this), slow_path(this); 2100 Label fast_path(this), slow_path(this);
2092 BranchIfFastPath(this, context, map, &fast_path, &slow_path); 2101 BranchIfFastRegExp(context, map, &fast_path, &slow_path);
2093 2102
2094 Bind(&fast_path); 2103 Bind(&fast_path);
2095 { 2104 {
2105 // TODO(jgruber): Even if map checks send us to the fast path, we still need
2106 // to verify the constructor property and jump to the slow path if it has
2107 // been changed.
2108
2096 // Convert {maybe_limit} to a uint32, capping at the maximal smi value. 2109 // Convert {maybe_limit} to a uint32, capping at the maximal smi value.
2097 CVariable var_limit(this, MachineRepresentation::kTagged); 2110 Variable var_limit(this, MachineRepresentation::kTagged);
2098 CLabel if_limitissmimax(this), limit_done(this); 2111 Label if_limitissmimax(this), limit_done(this);
2099 2112
2100 GotoIf(WordEqual(maybe_limit, undefined), &if_limitissmimax); 2113 GotoIf(IsUndefined(maybe_limit), &if_limitissmimax);
2101 2114
2102 { 2115 {
2103 Node* const limit = ToUint32(context, maybe_limit); 2116 Node* const limit = ToUint32(context, maybe_limit);
2104 GotoUnless(TaggedIsSmi(limit), &if_limitissmimax); 2117 GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
2105 2118
2106 var_limit.Bind(limit); 2119 var_limit.Bind(limit);
2107 Goto(&limit_done); 2120 Goto(&limit_done);
2108 } 2121 }
2109 2122
2110 Bind(&if_limitissmimax); 2123 Bind(&if_limitissmimax);
2111 { 2124 {
2112 // TODO(jgruber): In this case, we can probably generation of limit checks 2125 // TODO(jgruber): In this case, we can probably generation of limit checks
2113 // in Generate_RegExpPrototypeSplitBody. 2126 // in Generate_RegExpPrototypeSplitBody.
2114 Node* const smi_max = SmiConstant(Smi::kMaxValue); 2127 Node* const smi_max = SmiConstant(Smi::kMaxValue);
2115 var_limit.Bind(smi_max); 2128 var_limit.Bind(smi_max);
2116 Goto(&limit_done); 2129 Goto(&limit_done);
2117 } 2130 }
2118 2131
2119 Bind(&limit_done); 2132 Bind(&limit_done);
2120 { 2133 {
2121 Node* const limit = var_limit.value(); 2134 Node* const limit = var_limit.value();
2122 Generate_RegExpPrototypeSplitBody(this, receiver, string, limit, context); 2135 RegExpPrototypeSplitBody(context, receiver, string, limit);
2123 } 2136 }
2124 } 2137 }
2125 2138
2126 Bind(&slow_path); 2139 Bind(&slow_path);
2127 { 2140 {
2128 Node* const result = CallRuntime(Runtime::kRegExpSplit, context, receiver, 2141 Node* const result = CallRuntime(Runtime::kRegExpSplit, context, receiver,
2129 string, maybe_limit); 2142 string, maybe_limit);
2130 Return(result); 2143 Return(result);
2131 } 2144 }
2132 } 2145 }
2133 2146
2134 namespace { 2147 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
2135 2148 Node* context, Node* regexp, Node* string, Node* replace_callable) {
2136 Node* ReplaceGlobalCallableFastPath(CodeStubAssembler* a, Node* context,
2137 Node* regexp, Node* subject_string,
2138 Node* replace_callable) {
2139 // The fast path is reached only if {receiver} is a global unmodified 2149 // The fast path is reached only if {receiver} is a global unmodified
2140 // JSRegExp instance and {replace_callable} is callable. 2150 // JSRegExp instance and {replace_callable} is callable.
2141 2151
2142 Isolate* const isolate = a->isolate(); 2152 Isolate* const isolate = this->isolate();
2143 2153
2144 Node* const null = a->NullConstant(); 2154 Node* const null = NullConstant();
2145 Node* const undefined = a->UndefinedConstant(); 2155 Node* const undefined = UndefinedConstant();
2146 Node* const int_zero = a->IntPtrConstant(0); 2156 Node* const int_zero = IntPtrConstant(0);
2147 Node* const int_one = a->IntPtrConstant(1); 2157 Node* const int_one = IntPtrConstant(1);
2148 Node* const smi_zero = a->SmiConstant(Smi::kZero); 2158 Node* const smi_zero = SmiConstant(Smi::kZero);
2149 2159
2150 Node* const native_context = a->LoadNativeContext(context); 2160 Node* const native_context = LoadNativeContext(context);
2151 2161
2152 CLabel out(a); 2162 Label out(this);
2153 CVariable var_result(a, MachineRepresentation::kTagged); 2163 Variable var_result(this, MachineRepresentation::kTagged);
2154 2164
2155 // Set last index to 0. 2165 // Set last index to 0.
2156 FastStoreLastIndex(a, regexp, smi_zero); 2166 FastStoreLastIndex(regexp, smi_zero);
2157 2167
2158 // Allocate {result_array}. 2168 // Allocate {result_array}.
2159 Node* result_array; 2169 Node* result_array;
2160 { 2170 {
2161 ElementsKind kind = FAST_ELEMENTS; 2171 ElementsKind kind = FAST_ELEMENTS;
2162 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); 2172 Node* const array_map = LoadJSArrayElementsMap(kind, native_context);
2163 Node* const capacity = a->IntPtrConstant(16); 2173 Node* const capacity = IntPtrConstant(16);
2164 Node* const length = smi_zero; 2174 Node* const length = smi_zero;
2165 Node* const allocation_site = nullptr; 2175 Node* const allocation_site = nullptr;
2166 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; 2176 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS;
2167 2177
2168 result_array = a->AllocateJSArray(kind, array_map, capacity, length, 2178 result_array = AllocateJSArray(kind, array_map, capacity, length,
2169 allocation_site, capacity_mode); 2179 allocation_site, capacity_mode);
2170 } 2180 }
2171 2181
2172 // Call into runtime for RegExpExecMultiple. 2182 // Call into runtime for RegExpExecMultiple.
2173 Node* last_match_info = a->LoadContextElement( 2183 Node* last_match_info =
2174 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 2184 LoadContextElement(native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
2175 Node* const res = 2185 Node* const res = CallRuntime(Runtime::kRegExpExecMultiple, context, regexp,
2176 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, 2186 string, last_match_info, result_array);
2177 subject_string, last_match_info, result_array);
2178 2187
2179 // Reset last index to 0. 2188 // Reset last index to 0.
2180 FastStoreLastIndex(a, regexp, smi_zero); 2189 FastStoreLastIndex(regexp, smi_zero);
2181 2190
2182 // If no matches, return the subject string. 2191 // If no matches, return the subject string.
2183 var_result.Bind(subject_string); 2192 var_result.Bind(string);
2184 a->GotoIf(a->WordEqual(res, null), &out); 2193 GotoIf(WordEqual(res, null), &out);
2185 2194
2186 // Reload last match info since it might have changed. 2195 // Reload last match info since it might have changed.
2187 last_match_info = a->LoadContextElement( 2196 last_match_info =
2188 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 2197 LoadContextElement(native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
2189 2198
2190 Node* const res_length = a->LoadJSArrayLength(res); 2199 Node* const res_length = LoadJSArrayLength(res);
2191 Node* const res_elems = a->LoadElements(res); 2200 Node* const res_elems = LoadElements(res);
2192 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); 2201 CSA_ASSERT(this, HasInstanceType(res_elems, FIXED_ARRAY_TYPE));
2193 2202
2194 Node* const num_capture_registers = a->LoadFixedArrayElement( 2203 Node* const num_capture_registers = LoadFixedArrayElement(
2195 last_match_info, RegExpMatchInfo::kNumberOfCapturesIndex); 2204 last_match_info, RegExpMatchInfo::kNumberOfCapturesIndex);
2196 2205
2197 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); 2206 Label if_hasexplicitcaptures(this), if_noexplicitcaptures(this),
2198 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), 2207 create_result(this);
2199 &if_noexplicitcaptures, &if_hasexplicitcaptures); 2208 Branch(SmiEqual(num_capture_registers, SmiConstant(Smi::FromInt(2))),
2209 &if_noexplicitcaptures, &if_hasexplicitcaptures);
2200 2210
2201 a->Bind(&if_noexplicitcaptures); 2211 Bind(&if_noexplicitcaptures);
2202 { 2212 {
2203 // If the number of captures is two then there are no explicit captures in 2213 // If the number of captures is two then there are no explicit captures in
2204 // the regexp, just the implicit capture that captures the whole match. In 2214 // the regexp, just the implicit capture that captures the whole match. In
2205 // this case we can simplify quite a bit and end up with something faster. 2215 // this case we can simplify quite a bit and end up with something faster.
2206 // The builder will consist of some integers that indicate slices of the 2216 // The builder will consist of some integers that indicate slices of the
2207 // input string and some replacements that were returned from the replace 2217 // input string and some replacements that were returned from the replace
2208 // function. 2218 // function.
2209 2219
2210 CVariable var_match_start(a, MachineRepresentation::kTagged); 2220 Variable var_match_start(this, MachineRepresentation::kTagged);
2211 var_match_start.Bind(smi_zero); 2221 var_match_start.Bind(smi_zero);
2212 2222
2213 Node* const end = a->SmiUntag(res_length); 2223 Node* const end = SmiUntag(res_length);
2214 CVariable var_i(a, MachineType::PointerRepresentation()); 2224 Variable var_i(this, MachineType::PointerRepresentation());
2215 var_i.Bind(int_zero); 2225 var_i.Bind(int_zero);
2216 2226
2217 CVariable* vars[] = {&var_i, &var_match_start}; 2227 Variable* vars[] = {&var_i, &var_match_start};
2218 CLabel loop(a, 2, vars); 2228 Label loop(this, 2, vars);
2219 a->Goto(&loop); 2229 Goto(&loop);
2220 a->Bind(&loop); 2230 Bind(&loop);
2221 { 2231 {
2222 Node* const i = var_i.value(); 2232 Node* const i = var_i.value();
2223 a->GotoUnless(a->IntPtrLessThan(i, end), &create_result); 2233 GotoUnless(IntPtrLessThan(i, end), &create_result);
2224 2234
2225 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 2235 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
2226 Node* const elem = a->LoadFixedArrayElement(res_elems, i, 0, mode); 2236 Node* const elem = LoadFixedArrayElement(res_elems, i, 0, mode);
2227 2237
2228 CLabel if_issmi(a), if_isstring(a), loop_epilogue(a); 2238 Label if_issmi(this), if_isstring(this), loop_epilogue(this);
2229 a->Branch(a->TaggedIsSmi(elem), &if_issmi, &if_isstring); 2239 Branch(TaggedIsSmi(elem), &if_issmi, &if_isstring);
2230 2240
2231 a->Bind(&if_issmi); 2241 Bind(&if_issmi);
2232 { 2242 {
2233 // Integers represent slices of the original string. 2243 // Integers represent slices of the original string.
2234 CLabel if_isnegativeorzero(a), if_ispositive(a); 2244 Label if_isnegativeorzero(this), if_ispositive(this);
2235 a->BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero, 2245 BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero,
2236 &if_ispositive); 2246 &if_ispositive);
2237 2247
2238 a->Bind(&if_ispositive); 2248 Bind(&if_ispositive);
2239 { 2249 {
2240 Node* const int_elem = a->SmiUntag(elem); 2250 Node* const int_elem = SmiUntag(elem);
2241 Node* const new_match_start = 2251 Node* const new_match_start =
2242 a->IntPtrAdd(a->WordShr(int_elem, a->IntPtrConstant(11)), 2252 IntPtrAdd(WordShr(int_elem, IntPtrConstant(11)),
2243 a->WordAnd(int_elem, a->IntPtrConstant(0x7ff))); 2253 WordAnd(int_elem, IntPtrConstant(0x7ff)));
2244 var_match_start.Bind(a->SmiTag(new_match_start)); 2254 var_match_start.Bind(SmiTag(new_match_start));
2245 a->Goto(&loop_epilogue); 2255 Goto(&loop_epilogue);
2246 } 2256 }
2247 2257
2248 a->Bind(&if_isnegativeorzero); 2258 Bind(&if_isnegativeorzero);
2249 { 2259 {
2250 Node* const next_i = a->IntPtrAdd(i, int_one); 2260 Node* const next_i = IntPtrAdd(i, int_one);
2251 var_i.Bind(next_i); 2261 var_i.Bind(next_i);
2252 2262
2253 Node* const next_elem = 2263 Node* const next_elem =
2254 a->LoadFixedArrayElement(res_elems, next_i, 0, mode); 2264 LoadFixedArrayElement(res_elems, next_i, 0, mode);
2255 2265
2256 Node* const new_match_start = a->SmiSub(next_elem, elem); 2266 Node* const new_match_start = SmiSub(next_elem, elem);
2257 var_match_start.Bind(new_match_start); 2267 var_match_start.Bind(new_match_start);
2258 a->Goto(&loop_epilogue); 2268 Goto(&loop_epilogue);
2259 } 2269 }
2260 } 2270 }
2261 2271
2262 a->Bind(&if_isstring); 2272 Bind(&if_isstring);
2263 { 2273 {
2264 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(elem))); 2274 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(elem)));
2265 2275
2266 Callable call_callable = CodeFactory::Call(isolate); 2276 Callable call_callable = CodeFactory::Call(isolate);
2267 Node* const replacement_obj = 2277 Node* const replacement_obj =
2268 a->CallJS(call_callable, context, replace_callable, undefined, elem, 2278 CallJS(call_callable, context, replace_callable, undefined, elem,
2269 var_match_start.value(), subject_string); 2279 var_match_start.value(), string);
2270 2280
2271 Node* const replacement_str = a->ToString(context, replacement_obj); 2281 Node* const replacement_str = ToString(context, replacement_obj);
2272 a->StoreFixedArrayElement(res_elems, i, replacement_str); 2282 StoreFixedArrayElement(res_elems, i, replacement_str);
2273 2283
2274 Node* const elem_length = a->LoadStringLength(elem); 2284 Node* const elem_length = LoadStringLength(elem);
2275 Node* const new_match_start = 2285 Node* const new_match_start =
2276 a->SmiAdd(var_match_start.value(), elem_length); 2286 SmiAdd(var_match_start.value(), elem_length);
2277 var_match_start.Bind(new_match_start); 2287 var_match_start.Bind(new_match_start);
2278 2288
2279 a->Goto(&loop_epilogue); 2289 Goto(&loop_epilogue);
2280 } 2290 }
2281 2291
2282 a->Bind(&loop_epilogue); 2292 Bind(&loop_epilogue);
2283 { 2293 {
2284 var_i.Bind(a->IntPtrAdd(var_i.value(), int_one)); 2294 var_i.Bind(IntPtrAdd(var_i.value(), int_one));
2285 a->Goto(&loop); 2295 Goto(&loop);
2286 } 2296 }
2287 } 2297 }
2288 } 2298 }
2289 2299
2290 a->Bind(&if_hasexplicitcaptures); 2300 Bind(&if_hasexplicitcaptures);
2291 { 2301 {
2292 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 2302 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
2293 2303
2294 Node* const from = int_zero; 2304 Node* const from = int_zero;
2295 Node* const to = a->SmiUntag(res_length); 2305 Node* const to = SmiUntag(res_length);
2296 const int increment = 1; 2306 const int increment = 1;
2297 2307
2298 a->BuildFastLoop( 2308 BuildFastLoop(
2299 MachineType::PointerRepresentation(), from, to, 2309 MachineType::PointerRepresentation(), from, to,
2300 [res_elems, isolate, native_context, context, undefined, 2310 [this, res_elems, isolate, native_context, context, undefined,
2301 replace_callable, mode](CodeStubAssembler* a, Node* index) { 2311 replace_callable, mode](CodeStubAssembler* a, Node* index) {
2302 Node* const elem = 2312 Node* const elem = LoadFixedArrayElement(res_elems, index, 0, mode);
2303 a->LoadFixedArrayElement(res_elems, index, 0, mode); 2313
2304 2314 Label do_continue(this);
2305 CLabel do_continue(a); 2315 GotoIf(TaggedIsSmi(elem), &do_continue);
2306 a->GotoIf(a->TaggedIsSmi(elem), &do_continue);
2307 2316
2308 // elem must be an Array. 2317 // elem must be an Array.
2309 // Use the apply argument as backing for global RegExp properties. 2318 // Use the apply argument as backing for global RegExp properties.
2310 2319
2311 CSA_ASSERT(a, a->HasInstanceType(elem, JS_ARRAY_TYPE)); 2320 CSA_ASSERT(this, HasInstanceType(elem, JS_ARRAY_TYPE));
2312 2321
2313 // TODO(jgruber): Remove indirection through Call->ReflectApply. 2322 // TODO(jgruber): Remove indirection through Call->ReflectApply.
2314 Callable call_callable = CodeFactory::Call(isolate); 2323 Callable call_callable = CodeFactory::Call(isolate);
2315 Node* const reflect_apply = a->LoadContextElement( 2324 Node* const reflect_apply =
2316 native_context, Context::REFLECT_APPLY_INDEX); 2325 LoadContextElement(native_context, Context::REFLECT_APPLY_INDEX);
2317 2326
2318 Node* const replacement_obj = 2327 Node* const replacement_obj =
2319 a->CallJS(call_callable, context, reflect_apply, undefined, 2328 CallJS(call_callable, context, reflect_apply, undefined,
2320 replace_callable, undefined, elem); 2329 replace_callable, undefined, elem);
2321 2330
2322 // Overwrite the i'th element in the results with the string we got 2331 // Overwrite the i'th element in the results with the string we got
2323 // back from the callback function. 2332 // back from the callback function.
2324 2333
2325 Node* const replacement_str = a->ToString(context, replacement_obj); 2334 Node* const replacement_str = ToString(context, replacement_obj);
2326 a->StoreFixedArrayElement(res_elems, index, replacement_str, 2335 StoreFixedArrayElement(res_elems, index, replacement_str,
2327 UPDATE_WRITE_BARRIER, 0, mode); 2336 UPDATE_WRITE_BARRIER, 0, mode);
2328 2337
2329 a->Goto(&do_continue); 2338 Goto(&do_continue);
2330 a->Bind(&do_continue); 2339 Bind(&do_continue);
2331 }, 2340 },
2332 increment, CodeStubAssembler::IndexAdvanceMode::kPost); 2341 increment, CodeStubAssembler::IndexAdvanceMode::kPost);
2333 2342
2334 a->Goto(&create_result); 2343 Goto(&create_result);
2335 } 2344 }
2336 2345
2337 a->Bind(&create_result); 2346 Bind(&create_result);
2338 { 2347 {
2339 Node* const result = a->CallRuntime(Runtime::kStringBuilderConcat, context, 2348 Node* const result = CallRuntime(Runtime::kStringBuilderConcat, context,
2340 res, res_length, subject_string); 2349 res, res_length, string);
2341 var_result.Bind(result); 2350 var_result.Bind(result);
2342 a->Goto(&out); 2351 Goto(&out);
2343 } 2352 }
2344 2353
2345 a->Bind(&out); 2354 Bind(&out);
2346 return var_result.value(); 2355 return var_result.value();
2347 } 2356 }
2348 2357
2349 Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, Node* context, 2358 Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
2350 Node* regexp, Node* subject_string, 2359 Node* context, Node* regexp, Node* string, Node* replace_string) {
2351 Node* replace_string) {
2352 // The fast path is reached only if {receiver} is an unmodified 2360 // The fast path is reached only if {receiver} is an unmodified
2353 // JSRegExp instance, {replace_value} is non-callable, and 2361 // JSRegExp instance, {replace_value} is non-callable, and
2354 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple 2362 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple
2355 // string replacement. 2363 // string replacement.
2356 2364
2357 Isolate* const isolate = a->isolate(); 2365 Isolate* const isolate = this->isolate();
2358 2366
2359 Node* const null = a->NullConstant(); 2367 Node* const null = NullConstant();
2360 Node* const int_zero = a->IntPtrConstant(0); 2368 Node* const int_zero = IntPtrConstant(0);
2361 Node* const smi_zero = a->SmiConstant(Smi::kZero); 2369 Node* const smi_zero = SmiConstant(Smi::kZero);
2362 2370
2363 CLabel out(a); 2371 Label out(this);
2364 CVariable var_result(a, MachineRepresentation::kTagged); 2372 Variable var_result(this, MachineRepresentation::kTagged);
2365 2373
2366 // Load the last match info. 2374 // Load the last match info.
2367 Node* const native_context = a->LoadNativeContext(context); 2375 Node* const native_context = LoadNativeContext(context);
2368 Node* const last_match_info = a->LoadContextElement( 2376 Node* const last_match_info =
2369 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 2377 LoadContextElement(native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
2370 2378
2371 // Is {regexp} global? 2379 // Is {regexp} global?
2372 CLabel if_isglobal(a), if_isnonglobal(a); 2380 Label if_isglobal(this), if_isnonglobal(this);
2373 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 2381 Node* const flags = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
2374 Node* const is_global = 2382 Node* const is_global =
2375 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); 2383 WordAnd(SmiUntag(flags), IntPtrConstant(JSRegExp::kGlobal));
2376 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); 2384 Branch(WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal);
2377 2385
2378 a->Bind(&if_isglobal); 2386 Bind(&if_isglobal);
2379 { 2387 {
2380 // Hand off global regexps to runtime. 2388 // Hand off global regexps to runtime.
2381 FastStoreLastIndex(a, regexp, smi_zero); 2389 FastStoreLastIndex(regexp, smi_zero);
2382 Node* const result = 2390 Node* const result =
2383 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, 2391 CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context,
2384 subject_string, regexp, replace_string, last_match_info); 2392 string, regexp, replace_string, last_match_info);
2385 var_result.Bind(result); 2393 var_result.Bind(result);
2386 a->Goto(&out); 2394 Goto(&out);
2387 } 2395 }
2388 2396
2389 a->Bind(&if_isnonglobal); 2397 Bind(&if_isnonglobal);
2390 { 2398 {
2391 // Run exec, then manually construct the resulting string. 2399 // Run exec, then manually construct the resulting string.
2392 Callable exec_callable = CodeFactory::RegExpExec(isolate); 2400 Callable exec_callable = CodeFactory::RegExpExec(isolate);
2393 Node* const match_indices = 2401 Node* const match_indices = CallStub(exec_callable, context, regexp, string,
2394 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, 2402 smi_zero, last_match_info);
2395 last_match_info); 2403
2396 2404 Label if_matched(this), if_didnotmatch(this);
2397 CLabel if_matched(a), if_didnotmatch(a); 2405 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2398 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); 2406
2399 2407 Bind(&if_didnotmatch);
2400 a->Bind(&if_didnotmatch);
2401 { 2408 {
2402 FastStoreLastIndex(a, regexp, smi_zero); 2409 FastStoreLastIndex(regexp, smi_zero);
2403 var_result.Bind(subject_string); 2410 var_result.Bind(string);
2404 a->Goto(&out); 2411 Goto(&out);
2405 } 2412 }
2406 2413
2407 a->Bind(&if_matched); 2414 Bind(&if_matched);
2408 { 2415 {
2409 Node* const subject_start = smi_zero; 2416 Node* const subject_start = smi_zero;
2410 Node* const match_start = a->LoadFixedArrayElement( 2417 Node* const match_start = LoadFixedArrayElement(
2411 match_indices, RegExpMatchInfo::kFirstCaptureIndex); 2418 match_indices, RegExpMatchInfo::kFirstCaptureIndex);
2412 Node* const match_end = a->LoadFixedArrayElement( 2419 Node* const match_end = LoadFixedArrayElement(
2413 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); 2420 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
2414 Node* const subject_end = a->LoadStringLength(subject_string); 2421 Node* const subject_end = LoadStringLength(string);
2415 2422
2416 CLabel if_replaceisempty(a), if_replaceisnotempty(a); 2423 Label if_replaceisempty(this), if_replaceisnotempty(this);
2417 Node* const replace_length = a->LoadStringLength(replace_string); 2424 Node* const replace_length = LoadStringLength(replace_string);
2418 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, 2425 Branch(SmiEqual(replace_length, smi_zero), &if_replaceisempty,
2419 &if_replaceisnotempty); 2426 &if_replaceisnotempty);
2420 2427
2421 a->Bind(&if_replaceisempty); 2428 Bind(&if_replaceisempty);
2422 { 2429 {
2423 // TODO(jgruber): We could skip many of the checks that using SubString 2430 // TODO(jgruber): We could skip many of the checks that using SubString
2424 // here entails. 2431 // here entails.
2425 2432
2426 Node* const first_part = 2433 Node* const first_part =
2427 a->SubString(context, subject_string, subject_start, match_start); 2434 SubString(context, string, subject_start, match_start);
2428 Node* const second_part = 2435 Node* const second_part =
2429 a->SubString(context, subject_string, match_end, subject_end); 2436 SubString(context, string, match_end, subject_end);
2430 2437
2431 Node* const result = a->StringAdd(context, first_part, second_part); 2438 Node* const result = StringAdd(context, first_part, second_part);
2432 var_result.Bind(result); 2439 var_result.Bind(result);
2433 a->Goto(&out); 2440 Goto(&out);
2434 } 2441 }
2435 2442
2436 a->Bind(&if_replaceisnotempty); 2443 Bind(&if_replaceisnotempty);
2437 { 2444 {
2438 Node* const first_part = 2445 Node* const first_part =
2439 a->SubString(context, subject_string, subject_start, match_start); 2446 SubString(context, string, subject_start, match_start);
2440 Node* const second_part = replace_string; 2447 Node* const second_part = replace_string;
2441 Node* const third_part = 2448 Node* const third_part =
2442 a->SubString(context, subject_string, match_end, subject_end); 2449 SubString(context, string, match_end, subject_end);
2443 2450
2444 Node* result = a->StringAdd(context, first_part, second_part); 2451 Node* result = StringAdd(context, first_part, second_part);
2445 result = a->StringAdd(context, result, third_part); 2452 result = StringAdd(context, result, third_part);
2446 2453
2447 var_result.Bind(result); 2454 var_result.Bind(result);
2448 a->Goto(&out); 2455 Goto(&out);
2449 } 2456 }
2450 } 2457 }
2451 } 2458 }
2452 2459
2453 a->Bind(&out); 2460 Bind(&out);
2454 return var_result.value(); 2461 return var_result.value();
2455 } 2462 }
2456 2463
2457 } // namespace
2458
2459 // ES#sec-regexp.prototype-@@replace 2464 // ES#sec-regexp.prototype-@@replace
2460 // RegExp.prototype [ @@replace ] ( string, replaceValue ) 2465 // RegExp.prototype [ @@replace ] ( string, replaceValue )
2461 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { 2466 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
2462 Isolate* const isolate = this->isolate();
2463
2464 Node* const maybe_receiver = Parameter(0); 2467 Node* const maybe_receiver = Parameter(0);
2465 Node* const maybe_string = Parameter(1); 2468 Node* const maybe_string = Parameter(1);
2466 Node* const replace_value = Parameter(2); 2469 Node* const replace_value = Parameter(2);
2467 Node* const context = Parameter(5); 2470 Node* const context = Parameter(5);
2468 2471
2469 Node* const int_zero = IntPtrConstant(0); 2472 Node* const int_zero = IntPtrConstant(0);
2470 2473
2471 // Ensure {maybe_receiver} is a JSReceiver. 2474 // Ensure {maybe_receiver} is a JSReceiver.
2472 Node* const map = 2475 Node* const map = ThrowIfNotJSReceiver(
2473 ThrowIfNotJSReceiver(this, isolate, context, maybe_receiver, 2476 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
2474 MessageTemplate::kIncompatibleMethodReceiver, 2477 "RegExp.prototype.@@replace");
2475 "RegExp.prototype.@@replace");
2476 Node* const receiver = maybe_receiver; 2478 Node* const receiver = maybe_receiver;
2477 2479
2478 // Convert {maybe_string} to a String. 2480 // Convert {maybe_string} to a String.
2479 Callable tostring_callable = CodeFactory::ToString(isolate); 2481 Callable tostring_callable = CodeFactory::ToString(isolate());
2480 Node* const string = CallStub(tostring_callable, context, maybe_string); 2482 Node* const string = CallStub(tostring_callable, context, maybe_string);
2481 2483
2482 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? 2484 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
2483 CLabel checkreplacecallable(this), runtime(this, CLabel::kDeferred), 2485 Label checkreplacecallable(this), runtime(this, Label::kDeferred),
2484 fastpath(this); 2486 fastpath(this);
2485 BranchIfFastPath(this, context, map, &checkreplacecallable, &runtime); 2487 BranchIfFastRegExp(context, map, &checkreplacecallable, &runtime);
2486 2488
2487 Bind(&checkreplacecallable); 2489 Bind(&checkreplacecallable);
2488 Node* const regexp = receiver; 2490 Node* const regexp = receiver;
2489 2491
2490 // 2. Is {replace_value} callable? 2492 // 2. Is {replace_value} callable?
2491 CLabel checkreplacestring(this), if_iscallable(this); 2493 Label checkreplacestring(this), if_iscallable(this);
2492 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); 2494 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring);
2493 2495
2494 Node* const replace_value_map = LoadMap(replace_value); 2496 Node* const replace_value_map = LoadMap(replace_value);
2495 Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring); 2497 Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring);
2496 2498
2497 // 3. Does ToString({replace_value}) contain '$'? 2499 // 3. Does ToString({replace_value}) contain '$'?
2498 Bind(&checkreplacestring); 2500 Bind(&checkreplacestring);
2499 { 2501 {
2500 Node* const replace_string = 2502 Node* const replace_string =
2501 CallStub(tostring_callable, context, replace_value); 2503 CallStub(tostring_callable, context, replace_value);
2502 2504
2503 Node* const dollar_char = IntPtrConstant('$'); 2505 Node* const dollar_char = IntPtrConstant('$');
2504 Node* const smi_minusone = SmiConstant(Smi::FromInt(-1)); 2506 Node* const smi_minusone = SmiConstant(Smi::FromInt(-1));
2505 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char, 2507 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char,
2506 int_zero), 2508 int_zero),
2507 smi_minusone), 2509 smi_minusone),
2508 &runtime); 2510 &runtime);
2509 2511
2510 Return(ReplaceSimpleStringFastPath(this, context, regexp, string, 2512 Return(
2511 replace_string)); 2513 ReplaceSimpleStringFastPath(context, regexp, string, replace_string));
2512 } 2514 }
2513 2515
2514 // {regexp} is unmodified and {replace_value} is callable. 2516 // {regexp} is unmodified and {replace_value} is callable.
2515 Bind(&if_iscallable); 2517 Bind(&if_iscallable);
2516 { 2518 {
2517 Node* const replace_callable = replace_value; 2519 Node* const replace_callable = replace_value;
2518 2520
2519 // Check if the {regexp} is global. 2521 // Check if the {regexp} is global.
2520 CLabel if_isglobal(this), if_isnotglobal(this); 2522 Label if_isglobal(this), if_isnotglobal(this);
2521 Node* const is_global = FastFlagGetter(this, regexp, JSRegExp::kGlobal); 2523 Node* const is_global = FastFlagGetter(regexp, JSRegExp::kGlobal);
2522 Branch(is_global, &if_isglobal, &if_isnotglobal); 2524 Branch(is_global, &if_isglobal, &if_isnotglobal);
2523 2525
2524 Bind(&if_isglobal); 2526 Bind(&if_isglobal);
2525 { 2527 {
2526 Node* const result = ReplaceGlobalCallableFastPath( 2528 Node* const result = ReplaceGlobalCallableFastPath(
2527 this, context, regexp, string, replace_callable); 2529 context, regexp, string, replace_callable);
2528 Return(result); 2530 Return(result);
2529 } 2531 }
2530 2532
2531 Bind(&if_isnotglobal); 2533 Bind(&if_isnotglobal);
2532 { 2534 {
2533 Node* const result = 2535 Node* const result =
2534 CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, 2536 CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
2535 context, string, regexp, replace_callable); 2537 context, string, regexp, replace_callable);
2536 Return(result); 2538 Return(result);
2537 } 2539 }
2538 } 2540 }
2539 2541
2540 Bind(&runtime); 2542 Bind(&runtime);
2541 { 2543 {
2542 Node* const result = CallRuntime(Runtime::kRegExpReplace, context, receiver, 2544 Node* const result = CallRuntime(Runtime::kRegExpReplace, context, receiver,
2543 string, replace_value); 2545 string, replace_value);
2544 Return(result); 2546 Return(result);
2545 } 2547 }
2546 } 2548 }
2547 2549
2548 // Simple string matching functionality for internal use which does not modify 2550 // Simple string matching functionality for internal use which does not modify
2549 // the last match info. 2551 // the last match info.
2550 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { 2552 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
2551 Isolate* const isolate = this->isolate();
2552
2553 Node* const regexp = Parameter(1); 2553 Node* const regexp = Parameter(1);
2554 Node* const string = Parameter(2); 2554 Node* const string = Parameter(2);
2555 Node* const context = Parameter(5); 2555 Node* const context = Parameter(5);
2556 2556
2557 Node* const null = NullConstant(); 2557 Node* const null = NullConstant();
2558 Node* const smi_zero = SmiConstant(Smi::FromInt(0)); 2558 Node* const smi_zero = SmiConstant(Smi::FromInt(0));
2559 2559
2560 Node* const native_context = LoadNativeContext(context); 2560 Node* const native_context = LoadNativeContext(context);
2561 Node* const internal_match_info = LoadContextElement( 2561 Node* const internal_match_info = LoadContextElement(
2562 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); 2562 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX);
2563 2563
2564 Callable exec_callable = CodeFactory::RegExpExec(isolate); 2564 Callable exec_callable = CodeFactory::RegExpExec(isolate());
2565 Node* const match_indices = CallStub(exec_callable, context, regexp, string, 2565 Node* const match_indices = CallStub(exec_callable, context, regexp, string,
2566 smi_zero, internal_match_info); 2566 smi_zero, internal_match_info);
2567 2567
2568 CLabel if_matched(this), if_didnotmatch(this); 2568 Label if_matched(this), if_didnotmatch(this);
2569 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched); 2569 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2570 2570
2571 Bind(&if_didnotmatch); 2571 Bind(&if_didnotmatch);
2572 Return(null); 2572 Return(null);
2573 2573
2574 Bind(&if_matched); 2574 Bind(&if_matched);
2575 { 2575 {
2576 Node* result = ConstructNewResultFromMatchInfo(isolate, this, context, 2576 Node* result =
2577 match_indices, string); 2577 ConstructNewResultFromMatchInfo(context, match_indices, string);
2578 Return(result); 2578 Return(result);
2579 } 2579 }
2580 } 2580 }
2581 2581
2582 } // namespace internal 2582 } // namespace internal
2583 } // namespace v8 2583 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698