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

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

Issue 2668703002: [stubs] Add RegExpReplace and RegExpSplit stubs (Closed)
Patch Set: Rebase 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 | « src/builtins/builtins-regexp.h ('k') | src/builtins/builtins-string.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 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 415 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
416 Node* const has_initialmap = WordEqual(map, initial_map); 416 Node* const has_initialmap = WordEqual(map, initial_map);
417 417
418 return has_initialmap; 418 return has_initialmap;
419 } 419 }
420 420
421 // RegExp fast path implementations rely on unmodified JSRegExp instances. 421 // RegExp fast path implementations rely on unmodified JSRegExp instances.
422 // We use a fairly coarse granularity for this and simply check whether both 422 // We use a fairly coarse granularity for this and simply check whether both
423 // the regexp itself is unmodified (i.e. its map has not changed) and its 423 // the regexp itself is unmodified (i.e. its map has not changed) and its
424 // prototype is unmodified. 424 // prototype is unmodified.
425 void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* context, Node* map, 425 Node* RegExpBuiltinsAssembler::IsFastRegExpMap(Node* context, Node* map) {
426 Label* if_isunmodified, 426 Label out(this);
427 Label* if_ismodified) { 427 Variable var_result(this, MachineRepresentation::kWord32, Int32Constant(0));
Igor Sheludko 2017/02/03 09:17:54 Although the use cases look nicer with this change
jgruber 2017/02/03 10:29:28 Done.
428
428 Node* const native_context = LoadNativeContext(context); 429 Node* const native_context = LoadNativeContext(context);
429 Node* const regexp_fun = 430 Node* const regexp_fun =
430 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX); 431 LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
431 Node* const initial_map = 432 Node* const initial_map =
432 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset); 433 LoadObjectField(regexp_fun, JSFunction::kPrototypeOrInitialMapOffset);
433 Node* const has_initialmap = WordEqual(map, initial_map); 434 Node* const has_initialmap = WordEqual(map, initial_map);
434 435
435 GotoUnless(has_initialmap, if_ismodified); 436 GotoUnless(has_initialmap, &out);
436 437
437 Node* const initial_proto_initial_map = 438 Node* const initial_proto_initial_map =
438 LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX); 439 LoadContextElement(native_context, Context::REGEXP_PROTOTYPE_MAP_INDEX);
439 Node* const proto_map = LoadMap(LoadMapPrototype(map)); 440 Node* const proto_map = LoadMap(LoadMapPrototype(map));
440 Node* const proto_has_initialmap = 441 Node* const proto_has_initialmap =
441 WordEqual(proto_map, initial_proto_initial_map); 442 WordEqual(proto_map, initial_proto_initial_map);
442 443
444 var_result.Bind(proto_has_initialmap);
445 Goto(&out);
446
443 // TODO(ishell): Update this check once map changes for constant field 447 // TODO(ishell): Update this check once map changes for constant field
444 // tracking are landing. 448 // tracking are landing.
445 449
446 Branch(proto_has_initialmap, if_isunmodified, if_ismodified); 450 Bind(&out);
451 return var_result.value();
447 } 452 }
448 453
449 void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* context, Node* map, 454 void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* context, Node* map,
450 Label* if_isunmodified, 455 Label* if_isunmodified,
451 Label* if_ismodified) { 456 Label* if_ismodified) {
452 Node* const native_context = LoadNativeContext(context); 457 Node* const native_context = LoadNativeContext(context);
453 Node* const initial_regexp_result_map = 458 Node* const initial_regexp_result_map =
454 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX); 459 LoadContextElement(native_context, Context::REGEXP_RESULT_MAP_INDEX);
455 460
456 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified, 461 Branch(WordEqual(map, initial_regexp_result_map), if_isunmodified,
(...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after
1193 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp, 1198 Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
1194 Node* string) { 1199 Node* string) {
1195 Isolate* isolate = this->isolate(); 1200 Isolate* isolate = this->isolate();
1196 1201
1197 Node* const null = NullConstant(); 1202 Node* const null = NullConstant();
1198 1203
1199 Variable var_result(this, MachineRepresentation::kTagged); 1204 Variable var_result(this, MachineRepresentation::kTagged);
1200 Label out(this), if_isfastpath(this), if_isslowpath(this); 1205 Label out(this), if_isfastpath(this), if_isslowpath(this);
1201 1206
1202 Node* const map = LoadMap(regexp); 1207 Node* const map = LoadMap(regexp);
1203 BranchIfFastRegExp(context, map, &if_isfastpath, &if_isslowpath); 1208 Branch(IsFastRegExpMap(context, map), &if_isfastpath, &if_isslowpath);
1204 1209
1205 Bind(&if_isfastpath); 1210 Bind(&if_isfastpath);
1206 { 1211 {
1207 Node* const result = RegExpPrototypeExecBody(context, regexp, string, true); 1212 Node* const result = RegExpPrototypeExecBody(context, regexp, string, true);
1208 var_result.Bind(result); 1213 var_result.Bind(result);
1209 Goto(&out); 1214 Goto(&out);
1210 } 1215 }
1211 1216
1212 Bind(&if_isslowpath); 1217 Bind(&if_isslowpath);
1213 { 1218 {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 // Ensure {maybe_receiver} is a JSReceiver. 1272 // Ensure {maybe_receiver} is a JSReceiver.
1268 Node* const map = ThrowIfNotJSReceiver( 1273 Node* const map = ThrowIfNotJSReceiver(
1269 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 1274 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1270 "RegExp.prototype.test"); 1275 "RegExp.prototype.test");
1271 Node* const receiver = maybe_receiver; 1276 Node* const receiver = maybe_receiver;
1272 1277
1273 // Convert {maybe_string} to a String. 1278 // Convert {maybe_string} to a String.
1274 Node* const string = ToString(context, maybe_string); 1279 Node* const string = ToString(context, maybe_string);
1275 1280
1276 Label fast_path(this), slow_path(this); 1281 Label fast_path(this), slow_path(this);
1277 BranchIfFastRegExp(context, map, &fast_path, &slow_path); 1282 Branch(IsFastRegExpMap(context, map), &fast_path, &slow_path);
1278 1283
1279 Bind(&fast_path); 1284 Bind(&fast_path);
1280 { 1285 {
1281 Label if_didnotmatch(this); 1286 Label if_didnotmatch(this);
1282 RegExpPrototypeExecBodyWithoutResult(context, receiver, string, 1287 RegExpPrototypeExecBodyWithoutResult(context, receiver, string,
1283 &if_didnotmatch, true); 1288 &if_didnotmatch, true);
1284 Return(TrueConstant()); 1289 Return(TrueConstant());
1285 1290
1286 Bind(&if_didnotmatch); 1291 Bind(&if_didnotmatch);
1287 Return(FalseConstant()); 1292 Return(FalseConstant());
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
1642 // Ensure {maybe_receiver} is a JSReceiver. 1647 // Ensure {maybe_receiver} is a JSReceiver.
1643 Node* const map = ThrowIfNotJSReceiver( 1648 Node* const map = ThrowIfNotJSReceiver(
1644 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 1649 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1645 "RegExp.prototype.@@match"); 1650 "RegExp.prototype.@@match");
1646 Node* const receiver = maybe_receiver; 1651 Node* const receiver = maybe_receiver;
1647 1652
1648 // Convert {maybe_string} to a String. 1653 // Convert {maybe_string} to a String.
1649 Node* const string = ToString(context, maybe_string); 1654 Node* const string = ToString(context, maybe_string);
1650 1655
1651 Label fast_path(this), slow_path(this); 1656 Label fast_path(this), slow_path(this);
1652 BranchIfFastRegExp(context, map, &fast_path, &slow_path); 1657 Branch(IsFastRegExpMap(context, map), &fast_path, &slow_path);
1653 1658
1654 Bind(&fast_path); 1659 Bind(&fast_path);
1655 RegExpPrototypeMatchBody(context, receiver, string, true); 1660 RegExpPrototypeMatchBody(context, receiver, string, true);
1656 1661
1657 Bind(&slow_path); 1662 Bind(&slow_path);
1658 RegExpPrototypeMatchBody(context, receiver, string, false); 1663 RegExpPrototypeMatchBody(context, receiver, string, false);
1659 } 1664 }
1660 1665
1661 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast( 1666 void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodyFast(
1662 Node* const context, Node* const regexp, Node* const string) { 1667 Node* const context, Node* const regexp, Node* const string) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1767 // Ensure {maybe_receiver} is a JSReceiver. 1772 // Ensure {maybe_receiver} is a JSReceiver.
1768 Node* const map = ThrowIfNotJSReceiver( 1773 Node* const map = ThrowIfNotJSReceiver(
1769 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 1774 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
1770 "RegExp.prototype.@@search"); 1775 "RegExp.prototype.@@search");
1771 Node* const receiver = maybe_receiver; 1776 Node* const receiver = maybe_receiver;
1772 1777
1773 // Convert {maybe_string} to a String. 1778 // Convert {maybe_string} to a String.
1774 Node* const string = ToString(context, maybe_string); 1779 Node* const string = ToString(context, maybe_string);
1775 1780
1776 Label fast_path(this), slow_path(this); 1781 Label fast_path(this), slow_path(this);
1777 BranchIfFastRegExp(context, map, &fast_path, &slow_path); 1782 Branch(IsFastRegExpMap(context, map), &fast_path, &slow_path);
1778 1783
1779 Bind(&fast_path); 1784 Bind(&fast_path);
1780 RegExpPrototypeSearchBodyFast(context, receiver, string); 1785 RegExpPrototypeSearchBodyFast(context, receiver, string);
1781 1786
1782 Bind(&slow_path); 1787 Bind(&slow_path);
1783 RegExpPrototypeSearchBodySlow(context, receiver, string); 1788 RegExpPrototypeSearchBodySlow(context, receiver, string);
1784 } 1789 }
1785 1790
1786 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp, 1791 // Generates the fast path for @@split. {regexp} is an unmodified JSRegExp,
1787 // {string} is a String, and {limit} is a Smi. 1792 // {string} is a String, and {limit} is a Smi.
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
2022 Bind(&return_empty_array); 2027 Bind(&return_empty_array);
2023 { 2028 {
2024 Node* const length = smi_zero; 2029 Node* const length = smi_zero;
2025 Node* const capacity = int_zero; 2030 Node* const capacity = int_zero;
2026 Node* const result = AllocateJSArray(kind, array_map, capacity, length, 2031 Node* const result = AllocateJSArray(kind, array_map, capacity, length,
2027 allocation_site, mode); 2032 allocation_site, mode);
2028 Return(result); 2033 Return(result);
2029 } 2034 }
2030 } 2035 }
2031 2036
2037 // Helper that skips a few initial checks.
2038 TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) {
2039 typedef RegExpSplitDescriptor Descriptor;
2040
2041 Node* const regexp = Parameter(Descriptor::kReceiver);
2042 Node* const string = Parameter(Descriptor::kString);
2043 Node* const maybe_limit = Parameter(Descriptor::kLimit);
2044 Node* const context = Parameter(Descriptor::kContext);
2045
2046 CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp)));
2047 CSA_ASSERT(this, IsString(string));
2048
2049 // TODO(jgruber): Even if map checks send us to the fast path, we still need
2050 // to verify the constructor property and jump to the slow path if it has
2051 // been changed.
2052
2053 // Convert {maybe_limit} to a uint32, capping at the maximal smi value.
2054 Variable var_limit(this, MachineRepresentation::kTagged);
2055 Label if_limitissmimax(this), limit_done(this);
2056
2057 GotoIf(IsUndefined(maybe_limit), &if_limitissmimax);
2058
2059 {
2060 Node* const limit = ToUint32(context, maybe_limit);
2061 GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
2062
2063 var_limit.Bind(limit);
2064 Goto(&limit_done);
2065 }
2066
2067 Bind(&if_limitissmimax);
2068 {
2069 // TODO(jgruber): In this case, we can probably avoid generation of limit
2070 // checks in Generate_RegExpPrototypeSplitBody.
2071 var_limit.Bind(SmiConstant(Smi::kMaxValue));
2072 Goto(&limit_done);
2073 }
2074
2075 Bind(&limit_done);
2076 {
2077 Node* const limit = var_limit.value();
2078 RegExpPrototypeSplitBody(context, regexp, string, limit);
2079 }
2080 }
2081
2032 // ES#sec-regexp.prototype-@@split 2082 // ES#sec-regexp.prototype-@@split
2033 // RegExp.prototype [ @@split ] ( string, limit ) 2083 // RegExp.prototype [ @@split ] ( string, limit )
2034 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) { 2084 TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
2035 Node* const maybe_receiver = Parameter(0); 2085 Node* const maybe_receiver = Parameter(0);
2036 Node* const maybe_string = Parameter(1); 2086 Node* const maybe_string = Parameter(1);
2037 Node* const maybe_limit = Parameter(2); 2087 Node* const maybe_limit = Parameter(2);
2038 Node* const context = Parameter(5); 2088 Node* const context = Parameter(5);
2039 2089
2040 // Ensure {maybe_receiver} is a JSReceiver. 2090 // Ensure {maybe_receiver} is a JSReceiver.
2041 Node* const map = ThrowIfNotJSReceiver( 2091 Node* const map = ThrowIfNotJSReceiver(
2042 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 2092 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
2043 "RegExp.prototype.@@split"); 2093 "RegExp.prototype.@@split");
2044 Node* const receiver = maybe_receiver; 2094 Node* const receiver = maybe_receiver;
2045 2095
2046 // Convert {maybe_string} to a String. 2096 // Convert {maybe_string} to a String.
2047 Node* const string = ToString(context, maybe_string); 2097 Node* const string = ToString(context, maybe_string);
2048 2098
2049 Label fast_path(this), slow_path(this); 2099 Label stub(this), runtime(this, Label::kDeferred);
2050 BranchIfFastRegExp(context, map, &fast_path, &slow_path); 2100 Branch(IsFastRegExpMap(context, map), &stub, &runtime);
2051 2101
2052 Bind(&fast_path); 2102 Bind(&stub);
2053 { 2103 Callable split_callable = CodeFactory::RegExpSplit(isolate());
2054 // TODO(jgruber): Even if map checks send us to the fast path, we still need 2104 Return(CallStub(split_callable, context, receiver, string, maybe_limit));
2055 // to verify the constructor property and jump to the slow path if it has
2056 // been changed.
2057 2105
2058 // Convert {maybe_limit} to a uint32, capping at the maximal smi value. 2106 Bind(&runtime);
2059 Variable var_limit(this, MachineRepresentation::kTagged); 2107 Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string,
2060 Label if_limitissmimax(this), limit_done(this); 2108 maybe_limit));
2061
2062 GotoIf(IsUndefined(maybe_limit), &if_limitissmimax);
2063
2064 {
2065 Node* const limit = ToUint32(context, maybe_limit);
2066 GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
2067
2068 var_limit.Bind(limit);
2069 Goto(&limit_done);
2070 }
2071
2072 Bind(&if_limitissmimax);
2073 {
2074 // TODO(jgruber): In this case, we can probably generation of limit checks
2075 // in Generate_RegExpPrototypeSplitBody.
2076 Node* const smi_max = SmiConstant(Smi::kMaxValue);
2077 var_limit.Bind(smi_max);
2078 Goto(&limit_done);
2079 }
2080
2081 Bind(&limit_done);
2082 {
2083 Node* const limit = var_limit.value();
2084 RegExpPrototypeSplitBody(context, receiver, string, limit);
2085 }
2086 }
2087
2088 Bind(&slow_path);
2089 {
2090 Node* const result = CallRuntime(Runtime::kRegExpSplit, context, receiver,
2091 string, maybe_limit);
2092 Return(result);
2093 }
2094 } 2109 }
2095 2110
2096 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath( 2111 Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
2097 Node* context, Node* regexp, Node* string, Node* replace_callable) { 2112 Node* context, Node* regexp, Node* string, Node* replace_callable) {
2098 // The fast path is reached only if {receiver} is a global unmodified 2113 // The fast path is reached only if {receiver} is a global unmodified
2099 // JSRegExp instance and {replace_callable} is callable. 2114 // JSRegExp instance and {replace_callable} is callable.
2100 2115
2101 Isolate* const isolate = this->isolate(); 2116 Isolate* const isolate = this->isolate();
2102 2117
2103 Node* const null = NullConstant(); 2118 Node* const null = NullConstant();
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
2399 var_result.Bind(result); 2414 var_result.Bind(result);
2400 Goto(&out); 2415 Goto(&out);
2401 } 2416 }
2402 } 2417 }
2403 } 2418 }
2404 2419
2405 Bind(&out); 2420 Bind(&out);
2406 return var_result.value(); 2421 return var_result.value();
2407 } 2422 }
2408 2423
2409 // ES#sec-regexp.prototype-@@replace 2424 // Helper that skips a few initial checks.
2410 // RegExp.prototype [ @@replace ] ( string, replaceValue ) 2425 TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
2411 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) { 2426 typedef RegExpReplaceDescriptor Descriptor;
2412 Node* const maybe_receiver = Parameter(0);
2413 Node* const maybe_string = Parameter(1);
2414 Node* const replace_value = Parameter(2);
2415 Node* const context = Parameter(5);
2416 2427
2417 // Ensure {maybe_receiver} is a JSReceiver. 2428 Node* const regexp = Parameter(Descriptor::kReceiver);
2418 Node* const map = ThrowIfNotJSReceiver( 2429 Node* const string = Parameter(Descriptor::kString);
2419 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver, 2430 Node* const replace_value = Parameter(Descriptor::kReplaceValue);
2420 "RegExp.prototype.@@replace"); 2431 Node* const context = Parameter(Descriptor::kContext);
2421 Node* const receiver = maybe_receiver;
2422 2432
2423 // Convert {maybe_string} to a String. 2433 CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp)));
2424 Callable tostring_callable = CodeFactory::ToString(isolate()); 2434 CSA_ASSERT(this, IsString(string));
2425 Node* const string = CallStub(tostring_callable, context, maybe_string);
2426 2435
2427 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance? 2436 Label checkreplacestring(this), if_iscallable(this),
2428 Label checkreplacecallable(this), runtime(this, Label::kDeferred), 2437 runtime(this, Label::kDeferred);
2429 fastpath(this);
2430 BranchIfFastRegExp(context, map, &checkreplacecallable, &runtime);
2431
2432 Bind(&checkreplacecallable);
2433 Node* const regexp = receiver;
2434 2438
2435 // 2. Is {replace_value} callable? 2439 // 2. Is {replace_value} callable?
2436 Label checkreplacestring(this), if_iscallable(this);
2437 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring); 2440 GotoIf(TaggedIsSmi(replace_value), &checkreplacestring);
2438 2441 Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable,
2439 Node* const replace_value_map = LoadMap(replace_value); 2442 &checkreplacestring);
2440 Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring);
2441 2443
2442 // 3. Does ToString({replace_value}) contain '$'? 2444 // 3. Does ToString({replace_value}) contain '$'?
2443 Bind(&checkreplacestring); 2445 Bind(&checkreplacestring);
2444 { 2446 {
2447 Callable tostring_callable = CodeFactory::ToString(isolate());
2445 Node* const replace_string = 2448 Node* const replace_string =
2446 CallStub(tostring_callable, context, replace_value); 2449 CallStub(tostring_callable, context, replace_value);
2447 2450
2448 Node* const dollar_char = Int32Constant('$'); 2451 Node* const dollar_char = Int32Constant('$');
2449 Node* const smi_minusone = SmiConstant(Smi::FromInt(-1));
2450 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char, 2452 GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char,
2451 SmiConstant(0)), 2453 SmiConstant(0)),
2452 smi_minusone), 2454 SmiConstant(-1)),
2453 &runtime); 2455 &runtime);
2454 2456
2455 Return( 2457 Return(
2456 ReplaceSimpleStringFastPath(context, regexp, string, replace_string)); 2458 ReplaceSimpleStringFastPath(context, regexp, string, replace_string));
2457 } 2459 }
2458 2460
2459 // {regexp} is unmodified and {replace_value} is callable. 2461 // {regexp} is unmodified and {replace_value} is callable.
2460 Bind(&if_iscallable); 2462 Bind(&if_iscallable);
2461 { 2463 {
2462 Node* const replace_callable = replace_value; 2464 Node* const replace_fn = replace_value;
2463 2465
2464 // Check if the {regexp} is global. 2466 // Check if the {regexp} is global.
2465 Label if_isglobal(this), if_isnotglobal(this); 2467 Label if_isglobal(this), if_isnotglobal(this);
2468
2466 Node* const is_global = FastFlagGetter(regexp, JSRegExp::kGlobal); 2469 Node* const is_global = FastFlagGetter(regexp, JSRegExp::kGlobal);
2467 Branch(is_global, &if_isglobal, &if_isnotglobal); 2470 Branch(is_global, &if_isglobal, &if_isnotglobal);
2468 2471
2469 Bind(&if_isglobal); 2472 Bind(&if_isglobal);
2470 { 2473 Return(ReplaceGlobalCallableFastPath(context, regexp, string, replace_fn));
2471 Node* const result = ReplaceGlobalCallableFastPath(
2472 context, regexp, string, replace_callable);
2473 Return(result);
2474 }
2475 2474
2476 Bind(&if_isnotglobal); 2475 Bind(&if_isnotglobal);
2477 { 2476 Return(CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
2478 Node* const result = 2477 context, string, regexp, replace_fn));
2479 CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
2480 context, string, regexp, replace_callable);
2481 Return(result);
2482 }
2483 } 2478 }
2484 2479
2485 Bind(&runtime); 2480 Bind(&runtime);
2486 { 2481 Return(CallRuntime(Runtime::kRegExpReplace, context, regexp, string,
2487 Node* const result = CallRuntime(Runtime::kRegExpReplace, context, receiver, 2482 replace_value));
2488 string, replace_value); 2483 }
2489 Return(result); 2484
2490 } 2485 // ES#sec-regexp.prototype-@@replace
2486 // RegExp.prototype [ @@replace ] ( string, replaceValue )
2487 TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
2488 Node* const maybe_receiver = Parameter(0);
2489 Node* const maybe_string = Parameter(1);
2490 Node* const replace_value = Parameter(2);
2491 Node* const context = Parameter(5);
2492
2493 // Ensure {maybe_receiver} is a JSReceiver.
2494 Node* const map = ThrowIfNotJSReceiver(
2495 context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
2496 "RegExp.prototype.@@replace");
2497 Node* const receiver = maybe_receiver;
2498
2499 // Convert {maybe_string} to a String.
2500 Callable tostring_callable = CodeFactory::ToString(isolate());
2501 Node* const string = CallStub(tostring_callable, context, maybe_string);
2502
2503 // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
2504 Label stub(this), runtime(this, Label::kDeferred);
2505 Branch(IsFastRegExpMap(context, map), &stub, &runtime);
2506
2507 Bind(&stub);
2508 Callable replace_callable = CodeFactory::RegExpReplace(isolate());
2509 Return(CallStub(replace_callable, context, receiver, string, replace_value));
2510
2511 Bind(&runtime);
2512 Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string,
2513 replace_value));
2491 } 2514 }
2492 2515
2493 // Simple string matching functionality for internal use which does not modify 2516 // Simple string matching functionality for internal use which does not modify
2494 // the last match info. 2517 // the last match info.
2495 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) { 2518 TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
2496 Node* const regexp = Parameter(1); 2519 Node* const regexp = Parameter(1);
2497 Node* const string = Parameter(2); 2520 Node* const string = Parameter(2);
2498 Node* const context = Parameter(5); 2521 Node* const context = Parameter(5);
2499 2522
2500 Node* const null = NullConstant(); 2523 Node* const null = NullConstant();
(...skipping 16 matching lines...) Expand all
2517 Bind(&if_matched); 2540 Bind(&if_matched);
2518 { 2541 {
2519 Node* result = 2542 Node* result =
2520 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string); 2543 ConstructNewResultFromMatchInfo(context, regexp, match_indices, string);
2521 Return(result); 2544 Return(result);
2522 } 2545 }
2523 } 2546 }
2524 2547
2525 } // namespace internal 2548 } // namespace internal
2526 } // namespace v8 2549 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins-regexp.h ('k') | src/builtins/builtins-string.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698