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

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

Issue 2540153002: [regexp] Refactor RegExp.prototype.exec (Closed)
Patch Set: Address comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « 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"
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags)); 169 isolate, regexp, RegExpInitialize(isolate, regexp, pattern, flags));
170 170
171 // Return undefined for compatibility with JSC. 171 // Return undefined for compatibility with JSC.
172 // See http://crbug.com/585775 for web compat details. 172 // See http://crbug.com/585775 for web compat details.
173 173
174 return isolate->heap()->undefined_value(); 174 return isolate->heap()->undefined_value();
175 } 175 }
176 176
177 namespace { 177 namespace {
178 178
179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { 179 Node* FastLoadLastIndex(CodeStubAssembler* a, Node* regexp) {
180 // Load the in-object field. 180 // Load the in-object field.
181 static const int field_offset = 181 static const int field_offset =
182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 182 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
183 return a->LoadObjectField(regexp, field_offset); 183 return a->LoadObjectField(regexp, field_offset);
184 } 184 }
185 185
186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) { 186 Node* SlowLoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp) {
187 // Load through the GetProperty stub. 187 // Load through the GetProperty stub.
188 Node* const name = 188 Node* const name =
189 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 189 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 190 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
191 return a->CallStub(getproperty_callable, context, regexp, name); 191 return a->CallStub(getproperty_callable, context, regexp, name);
192 } 192 }
193 193
194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, 194 Node* LoadLastIndex(CodeStubAssembler* a, Node* context, Node* regexp,
195 Node* regexp) { 195 bool is_fastpath) {
196 CVariable var_value(a, MachineRepresentation::kTagged); 196 return is_fastpath ? FastLoadLastIndex(a, regexp)
197 197 : SlowLoadLastIndex(a, context, regexp);
198 CLabel out(a), if_unmodified(a), if_modified(a);
199 a->Branch(has_initialmap, &if_unmodified, &if_modified);
200
201 a->Bind(&if_unmodified);
202 {
203 var_value.Bind(FastLoadLastIndex(a, context, regexp));
204 a->Goto(&out);
205 }
206
207 a->Bind(&if_modified);
208 {
209 var_value.Bind(SlowLoadLastIndex(a, context, regexp));
210 a->Goto(&out);
211 }
212
213 a->Bind(&out);
214 return var_value.value();
215 } 198 }
216 199
217 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified 200 // The fast-path of StoreLastIndex when regexp is guaranteed to be an unmodified
218 // JSRegExp instance. 201 // JSRegExp instance.
219 void FastStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, 202 void FastStoreLastIndex(CodeStubAssembler* a, Node* regexp, Node* value) {
220 Node* value) {
221 // Store the in-object field. 203 // Store the in-object field.
222 static const int field_offset = 204 static const int field_offset =
223 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize; 205 JSRegExp::kSize + JSRegExp::kLastIndexFieldIndex * kPointerSize;
224 a->StoreObjectField(regexp, field_offset, value); 206 a->StoreObjectField(regexp, field_offset, value);
225 } 207 }
226 208
227 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp, 209 void SlowStoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp,
228 Node* value) { 210 Node* value) {
229 // Store through runtime. 211 // Store through runtime.
230 // TODO(ishell): Use SetPropertyStub here once available. 212 // TODO(ishell): Use SetPropertyStub here once available.
231 Node* const name = 213 Node* const name =
232 a->HeapConstant(a->isolate()->factory()->lastIndex_string()); 214 a->HeapConstant(a->isolate()->factory()->lastIndex_string());
233 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT)); 215 Node* const language_mode = a->SmiConstant(Smi::FromInt(STRICT));
234 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value, 216 a->CallRuntime(Runtime::kSetProperty, context, regexp, name, value,
235 language_mode); 217 language_mode);
236 } 218 }
237 219
238 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* has_initialmap, 220 void StoreLastIndex(CodeStubAssembler* a, Node* context, Node* regexp,
239 Node* regexp, Node* value) { 221 Node* value, bool is_fastpath) {
240 CLabel out(a), if_unmodified(a), if_modified(a); 222 if (is_fastpath) {
241 a->Branch(has_initialmap, &if_unmodified, &if_modified); 223 FastStoreLastIndex(a, regexp, value);
242 224 } else {
243 a->Bind(&if_unmodified); 225 SlowStoreLastIndex(a, context, regexp, value);
244 {
245 FastStoreLastIndex(a, context, regexp, value);
246 a->Goto(&out);
247 } 226 }
248
249 a->Bind(&if_modified);
250 {
251 SlowStoreLastIndex(a, context, regexp, value);
252 a->Goto(&out);
253 }
254
255 a->Bind(&out);
256 } 227 }
257 228
258 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a, 229 Node* ConstructNewResultFromMatchInfo(Isolate* isolate, CodeStubAssembler* a,
259 Node* context, Node* match_info, 230 Node* context, Node* match_info,
260 Node* string) { 231 Node* string) {
261 CLabel out(a); 232 CLabel out(a);
262 233
263 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 234 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
264 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement( 235 Node* const num_indices = a->SmiUntag(a->LoadFixedArrayElement(
265 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0, 236 match_info, a->IntPtrConstant(RegExpMatchInfo::kNumberOfCapturesIndex), 0,
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1))); 292 var_to_cursor.Bind(a->IntPtrAdd(to_cursor, a->IntPtrConstant(1)));
322 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out); 293 a->Branch(a->UintPtrLessThan(var_from_cursor.value(), limit), &loop, &out);
323 } 294 }
324 295
325 a->Bind(&out); 296 a->Bind(&out);
326 return result; 297 return result;
327 } 298 }
328 299
329 // ES#sec-regexp.prototype.exec 300 // ES#sec-regexp.prototype.exec
330 // RegExp.prototype.exec ( string ) 301 // RegExp.prototype.exec ( string )
331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, 302 // Implements the core of RegExp.prototype.exec but without actually
332 Node* maybe_receiver, Node* maybe_string) { 303 // constructing the JSRegExpResult. Returns either null (if the RegExp did not
304 // match) or a fixed array containing match indices as returned by
305 // RegExpExecStub.
306 Node* RegExpPrototypeExecBodyWithoutResult(
307 CodeStubAssembler* a, Node* const context, Node* const regexp,
308 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) {
333 Isolate* const isolate = a->isolate(); 309 Isolate* const isolate = a->isolate();
334 310
335 Node* const null = a->NullConstant(); 311 Node* const null = a->NullConstant();
336 Node* const int_zero = a->IntPtrConstant(0); 312 Node* const int_zero = a->IntPtrConstant(0);
337 Node* const smi_zero = a->SmiConstant(Smi::kZero); 313 Node* const smi_zero = a->SmiConstant(Smi::kZero);
338 314
315 if (!is_fastpath) {
316 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
317 "RegExp.prototype.exec");
318 }
319
320 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string)));
321 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE));
322
339 CVariable var_result(a, MachineRepresentation::kTagged); 323 CVariable var_result(a, MachineRepresentation::kTagged);
340 CLabel out(a); 324 CLabel out(a);
341 325
342 // Ensure {maybe_receiver} is a JSRegExp.
343 Node* const regexp_map = a->ThrowIfNotInstanceType(
344 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec");
345 Node* const regexp = maybe_receiver;
346
347 // Check whether the regexp instance is unmodified.
348 Node* const native_context = a->LoadNativeContext(context); 326 Node* const native_context = a->LoadNativeContext(context);
349 Node* const regexp_fun =
350 a->LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
351 Node* const initial_map =
352 a->LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
353 Node* const has_initialmap = a->WordEqual(regexp_map, initial_map);
354
355 // Convert {maybe_string} to a string.
356 Callable tostring_callable = CodeFactory::ToString(isolate);
357 Node* const string = a->CallStub(tostring_callable, context, maybe_string);
358 Node* const string_length = a->LoadStringLength(string); 327 Node* const string_length = a->LoadStringLength(string);
359 328
360 // Check whether the regexp is global or sticky, which determines whether we 329 // Check whether the regexp is global or sticky, which determines whether we
361 // update last index later on. 330 // update last index later on.
362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 331 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
363 Node* const is_global_or_sticky = 332 Node* const is_global_or_sticky =
364 a->WordAnd(a->SmiUntag(flags), 333 a->WordAnd(a->SmiUntag(flags),
365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); 334 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky));
366 Node* const should_update_last_index = 335 Node* const should_update_last_index =
367 a->WordNotEqual(is_global_or_sticky, int_zero); 336 a->WordNotEqual(is_global_or_sticky, int_zero);
368 337
369 // Grab and possibly update last index. 338 // Grab and possibly update last index.
370 CLabel run_exec(a); 339 CLabel run_exec(a);
371 CVariable var_lastindex(a, MachineRepresentation::kTagged); 340 CVariable var_lastindex(a, MachineRepresentation::kTagged);
372 { 341 {
373 CLabel if_doupdate(a), if_dontupdate(a); 342 CLabel if_doupdate(a), if_dontupdate(a);
374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); 343 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
375 344
376 a->Bind(&if_doupdate); 345 a->Bind(&if_doupdate);
377 { 346 {
378 Node* const regexp_lastindex = 347 Node* const regexp_lastindex =
379 LoadLastIndex(a, context, has_initialmap, regexp); 348 LoadLastIndex(a, context, regexp, is_fastpath);
349 var_lastindex.Bind(regexp_lastindex);
380 350
381 Callable tolength_callable = CodeFactory::ToLength(isolate); 351 // Omit ToLength if lastindex is a non-negative smi.
382 Node* const lastindex = 352 {
383 a->CallStub(tolength_callable, context, regexp_lastindex); 353 CLabel call_tolength(a, CLabel::kDeferred), next(a);
384 var_lastindex.Bind(lastindex); 354 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next,
355 &call_tolength);
356
357 a->Bind(&call_tolength);
358 {
359 Callable tolength_callable = CodeFactory::ToLength(isolate);
360 var_lastindex.Bind(
361 a->CallStub(tolength_callable, context, regexp_lastindex));
362 a->Goto(&next);
363 }
364
365 a->Bind(&next);
366 }
367
368 Node* const lastindex = var_lastindex.value();
385 369
386 CLabel if_isoob(a, CLabel::kDeferred); 370 CLabel if_isoob(a, CLabel::kDeferred);
387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); 371 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob);
388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); 372 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob);
389 a->Goto(&run_exec); 373 a->Goto(&run_exec);
390 374
391 a->Bind(&if_isoob); 375 a->Bind(&if_isoob);
392 { 376 {
393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); 377 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath);
394 var_result.Bind(null); 378 var_result.Bind(null);
395 a->Goto(&out); 379 a->Goto(if_didnotmatch);
396 } 380 }
397 } 381 }
398 382
399 a->Bind(&if_dontupdate); 383 a->Bind(&if_dontupdate);
400 { 384 {
401 var_lastindex.Bind(smi_zero); 385 var_lastindex.Bind(smi_zero);
402 a->Goto(&run_exec); 386 a->Goto(&run_exec);
403 } 387 }
404 } 388 }
405 389
406 Node* match_indices; 390 Node* match_indices;
407 CLabel successful_match(a); 391 CLabel successful_match(a);
408 a->Bind(&run_exec); 392 a->Bind(&run_exec);
409 { 393 {
410 // Get last match info from the context. 394 // Get last match info from the context.
411 Node* const last_match_info = a->LoadContextElement( 395 Node* const last_match_info = a->LoadContextElement(
412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 396 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
413 397
414 // Call the exec stub. 398 // Call the exec stub.
415 Callable exec_callable = CodeFactory::RegExpExec(isolate); 399 Callable exec_callable = CodeFactory::RegExpExec(isolate);
416 match_indices = a->CallStub(exec_callable, context, regexp, string, 400 match_indices = a->CallStub(exec_callable, context, regexp, string,
417 var_lastindex.value(), last_match_info); 401 var_lastindex.value(), last_match_info);
402 var_result.Bind(match_indices);
418 403
419 // {match_indices} is either null or the RegExpMatchInfo array. 404 // {match_indices} is either null or the RegExpMatchInfo array.
420 // Return early if exec failed, possibly updating last index. 405 // Return early if exec failed, possibly updating last index.
421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); 406 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match);
422 407
423 CLabel return_null(a); 408 a->GotoUnless(should_update_last_index, if_didnotmatch);
424 a->GotoUnless(should_update_last_index, &return_null);
425 409
426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); 410 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath);
427 a->Goto(&return_null); 411 a->Goto(if_didnotmatch);
428
429 a->Bind(&return_null);
430 var_result.Bind(null);
431 a->Goto(&out);
432 } 412 }
433 413
434 CLabel construct_result(a);
435 a->Bind(&successful_match); 414 a->Bind(&successful_match);
436 { 415 {
437 a->GotoUnless(should_update_last_index, &construct_result); 416 a->GotoUnless(should_update_last_index, &out);
438 417
439 // Update the new last index from {match_indices}. 418 // Update the new last index from {match_indices}.
440 Node* const new_lastindex = a->LoadFixedArrayElement( 419 Node* const new_lastindex = a->LoadFixedArrayElement(
441 match_indices, 420 match_indices,
442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); 421 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1));
443 422
444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); 423 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath);
445 a->Goto(&construct_result); 424 a->Goto(&out);
425 }
446 426
447 a->Bind(&construct_result); 427 a->Bind(&out);
448 { 428 return var_result.value();
449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, 429 }
450 match_indices, string); 430
451 var_result.Bind(result); 431 // ES#sec-regexp.prototype.exec
452 a->Goto(&out); 432 // RegExp.prototype.exec ( string )
453 } 433 Node* RegExpPrototypeExecBody(CodeStubAssembler* a, Node* const context,
434 Node* const regexp, Node* const string,
435 const bool is_fastpath) {
436 Isolate* const isolate = a->isolate();
437 Node* const null = a->NullConstant();
438
439 CVariable var_result(a, MachineRepresentation::kTagged);
440
441 CLabel if_didnotmatch(a), out(a);
442 Node* const indices_or_null = RegExpPrototypeExecBodyWithoutResult(
443 a, context, regexp, string, &if_didnotmatch, is_fastpath);
444
445 // Successful match.
446 {
447 Node* const match_indices = indices_or_null;
448 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context,
449 match_indices, string);
450 var_result.Bind(result);
451 a->Goto(&out);
452 }
453
454 a->Bind(&if_didnotmatch);
455 {
456 var_result.Bind(null);
457 a->Goto(&out);
454 } 458 }
455 459
456 a->Bind(&out); 460 a->Bind(&out);
457 return var_result.value(); 461 return var_result.value();
458 } 462 }
459 463
460 } // namespace 464 } // namespace
461 465
462 // ES#sec-regexp.prototype.exec
463 // RegExp.prototype.exec ( string )
464 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) {
465 CodeStubAssembler a(state);
466
467 Node* const maybe_receiver = a.Parameter(0);
468 Node* const maybe_string = a.Parameter(1);
469 Node* const context = a.Parameter(4);
470
471 Node* const result =
472 RegExpPrototypeExecInternal(&a, context, maybe_receiver, maybe_string);
473 a.Return(result);
474 }
475
476 namespace { 466 namespace {
477 467
478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, 468 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate,
479 Node* context, Node* value, 469 Node* context, Node* value,
480 MessageTemplate::Template msg_template, 470 MessageTemplate::Template msg_template,
481 char const* method_name) { 471 char const* method_name) {
482 CLabel out(a), throw_exception(a, CLabel::kDeferred); 472 CLabel out(a), throw_exception(a, CLabel::kDeferred);
483 CVariable var_value_map(a, MachineRepresentation::kTagged); 473 CVariable var_value_map(a, MachineRepresentation::kTagged);
484 474
485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); 475 a->GotoIf(a->TaggedIsSmi(value), &throw_exception);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 Node* const native_context = a->LoadNativeContext(context); 545 Node* const native_context = a->LoadNativeContext(context);
556 Node* const initial_regexp_result_map = 546 Node* const initial_regexp_result_map =
557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); 547 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
558 548
559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, 549 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified,
560 if_ismodified); 550 if_ismodified);
561 } 551 }
562 552
563 } // namespace 553 } // namespace
564 554
555 // ES#sec-regexp.prototype.exec
556 // RegExp.prototype.exec ( string )
557 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) {
558 CodeStubAssembler a(state);
559
560 Node* const maybe_receiver = a.Parameter(0);
561 Node* const maybe_string = a.Parameter(1);
562 Node* const context = a.Parameter(4);
563
564 // Ensure {maybe_receiver} is a JSRegExp.
565 Node* const regexp_map = a.ThrowIfNotInstanceType(
566 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec");
567 Node* const receiver = maybe_receiver;
568
569 // Convert {maybe_string} to a String.
570 Node* const string = a.ToString(context, maybe_string);
571
572 CLabel if_isfastpath(&a), if_isslowpath(&a);
573 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath,
574 &if_isslowpath);
575
576 a.Bind(&if_isfastpath);
577 {
578 Node* const result =
579 RegExpPrototypeExecBody(&a, context, receiver, string, true);
580 a.Return(result);
581 }
582
583 a.Bind(&if_isslowpath);
584 {
585 Node* const result =
586 RegExpPrototypeExecBody(&a, context, receiver, string, false);
587 a.Return(result);
588 }
589 }
590
565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { 591 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) {
566 CodeStubAssembler a(state); 592 CodeStubAssembler a(state);
567 593
568 Node* const receiver = a.Parameter(0); 594 Node* const receiver = a.Parameter(0);
569 Node* const context = a.Parameter(3); 595 Node* const context = a.Parameter(3);
570 596
571 Isolate* isolate = a.isolate(); 597 Isolate* isolate = a.isolate();
572 Node* const int_zero = a.IntPtrConstant(0); 598 Node* const int_zero = a.IntPtrConstant(0);
573 Node* const int_one = a.IntPtrConstant(1); 599 Node* const int_one = a.IntPtrConstant(1);
574 600
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 namespace { 1052 namespace {
1027 1053
1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) 1054 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, 1055 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv,
1030 Node* string) { 1056 Node* string) {
1031 Isolate* isolate = a->isolate(); 1057 Isolate* isolate = a->isolate();
1032 1058
1033 Node* const null = a->NullConstant(); 1059 Node* const null = a->NullConstant();
1034 1060
1035 CVariable var_result(a, MachineRepresentation::kTagged); 1061 CVariable var_result(a, MachineRepresentation::kTagged);
1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); 1062 CLabel out(a), if_isfastpath(a), if_isslowpath(a);
1037 1063
1038 Node* const map = a->LoadMap(recv); 1064 Node* const map = a->LoadMap(recv);
1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); 1065 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath);
1040 1066
1041 a->Bind(&call_builtin_exec); 1067 a->Bind(&if_isfastpath);
1042 { 1068 {
1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); 1069 Node* const result =
1070 RegExpPrototypeExecBody(a, context, recv, string, true);
1044 var_result.Bind(result); 1071 var_result.Bind(result);
1045 a->Goto(&out); 1072 a->Goto(&out);
1046 } 1073 }
1047 1074
1048 a->Bind(&slow_path); 1075 a->Bind(&if_isslowpath);
1049 { 1076 {
1050 // Take the slow path of fetching the exec property, calling it, and 1077 // Take the slow path of fetching the exec property, calling it, and
1051 // verifying its return value. 1078 // verifying its return value.
1052 1079
1053 // Get the exec property. 1080 // Get the exec property.
1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); 1081 Node* const name = a->HeapConstant(isolate->factory()->exec_string());
1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 1082 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); 1083 Node* const exec = a->CallStub(getproperty_callable, context, recv, name);
1057 1084
1058 // Is {exec} callable? 1085 // Is {exec} callable?
(...skipping 16 matching lines...) Expand all
1075 ThrowIfNotJSReceiver(a, isolate, context, result, 1102 ThrowIfNotJSReceiver(a, isolate, context, result,
1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); 1103 MessageTemplate::kInvalidRegExpExecResult, "unused");
1077 1104
1078 a->Goto(&out); 1105 a->Goto(&out);
1079 } 1106 }
1080 1107
1081 a->Bind(&if_isnotcallable); 1108 a->Bind(&if_isnotcallable);
1082 { 1109 {
1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, 1110 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE,
1084 "RegExp.prototype.exec"); 1111 "RegExp.prototype.exec");
1085 a->Goto(&call_builtin_exec); 1112
1113 Node* const result =
1114 RegExpPrototypeExecBody(a, context, recv, string, false);
1115 var_result.Bind(result);
1116 a->Goto(&out);
1086 } 1117 }
1087 } 1118 }
1088 1119
1089 a->Bind(&out); 1120 a->Bind(&out);
1090 return var_result.value(); 1121 return var_result.value();
1091 } 1122 }
1092 1123
1093 } // namespace 1124 } // namespace
1094 1125
1095 // ES#sec-regexp.prototype.test 1126 // ES#sec-regexp.prototype.test
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 Node* const regexp = receiver; 1332 Node* const regexp = receiver;
1302 Node* const is_global = 1333 Node* const is_global =
1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); 1334 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath);
1304 1335
1305 CLabel if_isglobal(a), if_isnotglobal(a); 1336 CLabel if_isglobal(a), if_isnotglobal(a);
1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); 1337 a->Branch(is_global, &if_isglobal, &if_isnotglobal);
1307 1338
1308 a->Bind(&if_isnotglobal); 1339 a->Bind(&if_isnotglobal);
1309 { 1340 {
1310 Node* const result = 1341 Node* const result =
1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) 1342 is_fastpath ? RegExpPrototypeExecBody(a, context, regexp, string, true)
1312 : RegExpExec(a, context, regexp, string); 1343 : RegExpExec(a, context, regexp, string);
1313 a->Return(result); 1344 a->Return(result);
1314 } 1345 }
1315 1346
1316 a->Bind(&if_isglobal); 1347 a->Bind(&if_isglobal);
1317 { 1348 {
1318 Node* const is_unicode = 1349 Node* const is_unicode =
1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); 1350 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath);
1320 1351
1321 if (is_fastpath) { 1352 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath);
1322 FastStoreLastIndex(a, context, regexp, smi_zero);
1323 } else {
1324 SlowStoreLastIndex(a, context, regexp, smi_zero);
1325 }
1326 1353
1327 // Allocate an array to store the resulting match strings. 1354 // Allocate an array to store the resulting match strings.
1328 1355
1329 GrowableFixedArray array(a); 1356 GrowableFixedArray array(a);
1330 1357
1331 // Loop preparations. Within the loop, collect results from RegExpExec 1358 // Loop preparations. Within the loop, collect results from RegExpExec
1332 // and store match strings in the array. 1359 // and store match strings in the array.
1333 1360
1334 CVariable* vars[] = {array.var_array(), array.var_length(), 1361 CVariable* vars[] = {array.var_array(), array.var_length(),
1335 array.var_capacity()}; 1362 array.var_capacity()};
1336 CLabel loop(a, 3, vars), out(a); 1363 CLabel loop(a, 3, vars), out(a);
1337 a->Goto(&loop); 1364 a->Goto(&loop);
1338 1365
1339 a->Bind(&loop); 1366 a->Bind(&loop);
1340 { 1367 {
1341 Node* const result = 1368 Node* const result = is_fastpath ? RegExpPrototypeExecBody(
1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) 1369 a, context, regexp, string, true)
1343 : RegExpExec(a, context, regexp, string); 1370 : RegExpExec(a, context, regexp, string);
1344 1371
1345 CLabel if_didmatch(a), if_didnotmatch(a); 1372 CLabel if_didmatch(a), if_didnotmatch(a);
1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); 1373 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch);
1347 1374
1348 a->Bind(&if_didnotmatch); 1375 a->Bind(&if_didnotmatch);
1349 { 1376 {
1350 // Return null if there were no matches, otherwise just exit the loop. 1377 // Return null if there were no matches, otherwise just exit the loop.
1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); 1378 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out);
1352 a->Return(null); 1379 a->Return(null);
1353 } 1380 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1408 1435
1409 // Store the match, growing the fixed array if needed. 1436 // Store the match, growing the fixed array if needed.
1410 1437
1411 array.Push(match); 1438 array.Push(match);
1412 1439
1413 // Advance last index if the match is the empty string. 1440 // Advance last index if the match is the empty string.
1414 1441
1415 Node* const match_length = a->LoadStringLength(match); 1442 Node* const match_length = a->LoadStringLength(match);
1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); 1443 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop);
1417 1444
1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) 1445 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath);
1419 : SlowLoadLastIndex(a, context, regexp);
1420 1446
1421 Callable tolength_callable = CodeFactory::ToLength(isolate); 1447 Callable tolength_callable = CodeFactory::ToLength(isolate);
1422 last_index = a->CallStub(tolength_callable, context, last_index); 1448 last_index = a->CallStub(tolength_callable, context, last_index);
1423 1449
1424 Node* const new_last_index = 1450 Node* const new_last_index =
1425 AdvanceStringIndex(a, string, last_index, is_unicode); 1451 AdvanceStringIndex(a, string, last_index, is_unicode);
1426 1452
1427 if (is_fastpath) { 1453 StoreLastIndex(a, context, regexp, new_last_index, is_fastpath);
1428 FastStoreLastIndex(a, context, regexp, new_last_index);
1429 } else {
1430 SlowStoreLastIndex(a, context, regexp, new_last_index);
1431 }
1432 1454
1433 a->Goto(&loop); 1455 a->Goto(&loop);
1434 } 1456 }
1435 } 1457 }
1436 1458
1437 a->Bind(&out); 1459 a->Bind(&out);
1438 { 1460 {
1439 // Wrap the match in a JSArray. 1461 // Wrap the match in a JSArray.
1440 1462
1441 Node* const result = array.ToJSArray(context); 1463 Node* const result = array.ToJSArray(context);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, 1501 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a,
1480 Node* const receiver, 1502 Node* const receiver,
1481 Node* const string, Node* const context, 1503 Node* const string, Node* const context,
1482 bool is_fastpath) { 1504 bool is_fastpath) {
1483 Isolate* const isolate = a->isolate(); 1505 Isolate* const isolate = a->isolate();
1484 1506
1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1507 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1486 1508
1487 // Grab the initial value of last index. 1509 // Grab the initial value of last index.
1488 Node* const previous_last_index = 1510 Node* const previous_last_index =
1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) 1511 LoadLastIndex(a, context, receiver, is_fastpath);
1490 : SlowLoadLastIndex(a, context, receiver);
1491 1512
1492 // Ensure last index is 0. 1513 // Ensure last index is 0.
1493 if (is_fastpath) { 1514 if (is_fastpath) {
1494 FastStoreLastIndex(a, context, receiver, smi_zero); 1515 FastStoreLastIndex(a, receiver, smi_zero);
1495 } else { 1516 } else {
1496 CLabel next(a); 1517 CLabel next(a);
1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); 1518 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next);
1498 1519
1499 SlowStoreLastIndex(a, context, receiver, smi_zero); 1520 SlowStoreLastIndex(a, context, receiver, smi_zero);
1500 a->Goto(&next); 1521 a->Goto(&next);
1501 a->Bind(&next); 1522 a->Bind(&next);
1502 } 1523 }
1503 1524
1504 // Call exec. 1525 // Call exec.
1505 Node* const match_indices = 1526 Node* const match_indices =
1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) 1527 is_fastpath ? RegExpPrototypeExecBody(a, context, receiver, string, true)
1507 : RegExpExec(a, context, receiver, string); 1528 : RegExpExec(a, context, receiver, string);
1508 1529
1509 // Reset last index if necessary. 1530 // Reset last index if necessary.
1510 if (is_fastpath) { 1531 if (is_fastpath) {
1511 FastStoreLastIndex(a, context, receiver, previous_last_index); 1532 FastStoreLastIndex(a, receiver, previous_last_index);
1512 } else { 1533 } else {
1513 CLabel next(a); 1534 CLabel next(a);
1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); 1535 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver);
1515 1536
1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), 1537 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context),
1517 &next); 1538 &next);
1518 1539
1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); 1540 SlowStoreLastIndex(a, context, receiver, previous_last_index);
1520 a->Goto(&next); 1541 a->Goto(&next);
1521 a->Bind(&next); 1542 a->Bind(&next);
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
1928 Node* const int_zero = a->IntPtrConstant(0); 1949 Node* const int_zero = a->IntPtrConstant(0);
1929 Node* const int_one = a->IntPtrConstant(1); 1950 Node* const int_one = a->IntPtrConstant(1);
1930 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1951 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1931 1952
1932 Node* const native_context = a->LoadNativeContext(context); 1953 Node* const native_context = a->LoadNativeContext(context);
1933 1954
1934 CLabel out(a); 1955 CLabel out(a);
1935 CVariable var_result(a, MachineRepresentation::kTagged); 1956 CVariable var_result(a, MachineRepresentation::kTagged);
1936 1957
1937 // Set last index to 0. 1958 // Set last index to 0.
1938 FastStoreLastIndex(a, context, regexp, smi_zero); 1959 FastStoreLastIndex(a, regexp, smi_zero);
1939 1960
1940 // Allocate {result_array}. 1961 // Allocate {result_array}.
1941 Node* result_array; 1962 Node* result_array;
1942 { 1963 {
1943 ElementsKind kind = FAST_ELEMENTS; 1964 ElementsKind kind = FAST_ELEMENTS;
1944 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); 1965 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context);
1945 Node* const capacity = a->IntPtrConstant(16); 1966 Node* const capacity = a->IntPtrConstant(16);
1946 Node* const length = smi_zero; 1967 Node* const length = smi_zero;
1947 Node* const allocation_site = nullptr; 1968 Node* const allocation_site = nullptr;
1948 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; 1969 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS;
1949 1970
1950 result_array = a->AllocateJSArray(kind, array_map, capacity, length, 1971 result_array = a->AllocateJSArray(kind, array_map, capacity, length,
1951 allocation_site, capacity_mode); 1972 allocation_site, capacity_mode);
1952 } 1973 }
1953 1974
1954 // Call into runtime for RegExpExecMultiple. 1975 // Call into runtime for RegExpExecMultiple.
1955 Node* last_match_info = a->LoadContextElement( 1976 Node* last_match_info = a->LoadContextElement(
1956 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1977 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1957 Node* const res = 1978 Node* const res =
1958 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, 1979 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp,
1959 subject_string, last_match_info, result_array); 1980 subject_string, last_match_info, result_array);
1960 1981
1961 // Reset last index to 0. 1982 // Reset last index to 0.
1962 FastStoreLastIndex(a, context, regexp, smi_zero); 1983 FastStoreLastIndex(a, regexp, smi_zero);
1963 1984
1964 // If no matches, return the subject string. 1985 // If no matches, return the subject string.
1965 var_result.Bind(subject_string); 1986 var_result.Bind(subject_string);
1966 a->GotoIf(a->WordEqual(res, null), &out); 1987 a->GotoIf(a->WordEqual(res, null), &out);
1967 1988
1968 // Reload last match info since it might have changed. 1989 // Reload last match info since it might have changed.
1969 last_match_info = a->LoadContextElement( 1990 last_match_info = a->LoadContextElement(
1970 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1991 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1971 1992
1972 Node* const res_length = a->LoadJSArrayLength(res); 1993 Node* const res_length = a->LoadJSArrayLength(res);
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
2155 // Is {regexp} global? 2176 // Is {regexp} global?
2156 CLabel if_isglobal(a), if_isnonglobal(a); 2177 CLabel if_isglobal(a), if_isnonglobal(a);
2157 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 2178 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
2158 Node* const is_global = 2179 Node* const is_global =
2159 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); 2180 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal));
2160 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); 2181 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal);
2161 2182
2162 a->Bind(&if_isglobal); 2183 a->Bind(&if_isglobal);
2163 { 2184 {
2164 // Hand off global regexps to runtime. 2185 // Hand off global regexps to runtime.
2165 FastStoreLastIndex(a, context, regexp, smi_zero); 2186 FastStoreLastIndex(a, regexp, smi_zero);
2166 Node* const result = 2187 Node* const result =
2167 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, 2188 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context,
2168 subject_string, regexp, replace_string, last_match_info); 2189 subject_string, regexp, replace_string, last_match_info);
2169 var_result.Bind(result); 2190 var_result.Bind(result);
2170 a->Goto(&out); 2191 a->Goto(&out);
2171 } 2192 }
2172 2193
2173 a->Bind(&if_isnonglobal); 2194 a->Bind(&if_isnonglobal);
2174 { 2195 {
2175 // Run exec, then manually construct the resulting string. 2196 // Run exec, then manually construct the resulting string.
2176 Callable exec_callable = CodeFactory::RegExpExec(isolate); 2197 Callable exec_callable = CodeFactory::RegExpExec(isolate);
2177 Node* const match_indices = 2198 Node* const match_indices =
2178 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, 2199 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero,
2179 last_match_info); 2200 last_match_info);
2180 2201
2181 CLabel if_matched(a), if_didnotmatch(a); 2202 CLabel if_matched(a), if_didnotmatch(a);
2182 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); 2203 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2183 2204
2184 a->Bind(&if_didnotmatch); 2205 a->Bind(&if_didnotmatch);
2185 { 2206 {
2186 FastStoreLastIndex(a, context, regexp, smi_zero); 2207 FastStoreLastIndex(a, regexp, smi_zero);
2187 var_result.Bind(subject_string); 2208 var_result.Bind(subject_string);
2188 a->Goto(&out); 2209 a->Goto(&out);
2189 } 2210 }
2190 2211
2191 a->Bind(&if_matched); 2212 a->Bind(&if_matched);
2192 { 2213 {
2193 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 2214 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
2194 2215
2195 Node* const subject_start = smi_zero; 2216 Node* const subject_start = smi_zero;
2196 Node* const match_start = a->LoadFixedArrayElement( 2217 Node* const match_start = a->LoadFixedArrayElement(
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
2366 a.Bind(&if_matched); 2387 a.Bind(&if_matched);
2367 { 2388 {
2368 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, 2389 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context,
2369 match_indices, string); 2390 match_indices, string);
2370 a.Return(result); 2391 a.Return(result);
2371 } 2392 }
2372 } 2393 }
2373 2394
2374 } // namespace internal 2395 } // namespace internal
2375 } // namespace v8 2396 } // 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