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

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

Issue 2540153002: [regexp] Refactor RegExp.prototype.exec (Closed)
Patch Set: Assert String/RegExp 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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 a->Bind(&next_iter); 290 a->Bind(&next_iter);
320 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2))); 291 var_from_cursor.Bind(a->IntPtrAdd(from_cursor, a->IntPtrConstant(2)));
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 Node* Generate_RegExpPrototypeExecBodyWithoutResult(
Igor Sheludko 2016/11/30 22:04:21 Please add a comment (especially about what does t
jgruber 2016/12/01 09:09:09 Done.
330 // RegExp.prototype.exec ( string ) 301 CodeStubAssembler* a, Node* const context, Node* const regexp,
331 Node* RegExpPrototypeExecInternal(CodeStubAssembler* a, Node* context, 302 Node* const string, CLabel* if_didnotmatch, const bool is_fastpath) {
332 Node* maybe_receiver, Node* maybe_string) {
333 Isolate* const isolate = a->isolate(); 303 Isolate* const isolate = a->isolate();
334 304
335 Node* const null = a->NullConstant(); 305 Node* const null = a->NullConstant();
336 Node* const int_zero = a->IntPtrConstant(0); 306 Node* const int_zero = a->IntPtrConstant(0);
337 Node* const smi_zero = a->SmiConstant(Smi::kZero); 307 Node* const smi_zero = a->SmiConstant(Smi::kZero);
338 308
309 if (!is_fastpath) {
310 a->ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
311 "RegExp.prototype.exec");
312 }
313
314 CSA_ASSERT(a, a->IsStringInstanceType(a->LoadInstanceType(string)));
315 CSA_ASSERT(a, a->HasInstanceType(regexp, JS_REGEXP_TYPE));
316
339 CVariable var_result(a, MachineRepresentation::kTagged); 317 CVariable var_result(a, MachineRepresentation::kTagged);
340 CLabel out(a); 318 CLabel out(a);
341 319
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); 320 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); 321 Node* const string_length = a->LoadStringLength(string);
359 322
360 // Check whether the regexp is global or sticky, which determines whether we 323 // Check whether the regexp is global or sticky, which determines whether we
361 // update last index later on. 324 // update last index later on.
362 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 325 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
363 Node* const is_global_or_sticky = 326 Node* const is_global_or_sticky =
364 a->WordAnd(a->SmiUntag(flags), 327 a->WordAnd(a->SmiUntag(flags),
365 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky)); 328 a->IntPtrConstant(JSRegExp::kGlobal | JSRegExp::kSticky));
366 Node* const should_update_last_index = 329 Node* const should_update_last_index =
367 a->WordNotEqual(is_global_or_sticky, int_zero); 330 a->WordNotEqual(is_global_or_sticky, int_zero);
368 331
369 // Grab and possibly update last index. 332 // Grab and possibly update last index.
370 CLabel run_exec(a); 333 CLabel run_exec(a);
371 CVariable var_lastindex(a, MachineRepresentation::kTagged); 334 CVariable var_lastindex(a, MachineRepresentation::kTagged);
372 { 335 {
373 CLabel if_doupdate(a), if_dontupdate(a); 336 CLabel if_doupdate(a), if_dontupdate(a);
374 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate); 337 a->Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
375 338
376 a->Bind(&if_doupdate); 339 a->Bind(&if_doupdate);
377 { 340 {
378 Node* const regexp_lastindex = 341 Node* const regexp_lastindex =
379 LoadLastIndex(a, context, has_initialmap, regexp); 342 LoadLastIndex(a, context, regexp, is_fastpath);
343 var_lastindex.Bind(regexp_lastindex);
380 344
381 Callable tolength_callable = CodeFactory::ToLength(isolate); 345 // Omit ToLength if lastindex is a non-negative smi.
382 Node* const lastindex = 346 {
383 a->CallStub(tolength_callable, context, regexp_lastindex); 347 CLabel call_tolength(a, CLabel::kDeferred), next(a);
384 var_lastindex.Bind(lastindex); 348 a->Branch(a->WordIsPositiveSmi(regexp_lastindex), &next,
349 &call_tolength);
350
351 a->Bind(&call_tolength);
352 {
353 Callable tolength_callable = CodeFactory::ToLength(isolate);
354 var_lastindex.Bind(
355 a->CallStub(tolength_callable, context, regexp_lastindex));
356 a->Goto(&next);
357 }
358
359 a->Bind(&next);
360 }
361
362 Node* const lastindex = var_lastindex.value();
385 363
386 CLabel if_isoob(a, CLabel::kDeferred); 364 CLabel if_isoob(a, CLabel::kDeferred);
387 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob); 365 a->GotoUnless(a->TaggedIsSmi(lastindex), &if_isoob);
388 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob); 366 a->GotoUnless(a->SmiLessThanOrEqual(lastindex, string_length), &if_isoob);
389 a->Goto(&run_exec); 367 a->Goto(&run_exec);
390 368
391 a->Bind(&if_isoob); 369 a->Bind(&if_isoob);
392 { 370 {
393 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); 371 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath);
394 var_result.Bind(null); 372 var_result.Bind(null);
395 a->Goto(&out); 373 a->Goto(if_didnotmatch);
396 } 374 }
397 } 375 }
398 376
399 a->Bind(&if_dontupdate); 377 a->Bind(&if_dontupdate);
400 { 378 {
401 var_lastindex.Bind(smi_zero); 379 var_lastindex.Bind(smi_zero);
402 a->Goto(&run_exec); 380 a->Goto(&run_exec);
403 } 381 }
404 } 382 }
405 383
406 Node* match_indices; 384 Node* match_indices;
407 CLabel successful_match(a); 385 CLabel successful_match(a);
408 a->Bind(&run_exec); 386 a->Bind(&run_exec);
409 { 387 {
410 // Get last match info from the context. 388 // Get last match info from the context.
411 Node* const last_match_info = a->LoadContextElement( 389 Node* const last_match_info = a->LoadContextElement(
412 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 390 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
413 391
414 // Call the exec stub. 392 // Call the exec stub.
415 Callable exec_callable = CodeFactory::RegExpExec(isolate); 393 Callable exec_callable = CodeFactory::RegExpExec(isolate);
416 match_indices = a->CallStub(exec_callable, context, regexp, string, 394 match_indices = a->CallStub(exec_callable, context, regexp, string,
417 var_lastindex.value(), last_match_info); 395 var_lastindex.value(), last_match_info);
396 var_result.Bind(match_indices);
418 397
419 // {match_indices} is either null or the RegExpMatchInfo array. 398 // {match_indices} is either null or the RegExpMatchInfo array.
420 // Return early if exec failed, possibly updating last index. 399 // Return early if exec failed, possibly updating last index.
421 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match); 400 a->GotoUnless(a->WordEqual(match_indices, null), &successful_match);
422 401
423 CLabel return_null(a); 402 a->GotoUnless(should_update_last_index, if_didnotmatch);
424 a->GotoUnless(should_update_last_index, &return_null);
425 403
426 StoreLastIndex(a, context, has_initialmap, regexp, smi_zero); 404 StoreLastIndex(a, context, regexp, smi_zero, is_fastpath);
427 a->Goto(&return_null); 405 a->Goto(if_didnotmatch);
428
429 a->Bind(&return_null);
430 var_result.Bind(null);
431 a->Goto(&out);
432 } 406 }
433 407
434 CLabel construct_result(a);
435 a->Bind(&successful_match); 408 a->Bind(&successful_match);
436 { 409 {
437 a->GotoUnless(should_update_last_index, &construct_result); 410 a->GotoUnless(should_update_last_index, &out);
438 411
439 // Update the new last index from {match_indices}. 412 // Update the new last index from {match_indices}.
440 Node* const new_lastindex = a->LoadFixedArrayElement( 413 Node* const new_lastindex = a->LoadFixedArrayElement(
441 match_indices, 414 match_indices,
442 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1)); 415 a->IntPtrConstant(RegExpMatchInfo::kFirstCaptureIndex + 1));
443 416
444 StoreLastIndex(a, context, has_initialmap, regexp, new_lastindex); 417 StoreLastIndex(a, context, regexp, new_lastindex, is_fastpath);
445 a->Goto(&construct_result); 418 a->Goto(&out);
419 }
446 420
447 a->Bind(&construct_result); 421 a->Bind(&out);
448 { 422 return var_result.value();
449 Node* result = ConstructNewResultFromMatchInfo(isolate, a, context, 423 }
450 match_indices, string); 424
451 var_result.Bind(result); 425 // ES#sec-regexp.prototype.exec
452 a->Goto(&out); 426 // RegExp.prototype.exec ( string )
453 } 427 Node* Generate_RegExpPrototypeExecBody(CodeStubAssembler* a,
Igor Sheludko 2016/11/30 22:12:08 I think you can drop the Generate_ prefix for read
jgruber 2016/12/01 09:09:09 Done.
428 Node* const context, Node* const regexp,
429 Node* const string,
430 const bool is_fastpath) {
431 Isolate* const isolate = a->isolate();
432 Node* const null = a->NullConstant();
433
434 CVariable var_result(a, MachineRepresentation::kTagged);
435
436 CLabel if_didnotmatch(a), out(a);
437 Node* const indices_or_null = Generate_RegExpPrototypeExecBodyWithoutResult(
438 a, context, regexp, string, &if_didnotmatch, is_fastpath);
439
440 // Successful match.
441 {
442 Node* const match_indices = indices_or_null;
443 Node* const result = ConstructNewResultFromMatchInfo(isolate, a, context,
444 match_indices, string);
445 var_result.Bind(result);
446 a->Goto(&out);
447 }
448
449 a->Bind(&if_didnotmatch);
450 {
451 var_result.Bind(null);
452 a->Goto(&out);
454 } 453 }
455 454
456 a->Bind(&out); 455 a->Bind(&out);
457 return var_result.value(); 456 return var_result.value();
458 } 457 }
459 458
460 } // namespace 459 } // namespace
461 460
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 { 461 namespace {
477 462
478 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate, 463 Node* ThrowIfNotJSReceiver(CodeStubAssembler* a, Isolate* isolate,
479 Node* context, Node* value, 464 Node* context, Node* value,
480 MessageTemplate::Template msg_template, 465 MessageTemplate::Template msg_template,
481 char const* method_name) { 466 char const* method_name) {
482 CLabel out(a), throw_exception(a, CLabel::kDeferred); 467 CLabel out(a), throw_exception(a, CLabel::kDeferred);
483 CVariable var_value_map(a, MachineRepresentation::kTagged); 468 CVariable var_value_map(a, MachineRepresentation::kTagged);
484 469
485 a->GotoIf(a->TaggedIsSmi(value), &throw_exception); 470 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); 540 Node* const native_context = a->LoadNativeContext(context);
556 Node* const initial_regexp_result_map = 541 Node* const initial_regexp_result_map =
557 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); 542 a->LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
558 543
559 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified, 544 a->Branch(a->WordEqual(map, initial_regexp_result_map), if_isunmodified,
560 if_ismodified); 545 if_ismodified);
561 } 546 }
562 547
563 } // namespace 548 } // namespace
564 549
550 // ES#sec-regexp.prototype.exec
551 // RegExp.prototype.exec ( string )
552 void Builtins::Generate_RegExpPrototypeExec(CodeAssemblerState* state) {
553 CodeStubAssembler a(state);
554
555 Node* const maybe_receiver = a.Parameter(0);
556 Node* const maybe_string = a.Parameter(1);
557 Node* const context = a.Parameter(4);
558
559 // Ensure {maybe_receiver} is a JSRegExp.
560 Node* const regexp_map = a.ThrowIfNotInstanceType(
561 context, maybe_receiver, JS_REGEXP_TYPE, "RegExp.prototype.exec");
562 Node* const receiver = maybe_receiver;
563
564 // Convert {maybe_string} to a String.
565 Node* const string = a.ToString(context, maybe_string);
566
567 CLabel if_isfastpath(&a), if_isslowpath(&a);
568 a.Branch(IsInitialRegExpMap(&a, context, regexp_map), &if_isfastpath,
569 &if_isslowpath);
570
571 a.Bind(&if_isfastpath);
572 {
573 Node* const result =
574 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, true);
575 a.Return(result);
576 }
577
578 a.Bind(&if_isslowpath);
579 {
580 Node* const result =
581 Generate_RegExpPrototypeExecBody(&a, context, receiver, string, false);
582 a.Return(result);
583 }
584 }
585
565 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) { 586 void Builtins::Generate_RegExpPrototypeFlagsGetter(CodeAssemblerState* state) {
566 CodeStubAssembler a(state); 587 CodeStubAssembler a(state);
567 588
568 Node* const receiver = a.Parameter(0); 589 Node* const receiver = a.Parameter(0);
569 Node* const context = a.Parameter(3); 590 Node* const context = a.Parameter(3);
570 591
571 Isolate* isolate = a.isolate(); 592 Isolate* isolate = a.isolate();
572 Node* const int_zero = a.IntPtrConstant(0); 593 Node* const int_zero = a.IntPtrConstant(0);
573 Node* const int_one = a.IntPtrConstant(1); 594 Node* const int_one = a.IntPtrConstant(1);
574 595
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 namespace { 1047 namespace {
1027 1048
1028 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) 1049 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S )
1029 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv, 1050 Node* RegExpExec(CodeStubAssembler* a, Node* context, Node* recv,
1030 Node* string) { 1051 Node* string) {
1031 Isolate* isolate = a->isolate(); 1052 Isolate* isolate = a->isolate();
1032 1053
1033 Node* const null = a->NullConstant(); 1054 Node* const null = a->NullConstant();
1034 1055
1035 CVariable var_result(a, MachineRepresentation::kTagged); 1056 CVariable var_result(a, MachineRepresentation::kTagged);
1036 CLabel out(a), call_builtin_exec(a), slow_path(a, CLabel::kDeferred); 1057 CLabel out(a), if_isfastpath(a), if_isslowpath(a);
1037 1058
1038 Node* const map = a->LoadMap(recv); 1059 Node* const map = a->LoadMap(recv);
1039 BranchIfFastPath(a, context, map, &call_builtin_exec, &slow_path); 1060 BranchIfFastPath(a, context, map, &if_isfastpath, &if_isslowpath);
1040 1061
1041 a->Bind(&call_builtin_exec); 1062 a->Bind(&if_isfastpath);
1042 { 1063 {
1043 Node* const result = RegExpPrototypeExecInternal(a, context, recv, string); 1064 Node* const result =
1065 Generate_RegExpPrototypeExecBody(a, context, recv, string, true);
1044 var_result.Bind(result); 1066 var_result.Bind(result);
1045 a->Goto(&out); 1067 a->Goto(&out);
1046 } 1068 }
1047 1069
1048 a->Bind(&slow_path); 1070 a->Bind(&if_isslowpath);
1049 { 1071 {
1050 // Take the slow path of fetching the exec property, calling it, and 1072 // Take the slow path of fetching the exec property, calling it, and
1051 // verifying its return value. 1073 // verifying its return value.
1052 1074
1053 // Get the exec property. 1075 // Get the exec property.
1054 Node* const name = a->HeapConstant(isolate->factory()->exec_string()); 1076 Node* const name = a->HeapConstant(isolate->factory()->exec_string());
1055 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); 1077 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate());
1056 Node* const exec = a->CallStub(getproperty_callable, context, recv, name); 1078 Node* const exec = a->CallStub(getproperty_callable, context, recv, name);
1057 1079
1058 // Is {exec} callable? 1080 // Is {exec} callable?
(...skipping 16 matching lines...) Expand all
1075 ThrowIfNotJSReceiver(a, isolate, context, result, 1097 ThrowIfNotJSReceiver(a, isolate, context, result,
1076 MessageTemplate::kInvalidRegExpExecResult, "unused"); 1098 MessageTemplate::kInvalidRegExpExecResult, "unused");
1077 1099
1078 a->Goto(&out); 1100 a->Goto(&out);
1079 } 1101 }
1080 1102
1081 a->Bind(&if_isnotcallable); 1103 a->Bind(&if_isnotcallable);
1082 { 1104 {
1083 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE, 1105 a->ThrowIfNotInstanceType(context, recv, JS_REGEXP_TYPE,
1084 "RegExp.prototype.exec"); 1106 "RegExp.prototype.exec");
1085 a->Goto(&call_builtin_exec); 1107
1108 Node* const result =
1109 Generate_RegExpPrototypeExecBody(a, context, recv, string, false);
1110 var_result.Bind(result);
1111 a->Goto(&out);
1086 } 1112 }
1087 } 1113 }
1088 1114
1089 a->Bind(&out); 1115 a->Bind(&out);
1090 return var_result.value(); 1116 return var_result.value();
1091 } 1117 }
1092 1118
1093 } // namespace 1119 } // namespace
1094 1120
1095 // ES#sec-regexp.prototype.test 1121 // ES#sec-regexp.prototype.test
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
1300 1326
1301 Node* const regexp = receiver; 1327 Node* const regexp = receiver;
1302 Node* const is_global = 1328 Node* const is_global =
1303 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath); 1329 FlagGetter(a, context, regexp, JSRegExp::kGlobal, is_fastpath);
1304 1330
1305 CLabel if_isglobal(a), if_isnotglobal(a); 1331 CLabel if_isglobal(a), if_isnotglobal(a);
1306 a->Branch(is_global, &if_isglobal, &if_isnotglobal); 1332 a->Branch(is_global, &if_isglobal, &if_isnotglobal);
1307 1333
1308 a->Bind(&if_isnotglobal); 1334 a->Bind(&if_isnotglobal);
1309 { 1335 {
1310 Node* const result = 1336 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody(
1311 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) 1337 a, context, regexp, string, true)
1312 : RegExpExec(a, context, regexp, string); 1338 : RegExpExec(a, context, regexp, string);
1313 a->Return(result); 1339 a->Return(result);
1314 } 1340 }
1315 1341
1316 a->Bind(&if_isglobal); 1342 a->Bind(&if_isglobal);
1317 { 1343 {
1318 Node* const is_unicode = 1344 Node* const is_unicode =
1319 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath); 1345 FlagGetter(a, context, regexp, JSRegExp::kUnicode, is_fastpath);
1320 1346
1321 if (is_fastpath) { 1347 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 1348
1327 // Allocate an array to store the resulting match strings. 1349 // Allocate an array to store the resulting match strings.
1328 1350
1329 GrowableFixedArray array(a); 1351 GrowableFixedArray array(a);
1330 1352
1331 // Loop preparations. Within the loop, collect results from RegExpExec 1353 // Loop preparations. Within the loop, collect results from RegExpExec
1332 // and store match strings in the array. 1354 // and store match strings in the array.
1333 1355
1334 CVariable* vars[] = {array.var_array(), array.var_length(), 1356 CVariable* vars[] = {array.var_array(), array.var_length(),
1335 array.var_capacity()}; 1357 array.var_capacity()};
1336 CLabel loop(a, 3, vars), out(a); 1358 CLabel loop(a, 3, vars), out(a);
1337 a->Goto(&loop); 1359 a->Goto(&loop);
1338 1360
1339 a->Bind(&loop); 1361 a->Bind(&loop);
1340 { 1362 {
1341 Node* const result = 1363 Node* const result = is_fastpath ? Generate_RegExpPrototypeExecBody(
1342 is_fastpath ? RegExpPrototypeExecInternal(a, context, regexp, string) 1364 a, context, regexp, string, true)
1343 : RegExpExec(a, context, regexp, string); 1365 : RegExpExec(a, context, regexp, string);
1344 1366
1345 CLabel if_didmatch(a), if_didnotmatch(a); 1367 CLabel if_didmatch(a), if_didnotmatch(a);
1346 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch); 1368 a->Branch(a->WordEqual(result, null), &if_didnotmatch, &if_didmatch);
1347 1369
1348 a->Bind(&if_didnotmatch); 1370 a->Bind(&if_didnotmatch);
1349 { 1371 {
1350 // Return null if there were no matches, otherwise just exit the loop. 1372 // Return null if there were no matches, otherwise just exit the loop.
1351 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out); 1373 a->GotoUnless(a->IntPtrEqual(array.length(), int_zero), &out);
1352 a->Return(null); 1374 a->Return(null);
1353 } 1375 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1408 1430
1409 // Store the match, growing the fixed array if needed. 1431 // Store the match, growing the fixed array if needed.
1410 1432
1411 array.Push(match); 1433 array.Push(match);
1412 1434
1413 // Advance last index if the match is the empty string. 1435 // Advance last index if the match is the empty string.
1414 1436
1415 Node* const match_length = a->LoadStringLength(match); 1437 Node* const match_length = a->LoadStringLength(match);
1416 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop); 1438 a->GotoUnless(a->SmiEqual(match_length, smi_zero), &loop);
1417 1439
1418 Node* last_index = is_fastpath ? FastLoadLastIndex(a, context, regexp) 1440 Node* last_index = LoadLastIndex(a, context, regexp, is_fastpath);
1419 : SlowLoadLastIndex(a, context, regexp);
1420 1441
1421 Callable tolength_callable = CodeFactory::ToLength(isolate); 1442 Callable tolength_callable = CodeFactory::ToLength(isolate);
1422 last_index = a->CallStub(tolength_callable, context, last_index); 1443 last_index = a->CallStub(tolength_callable, context, last_index);
1423 1444
1424 Node* const new_last_index = 1445 Node* const new_last_index =
1425 AdvanceStringIndex(a, string, last_index, is_unicode); 1446 AdvanceStringIndex(a, string, last_index, is_unicode);
1426 1447
1427 if (is_fastpath) { 1448 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 1449
1433 a->Goto(&loop); 1450 a->Goto(&loop);
1434 } 1451 }
1435 } 1452 }
1436 1453
1437 a->Bind(&out); 1454 a->Bind(&out);
1438 { 1455 {
1439 // Wrap the match in a JSArray. 1456 // Wrap the match in a JSArray.
1440 1457
1441 Node* const result = array.ToJSArray(context); 1458 Node* const result = array.ToJSArray(context);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a, 1496 void Generate_RegExpPrototypeSearchBody(CodeStubAssembler* a,
1480 Node* const receiver, 1497 Node* const receiver,
1481 Node* const string, Node* const context, 1498 Node* const string, Node* const context,
1482 bool is_fastpath) { 1499 bool is_fastpath) {
1483 Isolate* const isolate = a->isolate(); 1500 Isolate* const isolate = a->isolate();
1484 1501
1485 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1502 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1486 1503
1487 // Grab the initial value of last index. 1504 // Grab the initial value of last index.
1488 Node* const previous_last_index = 1505 Node* const previous_last_index =
1489 is_fastpath ? FastLoadLastIndex(a, context, receiver) 1506 LoadLastIndex(a, context, receiver, is_fastpath);
1490 : SlowLoadLastIndex(a, context, receiver);
1491 1507
1492 // Ensure last index is 0. 1508 // Ensure last index is 0.
1493 if (is_fastpath) { 1509 if (is_fastpath) {
1494 FastStoreLastIndex(a, context, receiver, smi_zero); 1510 FastStoreLastIndex(a, receiver, smi_zero);
1495 } else { 1511 } else {
1496 CLabel next(a); 1512 CLabel next(a);
1497 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next); 1513 a->GotoIf(a->SameValue(previous_last_index, smi_zero, context), &next);
1498 1514
1499 SlowStoreLastIndex(a, context, receiver, smi_zero); 1515 SlowStoreLastIndex(a, context, receiver, smi_zero);
1500 a->Goto(&next); 1516 a->Goto(&next);
1501 a->Bind(&next); 1517 a->Bind(&next);
1502 } 1518 }
1503 1519
1504 // Call exec. 1520 // Call exec.
1505 Node* const match_indices = 1521 Node* const match_indices =
1506 is_fastpath ? RegExpPrototypeExecInternal(a, context, receiver, string) 1522 is_fastpath
1507 : RegExpExec(a, context, receiver, string); 1523 ? Generate_RegExpPrototypeExecBody(a, context, receiver, string, true)
1524 : RegExpExec(a, context, receiver, string);
1508 1525
1509 // Reset last index if necessary. 1526 // Reset last index if necessary.
1510 if (is_fastpath) { 1527 if (is_fastpath) {
1511 FastStoreLastIndex(a, context, receiver, previous_last_index); 1528 FastStoreLastIndex(a, receiver, previous_last_index);
1512 } else { 1529 } else {
1513 CLabel next(a); 1530 CLabel next(a);
1514 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver); 1531 Node* const current_last_index = SlowLoadLastIndex(a, context, receiver);
1515 1532
1516 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context), 1533 a->GotoIf(a->SameValue(current_last_index, previous_last_index, context),
1517 &next); 1534 &next);
1518 1535
1519 SlowStoreLastIndex(a, context, receiver, previous_last_index); 1536 SlowStoreLastIndex(a, context, receiver, previous_last_index);
1520 a->Goto(&next); 1537 a->Goto(&next);
1521 a->Bind(&next); 1538 a->Bind(&next);
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1927 Node* const int_zero = a->IntPtrConstant(0); 1944 Node* const int_zero = a->IntPtrConstant(0);
1928 Node* const int_one = a->IntPtrConstant(1); 1945 Node* const int_one = a->IntPtrConstant(1);
1929 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1946 Node* const smi_zero = a->SmiConstant(Smi::kZero);
1930 1947
1931 Node* const native_context = a->LoadNativeContext(context); 1948 Node* const native_context = a->LoadNativeContext(context);
1932 1949
1933 CLabel out(a); 1950 CLabel out(a);
1934 CVariable var_result(a, MachineRepresentation::kTagged); 1951 CVariable var_result(a, MachineRepresentation::kTagged);
1935 1952
1936 // Set last index to 0. 1953 // Set last index to 0.
1937 FastStoreLastIndex(a, context, regexp, smi_zero); 1954 FastStoreLastIndex(a, regexp, smi_zero);
1938 1955
1939 // Allocate {result_array}. 1956 // Allocate {result_array}.
1940 Node* result_array; 1957 Node* result_array;
1941 { 1958 {
1942 ElementsKind kind = FAST_ELEMENTS; 1959 ElementsKind kind = FAST_ELEMENTS;
1943 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context); 1960 Node* const array_map = a->LoadJSArrayElementsMap(kind, native_context);
1944 Node* const capacity = a->IntPtrConstant(16); 1961 Node* const capacity = a->IntPtrConstant(16);
1945 Node* const length = smi_zero; 1962 Node* const length = smi_zero;
1946 Node* const allocation_site = nullptr; 1963 Node* const allocation_site = nullptr;
1947 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS; 1964 ParameterMode capacity_mode = CodeStubAssembler::INTPTR_PARAMETERS;
1948 1965
1949 result_array = a->AllocateJSArray(kind, array_map, capacity, length, 1966 result_array = a->AllocateJSArray(kind, array_map, capacity, length,
1950 allocation_site, capacity_mode); 1967 allocation_site, capacity_mode);
1951 } 1968 }
1952 1969
1953 // Call into runtime for RegExpExecMultiple. 1970 // Call into runtime for RegExpExecMultiple.
1954 Node* last_match_info = a->LoadContextElement( 1971 Node* last_match_info = a->LoadContextElement(
1955 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1972 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1956 Node* const res = 1973 Node* const res =
1957 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp, 1974 a->CallRuntime(Runtime::kRegExpExecMultiple, context, regexp,
1958 subject_string, last_match_info, result_array); 1975 subject_string, last_match_info, result_array);
1959 1976
1960 // Reset last index to 0. 1977 // Reset last index to 0.
1961 FastStoreLastIndex(a, context, regexp, smi_zero); 1978 FastStoreLastIndex(a, regexp, smi_zero);
1962 1979
1963 // If no matches, return the subject string. 1980 // If no matches, return the subject string.
1964 var_result.Bind(subject_string); 1981 var_result.Bind(subject_string);
1965 a->GotoIf(a->WordEqual(res, null), &out); 1982 a->GotoIf(a->WordEqual(res, null), &out);
1966 1983
1967 // Reload last match info since it might have changed. 1984 // Reload last match info since it might have changed.
1968 last_match_info = a->LoadContextElement( 1985 last_match_info = a->LoadContextElement(
1969 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 1986 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
1970 1987
1971 Node* const res_length = a->LoadJSArrayLength(res); 1988 Node* const res_length = a->LoadJSArrayLength(res);
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
2154 // Is {regexp} global? 2171 // Is {regexp} global?
2155 CLabel if_isglobal(a), if_isnonglobal(a); 2172 CLabel if_isglobal(a), if_isnonglobal(a);
2156 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset); 2173 Node* const flags = a->LoadObjectField(regexp, JSRegExp::kFlagsOffset);
2157 Node* const is_global = 2174 Node* const is_global =
2158 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal)); 2175 a->WordAnd(a->SmiUntag(flags), a->IntPtrConstant(JSRegExp::kGlobal));
2159 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal); 2176 a->Branch(a->WordEqual(is_global, int_zero), &if_isnonglobal, &if_isglobal);
2160 2177
2161 a->Bind(&if_isglobal); 2178 a->Bind(&if_isglobal);
2162 { 2179 {
2163 // Hand off global regexps to runtime. 2180 // Hand off global regexps to runtime.
2164 FastStoreLastIndex(a, context, regexp, smi_zero); 2181 FastStoreLastIndex(a, regexp, smi_zero);
2165 Node* const result = 2182 Node* const result =
2166 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, 2183 a->CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context,
2167 subject_string, regexp, replace_string, last_match_info); 2184 subject_string, regexp, replace_string, last_match_info);
2168 var_result.Bind(result); 2185 var_result.Bind(result);
2169 a->Goto(&out); 2186 a->Goto(&out);
2170 } 2187 }
2171 2188
2172 a->Bind(&if_isnonglobal); 2189 a->Bind(&if_isnonglobal);
2173 { 2190 {
2174 // Run exec, then manually construct the resulting string. 2191 // Run exec, then manually construct the resulting string.
2175 Callable exec_callable = CodeFactory::RegExpExec(isolate); 2192 Callable exec_callable = CodeFactory::RegExpExec(isolate);
2176 Node* const match_indices = 2193 Node* const match_indices =
2177 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero, 2194 a->CallStub(exec_callable, context, regexp, subject_string, smi_zero,
2178 last_match_info); 2195 last_match_info);
2179 2196
2180 CLabel if_matched(a), if_didnotmatch(a); 2197 CLabel if_matched(a), if_didnotmatch(a);
2181 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched); 2198 a->Branch(a->WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2182 2199
2183 a->Bind(&if_didnotmatch); 2200 a->Bind(&if_didnotmatch);
2184 { 2201 {
2185 FastStoreLastIndex(a, context, regexp, smi_zero); 2202 FastStoreLastIndex(a, regexp, smi_zero);
2186 var_result.Bind(subject_string); 2203 var_result.Bind(subject_string);
2187 a->Goto(&out); 2204 a->Goto(&out);
2188 } 2205 }
2189 2206
2190 a->Bind(&if_matched); 2207 a->Bind(&if_matched);
2191 { 2208 {
2192 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS; 2209 ParameterMode mode = CodeStubAssembler::INTPTR_PARAMETERS;
2193 2210
2194 Node* const subject_start = smi_zero; 2211 Node* const subject_start = smi_zero;
2195 Node* const match_start = a->LoadFixedArrayElement( 2212 Node* const match_start = a->LoadFixedArrayElement(
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
2365 a.Bind(&if_matched); 2382 a.Bind(&if_matched);
2366 { 2383 {
2367 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context, 2384 Node* result = ConstructNewResultFromMatchInfo(isolate, &a, context,
2368 match_indices, string); 2385 match_indices, string);
2369 a.Return(result); 2386 a.Return(result);
2370 } 2387 }
2371 } 2388 }
2372 2389
2373 } // namespace internal 2390 } // namespace internal
2374 } // namespace v8 2391 } // 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