| Index: src/builtins/builtins-string-gen.cc
|
| diff --git a/src/builtins/builtins-string-gen.cc b/src/builtins/builtins-string-gen.cc
|
| index 25bf14ce2bd83dbe2bf41dfa31d03235c4fdfdd0..18fbe9a72970654466cb9f1ac9620b13d64abdb2 100644
|
| --- a/src/builtins/builtins-string-gen.cc
|
| +++ b/src/builtins/builtins-string-gen.cc
|
| @@ -19,6 +19,11 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
| explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
| : CodeStubAssembler(state) {}
|
|
|
| + // ES#sec-getsubstitution
|
| + Node* GetSubstitution(Node* context, Node* subject_string,
|
| + Node* match_start_index, Node* match_end_index,
|
| + Node* replace_string);
|
| +
|
| protected:
|
| Node* DirectStringData(Node* string, Node* string_instance_type) {
|
| // Compute the effective offset of the first character.
|
| @@ -112,6 +117,8 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
|
| Node* search_string_instance_type, Node* position,
|
| std::function<void(Node*)> f_return);
|
|
|
| + Node* IndexOfDollarChar(Node* const context, Node* const string);
|
| +
|
| Node* IsNullOrUndefined(Node* const value);
|
| void RequireObjectCoercible(Node* const context, Node* const value,
|
| const char* method_name);
|
| @@ -991,6 +998,60 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
|
| BIND(&out);
|
| }
|
|
|
| +compiler::Node* StringBuiltinsAssembler::IndexOfDollarChar(Node* const context,
|
| + Node* const string) {
|
| + CSA_ASSERT(this, IsString(string));
|
| +
|
| + Node* const dollar_string = HeapConstant(
|
| + isolate()->factory()->LookupSingleCharacterStringFromCode('$'));
|
| + Node* const dollar_ix = CallBuiltin(Builtins::kStringIndexOf, context, string,
|
| + dollar_string, SmiConstant(0));
|
| +
|
| + CSA_ASSERT(this, TaggedIsSmi(dollar_ix));
|
| + return dollar_ix;
|
| +}
|
| +
|
| +compiler::Node* StringBuiltinsAssembler::GetSubstitution(
|
| + Node* context, Node* subject_string, Node* match_start_index,
|
| + Node* match_end_index, Node* replace_string) {
|
| + CSA_ASSERT(this, IsString(subject_string));
|
| + CSA_ASSERT(this, IsString(replace_string));
|
| + CSA_ASSERT(this, TaggedIsPositiveSmi(match_start_index));
|
| + CSA_ASSERT(this, TaggedIsPositiveSmi(match_end_index));
|
| +
|
| + VARIABLE(var_result, MachineRepresentation::kTagged, replace_string);
|
| + Label runtime(this), out(this);
|
| +
|
| + // In this primitive implementation we simply look for the next '$' char in
|
| + // {replace_string}. If it doesn't exist, we can simply return
|
| + // {replace_string} itself. If it does, then we delegate to
|
| + // String::GetSubstitution, passing in the index of the first '$' to avoid
|
| + // repeated scanning work.
|
| + // TODO(jgruber): Possibly extend this in the future to handle more complex
|
| + // cases without runtime calls.
|
| +
|
| + Node* const dollar_index = IndexOfDollarChar(context, replace_string);
|
| + Branch(SmiIsNegative(dollar_index), &out, &runtime);
|
| +
|
| + BIND(&runtime);
|
| + {
|
| + CSA_ASSERT(this, TaggedIsPositiveSmi(dollar_index));
|
| +
|
| + Callable substring_callable = CodeFactory::SubString(isolate());
|
| + Node* const matched = CallStub(substring_callable, context, subject_string,
|
| + match_start_index, match_end_index);
|
| + Node* const replacement_string =
|
| + CallRuntime(Runtime::kGetSubstitution, context, matched, subject_string,
|
| + match_start_index, replace_string, dollar_index);
|
| + var_result.Bind(replacement_string);
|
| +
|
| + Goto(&out);
|
| + }
|
| +
|
| + BIND(&out);
|
| + return var_result.value();
|
| +}
|
| +
|
| // ES6 #sec-string.prototype.replace
|
| TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
|
| Label out(this);
|
| @@ -1033,7 +1094,7 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
|
| Node* const subject_length = LoadStringLength(subject_string);
|
| Node* const search_length = LoadStringLength(search_string);
|
|
|
| - // Fast-path single-char {search}, long {receiver}, and simple string
|
| + // Fast-path single-char {search}, long cons {receiver}, and simple string
|
| // {replace}.
|
| {
|
| Label next(this);
|
| @@ -1043,11 +1104,10 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
|
| GotoIf(TaggedIsSmi(replace), &next);
|
| GotoIfNot(IsString(replace), &next);
|
|
|
| - Node* const dollar_string = HeapConstant(
|
| - isolate()->factory()->LookupSingleCharacterStringFromCode('$'));
|
| - Node* const dollar_ix =
|
| - CallStub(indexof_callable, context, replace, dollar_string, smi_zero);
|
| - GotoIfNot(SmiIsNegative(dollar_ix), &next);
|
| + Node* const subject_instance_type = LoadInstanceType(subject_string);
|
| + GotoIfNot(IsConsStringInstanceType(subject_instance_type), &next);
|
| +
|
| + GotoIf(TaggedIsPositiveSmi(IndexOfDollarChar(context, replace)), &next);
|
|
|
| // Searching by traversing a cons string tree and replace with cons of
|
| // slices works only when the replaced string is a single character, being
|
| @@ -1136,15 +1196,11 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
|
| BIND(&if_notcallablereplace);
|
| {
|
| Node* const replace_string = CallStub(tostring_callable, context, replace);
|
| -
|
| - // TODO(jgruber): Simplified GetSubstitution implementation in CSA.
|
| - Node* const matched = CallStub(substring_callable, context, subject_string,
|
| - match_start_index, match_end_index);
|
| - Node* const replacement_string =
|
| - CallRuntime(Runtime::kGetSubstitution, context, matched, subject_string,
|
| - match_start_index, replace_string);
|
| - var_result.Bind(CallStub(stringadd_callable, context, var_result.value(),
|
| - replacement_string));
|
| + Node* const replacement =
|
| + GetSubstitution(context, subject_string, match_start_index,
|
| + match_end_index, replace_string);
|
| + var_result.Bind(
|
| + CallStub(stringadd_callable, context, var_result.value(), replacement));
|
| Goto(&out);
|
| }
|
|
|
|
|