OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |