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

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

Issue 2685183003: [regexp] Sticky handling in fast slow path (Closed)
Patch Set: Revert "Remove custom ToUint32" Created 3 years, 10 months 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 | src/runtime/runtime-regexp.cc » ('j') | 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-regexp.h" 5 #include "src/builtins/builtins-regexp.h"
6 6
7 #include "src/builtins/builtins-constructor.h" 7 #include "src/builtins/builtins-constructor.h"
8 #include "src/builtins/builtins-utils.h" 8 #include "src/builtins/builtins-utils.h"
9 #include "src/builtins/builtins.h" 9 #include "src/builtins/builtins.h"
10 #include "src/code-factory.h" 10 #include "src/code-factory.h"
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE, 231 ThrowIfNotInstanceType(context, regexp, JS_REGEXP_TYPE,
232 "RegExp.prototype.exec"); 232 "RegExp.prototype.exec");
233 } 233 }
234 234
235 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string))); 235 CSA_ASSERT(this, IsStringInstanceType(LoadInstanceType(string)));
236 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE)); 236 CSA_ASSERT(this, HasInstanceType(regexp, JS_REGEXP_TYPE));
237 237
238 Variable var_result(this, MachineRepresentation::kTagged); 238 Variable var_result(this, MachineRepresentation::kTagged);
239 Label out(this); 239 Label out(this);
240 240
241 Node* const native_context = LoadNativeContext(context);
242 Node* const string_length = LoadStringLength(string);
243
244 // Load lastIndex. 241 // Load lastIndex.
245 Variable var_lastindex(this, MachineRepresentation::kTagged); 242 Variable var_lastindex(this, MachineRepresentation::kTagged);
246 { 243 {
247 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath); 244 Node* const regexp_lastindex = LoadLastIndex(context, regexp, is_fastpath);
248 var_lastindex.Bind(regexp_lastindex); 245 var_lastindex.Bind(regexp_lastindex);
249 246
250 // Omit ToLength if lastindex is a non-negative smi. 247 // Omit ToLength if lastindex is a non-negative smi.
251 Label call_tolength(this, Label::kDeferred), next(this); 248 Label call_tolength(this, Label::kDeferred), next(this);
252 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength); 249 Branch(TaggedIsPositiveSmi(regexp_lastindex), &next, &call_tolength);
253 250
(...skipping 21 matching lines...) Expand all
275 { 272 {
276 Label if_doupdate(this), if_dontupdate(this); 273 Label if_doupdate(this), if_dontupdate(this);
277 Branch(should_update_last_index, &if_doupdate, &if_dontupdate); 274 Branch(should_update_last_index, &if_doupdate, &if_dontupdate);
278 275
279 Bind(&if_doupdate); 276 Bind(&if_doupdate);
280 { 277 {
281 Node* const lastindex = var_lastindex.value(); 278 Node* const lastindex = var_lastindex.value();
282 279
283 Label if_isoob(this, Label::kDeferred); 280 Label if_isoob(this, Label::kDeferred);
284 GotoUnless(TaggedIsSmi(lastindex), &if_isoob); 281 GotoUnless(TaggedIsSmi(lastindex), &if_isoob);
282 Node* const string_length = LoadStringLength(string);
jgruber 2017/02/13 12:15:38 This and below are drive-by cleanups that push loa
285 GotoUnless(SmiLessThanOrEqual(lastindex, string_length), &if_isoob); 283 GotoUnless(SmiLessThanOrEqual(lastindex, string_length), &if_isoob);
286 Goto(&run_exec); 284 Goto(&run_exec);
287 285
288 Bind(&if_isoob); 286 Bind(&if_isoob);
289 { 287 {
290 StoreLastIndex(context, regexp, smi_zero, is_fastpath); 288 StoreLastIndex(context, regexp, smi_zero, is_fastpath);
291 var_result.Bind(null); 289 var_result.Bind(null);
292 Goto(if_didnotmatch); 290 Goto(if_didnotmatch);
293 } 291 }
294 } 292 }
295 293
296 Bind(&if_dontupdate); 294 Bind(&if_dontupdate);
297 { 295 {
298 var_lastindex.Bind(smi_zero); 296 var_lastindex.Bind(smi_zero);
299 Goto(&run_exec); 297 Goto(&run_exec);
300 } 298 }
301 } 299 }
302 300
303 Node* match_indices; 301 Node* match_indices;
304 Label successful_match(this); 302 Label successful_match(this);
305 Bind(&run_exec); 303 Bind(&run_exec);
306 { 304 {
307 // Get last match info from the context. 305 // Get last match info from the context.
306 Node* const native_context = LoadNativeContext(context);
308 Node* const last_match_info = LoadContextElement( 307 Node* const last_match_info = LoadContextElement(
309 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 308 native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
310 309
311 // Call the exec stub. 310 // Call the exec stub.
312 Callable exec_callable = CodeFactory::RegExpExec(isolate); 311 Callable exec_callable = CodeFactory::RegExpExec(isolate);
313 match_indices = CallStub(exec_callable, context, regexp, string, 312 match_indices = CallStub(exec_callable, context, regexp, string,
314 var_lastindex.value(), last_match_info); 313 var_lastindex.value(), last_match_info);
315 var_result.Bind(match_indices); 314 var_result.Bind(match_indices);
316 315
317 // {match_indices} is either null or the RegExpMatchInfo array. 316 // {match_indices} is either null or the RegExpMatchInfo array.
(...skipping 2012 matching lines...) Expand 10 before | Expand all | Expand 10 after
2330 return var_result.value(); 2329 return var_result.value();
2331 } 2330 }
2332 2331
2333 Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath( 2332 Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
2334 Node* context, Node* regexp, Node* string, Node* replace_string) { 2333 Node* context, Node* regexp, Node* string, Node* replace_string) {
2335 // The fast path is reached only if {receiver} is an unmodified 2334 // The fast path is reached only if {receiver} is an unmodified
2336 // JSRegExp instance, {replace_value} is non-callable, and 2335 // JSRegExp instance, {replace_value} is non-callable, and
2337 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple 2336 // ToString({replace_value}) does not contain '$', i.e. we're doing a simple
2338 // string replacement. 2337 // string replacement.
2339 2338
2340 Isolate* const isolate = this->isolate();
2341
2342 Node* const null = NullConstant();
2343 Node* const int_zero = IntPtrConstant(0); 2339 Node* const int_zero = IntPtrConstant(0);
2344 Node* const smi_zero = SmiConstant(Smi::kZero); 2340 Node* const smi_zero = SmiConstant(Smi::kZero);
2345 2341
2346 Label out(this); 2342 Label out(this);
2347 Variable var_result(this, MachineRepresentation::kTagged); 2343 Variable var_result(this, MachineRepresentation::kTagged);
2348 2344
2349 // Load the last match info. 2345 // Load the last match info.
2350 Node* const native_context = LoadNativeContext(context); 2346 Node* const native_context = LoadNativeContext(context);
2351 Node* const last_match_info = 2347 Node* const last_match_info =
2352 LoadContextElement(native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX); 2348 LoadContextElement(native_context, Context::REGEXP_LAST_MATCH_INFO_INDEX);
(...skipping 12 matching lines...) Expand all
2365 Node* const result = 2361 Node* const result =
2366 CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context, 2362 CallRuntime(Runtime::kStringReplaceGlobalRegExpWithString, context,
2367 string, regexp, replace_string, last_match_info); 2363 string, regexp, replace_string, last_match_info);
2368 var_result.Bind(result); 2364 var_result.Bind(result);
2369 Goto(&out); 2365 Goto(&out);
2370 } 2366 }
2371 2367
2372 Bind(&if_isnonglobal); 2368 Bind(&if_isnonglobal);
2373 { 2369 {
2374 // Run exec, then manually construct the resulting string. 2370 // Run exec, then manually construct the resulting string.
2375 Callable exec_callable = CodeFactory::RegExpExec(isolate); 2371 Label if_didnotmatch(this);
2376 Node* const match_indices = CallStub(exec_callable, context, regexp, string, 2372 Node* const match_indices = RegExpPrototypeExecBodyWithoutResult(
jgruber 2017/02/13 12:15:38 Replaced RE.p.exec emulation by inlined version of
2377 smi_zero, last_match_info); 2373 context, regexp, string, &if_didnotmatch, true);
2378 2374
2379 Label if_matched(this), if_didnotmatch(this); 2375 // Successful match.
2380 Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
2381
2382 Bind(&if_didnotmatch);
2383 {
2384 FastStoreLastIndex(regexp, smi_zero);
2385 var_result.Bind(string);
2386 Goto(&out);
2387 }
2388
2389 Bind(&if_matched);
2390 { 2376 {
2391 Node* const subject_start = smi_zero; 2377 Node* const subject_start = smi_zero;
2392 Node* const match_start = LoadFixedArrayElement( 2378 Node* const match_start = LoadFixedArrayElement(
2393 match_indices, RegExpMatchInfo::kFirstCaptureIndex); 2379 match_indices, RegExpMatchInfo::kFirstCaptureIndex);
2394 Node* const match_end = LoadFixedArrayElement( 2380 Node* const match_end = LoadFixedArrayElement(
2395 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1); 2381 match_indices, RegExpMatchInfo::kFirstCaptureIndex + 1);
2396 Node* const subject_end = LoadStringLength(string); 2382 Node* const subject_end = LoadStringLength(string);
2397 2383
2398 Label if_replaceisempty(this), if_replaceisnotempty(this); 2384 Label if_replaceisempty(this), if_replaceisnotempty(this);
2399 Node* const replace_length = LoadStringLength(replace_string); 2385 Node* const replace_length = LoadStringLength(replace_string);
(...skipping 23 matching lines...) Expand all
2423 Node* const third_part = 2409 Node* const third_part =
2424 SubString(context, string, match_end, subject_end); 2410 SubString(context, string, match_end, subject_end);
2425 2411
2426 Node* result = StringAdd(context, first_part, second_part); 2412 Node* result = StringAdd(context, first_part, second_part);
2427 result = StringAdd(context, result, third_part); 2413 result = StringAdd(context, result, third_part);
2428 2414
2429 var_result.Bind(result); 2415 var_result.Bind(result);
2430 Goto(&out); 2416 Goto(&out);
2431 } 2417 }
2432 } 2418 }
2419
2420 Bind(&if_didnotmatch);
2421 {
2422 var_result.Bind(string);
2423 Goto(&out);
2424 }
2433 } 2425 }
2434 2426
2435 Bind(&out); 2427 Bind(&out);
2436 return var_result.value(); 2428 return var_result.value();
2437 } 2429 }
2438 2430
2439 // Helper that skips a few initial checks. 2431 // Helper that skips a few initial checks.
2440 TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) { 2432 TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
2441 typedef RegExpReplaceDescriptor Descriptor; 2433 typedef RegExpReplaceDescriptor Descriptor;
2442 2434
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
2499 } 2491 }
2500 2492
2501 // ES#sec-regexp.prototype-@@replace 2493 // ES#sec-regexp.prototype-@@replace
2502 // RegExp.prototype [ @@replace ] ( string, replaceValue ) 2494 // RegExp.prototype [ @@replace ] ( string, replaceValue )
2503 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { 2495 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
2504 Node* const maybe_receiver = Parameter(0); 2496 Node* const maybe_receiver = Parameter(0);
2505 Node* const maybe_string = Parameter(1); 2497 Node* const maybe_string = Parameter(1);
2506 Node* const replace_value = Parameter(2); 2498 Node* const replace_value = Parameter(2);
2507 Node* const context = Parameter(5); 2499 Node* const context = Parameter(5);
2508 2500
2501 // RegExpPrototypeReplace is a bit of a beast - a summary of dispatch logic:
2502 //
2503 // if (!IsFastRegExp(receiver)) CallRuntime(RegExpReplace)
2504 // if (IsCallable(replace)) {
2505 // if (IsGlobal(receiver)) {
2506 // // Called 'fast-path' but contains several runtime calls.
2507 // ReplaceGlobalCallableFastPath()
2508 // } else {
2509 // CallRuntime(StringReplaceNonGlobalRegExpWithFunction)
2510 // }
2511 // } else {
2512 // if (replace.contains("$")) {
2513 // CallRuntime(RegExpReplace)
2514 // } else {
2515 // ReplaceSimpleStringFastPath() // Bails to runtime for global regexps.
2516 // }
2517 // }
2518
2509 // Ensure {maybe_receiver} is a JSReceiver. 2519 // Ensure {maybe_receiver} is a JSReceiver.
2510 Node* const map = ThrowIfNotJSReceiver( 2520 Node* const map = ThrowIfNotJSReceiver(
2511 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 2521 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
2512 "RegExp.prototype.@@replace"); 2522 "RegExp.prototype.@@replace");
2513 Node* const receiver = maybe_receiver; 2523 Node* const receiver = maybe_receiver;
2514 2524
2515 // Convert {maybe_string} to a String. 2525 // Convert {maybe_string} to a String.
2516 Callable tostring_callable = CodeFactory::ToString(isolate()); 2526 Callable tostring_callable = CodeFactory::ToString(isolate());
2517 Node* const string = CallStub(tostring_callable, context, maybe_string); 2527 Node* const string = CallStub(tostring_callable, context, maybe_string);
2518 2528
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2556 Bind(&if_matched); 2566 Bind(&if_matched);
2557 { 2567 {
2558 Node* result = 2568 Node* result =
2559 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); 2569 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
2560 Return(result); 2570 Return(result);
2561 } 2571 }
2562 } 2572 }
2563 2573
2564 } // namespace internal 2574 } // namespace internal
2565 } // namespace v8 2575 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/runtime/runtime-regexp.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698