OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/regexp/jsregexp.h" | 9 #include "src/regexp/jsregexp.h" |
10 #include "src/regexp/regexp-utils.h" | 10 #include "src/regexp/regexp-utils.h" |
11 #include "src/string-builder.h" | 11 #include "src/string-builder.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 | 15 |
| 16 typedef compiler::Node Node; |
| 17 typedef CodeStubAssembler::Label CLabel; |
| 18 typedef CodeStubAssembler::Variable CVariable; |
| 19 typedef compiler::CodeAssemblerState CodeAssemblerState; |
| 20 |
16 // ----------------------------------------------------------------------------- | 21 // ----------------------------------------------------------------------------- |
17 // ES6 section 21.2 RegExp Objects | 22 // ES6 section 21.2 RegExp Objects |
18 | 23 |
19 namespace { | 24 namespace { |
20 | 25 |
21 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { | 26 Handle<String> PatternFlags(Isolate* isolate, Handle<JSRegExp> regexp) { |
22 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; | 27 static const int kMaxFlagsLength = 5 + 1; // 5 flags and '\0'; |
23 char flags_string[kMaxFlagsLength]; | 28 char flags_string[kMaxFlagsLength]; |
24 int i = 0; | 29 int i = 0; |
25 | 30 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); | 168 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); |
164 | 169 |
165 // Return undefined for compatibility with JSC. | 170 // Return undefined for compatibility with JSC. |
166 // See http://crbug.com/585775 for web compat details. | 171 // See http://crbug.com/585775 for web compat details. |
167 | 172 |
168 return isolate->heap()->undefined_value(); | 173 return isolate->heap()->undefined_value(); |
169 } | 174 } |
170 | 175 |
171 namespace { | 176 namespace { |
172 | 177 |
173 compiler::Node* FastLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 178 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
174 compiler::Node* regexp) { | |
175 // Load the in-object field. | 179 // Load the in-object field. |
176 static const int field_offset = | 180 static const int field_offset = |
177 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 181 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
178 return a->LoadObjectField(regexp, field_offset); | 182 return a->LoadObjectField(regexp, field_offset); |
179 } | 183 } |
180 | 184 |
181 compiler::Node* SlowLoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 185 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { |
182 compiler::Node* regexp) { | |
183 // Load through the GetProperty stub. | 186 // Load through the GetProperty stub. |
184 typedef compiler::Node Node; | |
185 | |
186 Node* const name = | 187 Node* const name = |
187 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 188 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
188 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 189 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
189 return a->CallStub(getproperty_callable, context, regexp, name); | 190 return a->CallStub(getproperty_callable, context, regexp, name); |
190 } | 191 } |
191 | 192 |
192 compiler::Node* LoadLastIndex(CodeStubAssembler* a, compiler::Node* context, | 193 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, |
193 compiler::Node* has_initialmap, | 194 Node* regexp) { |
194 compiler::Node* regexp) { | 195 CVariable var_value(a, MachineRepresentation::kTagged); |
195 typedef CodeStubAssembler::Variable Variable; | |
196 typedef CodeStubAssembler::Label Label; | |
197 | 196 |
198 Variable var_value(a, MachineRepresentation::kTagged); | 197 CLabel out(a), if_unmodified(a), if_modified(a); |
199 | |
200 Label out(a), if_unmodified(a), if_modified(a); | |
201 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 198 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
202 | 199 |
203 a->Bind(&if_unmodified); | 200 a->Bind(&if_unmodified); |
204 { | 201 { |
205 var_value.Bind(FastLoadLastIndex(a, context, regexp)); | 202 var_value.Bind(FastLoadLastIndex(a, context, regexp)); |
206 a->Goto(&out); | 203 a->Goto(&out); |
207 } | 204 } |
208 | 205 |
209 a->Bind(&if_modified); | 206 a->Bind(&if_modified); |
210 { | 207 { |
211 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); | 208 var_value.Bind(SlowLoadLastIndex(a, context, regexp)); |
212 a->Goto(&out); | 209 a->Goto(&out); |
213 } | 210 } |
214 | 211 |
215 a->Bind(&out); | 212 a->Bind(&out); |
216 return var_value.value(); | 213 return var_value.value(); |
217 } | 214 } |
218 | 215 |
219 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified | 216 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified |
220 // JSRegExp instance. | 217 // JSRegExp instance. |
221 void FastStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 218 void FastStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
222 compiler::Node* regexp, compiler::Node* value) { | 219 Node* value) { |
223 // Store the in-object field. | 220 // Store the in-object field. |
224 static const int field_offset = | 221 static const int field_offset = |
225 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; | 222 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; |
226 a->StoreObjectField(regexp, field_offset, value); | 223 a->StoreObjectField(regexp, field_offset, value); |
227 } | 224 } |
228 | 225 |
229 void SlowStoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 226 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, |
230 compiler::Node* regexp, compiler::Node* value) { | 227 Node* value) { |
231 // Store through runtime. | 228 // Store through runtime. |
232 // TODO(ishell): Use SetPropertyStub here once available. | 229 // TODO(ishell): Use SetPropertyStub here once available. |
233 typedef compiler::Node Node; | |
234 | |
235 Node* const name = | 230 Node* const name = |
236 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); | 231 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); |
237 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); | 232 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); |
238 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, | 233 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, |
239 language_mode); | 234 language_mode); |
240 } | 235 } |
241 | 236 |
242 void StoreLastIndex(CodeStubAssembler* a, compiler::Node* context, | 237 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, |
243 compiler::Node* has_initialmap, compiler::Node* regexp, | 238 Node* regexp, Node* value) { |
244 compiler::Node* value) { | 239 CLabel out(a), if_unmodified(a), if_modified(a); |
245 typedef CodeStubAssembler::Label Label; | |
246 | |
247 Label out(a), if_unmodified(a), if_modified(a); | |
248 a->Branch(has_initialmap, &if_unmodified, &if_modified); | 240 a->Branch(has_initialmap, &if_unmodified, &if_modified); |
249 | 241 |
250 a->Bind(&if_unmodified); | 242 a->Bind(&if_unmodified); |
251 { | 243 { |
252 FastStoreLastIndex(a, context, regexp, value); | 244 FastStoreLastIndex(a, context, regexp, value); |
253 a->Goto(&out); | 245 a->Goto(&out); |
254 } | 246 } |
255 | 247 |
256 a->Bind(&if_modified); | 248 a->Bind(&if_modified); |
257 { | 249 { |
258 SlowStoreLastIndex(a, context, regexp, value); | 250 SlowStoreLastIndex(a, context, regexp, value); |
259 a->Goto(&out); | 251 a->Goto(&out); |
260 } | 252 } |
261 | 253 |
262 a->Bind(&out); | 254 a->Bind(&out); |
263 } | 255 } |
264 | 256 |
265 compiler::Node* ConstructNewResultFromMatchInfo(Isolate* isolate, | 257 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, |
266 CodeStubAssembler* a, | 258 Node* context, Node* match_info, |
267 compiler::Node* context, | 259 Node* string) { |
268 compiler::Node* match_info, | 260 CLabel out(a); |
269 compiler::Node* string) { | |
270 typedef CodeStubAssembler::Variable Variable; | |
271 typedef CodeStubAssembler::Label Label; | |
272 typedef compiler::Node Node; | |
273 | |
274 Label out(a); | |
275 | 261 |
276 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 262 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
277 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( | 263 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( |
278 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, | 264 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, |
279 mode)); | 265 mode)); |
280 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); | 266 Node* const num_results = a->SmiTag(a->WordShr(num_indices, 1)); |
281 Node* const start = a->LoadFixedArrayElement( | 267 Node* const start = a->LoadFixedArrayElement( |
282 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, | 268 match_info, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), 0, |
283 mode); | 269 mode); |
284 Node* const end = a->LoadFixedArrayElement( | 270 Node* const end = a->LoadFixedArrayElement( |
(...skipping 10 matching lines...) Expand all Loading... |
295 | 281 |
296 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, | 282 a->StoreFixedArrayElement(result_elements, a->IntPtrConstant(0), first, |
297 SKIP_WRITE_BARRIER); | 283 SKIP_WRITE_BARRIER); |
298 | 284 |
299 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); | 285 a->GotoIf(a->SmiEqual(num_results, a->SmiConstant(Smi::FromInt(1))), &out); |
300 | 286 |
301 // Store all remaining captures. | 287 // Store all remaining captures. |
302 Node* const limit = a->IntPtrAdd( | 288 Node* const limit = a->IntPtrAdd( |
303 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); | 289 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), num_indices); |
304 | 290 |
305 Variable var_from_cursor(a, MachineType::PointerRepresentation()); | 291 CVariable var_from_cursor(a, MachineType::PointerRepresentation()); |
306 Variable var_to_cursor(a, MachineType::PointerRepresentation()); | 292 CVariable var_to_cursor(a, MachineType::PointerRepresentation()); |
307 | 293 |
308 var_from_cursor.Bind( | 294 var_from_cursor.Bind( |
309 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); | 295 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 2)); |
310 var_to_cursor.Bind(a->IntPtrConstant(1)); | 296 var_to_cursor.Bind(a->IntPtrConstant(1)); |
311 | 297 |
312 Variable* vars[] = {&var_from_cursor, &var_to_cursor}; | 298 CVariable* vars[] = {&var_from_cursor, &var_to_cursor}; |
313 Label loop(a, 2, vars); | 299 CLabel loop(a, 2, vars); |
314 | 300 |
315 a->Goto(&loop); | 301 a->Goto(&loop); |
316 a->Bind(&loop); | 302 a->Bind(&loop); |
317 { | 303 { |
318 Node* const from_cursor = var_from_cursor.value(); | 304 Node* const from_cursor = var_from_cursor.value(); |
319 Node* const to_cursor = var_to_cursor.value(); | 305 Node* const to_cursor = var_to_cursor.value(); |
320 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); | 306 Node* const start = a->LoadFixedArrayElement(match_info, from_cursor); |
321 | 307 |
322 Label next_iter(a); | 308 CLabel next_iter(a); |
323 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); | 309 a->GotoIf(a->SmiEqual(start, a->SmiConstant(Smi::FromInt(-1))), &next_iter); |
324 | 310 |
325 Node* const from_cursor_plus1 = | 311 Node* const from_cursor_plus1 = |
326 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); | 312 a->IntPtrAdd(from_cursor, a->IntPtrConstant(1)); |
327 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1); | 313 Node* const end = a->LoadFixedArrayElement(match_info, from_cursor_plus1); |
328 | 314 |
329 Node* const capture = a->SubString(context, string, start, end); | 315 Node* const capture = a->SubString(context, string, start, end); |
330 a->StoreFixedArrayElement(result_elements, to_cursor, capture); | 316 a->StoreFixedArrayElement(result_elements, to_cursor, capture); |
331 a->Goto(&next_iter); | 317 a->Goto(&next_iter); |
332 | 318 |
333 a->Bind(&next_iter); | 319 a->Bind(&next_iter); |
334 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); | 320 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); |
335 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); | 321 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); |
336 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); | 322 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); |
337 } | 323 } |
338 | 324 |
339 a->Bind(&out); | 325 a->Bind(&out); |
340 return result; | 326 return result; |
341 } | 327 } |
342 | 328 |
343 // ES#sec-regexp.prototype.exec | 329 // ES#sec-regexp.prototype.exec |
344 // RegExp.prototype.exec ( string ) | 330 // RegExp.prototype.exec ( string ) |
345 compiler::Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, | 331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, |
346 compiler::Node* context, | 332 Node* maybe_receiver, Node* maybe_string) { |
347 compiler::Node* maybe_receiver, | |
348 compiler::Node* maybe_string) { | |
349 typedef CodeStubAssembler::Variable Variable; | |
350 typedef CodeStubAssembler::Label Label; | |
351 typedef compiler::Node Node; | |
352 | |
353 Isolate* const isolate = a->isolate(); | 333 Isolate* const isolate = a->isolate(); |
354 | 334 |
355 Node* const null = a->NullConstant(); | 335 Node* const null = a->NullConstant(); |
356 Node* const int_zero = a->IntPtrConstant(0); | 336 Node* const int_zero = a->IntPtrConstant(0); |
357 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 337 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
358 | 338 |
359 Variable var_result(a, MachineRepresentation::kTagged); | 339 CVariable var_result(a, MachineRepresentation::kTagged); |
360 Label out(a); | 340 CLabel out(a); |
361 | 341 |
362 // Ensure {maybe_receiver} is a JSRegExp. | 342 // Ensure {maybe_receiver} is a JSRegExp. |
363 Node* const regexp_map = a->ThrowIfNotInstanceType( | 343 Node* const regexp_map = a->ThrowIfNotInstanceType( |
364 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); | 344 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec"); |
365 Node* const regexp = maybe_receiver; | 345 Node* const regexp = maybe_receiver; |
366 | 346 |
367 // Check whether the regexp instance is unmodified. | 347 // Check whether the regexp instance is unmodified. |
368 Node* const native_context = a->LoadNativeContext(context); | 348 Node* const native_context = a->LoadNativeContext(context); |
369 Node* const regexp_fun = | 349 Node* const regexp_fun = |
370 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 350 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
371 Node* const initial_map = | 351 Node* const initial_map = |
372 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 352 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
373 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); | 353 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map); |
374 | 354 |
375 // Convert {maybe_string} to a string. | 355 // Convert {maybe_string} to a string. |
376 Callable tostring_callable = CodeFactory::ToString(isolate); | 356 Callable tostring_callable = CodeFactory::ToString(isolate); |
377 Node* const string = a->CallStub(tostring_callable, context, maybe_string); | 357 Node* const string = a->CallStub(tostring_callable, context, maybe_string); |
378 Node* const string_length = a->LoadStringLength(string); | 358 Node* const string_length = a->LoadStringLength(string); |
379 | 359 |
380 // Check whether the regexp is global or sticky, which determines whether we | 360 // Check whether the regexp is global or sticky, which determines whether we |
381 // update last index later on. | 361 // update last index later on. |
382 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
383 Node* const is_global_or_sticky = | 363 Node* const is_global_or_sticky = |
384 a->WordAnd(a->SmiUntag(flags), | 364 a->WordAnd(a->SmiUntag(flags), |
385 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); | 365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); |
386 Node* const should_update_last_index = | 366 Node* const should_update_last_index = |
387 a->WordNotEqual(is_global_or_sticky, int_zero); | 367 a->WordNotEqual(is_global_or_sticky, int_zero); |
388 | 368 |
389 // Grab and possibly update last index. | 369 // Grab and possibly update last index. |
390 Label run_exec(a); | 370 CLabel run_exec(a); |
391 Variable var_lastindex(a, MachineRepresentation::kTagged); | 371 CVariable var_lastindex(a, MachineRepresentation::kTagged); |
392 { | 372 { |
393 Label if_doupdate(a), if_dontupdate(a); | 373 CLabel if_doupdate(a), if_dontupdate(a); |
394 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); | 374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); |
395 | 375 |
396 a->Bind(&if_doupdate); | 376 a->Bind(&if_doupdate); |
397 { | 377 { |
398 Node* const regexp_lastindex = | 378 Node* const regexp_lastindex = |
399 LoadLastIndex(a, context, has_initialmap, regexp); | 379 LoadLastIndex(a, context, has_initialmap, regexp); |
400 | 380 |
401 Callable tolength_callable = CodeFactory::ToLength(isolate); | 381 Callable tolength_callable = CodeFactory::ToLength(isolate); |
402 Node* const lastindex = | 382 Node* const lastindex = |
403 a->CallStub(tolength_callable, context, regexp_lastindex); | 383 a->CallStub(tolength_callable, context, regexp_lastindex); |
404 var_lastindex.Bind(lastindex); | 384 var_lastindex.Bind(lastindex); |
405 | 385 |
406 Label if_isoob(a, Label::kDeferred); | 386 CLabel if_isoob(a, CLabel::kDeferred); |
407 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); | 387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); |
408 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); | 388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); |
409 a->Goto(&run_exec); | 389 a->Goto(&run_exec); |
410 | 390 |
411 a->Bind(&if_isoob); | 391 a->Bind(&if_isoob); |
412 { | 392 { |
413 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); |
414 var_result.Bind(null); | 394 var_result.Bind(null); |
415 a->Goto(&out); | 395 a->Goto(&out); |
416 } | 396 } |
417 } | 397 } |
418 | 398 |
419 a->Bind(&if_dontupdate); | 399 a->Bind(&if_dontupdate); |
420 { | 400 { |
421 var_lastindex.Bind(smi_zero); | 401 var_lastindex.Bind(smi_zero); |
422 a->Goto(&run_exec); | 402 a->Goto(&run_exec); |
423 } | 403 } |
424 } | 404 } |
425 | 405 |
426 Node* match_indices; | 406 Node* match_indices; |
427 Label successful_match(a); | 407 CLabel successful_match(a); |
428 a->Bind(&run_exec); | 408 a->Bind(&run_exec); |
429 { | 409 { |
430 // Get last match info from the context. | 410 // Get last match info from the context. |
431 Node* const last_match_info = a->LoadContextElement( | 411 Node* const last_match_info = a->LoadContextElement( |
432 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
433 | 413 |
434 // Call the exec stub. | 414 // Call the exec stub. |
435 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 415 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
436 match_indices = a->CallStub(exec_callable, context, regexp, string, | 416 match_indices = a->CallStub(exec_callable, context, regexp, string, |
437 var_lastindex.value(), last_match_info); | 417 var_lastindex.value(), last_match_info); |
438 | 418 |
439 // {match_indices} is either null or the RegExpMatchInfo array. | 419 // {match_indices} is either null or the RegExpMatchInfo array. |
440 // Return early if exec failed, possibly updating last index. | 420 // Return early if exec failed, possibly updating last index. |
441 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); | 421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); |
442 | 422 |
443 Label return_null(a); | 423 CLabel return_null(a); |
444 a->GotoUnless(should_update_last_index, &return_null); | 424 a->GotoUnless(should_update_last_index, &return_null); |
445 | 425 |
446 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); | 426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); |
447 a->Goto(&return_null); | 427 a->Goto(&return_null); |
448 | 428 |
449 a->Bind(&return_null); | 429 a->Bind(&return_null); |
450 var_result.Bind(null); | 430 var_result.Bind(null); |
451 a->Goto(&out); | 431 a->Goto(&out); |
452 } | 432 } |
453 | 433 |
454 Label construct_result(a); | 434 CLabel construct_result(a); |
455 a->Bind(&successful_match); | 435 a->Bind(&successful_match); |
456 { | 436 { |
457 a->GotoUnless(should_update_last_index, &construct_result); | 437 a->GotoUnless(should_update_last_index, &construct_result); |
458 | 438 |
459 // Update the new last index from {match_indices}. | 439 // Update the new last index from {match_indices}. |
460 Node* const new_lastindex = a->LoadFixedArrayElement( | 440 Node* const new_lastindex = a->LoadFixedArrayElement( |
461 match_indices, | 441 match_indices, |
462 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); | 442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); |
463 | 443 |
464 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); | 444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); |
465 a->Goto(&construct_result); | 445 a->Goto(&construct_result); |
466 | 446 |
467 a->Bind(&construct_result); | 447 a->Bind(&construct_result); |
468 { | 448 { |
469 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, | 449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, |
470 match_indices, string); | 450 match_indices, string); |
471 var_result.Bind(result); | 451 var_result.Bind(result); |
472 a->Goto(&out); | 452 a->Goto(&out); |
473 } | 453 } |
474 } | 454 } |
475 | 455 |
476 a->Bind(&out); | 456 a->Bind(&out); |
477 return var_result.value(); | 457 return var_result.value(); |
478 } | 458 } |
479 | 459 |
480 } // namespace | 460 } // namespace |
481 | 461 |
482 // ES#sec-regexp.prototype.exec | 462 // ES#sec-regexp.prototype.exec |
483 // RegExp.prototype.exec ( string ) | 463 // RegExp.prototype.exec ( string ) |
484 void Builtins::Generate_RegExpPrototypeExec( | 464 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) { |
485 compiler::CodeAssemblerState* state) { | |
486 typedef compiler::Node Node; | |
487 CodeStubAssembler a(state); | 465 CodeStubAssembler a(state); |
488 | 466 |
489 Node* const maybe_receiver = a.Parameter(0); | 467 Node* const maybe_receiver = a.Parameter(0); |
490 Node* const maybe_string = a.Parameter(1); | 468 Node* const maybe_string = a.Parameter(1); |
491 Node* const context = a.Parameter(4); | 469 Node* const context = a.Parameter(4); |
492 | 470 |
493 Node* const result = | 471 Node* const result = |
494 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); | 472 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string); |
495 a.Return(result); | 473 a.Return(result); |
496 } | 474 } |
497 | 475 |
498 namespace { | 476 namespace { |
499 | 477 |
500 compiler::Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, | 478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, |
501 compiler::Node* context, | 479 Node* context, Node* value, |
502 compiler::Node* value, | 480 MessageTemplate::Template msg_template, |
503 MessageTemplate::Template msg_template, | 481 char const* method_name) { |
504 char const* method_name) { | 482 CLabel out(a), throw_exception(a, CLabel::kDeferred); |
505 typedef compiler::Node Node; | 483 CVariable var_value_map(a, MachineRepresentation::kTagged); |
506 typedef CodeStubAssembler::Label Label; | |
507 typedef CodeStubAssembler::Variable Variable; | |
508 | |
509 Label out(a), throw_exception(a, Label::kDeferred); | |
510 Variable var_value_map(a, MachineRepresentation::kTagged); | |
511 | 484 |
512 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); | 485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); |
513 | 486 |
514 // Load the instance type of the {value}. | 487 // Load the instance type of the {value}. |
515 var_value_map.Bind(a->LoadMap(value)); | 488 var_value_map.Bind(a->LoadMap(value)); |
516 Node* const value_instance_type = | 489 Node* const value_instance_type = |
517 a->LoadMapInstanceType(var_value_map.value()); | 490 a->LoadMapInstanceType(var_value_map.value()); |
518 | 491 |
519 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, | 492 a->Branch(a->IsJSReceiverInstanceType(value_instance_type), &out, |
520 &throw_exception); | 493 &throw_exception); |
(...skipping 11 matching lines...) Expand all Loading... |
532 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, | 505 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, |
533 method_name_str, value_str); | 506 method_name_str, value_str); |
534 var_value_map.Bind(a->UndefinedConstant()); | 507 var_value_map.Bind(a->UndefinedConstant()); |
535 a->Goto(&out); // Never reached. | 508 a->Goto(&out); // Never reached. |
536 } | 509 } |
537 | 510 |
538 a->Bind(&out); | 511 a->Bind(&out); |
539 return var_value_map.value(); | 512 return var_value_map.value(); |
540 } | 513 } |
541 | 514 |
542 compiler::Node* IsInitialRegExpMap(CodeStubAssembler* a, | 515 Node* IsInitialRegExpMap(CodeStubAssembler* a, Node* context, Node* map) { |
543 compiler::Node* context, | |
544 compiler::Node* map) { | |
545 typedef compiler::Node Node; | |
546 | |
547 Node* const native_context = a->LoadNativeContext(context); | 516 Node* const native_context = a->LoadNativeContext(context); |
548 Node* const regexp_fun = | 517 Node* const regexp_fun = |
549 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 518 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
550 Node* const initial_map = | 519 Node* const initial_map = |
551 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 520 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
552 Node* const has_initialmap = a->WordEqual(map, initial_map); | 521 Node* const has_initialmap = a->WordEqual(map, initial_map); |
553 | 522 |
554 return has_initialmap; | 523 return has_initialmap; |
555 } | 524 } |
556 | 525 |
557 // RegExp fast path implementations rely on unmodified JSRegExp instances. | 526 // RegExp fast path implementations rely on unmodified JSRegExp instances. |
558 // We use a fairly coarse granularity for this and simply check whether both | 527 // We use a fairly coarse granularity for this and simply check whether both |
559 // the regexp itself is unmodified (i.e. its map has not changed) and its | 528 // the regexp itself is unmodified (i.e. its map has not changed) and its |
560 // prototype is unmodified. | 529 // prototype is unmodified. |
561 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context, | 530 void BranchIfFastPath(CodeStubAssembler* a, Node* context, Node* map, |
562 compiler::Node* map, | 531 CLabel* if_isunmodified, CLabel* if_ismodified) { |
563 CodeStubAssembler::Label* if_isunmodified, | |
564 CodeStubAssembler::Label* if_ismodified) { | |
565 typedef compiler::Node Node; | |
566 | |
567 Node* const native_context = a->LoadNativeContext(context); | 532 Node* const native_context = a->LoadNativeContext(context); |
568 Node* const regexp_fun = | 533 Node* const regexp_fun = |
569 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 534 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
570 Node* const initial_map = | 535 Node* const initial_map = |
571 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 536 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
572 Node* const has_initialmap = a->WordEqual(map, initial_map); | 537 Node* const has_initialmap = a->WordEqual(map, initial_map); |
573 | 538 |
574 a->GotoUnless(has_initialmap, if_ismodified); | 539 a->GotoUnless(has_initialmap, if_ismodified); |
575 | 540 |
576 Node* const initial_proto_initial_map = a->LoadContextElement( | 541 Node* const initial_proto_initial_map = a->LoadContextElement( |
577 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); | 542 native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); |
578 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); | 543 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); |
579 Node* const proto_has_initialmap = | 544 Node* const proto_has_initialmap = |
580 a->WordEqual(proto_map, initial_proto_initial_map); | 545 a->WordEqual(proto_map, initial_proto_initial_map); |
581 | 546 |
582 // TODO(ishell): Update this check once map changes for constant field | 547 // TODO(ishell): Update this check once map changes for constant field |
583 // tracking are landing. | 548 // tracking are landing. |
584 | 549 |
585 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | 550 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
586 } | 551 } |
587 | 552 |
588 } // namespace | 553 } // namespace |
589 | 554 |
590 void Builtins::Generate_RegExpPrototypeFlagsGetter( | 555 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { |
591 compiler::CodeAssemblerState* state) { | |
592 typedef CodeStubAssembler::Variable Variable; | |
593 typedef CodeStubAssembler::Label Label; | |
594 typedef compiler::Node Node; | |
595 CodeStubAssembler a(state); | 556 CodeStubAssembler a(state); |
596 | 557 |
597 Node* const receiver = a.Parameter(0); | 558 Node* const receiver = a.Parameter(0); |
598 Node* const context = a.Parameter(3); | 559 Node* const context = a.Parameter(3); |
599 | 560 |
600 Isolate* isolate = a.isolate(); | 561 Isolate* isolate = a.isolate(); |
601 Node* const int_zero = a.IntPtrConstant(0); | 562 Node* const int_zero = a.IntPtrConstant(0); |
602 Node* const int_one = a.IntPtrConstant(1); | 563 Node* const int_one = a.IntPtrConstant(1); |
603 | 564 |
604 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver, | 565 Node* const map = ThrowIfNotJSReceiver(&a, isolate, context, receiver, |
605 MessageTemplate::kRegExpNonObject, | 566 MessageTemplate::kRegExpNonObject, |
606 "RegExp.prototype.flags"); | 567 "RegExp.prototype.flags"); |
607 | 568 |
608 Variable var_length(&a, MachineType::PointerRepresentation()); | 569 CVariable var_length(&a, MachineType::PointerRepresentation()); |
609 Variable var_flags(&a, MachineType::PointerRepresentation()); | 570 CVariable var_flags(&a, MachineType::PointerRepresentation()); |
610 | 571 |
611 // First, count the number of characters we will need and check which flags | 572 // First, count the number of characters we will need and check which flags |
612 // are set. | 573 // are set. |
613 | 574 |
614 var_length.Bind(int_zero); | 575 var_length.Bind(int_zero); |
615 | 576 |
616 Label if_isunmodifiedjsregexp(&a), | 577 CLabel if_isunmodifiedjsregexp(&a), |
617 if_isnotunmodifiedjsregexp(&a, Label::kDeferred); | 578 if_isnotunmodifiedjsregexp(&a, CLabel::kDeferred); |
618 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, | 579 a.Branch(IsInitialRegExpMap(&a, context, map), &if_isunmodifiedjsregexp, |
619 &if_isnotunmodifiedjsregexp); | 580 &if_isnotunmodifiedjsregexp); |
620 | 581 |
621 Label construct_string(&a); | 582 CLabel construct_string(&a); |
622 a.Bind(&if_isunmodifiedjsregexp); | 583 a.Bind(&if_isunmodifiedjsregexp); |
623 { | 584 { |
624 // Refer to JSRegExp's flag property on the fast-path. | 585 // Refer to JSRegExp's flag property on the fast-path. |
625 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); | 586 Node* const flags_smi = a.LoadObjectField(receiver, JSRegExp::kFlagsOffset); |
626 Node* const flags_intptr = a.SmiUntag(flags_smi); | 587 Node* const flags_intptr = a.SmiUntag(flags_smi); |
627 var_flags.Bind(flags_intptr); | 588 var_flags.Bind(flags_intptr); |
628 | 589 |
629 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 590 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
630 label_unicode(&a), label_sticky(&a); | 591 label_unicode(&a), label_sticky(&a); |
631 | 592 |
632 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ | 593 #define CASE_FOR_FLAG(FLAG, LABEL, NEXT_LABEL) \ |
633 do { \ | 594 do { \ |
634 a.Bind(&LABEL); \ | 595 a.Bind(&LABEL); \ |
635 Node* const mask = a.IntPtrConstant(FLAG); \ | 596 Node* const mask = a.IntPtrConstant(FLAG); \ |
636 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 597 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ |
637 &NEXT_LABEL); \ | 598 &NEXT_LABEL); \ |
638 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 599 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ |
639 a.Goto(&NEXT_LABEL); \ | 600 a.Goto(&NEXT_LABEL); \ |
640 } while (false) | 601 } while (false) |
641 | 602 |
642 a.Goto(&label_global); | 603 a.Goto(&label_global); |
643 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); | 604 CASE_FOR_FLAG(JSRegExp::kGlobal, label_global, label_ignorecase); |
644 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); | 605 CASE_FOR_FLAG(JSRegExp::kIgnoreCase, label_ignorecase, label_multiline); |
645 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); | 606 CASE_FOR_FLAG(JSRegExp::kMultiline, label_multiline, label_unicode); |
646 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); | 607 CASE_FOR_FLAG(JSRegExp::kUnicode, label_unicode, label_sticky); |
647 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); | 608 CASE_FOR_FLAG(JSRegExp::kSticky, label_sticky, construct_string); |
648 #undef CASE_FOR_FLAG | 609 #undef CASE_FOR_FLAG |
649 } | 610 } |
650 | 611 |
651 a.Bind(&if_isnotunmodifiedjsregexp); | 612 a.Bind(&if_isnotunmodifiedjsregexp); |
652 { | 613 { |
653 // Fall back to GetProperty stub on the slow-path. | 614 // Fall back to GetProperty stub on the slow-path. |
654 var_flags.Bind(int_zero); | 615 var_flags.Bind(int_zero); |
655 | 616 |
656 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); | 617 Callable getproperty_callable = CodeFactory::GetProperty(a.isolate()); |
657 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 618 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
658 label_unicode(&a), label_sticky(&a); | 619 label_unicode(&a), label_sticky(&a); |
659 | 620 |
660 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ | 621 #define CASE_FOR_FLAG(NAME, FLAG, LABEL, NEXT_LABEL) \ |
661 do { \ | 622 do { \ |
662 a.Bind(&LABEL); \ | 623 a.Bind(&LABEL); \ |
663 Node* const name = \ | 624 Node* const name = \ |
664 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ | 625 a.HeapConstant(isolate->factory()->NewStringFromAsciiChecked(NAME)); \ |
665 Node* const flag = \ | 626 Node* const flag = \ |
666 a.CallStub(getproperty_callable, context, receiver, name); \ | 627 a.CallStub(getproperty_callable, context, receiver, name); \ |
667 Label if_isflagset(&a); \ | 628 CLabel if_isflagset(&a); \ |
668 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ | 629 a.BranchIfToBooleanIsTrue(flag, &if_isflagset, &NEXT_LABEL); \ |
669 a.Bind(&if_isflagset); \ | 630 a.Bind(&if_isflagset); \ |
670 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ | 631 var_length.Bind(a.IntPtrAdd(var_length.value(), int_one)); \ |
671 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ | 632 var_flags.Bind(a.WordOr(var_flags.value(), a.IntPtrConstant(FLAG))); \ |
672 a.Goto(&NEXT_LABEL); \ | 633 a.Goto(&NEXT_LABEL); \ |
673 } while (false) | 634 } while (false) |
674 | 635 |
675 a.Goto(&label_global); | 636 a.Goto(&label_global); |
676 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); | 637 CASE_FOR_FLAG("global", JSRegExp::kGlobal, label_global, label_ignorecase); |
677 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, | 638 CASE_FOR_FLAG("ignoreCase", JSRegExp::kIgnoreCase, label_ignorecase, |
678 label_multiline); | 639 label_multiline); |
679 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, | 640 CASE_FOR_FLAG("multiline", JSRegExp::kMultiline, label_multiline, |
680 label_unicode); | 641 label_unicode); |
681 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); | 642 CASE_FOR_FLAG("unicode", JSRegExp::kUnicode, label_unicode, label_sticky); |
682 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); | 643 CASE_FOR_FLAG("sticky", JSRegExp::kSticky, label_sticky, construct_string); |
683 #undef CASE_FOR_FLAG | 644 #undef CASE_FOR_FLAG |
684 } | 645 } |
685 | 646 |
686 // Allocate a string of the required length and fill it with the corresponding | 647 // Allocate a string of the required length and fill it with the corresponding |
687 // char for each set flag. | 648 // char for each set flag. |
688 | 649 |
689 a.Bind(&construct_string); | 650 a.Bind(&construct_string); |
690 { | 651 { |
691 Node* const result = | 652 Node* const result = |
692 a.AllocateSeqOneByteString(context, var_length.value()); | 653 a.AllocateSeqOneByteString(context, var_length.value()); |
693 Node* const flags_intptr = var_flags.value(); | 654 Node* const flags_intptr = var_flags.value(); |
694 | 655 |
695 Variable var_offset(&a, MachineType::PointerRepresentation()); | 656 CVariable var_offset(&a, MachineType::PointerRepresentation()); |
696 var_offset.Bind( | 657 var_offset.Bind( |
697 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 658 a.IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
698 | 659 |
699 Label label_global(&a), label_ignorecase(&a), label_multiline(&a), | 660 CLabel label_global(&a), label_ignorecase(&a), label_multiline(&a), |
700 label_unicode(&a), label_sticky(&a), out(&a); | 661 label_unicode(&a), label_sticky(&a), out(&a); |
701 | 662 |
702 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ | 663 #define CASE_FOR_FLAG(FLAG, CHAR, LABEL, NEXT_LABEL) \ |
703 do { \ | 664 do { \ |
704 a.Bind(&LABEL); \ | 665 a.Bind(&LABEL); \ |
705 Node* const mask = a.IntPtrConstant(FLAG); \ | 666 Node* const mask = a.IntPtrConstant(FLAG); \ |
706 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ | 667 a.GotoIf(a.WordEqual(a.WordAnd(flags_intptr, mask), int_zero), \ |
707 &NEXT_LABEL); \ | 668 &NEXT_LABEL); \ |
708 Node* const value = a.IntPtrConstant(CHAR); \ | 669 Node* const value = a.IntPtrConstant(CHAR); \ |
709 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ | 670 a.StoreNoWriteBarrier(MachineRepresentation::kWord8, result, \ |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 | 747 |
787 // ES6 21.2.4.2. | 748 // ES6 21.2.4.2. |
788 BUILTIN(RegExpPrototypeSpeciesGetter) { | 749 BUILTIN(RegExpPrototypeSpeciesGetter) { |
789 HandleScope scope(isolate); | 750 HandleScope scope(isolate); |
790 return *args.receiver(); | 751 return *args.receiver(); |
791 } | 752 } |
792 | 753 |
793 namespace { | 754 namespace { |
794 | 755 |
795 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. | 756 // Fast-path implementation for flag checks on an unmodified JSRegExp instance. |
796 compiler::Node* FastFlagGetter(CodeStubAssembler* a, | 757 Node* FastFlagGetter(CodeStubAssembler* a, Node* const regexp, |
797 compiler::Node* const regexp, | 758 JSRegExp::Flag flag) { |
798 JSRegExp::Flag flag) { | |
799 typedef compiler::Node Node; | |
800 | |
801 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 759 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
802 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 760 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
803 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); | 761 Node* const mask = a->SmiConstant(Smi::FromInt(flag)); |
804 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); | 762 Node* const is_flag_set = a->WordNotEqual(a->WordAnd(flags, mask), smi_zero); |
805 | 763 |
806 return is_flag_set; | 764 return is_flag_set; |
807 } | 765 } |
808 | 766 |
809 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, | 767 void Generate_FlagGetter(CodeStubAssembler* a, JSRegExp::Flag flag, |
810 v8::Isolate::UseCounterFeature counter, | 768 v8::Isolate::UseCounterFeature counter, |
811 const char* method_name) { | 769 const char* method_name) { |
812 typedef CodeStubAssembler::Label Label; | |
813 typedef compiler::Node Node; | |
814 | |
815 Node* const receiver = a->Parameter(0); | 770 Node* const receiver = a->Parameter(0); |
816 Node* const context = a->Parameter(3); | 771 Node* const context = a->Parameter(3); |
817 | 772 |
818 Isolate* isolate = a->isolate(); | 773 Isolate* isolate = a->isolate(); |
819 | 774 |
820 // Check whether we have an unmodified regexp instance. | 775 // Check whether we have an unmodified regexp instance. |
821 Label if_isunmodifiedjsregexp(a), | 776 CLabel if_isunmodifiedjsregexp(a), |
822 if_isnotunmodifiedjsregexp(a, Label::kDeferred); | 777 if_isnotunmodifiedjsregexp(a, CLabel::kDeferred); |
823 | 778 |
824 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); | 779 a->GotoIf(a->TaggedIsSmi(receiver), &if_isnotunmodifiedjsregexp); |
825 | 780 |
826 Node* const receiver_map = a->LoadMap(receiver); | 781 Node* const receiver_map = a->LoadMap(receiver); |
827 Node* const instance_type = a->LoadMapInstanceType(receiver_map); | 782 Node* const instance_type = a->LoadMapInstanceType(receiver_map); |
828 | 783 |
829 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), | 784 a->Branch(a->Word32Equal(instance_type, a->Int32Constant(JS_REGEXP_TYPE)), |
830 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); | 785 &if_isunmodifiedjsregexp, &if_isnotunmodifiedjsregexp); |
831 | 786 |
832 a->Bind(&if_isunmodifiedjsregexp); | 787 a->Bind(&if_isunmodifiedjsregexp); |
833 { | 788 { |
834 // Refer to JSRegExp's flag property on the fast-path. | 789 // Refer to JSRegExp's flag property on the fast-path. |
835 Node* const is_flag_set = FastFlagGetter(a, receiver, flag); | 790 Node* const is_flag_set = FastFlagGetter(a, receiver, flag); |
836 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant())); | 791 a->Return(a->Select(is_flag_set, a->TrueConstant(), a->FalseConstant())); |
837 } | 792 } |
838 | 793 |
839 a->Bind(&if_isnotunmodifiedjsregexp); | 794 a->Bind(&if_isnotunmodifiedjsregexp); |
840 { | 795 { |
841 Node* const native_context = a->LoadNativeContext(context); | 796 Node* const native_context = a->LoadNativeContext(context); |
842 Node* const regexp_fun = | 797 Node* const regexp_fun = |
843 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); | 798 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); |
844 Node* const initial_map = a->LoadObjectField( | 799 Node* const initial_map = a->LoadObjectField( |
845 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); | 800 regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); |
846 Node* const initial_prototype = a->LoadMapPrototype(initial_map); | 801 Node* const initial_prototype = a->LoadMapPrototype(initial_map); |
847 | 802 |
848 Label if_isprototype(a), if_isnotprototype(a); | 803 CLabel if_isprototype(a), if_isnotprototype(a); |
849 a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype, | 804 a->Branch(a->WordEqual(receiver, initial_prototype), &if_isprototype, |
850 &if_isnotprototype); | 805 &if_isnotprototype); |
851 | 806 |
852 a->Bind(&if_isprototype); | 807 a->Bind(&if_isprototype); |
853 { | 808 { |
854 Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter)); | 809 Node* const counter_smi = a->SmiConstant(Smi::FromInt(counter)); |
855 a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); | 810 a->CallRuntime(Runtime::kIncrementUseCounter, context, counter_smi); |
856 a->Return(a->UndefinedConstant()); | 811 a->Return(a->UndefinedConstant()); |
857 } | 812 } |
858 | 813 |
859 a->Bind(&if_isnotprototype); | 814 a->Bind(&if_isnotprototype); |
860 { | 815 { |
861 Node* const message_id = | 816 Node* const message_id = |
862 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); | 817 a->SmiConstant(Smi::FromInt(MessageTemplate::kRegExpNonRegExp)); |
863 Node* const method_name_str = a->HeapConstant( | 818 Node* const method_name_str = a->HeapConstant( |
864 isolate->factory()->NewStringFromAsciiChecked(method_name)); | 819 isolate->factory()->NewStringFromAsciiChecked(method_name)); |
865 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, | 820 a->CallRuntime(Runtime::kThrowTypeError, context, message_id, |
866 method_name_str); | 821 method_name_str); |
867 a->Return(a->UndefinedConstant()); // Never reached. | 822 a->Return(a->UndefinedConstant()); // Never reached. |
868 } | 823 } |
869 } | 824 } |
870 } | 825 } |
871 | 826 |
872 } // namespace | 827 } // namespace |
873 | 828 |
874 // ES6 21.2.5.4. | 829 // ES6 21.2.5.4. |
875 void Builtins::Generate_RegExpPrototypeGlobalGetter( | 830 void Builtins::Generate_RegExpPrototypeGlobalGetter(CodeAssemblerState* state) { |
876 compiler::CodeAssemblerState* state) { | |
877 CodeStubAssembler a(state); | 831 CodeStubAssembler a(state); |
878 Generate_FlagGetter(&a, JSRegExp::kGlobal, | 832 Generate_FlagGetter(&a, JSRegExp::kGlobal, |
879 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 833 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
880 "RegExp.prototype.global"); | 834 "RegExp.prototype.global"); |
881 } | 835 } |
882 | 836 |
883 // ES6 21.2.5.5. | 837 // ES6 21.2.5.5. |
884 void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter( | 838 void Builtins::Generate_RegExpPrototypeIgnoreCaseGetter( |
885 compiler::CodeAssemblerState* state) { | 839 CodeAssemblerState* state) { |
886 CodeStubAssembler a(state); | 840 CodeStubAssembler a(state); |
887 Generate_FlagGetter(&a, JSRegExp::kIgnoreCase, | 841 Generate_FlagGetter(&a, JSRegExp::kIgnoreCase, |
888 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 842 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
889 "RegExp.prototype.ignoreCase"); | 843 "RegExp.prototype.ignoreCase"); |
890 } | 844 } |
891 | 845 |
892 // ES6 21.2.5.7. | 846 // ES6 21.2.5.7. |
893 void Builtins::Generate_RegExpPrototypeMultilineGetter( | 847 void Builtins::Generate_RegExpPrototypeMultilineGetter( |
894 compiler::CodeAssemblerState* state) { | 848 CodeAssemblerState* state) { |
895 CodeStubAssembler a(state); | 849 CodeStubAssembler a(state); |
896 Generate_FlagGetter(&a, JSRegExp::kMultiline, | 850 Generate_FlagGetter(&a, JSRegExp::kMultiline, |
897 v8::Isolate::kRegExpPrototypeOldFlagGetter, | 851 v8::Isolate::kRegExpPrototypeOldFlagGetter, |
898 "RegExp.prototype.multiline"); | 852 "RegExp.prototype.multiline"); |
899 } | 853 } |
900 | 854 |
901 // ES6 21.2.5.12. | 855 // ES6 21.2.5.12. |
902 void Builtins::Generate_RegExpPrototypeStickyGetter( | 856 void Builtins::Generate_RegExpPrototypeStickyGetter(CodeAssemblerState* state) { |
903 compiler::CodeAssemblerState* state) { | |
904 CodeStubAssembler a(state); | 857 CodeStubAssembler a(state); |
905 Generate_FlagGetter(&a, JSRegExp::kSticky, | 858 Generate_FlagGetter(&a, JSRegExp::kSticky, |
906 v8::Isolate::kRegExpPrototypeStickyGetter, | 859 v8::Isolate::kRegExpPrototypeStickyGetter, |
907 "RegExp.prototype.sticky"); | 860 "RegExp.prototype.sticky"); |
908 } | 861 } |
909 | 862 |
910 // ES6 21.2.5.15. | 863 // ES6 21.2.5.15. |
911 void Builtins::Generate_RegExpPrototypeUnicodeGetter( | 864 void Builtins::Generate_RegExpPrototypeUnicodeGetter( |
912 compiler::CodeAssemblerState* state) { | 865 CodeAssemblerState* state) { |
913 CodeStubAssembler a(state); | 866 CodeStubAssembler a(state); |
914 Generate_FlagGetter(&a, JSRegExp::kUnicode, | 867 Generate_FlagGetter(&a, JSRegExp::kUnicode, |
915 v8::Isolate::kRegExpPrototypeUnicodeGetter, | 868 v8::Isolate::kRegExpPrototypeUnicodeGetter, |
916 "RegExp.prototype.unicode"); | 869 "RegExp.prototype.unicode"); |
917 } | 870 } |
918 | 871 |
919 // The properties $1..$9 are the first nine capturing substrings of the last | 872 // The properties $1..$9 are the first nine capturing substrings of the last |
920 // successful match, or ''. The function RegExpMakeCaptureGetter will be | 873 // successful match, or ''. The function RegExpMakeCaptureGetter will be |
921 // called with indices from 1 to 9. | 874 // called with indices from 1 to 9. |
922 #define DEFINE_CAPTURE_GETTER(i) \ | 875 #define DEFINE_CAPTURE_GETTER(i) \ |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); | 948 Handle<RegExpMatchInfo> match_info = isolate->regexp_last_match_info(); |
996 const int start_index = match_info->Capture(1); | 949 const int start_index = match_info->Capture(1); |
997 Handle<String> last_subject(match_info->LastSubject()); | 950 Handle<String> last_subject(match_info->LastSubject()); |
998 const int len = last_subject->length(); | 951 const int len = last_subject->length(); |
999 return *isolate->factory()->NewSubString(last_subject, start_index, len); | 952 return *isolate->factory()->NewSubString(last_subject, start_index, len); |
1000 } | 953 } |
1001 | 954 |
1002 namespace { | 955 namespace { |
1003 | 956 |
1004 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 957 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
1005 compiler::Node* RegExpExec(CodeStubAssembler* a, compiler::Node* context, | 958 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, |
1006 compiler::Node* recv, compiler::Node* string) { | 959 Node* string) { |
1007 typedef CodeStubAssembler::Variable Variable; | |
1008 typedef CodeStubAssembler::Label Label; | |
1009 typedef compiler::Node Node; | |
1010 | |
1011 Isolate* isolate = a->isolate(); | 960 Isolate* isolate = a->isolate(); |
1012 | 961 |
1013 Node* const null = a->NullConstant(); | 962 Node* const null = a->NullConstant(); |
1014 | 963 |
1015 Variable var_result(a, MachineRepresentation::kTagged); | 964 CVariable var_result(a, MachineRepresentation::kTagged); |
1016 Label out(a), call_builtin_exec(a), slow_path(a, Label::kDeferred); | 965 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); |
1017 | 966 |
1018 Node* const map = a->LoadMap(recv); | 967 Node* const map = a->LoadMap(recv); |
1019 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); | 968 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); |
1020 | 969 |
1021 a->Bind(&call_builtin_exec); | 970 a->Bind(&call_builtin_exec); |
1022 { | 971 { |
1023 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); | 972 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); |
1024 var_result.Bind(result); | 973 var_result.Bind(result); |
1025 a->Goto(&out); | 974 a->Goto(&out); |
1026 } | 975 } |
1027 | 976 |
1028 a->Bind(&slow_path); | 977 a->Bind(&slow_path); |
1029 { | 978 { |
1030 // Take the slow path of fetching the exec property, calling it, and | 979 // Take the slow path of fetching the exec property, calling it, and |
1031 // verifying its return value. | 980 // verifying its return value. |
1032 | 981 |
1033 // Get the exec property. | 982 // Get the exec property. |
1034 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); | 983 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); |
1035 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | 984 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
1036 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); | 985 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); |
1037 | 986 |
1038 // Is {exec} callable? | 987 // Is {exec} callable? |
1039 Label if_iscallable(a), if_isnotcallable(a); | 988 CLabel if_iscallable(a), if_isnotcallable(a); |
1040 | 989 |
1041 a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable); | 990 a->GotoIf(a->TaggedIsSmi(exec), &if_isnotcallable); |
1042 | 991 |
1043 Node* const exec_map = a->LoadMap(exec); | 992 Node* const exec_map = a->LoadMap(exec); |
1044 a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); | 993 a->Branch(a->IsCallableMap(exec_map), &if_iscallable, &if_isnotcallable); |
1045 | 994 |
1046 a->Bind(&if_iscallable); | 995 a->Bind(&if_iscallable); |
1047 { | 996 { |
1048 Callable call_callable = CodeFactory::Call(isolate); | 997 Callable call_callable = CodeFactory::Call(isolate); |
1049 Node* const result = | 998 Node* const result = |
(...skipping 17 matching lines...) Expand all Loading... |
1067 } | 1016 } |
1068 | 1017 |
1069 a->Bind(&out); | 1018 a->Bind(&out); |
1070 return var_result.value(); | 1019 return var_result.value(); |
1071 } | 1020 } |
1072 | 1021 |
1073 } // namespace | 1022 } // namespace |
1074 | 1023 |
1075 // ES#sec-regexp.prototype.test | 1024 // ES#sec-regexp.prototype.test |
1076 // RegExp.prototype.test ( S ) | 1025 // RegExp.prototype.test ( S ) |
1077 void Builtins::Generate_RegExpPrototypeTest( | 1026 void Builtins::Generate_RegExpPrototypeTest(CodeAssemblerState* state) { |
1078 compiler::CodeAssemblerState* state) { | |
1079 typedef compiler::Node Node; | |
1080 CodeStubAssembler a(state); | 1027 CodeStubAssembler a(state); |
1081 | 1028 |
1082 Isolate* const isolate = a.isolate(); | 1029 Isolate* const isolate = a.isolate(); |
1083 | 1030 |
1084 Node* const maybe_receiver = a.Parameter(0); | 1031 Node* const maybe_receiver = a.Parameter(0); |
1085 Node* const maybe_string = a.Parameter(1); | 1032 Node* const maybe_string = a.Parameter(1); |
1086 Node* const context = a.Parameter(4); | 1033 Node* const context = a.Parameter(4); |
1087 | 1034 |
1088 // Ensure {maybe_receiver} is a JSReceiver. | 1035 // Ensure {maybe_receiver} is a JSReceiver. |
1089 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1036 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1170 } | 1117 } |
1171 } | 1118 } |
1172 | 1119 |
1173 elems->Shrink(n); | 1120 elems->Shrink(n); |
1174 return *isolate->factory()->NewJSArrayWithElements(elems); | 1121 return *isolate->factory()->NewJSArrayWithElements(elems); |
1175 } | 1122 } |
1176 | 1123 |
1177 namespace { | 1124 namespace { |
1178 | 1125 |
1179 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, | 1126 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, |
1180 compiler::Node* const receiver, | 1127 Node* const receiver, |
1181 compiler::Node* const string, | 1128 Node* const string, Node* const context, |
1182 compiler::Node* const context, | |
1183 bool is_fastpath) { | 1129 bool is_fastpath) { |
1184 typedef CodeStubAssembler::Label Label; | |
1185 typedef compiler::Node Node; | |
1186 | |
1187 Isolate* const isolate = a->isolate(); | 1130 Isolate* const isolate = a->isolate(); |
1188 | 1131 |
1189 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1132 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1190 | 1133 |
1191 // Grab the initial value of last index. | 1134 // Grab the initial value of last index. |
1192 Node* const previous_last_index = | 1135 Node* const previous_last_index = |
1193 is_fastpath ? FastLoadLastIndex(a, context, receiver) | 1136 is_fastpath ? FastLoadLastIndex(a, context, receiver) |
1194 : SlowLoadLastIndex(a, context, receiver); | 1137 : SlowLoadLastIndex(a, context, receiver); |
1195 | 1138 |
1196 // Ensure last index is 0. | 1139 // Ensure last index is 0. |
1197 if (is_fastpath) { | 1140 if (is_fastpath) { |
1198 FastStoreLastIndex(a, context, receiver, smi_zero); | 1141 FastStoreLastIndex(a, context, receiver, smi_zero); |
1199 } else { | 1142 } else { |
1200 Label next(a); | 1143 CLabel next(a); |
1201 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); | 1144 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); |
1202 | 1145 |
1203 SlowStoreLastIndex(a, context, receiver, smi_zero); | 1146 SlowStoreLastIndex(a, context, receiver, smi_zero); |
1204 a->Goto(&next); | 1147 a->Goto(&next); |
1205 a->Bind(&next); | 1148 a->Bind(&next); |
1206 } | 1149 } |
1207 | 1150 |
1208 // Call exec. | 1151 // Call exec. |
1209 Node* const match_indices = | 1152 Node* const match_indices = |
1210 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) | 1153 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) |
1211 : RegExpExec(a, context, receiver, string); | 1154 : RegExpExec(a, context, receiver, string); |
1212 | 1155 |
1213 // Reset last index if necessary. | 1156 // Reset last index if necessary. |
1214 if (is_fastpath) { | 1157 if (is_fastpath) { |
1215 FastStoreLastIndex(a, context, receiver, previous_last_index); | 1158 FastStoreLastIndex(a, context, receiver, previous_last_index); |
1216 } else { | 1159 } else { |
1217 Label next(a); | 1160 CLabel next(a); |
1218 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); | 1161 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); |
1219 | 1162 |
1220 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), | 1163 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), |
1221 &next); | 1164 &next); |
1222 | 1165 |
1223 SlowStoreLastIndex(a, context, receiver, previous_last_index); | 1166 SlowStoreLastIndex(a, context, receiver, previous_last_index); |
1224 a->Goto(&next); | 1167 a->Goto(&next); |
1225 a->Bind(&next); | 1168 a->Bind(&next); |
1226 } | 1169 } |
1227 | 1170 |
1228 // Return -1 if no match was found. | 1171 // Return -1 if no match was found. |
1229 { | 1172 { |
1230 Label next(a); | 1173 CLabel next(a); |
1231 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); | 1174 a->GotoUnless(a->WordEqual(match_indices, a->NullConstant()), &next); |
1232 a->Return(a->SmiConstant(-1)); | 1175 a->Return(a->SmiConstant(-1)); |
1233 a->Bind(&next); | 1176 a->Bind(&next); |
1234 } | 1177 } |
1235 | 1178 |
1236 // Return the index of the match. | 1179 // Return the index of the match. |
1237 { | 1180 { |
1238 Label fast_result(a), slow_result(a, Label::kDeferred); | 1181 CLabel fast_result(a), slow_result(a, CLabel::kDeferred); |
1239 | 1182 |
1240 Node* const native_context = a->LoadNativeContext(context); | 1183 Node* const native_context = a->LoadNativeContext(context); |
1241 Node* const initial_regexp_result_map = | 1184 Node* const initial_regexp_result_map = |
1242 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); | 1185 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); |
1243 Node* const match_indices_map = a->LoadMap(match_indices); | 1186 Node* const match_indices_map = a->LoadMap(match_indices); |
1244 | 1187 |
1245 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), | 1188 a->Branch(a->WordEqual(match_indices_map, initial_regexp_result_map), |
1246 &fast_result, &slow_result); | 1189 &fast_result, &slow_result); |
1247 | 1190 |
1248 a->Bind(&fast_result); | 1191 a->Bind(&fast_result); |
(...skipping 12 matching lines...) Expand all Loading... |
1261 a->CallStub(getproperty_callable, context, match_indices, name); | 1204 a->CallStub(getproperty_callable, context, match_indices, name); |
1262 a->Return(index); | 1205 a->Return(index); |
1263 } | 1206 } |
1264 } | 1207 } |
1265 } | 1208 } |
1266 | 1209 |
1267 } // namespace | 1210 } // namespace |
1268 | 1211 |
1269 // ES#sec-regexp.prototype-@@search | 1212 // ES#sec-regexp.prototype-@@search |
1270 // RegExp.prototype [ @@search ] ( string ) | 1213 // RegExp.prototype [ @@search ] ( string ) |
1271 void Builtins::Generate_RegExpPrototypeSearch( | 1214 void Builtins::Generate_RegExpPrototypeSearch(CodeAssemblerState* state) { |
1272 compiler::CodeAssemblerState* state) { | |
1273 typedef CodeStubAssembler::Label Label; | |
1274 typedef compiler::Node Node; | |
1275 CodeStubAssembler a(state); | 1215 CodeStubAssembler a(state); |
1276 | 1216 |
1277 Isolate* const isolate = a.isolate(); | 1217 Isolate* const isolate = a.isolate(); |
1278 | 1218 |
1279 Node* const maybe_receiver = a.Parameter(0); | 1219 Node* const maybe_receiver = a.Parameter(0); |
1280 Node* const maybe_string = a.Parameter(1); | 1220 Node* const maybe_string = a.Parameter(1); |
1281 Node* const context = a.Parameter(4); | 1221 Node* const context = a.Parameter(4); |
1282 | 1222 |
1283 // Ensure {maybe_receiver} is a JSReceiver. | 1223 // Ensure {maybe_receiver} is a JSReceiver. |
1284 Node* const map = | 1224 Node* const map = |
1285 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1225 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
1286 MessageTemplate::kIncompatibleMethodReceiver, | 1226 MessageTemplate::kIncompatibleMethodReceiver, |
1287 "RegExp.prototype.@@search"); | 1227 "RegExp.prototype.@@search"); |
1288 Node* const receiver = maybe_receiver; | 1228 Node* const receiver = maybe_receiver; |
1289 | 1229 |
1290 // Convert {maybe_string} to a String. | 1230 // Convert {maybe_string} to a String. |
1291 Node* const string = a.ToString(context, maybe_string); | 1231 Node* const string = a.ToString(context, maybe_string); |
1292 | 1232 |
1293 Label fast_path(&a), slow_path(&a); | 1233 CLabel fast_path(&a), slow_path(&a); |
1294 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); | 1234 BranchIfFastPath(&a, context, map, &fast_path, &slow_path); |
1295 | 1235 |
1296 a.Bind(&fast_path); | 1236 a.Bind(&fast_path); |
1297 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, true); | 1237 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, true); |
1298 | 1238 |
1299 a.Bind(&slow_path); | 1239 a.Bind(&slow_path); |
1300 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, false); | 1240 Generate_RegExpPrototypeSearchBody(&a, receiver, string, context, false); |
1301 } | 1241 } |
1302 | 1242 |
1303 namespace { | 1243 namespace { |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1639 Handle<String> substr = | 1579 Handle<String> substr = |
1640 factory->NewSubString(string, prev_string_index, length); | 1580 factory->NewSubString(string, prev_string_index, length); |
1641 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); | 1581 elems = FixedArray::SetAndGrow(elems, num_elems++, substr); |
1642 } | 1582 } |
1643 | 1583 |
1644 return *NewJSArrayWithElements(isolate, elems, num_elems); | 1584 return *NewJSArrayWithElements(isolate, elems, num_elems); |
1645 } | 1585 } |
1646 | 1586 |
1647 namespace { | 1587 namespace { |
1648 | 1588 |
1649 compiler::Node* ReplaceGlobalCallableFastPath( | 1589 Node* ReplaceGlobalCallableFastPath(CodeStubAssembler* a, Node* context, |
1650 CodeStubAssembler* a, compiler::Node* context, compiler::Node* regexp, | 1590 Node* regexp, Node* subject_string, |
1651 compiler::Node* subject_string, compiler::Node* replace_callable) { | 1591 Node* replace_callable) { |
1652 // The fast path is reached only if {receiver} is a global unmodified | 1592 // The fast path is reached only if {receiver} is a global unmodified |
1653 // JSRegExp instance and {replace_callable} is callable. | 1593 // JSRegExp instance and {replace_callable} is callable. |
1654 | 1594 |
1655 typedef CodeStubAssembler::Variable Variable; | |
1656 typedef CodeStubAssembler::Label Label; | |
1657 typedef compiler::Node Node; | |
1658 | |
1659 Isolate* const isolate = a->isolate(); | 1595 Isolate* const isolate = a->isolate(); |
1660 | 1596 |
1661 Node* const null = a->NullConstant(); | 1597 Node* const null = a->NullConstant(); |
1662 Node* const undefined = a->UndefinedConstant(); | 1598 Node* const undefined = a->UndefinedConstant(); |
1663 Node* const int_zero = a->IntPtrConstant(0); | 1599 Node* const int_zero = a->IntPtrConstant(0); |
1664 Node* const int_one = a->IntPtrConstant(1); | 1600 Node* const int_one = a->IntPtrConstant(1); |
1665 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1601 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1666 | 1602 |
1667 Node* const native_context = a->LoadNativeContext(context); | 1603 Node* const native_context = a->LoadNativeContext(context); |
1668 | 1604 |
1669 Label out(a); | 1605 CLabel out(a); |
1670 Variable var_result(a, MachineRepresentation::kTagged); | 1606 CVariable var_result(a, MachineRepresentation::kTagged); |
1671 | 1607 |
1672 // Set last index to 0. | 1608 // Set last index to 0. |
1673 FastStoreLastIndex(a, context, regexp, smi_zero); | 1609 FastStoreLastIndex(a, context, regexp, smi_zero); |
1674 | 1610 |
1675 // Allocate {result_array}. | 1611 // Allocate {result_array}. |
1676 Node* result_array; | 1612 Node* result_array; |
1677 { | 1613 { |
1678 ElementsKind kind = FAST_ELEMENTS; | 1614 ElementsKind kind = FAST_ELEMENTS; |
1679 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); | 1615 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); |
1680 Node* const capacity = a->IntPtrConstant(16); | 1616 Node* const capacity = a->IntPtrConstant(16); |
(...skipping 26 matching lines...) Expand all Loading... |
1707 | 1643 |
1708 Node* const res_length = a->LoadJSArrayLength(res); | 1644 Node* const res_length = a->LoadJSArrayLength(res); |
1709 Node* const res_elems = a->LoadElements(res); | 1645 Node* const res_elems = a->LoadElements(res); |
1710 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); | 1646 CSA_ASSERT(a, a->HasInstanceType(res_elems, FIXED_ARRAY_TYPE)); |
1711 | 1647 |
1712 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; | 1648 CodeStubAssembler::ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; |
1713 Node* const num_capture_registers = a->LoadFixedArrayElement( | 1649 Node* const num_capture_registers = a->LoadFixedArrayElement( |
1714 last_match_info, | 1650 last_match_info, |
1715 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); | 1651 a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, mode); |
1716 | 1652 |
1717 Label if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); | 1653 CLabel if_hasexplicitcaptures(a), if_noexplicitcaptures(a), create_result(a); |
1718 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), | 1654 a->Branch(a->SmiEqual(num_capture_registers, a->SmiConstant(Smi::FromInt(2))), |
1719 &if_noexplicitcaptures, &if_hasexplicitcaptures); | 1655 &if_noexplicitcaptures, &if_hasexplicitcaptures); |
1720 | 1656 |
1721 a->Bind(&if_noexplicitcaptures); | 1657 a->Bind(&if_noexplicitcaptures); |
1722 { | 1658 { |
1723 // If the number of captures is two then there are no explicit captures in | 1659 // If the number of captures is two then there are no explicit captures in |
1724 // the regexp, just the implicit capture that captures the whole match. In | 1660 // the regexp, just the implicit capture that captures the whole match. In |
1725 // this case we can simplify quite a bit and end up with something faster. | 1661 // this case we can simplify quite a bit and end up with something faster. |
1726 // The builder will consist of some integers that indicate slices of the | 1662 // The builder will consist of some integers that indicate slices of the |
1727 // input string and some replacements that were returned from the replace | 1663 // input string and some replacements that were returned from the replace |
1728 // function. | 1664 // function. |
1729 | 1665 |
1730 Variable var_match_start(a, MachineRepresentation::kTagged); | 1666 CVariable var_match_start(a, MachineRepresentation::kTagged); |
1731 var_match_start.Bind(smi_zero); | 1667 var_match_start.Bind(smi_zero); |
1732 | 1668 |
1733 Node* const end = a->SmiUntag(res_length); | 1669 Node* const end = a->SmiUntag(res_length); |
1734 Variable var_i(a, MachineType::PointerRepresentation()); | 1670 CVariable var_i(a, MachineType::PointerRepresentation()); |
1735 var_i.Bind(int_zero); | 1671 var_i.Bind(int_zero); |
1736 | 1672 |
1737 Variable* vars[] = {&var_i, &var_match_start}; | 1673 CVariable* vars[] = {&var_i, &var_match_start}; |
1738 Label loop(a, 2, vars); | 1674 CLabel loop(a, 2, vars); |
1739 a->Goto(&loop); | 1675 a->Goto(&loop); |
1740 a->Bind(&loop); | 1676 a->Bind(&loop); |
1741 { | 1677 { |
1742 Node* const i = var_i.value(); | 1678 Node* const i = var_i.value(); |
1743 a->GotoUnless(a->IntPtrLessThan(i, end), &create_result); | 1679 a->GotoUnless(a->IntPtrLessThan(i, end), &create_result); |
1744 | 1680 |
1745 CodeStubAssembler::ParameterMode mode = | 1681 CodeStubAssembler::ParameterMode mode = |
1746 CodeStubAssembler::INTPTR_PARAMETERS; | 1682 CodeStubAssembler::INTPTR_PARAMETERS; |
1747 Node* const elem = a->LoadFixedArrayElement(res_elems, i, 0, mode); | 1683 Node* const elem = a->LoadFixedArrayElement(res_elems, i, 0, mode); |
1748 | 1684 |
1749 Label if_issmi(a), if_isstring(a), loop_epilogue(a); | 1685 CLabel if_issmi(a), if_isstring(a), loop_epilogue(a); |
1750 a->Branch(a->TaggedIsSmi(elem), &if_issmi, &if_isstring); | 1686 a->Branch(a->TaggedIsSmi(elem), &if_issmi, &if_isstring); |
1751 | 1687 |
1752 a->Bind(&if_issmi); | 1688 a->Bind(&if_issmi); |
1753 { | 1689 { |
1754 // Integers represent slices of the original string. | 1690 // Integers represent slices of the original string. |
1755 Label if_isnegativeorzero(a), if_ispositive(a); | 1691 CLabel if_isnegativeorzero(a), if_ispositive(a); |
1756 a->BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero, | 1692 a->BranchIfSmiLessThanOrEqual(elem, smi_zero, &if_isnegativeorzero, |
1757 &if_ispositive); | 1693 &if_ispositive); |
1758 | 1694 |
1759 a->Bind(&if_ispositive); | 1695 a->Bind(&if_ispositive); |
1760 { | 1696 { |
1761 Node* const int_elem = a->SmiUntag(elem); | 1697 Node* const int_elem = a->SmiUntag(elem); |
1762 Node* const new_match_start = | 1698 Node* const new_match_start = |
1763 a->IntPtrAdd(a->WordShr(int_elem, a->IntPtrConstant(11)), | 1699 a->IntPtrAdd(a->WordShr(int_elem, a->IntPtrConstant(11)), |
1764 a->WordAnd(int_elem, a->IntPtrConstant(0x7ff))); | 1700 a->WordAnd(int_elem, a->IntPtrConstant(0x7ff))); |
1765 var_match_start.Bind(a->SmiTag(new_match_start)); | 1701 var_match_start.Bind(a->SmiTag(new_match_start)); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1817 Node* const to = a->SmiUntag(res_length); | 1753 Node* const to = a->SmiUntag(res_length); |
1818 const int increment = 1; | 1754 const int increment = 1; |
1819 | 1755 |
1820 a->BuildFastLoop( | 1756 a->BuildFastLoop( |
1821 MachineType::PointerRepresentation(), from, to, | 1757 MachineType::PointerRepresentation(), from, to, |
1822 [res_elems, isolate, native_context, context, undefined, | 1758 [res_elems, isolate, native_context, context, undefined, |
1823 replace_callable, mode](CodeStubAssembler* a, Node* index) { | 1759 replace_callable, mode](CodeStubAssembler* a, Node* index) { |
1824 Node* const elem = | 1760 Node* const elem = |
1825 a->LoadFixedArrayElement(res_elems, index, 0, mode); | 1761 a->LoadFixedArrayElement(res_elems, index, 0, mode); |
1826 | 1762 |
1827 Label do_continue(a); | 1763 CLabel do_continue(a); |
1828 a->GotoIf(a->TaggedIsSmi(elem), &do_continue); | 1764 a->GotoIf(a->TaggedIsSmi(elem), &do_continue); |
1829 | 1765 |
1830 // elem must be an Array. | 1766 // elem must be an Array. |
1831 // Use the apply argument as backing for global RegExp properties. | 1767 // Use the apply argument as backing for global RegExp properties. |
1832 | 1768 |
1833 CSA_ASSERT(a, a->HasInstanceType(elem, JS_ARRAY_TYPE)); | 1769 CSA_ASSERT(a, a->HasInstanceType(elem, JS_ARRAY_TYPE)); |
1834 | 1770 |
1835 // TODO(jgruber): Remove indirection through Call->ReflectApply. | 1771 // TODO(jgruber): Remove indirection through Call->ReflectApply. |
1836 Callable call_callable = CodeFactory::Call(isolate); | 1772 Callable call_callable = CodeFactory::Call(isolate); |
1837 Node* const reflect_apply = a->LoadContextElement( | 1773 Node* const reflect_apply = a->LoadContextElement( |
(...skipping 23 matching lines...) Expand all Loading... |
1861 Node* const result = a->CallRuntime(Runtime::kStringBuilderConcat, context, | 1797 Node* const result = a->CallRuntime(Runtime::kStringBuilderConcat, context, |
1862 res, res_length, subject_string); | 1798 res, res_length, subject_string); |
1863 var_result.Bind(result); | 1799 var_result.Bind(result); |
1864 a->Goto(&out); | 1800 a->Goto(&out); |
1865 } | 1801 } |
1866 | 1802 |
1867 a->Bind(&out); | 1803 a->Bind(&out); |
1868 return var_result.value(); | 1804 return var_result.value(); |
1869 } | 1805 } |
1870 | 1806 |
1871 compiler::Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, | 1807 Node* ReplaceSimpleStringFastPath(CodeStubAssembler* a, Node* context, |
1872 compiler::Node* context, | 1808 Node* regexp, Node* subject_string, |
1873 compiler::Node* regexp, | 1809 Node* replace_string) { |
1874 compiler::Node* subject_string, | |
1875 compiler::Node* replace_string) { | |
1876 // The fast path is reached only if {receiver} is an unmodified | 1810 // The fast path is reached only if {receiver} is an unmodified |
1877 // JSRegExp instance, {replace_value} is non-callable, and | 1811 // JSRegExp instance, {replace_value} is non-callable, and |
1878 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple | 1812 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple |
1879 // string replacement. | 1813 // string replacement. |
1880 | 1814 |
1881 typedef CodeStubAssembler::Variable Variable; | |
1882 typedef CodeStubAssembler::Label Label; | |
1883 typedef compiler::Node Node; | |
1884 | |
1885 Isolate* const isolate = a->isolate(); | 1815 Isolate* const isolate = a->isolate(); |
1886 | 1816 |
1887 Node* const null = a->NullConstant(); | 1817 Node* const null = a->NullConstant(); |
1888 Node* const int_zero = a->IntPtrConstant(0); | 1818 Node* const int_zero = a->IntPtrConstant(0); |
1889 Node* const smi_zero = a->SmiConstant(Smi::kZero); | 1819 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
1890 | 1820 |
1891 Label out(a); | 1821 CLabel out(a); |
1892 Variable var_result(a, MachineRepresentation::kTagged); | 1822 CVariable var_result(a, MachineRepresentation::kTagged); |
1893 | 1823 |
1894 // Load the last match info. | 1824 // Load the last match info. |
1895 Node* const native_context = a->LoadNativeContext(context); | 1825 Node* const native_context = a->LoadNativeContext(context); |
1896 Node* const last_match_info = a->LoadContextElement( | 1826 Node* const last_match_info = a->LoadContextElement( |
1897 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); | 1827 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); |
1898 | 1828 |
1899 // Is {regexp} global? | 1829 // Is {regexp} global? |
1900 Label if_isglobal(a), if_isnonglobal(a); | 1830 CLabel if_isglobal(a), if_isnonglobal(a); |
1901 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); | 1831 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); |
1902 Node* const is_global = | 1832 Node* const is_global = |
1903 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); | 1833 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); |
1904 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); | 1834 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); |
1905 | 1835 |
1906 a->Bind(&if_isglobal); | 1836 a->Bind(&if_isglobal); |
1907 { | 1837 { |
1908 // Hand off global regexps to runtime. | 1838 // Hand off global regexps to runtime. |
1909 FastStoreLastIndex(a, context, regexp, smi_zero); | 1839 FastStoreLastIndex(a, context, regexp, smi_zero); |
1910 Node* const result = | 1840 Node* const result = |
1911 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, | 1841 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, |
1912 subject_string, regexp, replace_string, last_match_info); | 1842 subject_string, regexp, replace_string, last_match_info); |
1913 var_result.Bind(result); | 1843 var_result.Bind(result); |
1914 a->Goto(&out); | 1844 a->Goto(&out); |
1915 } | 1845 } |
1916 | 1846 |
1917 a->Bind(&if_isnonglobal); | 1847 a->Bind(&if_isnonglobal); |
1918 { | 1848 { |
1919 // Run exec, then manually construct the resulting string. | 1849 // Run exec, then manually construct the resulting string. |
1920 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 1850 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
1921 Node* const match_indices = | 1851 Node* const match_indices = |
1922 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, | 1852 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, |
1923 last_match_info); | 1853 last_match_info); |
1924 | 1854 |
1925 Label if_matched(a), if_didnotmatch(a); | 1855 CLabel if_matched(a), if_didnotmatch(a); |
1926 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 1856 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
1927 | 1857 |
1928 a->Bind(&if_didnotmatch); | 1858 a->Bind(&if_didnotmatch); |
1929 { | 1859 { |
1930 FastStoreLastIndex(a, context, regexp, smi_zero); | 1860 FastStoreLastIndex(a, context, regexp, smi_zero); |
1931 var_result.Bind(subject_string); | 1861 var_result.Bind(subject_string); |
1932 a->Goto(&out); | 1862 a->Goto(&out); |
1933 } | 1863 } |
1934 | 1864 |
1935 a->Bind(&if_matched); | 1865 a->Bind(&if_matched); |
1936 { | 1866 { |
1937 CodeStubAssembler::ParameterMode mode = | 1867 CodeStubAssembler::ParameterMode mode = |
1938 CodeStubAssembler::INTPTR_PARAMETERS; | 1868 CodeStubAssembler::INTPTR_PARAMETERS; |
1939 | 1869 |
1940 Node* const subject_start = smi_zero; | 1870 Node* const subject_start = smi_zero; |
1941 Node* const match_start = a->LoadFixedArrayElement( | 1871 Node* const match_start = a->LoadFixedArrayElement( |
1942 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), | 1872 match_indices, a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex), |
1943 0, mode); | 1873 0, mode); |
1944 Node* const match_end = a->LoadFixedArrayElement( | 1874 Node* const match_end = a->LoadFixedArrayElement( |
1945 match_indices, | 1875 match_indices, |
1946 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); | 1876 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1), 0, mode); |
1947 Node* const subject_end = a->LoadStringLength(subject_string); | 1877 Node* const subject_end = a->LoadStringLength(subject_string); |
1948 | 1878 |
1949 Label if_replaceisempty(a), if_replaceisnotempty(a); | 1879 CLabel if_replaceisempty(a), if_replaceisnotempty(a); |
1950 Node* const replace_length = a->LoadStringLength(replace_string); | 1880 Node* const replace_length = a->LoadStringLength(replace_string); |
1951 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, | 1881 a->Branch(a->SmiEqual(replace_length, smi_zero), &if_replaceisempty, |
1952 &if_replaceisnotempty); | 1882 &if_replaceisnotempty); |
1953 | 1883 |
1954 a->Bind(&if_replaceisempty); | 1884 a->Bind(&if_replaceisempty); |
1955 { | 1885 { |
1956 // TODO(jgruber): We could skip many of the checks that using SubString | 1886 // TODO(jgruber): We could skip many of the checks that using SubString |
1957 // here entails. | 1887 // here entails. |
1958 | 1888 |
1959 Node* const first_part = | 1889 Node* const first_part = |
(...skipping 24 matching lines...) Expand all Loading... |
1984 } | 1914 } |
1985 | 1915 |
1986 a->Bind(&out); | 1916 a->Bind(&out); |
1987 return var_result.value(); | 1917 return var_result.value(); |
1988 } | 1918 } |
1989 | 1919 |
1990 } // namespace | 1920 } // namespace |
1991 | 1921 |
1992 // ES#sec-regexp.prototype-@@replace | 1922 // ES#sec-regexp.prototype-@@replace |
1993 // RegExp.prototype [ @@replace ] ( string, replaceValue ) | 1923 // RegExp.prototype [ @@replace ] ( string, replaceValue ) |
1994 void Builtins::Generate_RegExpPrototypeReplace( | 1924 void Builtins::Generate_RegExpPrototypeReplace(CodeAssemblerState* state) { |
1995 compiler::CodeAssemblerState* state) { | |
1996 typedef CodeStubAssembler::Label Label; | |
1997 typedef compiler::Node Node; | |
1998 CodeStubAssembler a(state); | 1925 CodeStubAssembler a(state); |
1999 | 1926 |
2000 Isolate* const isolate = a.isolate(); | 1927 Isolate* const isolate = a.isolate(); |
2001 | 1928 |
2002 Node* const maybe_receiver = a.Parameter(0); | 1929 Node* const maybe_receiver = a.Parameter(0); |
2003 Node* const maybe_string = a.Parameter(1); | 1930 Node* const maybe_string = a.Parameter(1); |
2004 Node* const replace_value = a.Parameter(2); | 1931 Node* const replace_value = a.Parameter(2); |
2005 Node* const context = a.Parameter(5); | 1932 Node* const context = a.Parameter(5); |
2006 | 1933 |
2007 Node* const int_zero = a.IntPtrConstant(0); | 1934 Node* const int_zero = a.IntPtrConstant(0); |
2008 | 1935 |
2009 // Ensure {maybe_receiver} is a JSReceiver. | 1936 // Ensure {maybe_receiver} is a JSReceiver. |
2010 Node* const map = | 1937 Node* const map = |
2011 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, | 1938 ThrowIfNotJSReceiver(&a, isolate, context, maybe_receiver, |
2012 MessageTemplate::kIncompatibleMethodReceiver, | 1939 MessageTemplate::kIncompatibleMethodReceiver, |
2013 "RegExp.prototype.@@replace"); | 1940 "RegExp.prototype.@@replace"); |
2014 Node* const receiver = maybe_receiver; | 1941 Node* const receiver = maybe_receiver; |
2015 | 1942 |
2016 // Convert {maybe_string} to a String. | 1943 // Convert {maybe_string} to a String. |
2017 Callable tostring_callable = CodeFactory::ToString(isolate); | 1944 Callable tostring_callable = CodeFactory::ToString(isolate); |
2018 Node* const string = a.CallStub(tostring_callable, context, maybe_string); | 1945 Node* const string = a.CallStub(tostring_callable, context, maybe_string); |
2019 | 1946 |
2020 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? | 1947 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? |
2021 Label checkreplacecallable(&a), runtime(&a, Label::kDeferred), fastpath(&a); | 1948 CLabel checkreplacecallable(&a), runtime(&a, CLabel::kDeferred), fastpath(&a); |
2022 BranchIfFastPath(&a, context, map, &checkreplacecallable, &runtime); | 1949 BranchIfFastPath(&a, context, map, &checkreplacecallable, &runtime); |
2023 | 1950 |
2024 a.Bind(&checkreplacecallable); | 1951 a.Bind(&checkreplacecallable); |
2025 Node* const regexp = receiver; | 1952 Node* const regexp = receiver; |
2026 | 1953 |
2027 // 2. Is {replace_value} callable? | 1954 // 2. Is {replace_value} callable? |
2028 Label checkreplacestring(&a), if_iscallable(&a); | 1955 CLabel checkreplacestring(&a), if_iscallable(&a); |
2029 a.GotoIf(a.TaggedIsSmi(replace_value), &checkreplacestring); | 1956 a.GotoIf(a.TaggedIsSmi(replace_value), &checkreplacestring); |
2030 | 1957 |
2031 Node* const replace_value_map = a.LoadMap(replace_value); | 1958 Node* const replace_value_map = a.LoadMap(replace_value); |
2032 a.Branch(a.IsCallableMap(replace_value_map), &if_iscallable, | 1959 a.Branch(a.IsCallableMap(replace_value_map), &if_iscallable, |
2033 &checkreplacestring); | 1960 &checkreplacestring); |
2034 | 1961 |
2035 // 3. Does ToString({replace_value}) contain '$'? | 1962 // 3. Does ToString({replace_value}) contain '$'? |
2036 a.Bind(&checkreplacestring); | 1963 a.Bind(&checkreplacestring); |
2037 { | 1964 { |
2038 Node* const replace_string = | 1965 Node* const replace_string = |
2039 a.CallStub(tostring_callable, context, replace_value); | 1966 a.CallStub(tostring_callable, context, replace_value); |
2040 | 1967 |
2041 Node* const dollar_char = a.IntPtrConstant('$'); | 1968 Node* const dollar_char = a.IntPtrConstant('$'); |
2042 Node* const smi_minusone = a.SmiConstant(Smi::FromInt(-1)); | 1969 Node* const smi_minusone = a.SmiConstant(Smi::FromInt(-1)); |
2043 a.GotoUnless(a.SmiEqual(a.StringIndexOfChar(context, replace_string, | 1970 a.GotoUnless(a.SmiEqual(a.StringIndexOfChar(context, replace_string, |
2044 dollar_char, int_zero), | 1971 dollar_char, int_zero), |
2045 smi_minusone), | 1972 smi_minusone), |
2046 &runtime); | 1973 &runtime); |
2047 | 1974 |
2048 a.Return(ReplaceSimpleStringFastPath(&a, context, regexp, string, | 1975 a.Return(ReplaceSimpleStringFastPath(&a, context, regexp, string, |
2049 replace_string)); | 1976 replace_string)); |
2050 } | 1977 } |
2051 | 1978 |
2052 // {regexp} is unmodified and {replace_value} is callable. | 1979 // {regexp} is unmodified and {replace_value} is callable. |
2053 a.Bind(&if_iscallable); | 1980 a.Bind(&if_iscallable); |
2054 { | 1981 { |
2055 Node* const replace_callable = replace_value; | 1982 Node* const replace_callable = replace_value; |
2056 | 1983 |
2057 // Check if the {regexp} is global. | 1984 // Check if the {regexp} is global. |
2058 Label if_isglobal(&a), if_isnotglobal(&a); | 1985 CLabel if_isglobal(&a), if_isnotglobal(&a); |
2059 Node* const is_global = FastFlagGetter(&a, regexp, JSRegExp::kGlobal); | 1986 Node* const is_global = FastFlagGetter(&a, regexp, JSRegExp::kGlobal); |
2060 a.Branch(is_global, &if_isglobal, &if_isnotglobal); | 1987 a.Branch(is_global, &if_isglobal, &if_isnotglobal); |
2061 | 1988 |
2062 a.Bind(&if_isglobal); | 1989 a.Bind(&if_isglobal); |
2063 { | 1990 { |
2064 Node* const result = ReplaceGlobalCallableFastPath( | 1991 Node* const result = ReplaceGlobalCallableFastPath( |
2065 &a, context, regexp, string, replace_callable); | 1992 &a, context, regexp, string, replace_callable); |
2066 a.Return(result); | 1993 a.Return(result); |
2067 } | 1994 } |
2068 | 1995 |
2069 a.Bind(&if_isnotglobal); | 1996 a.Bind(&if_isnotglobal); |
2070 { | 1997 { |
2071 Node* const result = | 1998 Node* const result = |
2072 a.CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, | 1999 a.CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction, |
2073 context, string, regexp, replace_callable); | 2000 context, string, regexp, replace_callable); |
2074 a.Return(result); | 2001 a.Return(result); |
2075 } | 2002 } |
2076 } | 2003 } |
2077 | 2004 |
2078 a.Bind(&runtime); | 2005 a.Bind(&runtime); |
2079 { | 2006 { |
2080 Node* const result = a.CallRuntime(Runtime::kRegExpReplace, context, | 2007 Node* const result = a.CallRuntime(Runtime::kRegExpReplace, context, |
2081 receiver, string, replace_value); | 2008 receiver, string, replace_value); |
2082 a.Return(result); | 2009 a.Return(result); |
2083 } | 2010 } |
2084 } | 2011 } |
2085 | 2012 |
2086 // Simple string matching functionality for internal use which does not modify | 2013 // Simple string matching functionality for internal use which does not modify |
2087 // the last match info. | 2014 // the last match info. |
2088 void Builtins::Generate_RegExpInternalMatch( | 2015 void Builtins::Generate_RegExpInternalMatch(CodeAssemblerState* state) { |
2089 compiler::CodeAssemblerState* state) { | |
2090 typedef CodeStubAssembler::Label Label; | |
2091 typedef compiler::Node Node; | |
2092 CodeStubAssembler a(state); | 2016 CodeStubAssembler a(state); |
2093 | 2017 |
2094 Isolate* const isolate = a.isolate(); | 2018 Isolate* const isolate = a.isolate(); |
2095 | 2019 |
2096 Node* const regexp = a.Parameter(1); | 2020 Node* const regexp = a.Parameter(1); |
2097 Node* const string = a.Parameter(2); | 2021 Node* const string = a.Parameter(2); |
2098 Node* const context = a.Parameter(5); | 2022 Node* const context = a.Parameter(5); |
2099 | 2023 |
2100 Node* const null = a.NullConstant(); | 2024 Node* const null = a.NullConstant(); |
2101 Node* const smi_zero = a.SmiConstant(Smi::FromInt(0)); | 2025 Node* const smi_zero = a.SmiConstant(Smi::FromInt(0)); |
2102 | 2026 |
2103 Node* const native_context = a.LoadNativeContext(context); | 2027 Node* const native_context = a.LoadNativeContext(context); |
2104 Node* const internal_match_info = a.LoadContextElement( | 2028 Node* const internal_match_info = a.LoadContextElement( |
2105 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); | 2029 native_context, Context::REGEXP_INTERNAL_MATCH_INFO_INDEX); |
2106 | 2030 |
2107 Callable exec_callable = CodeFactory::RegExpExec(isolate); | 2031 Callable exec_callable = CodeFactory::RegExpExec(isolate); |
2108 Node* const match_indices = a.CallStub(exec_callable, context, regexp, string, | 2032 Node* const match_indices = a.CallStub(exec_callable, context, regexp, string, |
2109 smi_zero, internal_match_info); | 2033 smi_zero, internal_match_info); |
2110 | 2034 |
2111 Label if_matched(&a), if_didnotmatch(&a); | 2035 CLabel if_matched(&a), if_didnotmatch(&a); |
2112 a.Branch(a.WordEqual(match_indices, null), &if_didnotmatch, &if_matched); | 2036 a.Branch(a.WordEqual(match_indices, null), &if_didnotmatch, &if_matched); |
2113 | 2037 |
2114 a.Bind(&if_didnotmatch); | 2038 a.Bind(&if_didnotmatch); |
2115 a.Return(null); | 2039 a.Return(null); |
2116 | 2040 |
2117 a.Bind(&if_matched); | 2041 a.Bind(&if_matched); |
2118 { | 2042 { |
2119 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, | 2043 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, |
2120 match_indices, string); | 2044 match_indices, string); |
2121 a.Return(result); | 2045 a.Return(result); |
2122 } | 2046 } |
2123 } | 2047 } |
2124 | 2048 |
2125 } // namespace internal | 2049 } // namespace internal |
2126 } // namespace v8 | 2050 } // namespace v8 |
OLD | NEW |