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

Unified Diff: src/builtins/builtins-regexp.cc

Issue 2668703002: [stubs] Add RegExpReplace and RegExpSplit stubs (Closed)
Patch Set: BranchIfFastRegExp/IsFastRegExpMap 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins/builtins-regexp.h ('k') | src/builtins/builtins-string.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins/builtins-regexp.cc
diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc
index b907a1bf45dd0559bbf92279e69cb6704121e94f..95979c91e1908023617c155bc685afa9e0b5934f 100644
--- a/src/builtins/builtins-regexp.cc
+++ b/src/builtins/builtins-regexp.cc
@@ -422,9 +422,10 @@ Node* RegExpBuiltinsAssembler::IsInitialRegExpMap(Node* context, Node* map) {
// We use a fairly coarse granularity for this and simply check whether both
// the regexp itself is unmodified (i.e. its map has not changed) and its
// prototype is unmodified.
-void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* context, Node* map,
- Label* if_isunmodified,
- Label* if_ismodified) {
+void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* const context,
+ Node* const map,
+ Label* const if_isunmodified,
+ Label* const if_ismodified) {
Node* const native_context = LoadNativeContext(context);
Node* const regexp_fun =
LoadContextElement(native_context, Context::REGEXP_FUNCTION_INDEX);
@@ -446,6 +447,25 @@ void RegExpBuiltinsAssembler::BranchIfFastRegExp(Node* context, Node* map,
Branch(proto_has_initialmap, if_isunmodified, if_ismodified);
}
+Node* RegExpBuiltinsAssembler::IsFastRegExpMap(Node* const context,
+ Node* const map) {
+ Label yup(this), nope(this), out(this);
+ Variable var_result(this, MachineRepresentation::kWord32);
+
+ BranchIfFastRegExp(context, map, &yup, &nope);
+
+ Bind(&yup);
+ var_result.Bind(Int32Constant(1));
+ Goto(&out);
+
+ Bind(&nope);
+ var_result.Bind(Int32Constant(0));
+ Goto(&out);
+
+ Bind(&out);
+ return var_result.value();
+}
+
void RegExpBuiltinsAssembler::BranchIfFastRegExpResult(Node* context, Node* map,
Label* if_isunmodified,
Label* if_ismodified) {
@@ -2029,6 +2049,51 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
}
}
+// Helper that skips a few initial checks.
+TF_BUILTIN(RegExpSplit, RegExpBuiltinsAssembler) {
+ typedef RegExpSplitDescriptor Descriptor;
+
+ Node* const regexp = Parameter(Descriptor::kReceiver);
+ Node* const string = Parameter(Descriptor::kString);
+ Node* const maybe_limit = Parameter(Descriptor::kLimit);
+ Node* const context = Parameter(Descriptor::kContext);
+
+ CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp)));
+ CSA_ASSERT(this, IsString(string));
+
+ // TODO(jgruber): Even if map checks send us to the fast path, we still need
+ // to verify the constructor property and jump to the slow path if it has
+ // been changed.
+
+ // Convert {maybe_limit} to a uint32, capping at the maximal smi value.
+ Variable var_limit(this, MachineRepresentation::kTagged);
+ Label if_limitissmimax(this), limit_done(this);
+
+ GotoIf(IsUndefined(maybe_limit), &if_limitissmimax);
+
+ {
+ Node* const limit = ToUint32(context, maybe_limit);
+ GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
+
+ var_limit.Bind(limit);
+ Goto(&limit_done);
+ }
+
+ Bind(&if_limitissmimax);
+ {
+ // TODO(jgruber): In this case, we can probably avoid generation of limit
+ // checks in Generate_RegExpPrototypeSplitBody.
+ var_limit.Bind(SmiConstant(Smi::kMaxValue));
+ Goto(&limit_done);
+ }
+
+ Bind(&limit_done);
+ {
+ Node* const limit = var_limit.value();
+ RegExpPrototypeSplitBody(context, regexp, string, limit);
+ }
+}
+
// ES#sec-regexp.prototype-@@split
// RegExp.prototype [ @@split ] ( string, limit )
TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
@@ -2046,51 +2111,16 @@ TF_BUILTIN(RegExpPrototypeSplit, RegExpBuiltinsAssembler) {
// Convert {maybe_string} to a String.
Node* const string = ToString(context, maybe_string);
- Label fast_path(this), slow_path(this);
- BranchIfFastRegExp(context, map, &fast_path, &slow_path);
-
- Bind(&fast_path);
- {
- // TODO(jgruber): Even if map checks send us to the fast path, we still need
- // to verify the constructor property and jump to the slow path if it has
- // been changed.
-
- // Convert {maybe_limit} to a uint32, capping at the maximal smi value.
- Variable var_limit(this, MachineRepresentation::kTagged);
- Label if_limitissmimax(this), limit_done(this);
-
- GotoIf(IsUndefined(maybe_limit), &if_limitissmimax);
-
- {
- Node* const limit = ToUint32(context, maybe_limit);
- GotoUnless(TaggedIsSmi(limit), &if_limitissmimax);
-
- var_limit.Bind(limit);
- Goto(&limit_done);
- }
-
- Bind(&if_limitissmimax);
- {
- // TODO(jgruber): In this case, we can probably generation of limit checks
- // in Generate_RegExpPrototypeSplitBody.
- Node* const smi_max = SmiConstant(Smi::kMaxValue);
- var_limit.Bind(smi_max);
- Goto(&limit_done);
- }
+ Label stub(this), runtime(this, Label::kDeferred);
+ BranchIfFastRegExp(context, map, &stub, &runtime);
- Bind(&limit_done);
- {
- Node* const limit = var_limit.value();
- RegExpPrototypeSplitBody(context, receiver, string, limit);
- }
- }
+ Bind(&stub);
+ Callable split_callable = CodeFactory::RegExpSplit(isolate());
+ Return(CallStub(split_callable, context, receiver, string, maybe_limit));
- Bind(&slow_path);
- {
- Node* const result = CallRuntime(Runtime::kRegExpSplit, context, receiver,
- string, maybe_limit);
- Return(result);
- }
+ Bind(&runtime);
+ Return(CallRuntime(Runtime::kRegExpSplit, context, receiver, string,
+ maybe_limit));
}
Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
@@ -2406,50 +2436,37 @@ Node* RegExpBuiltinsAssembler::ReplaceSimpleStringFastPath(
return var_result.value();
}
-// ES#sec-regexp.prototype-@@replace
-// RegExp.prototype [ @@replace ] ( string, replaceValue )
-TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
- Node* const maybe_receiver = Parameter(0);
- Node* const maybe_string = Parameter(1);
- Node* const replace_value = Parameter(2);
- Node* const context = Parameter(5);
-
- // Ensure {maybe_receiver} is a JSReceiver.
- Node* const map = ThrowIfNotJSReceiver(
- context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
- "RegExp.prototype.@@replace");
- Node* const receiver = maybe_receiver;
+// Helper that skips a few initial checks.
+TF_BUILTIN(RegExpReplace, RegExpBuiltinsAssembler) {
+ typedef RegExpReplaceDescriptor Descriptor;
- // Convert {maybe_string} to a String.
- Callable tostring_callable = CodeFactory::ToString(isolate());
- Node* const string = CallStub(tostring_callable, context, maybe_string);
+ Node* const regexp = Parameter(Descriptor::kReceiver);
+ Node* const string = Parameter(Descriptor::kString);
+ Node* const replace_value = Parameter(Descriptor::kReplaceValue);
+ Node* const context = Parameter(Descriptor::kContext);
- // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
- Label checkreplacecallable(this), runtime(this, Label::kDeferred),
- fastpath(this);
- BranchIfFastRegExp(context, map, &checkreplacecallable, &runtime);
+ CSA_ASSERT(this, IsFastRegExpMap(context, LoadMap(regexp)));
+ CSA_ASSERT(this, IsString(string));
- Bind(&checkreplacecallable);
- Node* const regexp = receiver;
+ Label checkreplacestring(this), if_iscallable(this),
+ runtime(this, Label::kDeferred);
// 2. Is {replace_value} callable?
- Label checkreplacestring(this), if_iscallable(this);
GotoIf(TaggedIsSmi(replace_value), &checkreplacestring);
-
- Node* const replace_value_map = LoadMap(replace_value);
- Branch(IsCallableMap(replace_value_map), &if_iscallable, &checkreplacestring);
+ Branch(IsCallableMap(LoadMap(replace_value)), &if_iscallable,
+ &checkreplacestring);
// 3. Does ToString({replace_value}) contain '$'?
Bind(&checkreplacestring);
{
+ Callable tostring_callable = CodeFactory::ToString(isolate());
Node* const replace_string =
CallStub(tostring_callable, context, replace_value);
Node* const dollar_char = Int32Constant('$');
- Node* const smi_minusone = SmiConstant(Smi::FromInt(-1));
GotoUnless(SmiEqual(StringIndexOfChar(context, replace_string, dollar_char,
SmiConstant(0)),
- smi_minusone),
+ SmiConstant(-1)),
&runtime);
Return(
@@ -2459,35 +2476,56 @@ TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
// {regexp} is unmodified and {replace_value} is callable.
Bind(&if_iscallable);
{
- Node* const replace_callable = replace_value;
+ Node* const replace_fn = replace_value;
// Check if the {regexp} is global.
Label if_isglobal(this), if_isnotglobal(this);
+
Node* const is_global = FastFlagGetter(regexp, JSRegExp::kGlobal);
Branch(is_global, &if_isglobal, &if_isnotglobal);
Bind(&if_isglobal);
- {
- Node* const result = ReplaceGlobalCallableFastPath(
- context, regexp, string, replace_callable);
- Return(result);
- }
+ Return(ReplaceGlobalCallableFastPath(context, regexp, string, replace_fn));
Bind(&if_isnotglobal);
- {
- Node* const result =
- CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
- context, string, regexp, replace_callable);
- Return(result);
- }
+ Return(CallRuntime(Runtime::kStringReplaceNonGlobalRegExpWithFunction,
+ context, string, regexp, replace_fn));
}
Bind(&runtime);
- {
- Node* const result = CallRuntime(Runtime::kRegExpReplace, context, receiver,
- string, replace_value);
- Return(result);
- }
+ Return(CallRuntime(Runtime::kRegExpReplace, context, regexp, string,
+ replace_value));
+}
+
+// ES#sec-regexp.prototype-@@replace
+// RegExp.prototype [ @@replace ] ( string, replaceValue )
+TF_BUILTIN(RegExpPrototypeReplace, RegExpBuiltinsAssembler) {
+ Node* const maybe_receiver = Parameter(0);
+ Node* const maybe_string = Parameter(1);
+ Node* const replace_value = Parameter(2);
+ Node* const context = Parameter(5);
+
+ // Ensure {maybe_receiver} is a JSReceiver.
+ Node* const map = ThrowIfNotJSReceiver(
+ context, maybe_receiver, MessageTemplate::kIncompatibleMethodReceiver,
+ "RegExp.prototype.@@replace");
+ Node* const receiver = maybe_receiver;
+
+ // Convert {maybe_string} to a String.
+ Callable tostring_callable = CodeFactory::ToString(isolate());
+ Node* const string = CallStub(tostring_callable, context, maybe_string);
+
+ // Fast-path checks: 1. Is the {receiver} an unmodified JSRegExp instance?
+ Label stub(this), runtime(this, Label::kDeferred);
+ BranchIfFastRegExp(context, map, &stub, &runtime);
+
+ Bind(&stub);
+ Callable replace_callable = CodeFactory::RegExpReplace(isolate());
+ Return(CallStub(replace_callable, context, receiver, string, replace_value));
+
+ Bind(&runtime);
+ Return(CallRuntime(Runtime::kRegExpReplace, context, receiver, string,
+ replace_value));
}
// Simple string matching functionality for internal use which does not modify
« 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