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

Side by Side Diff: src/builtins/builtins-string-gen.cc

Issue 2813843002: [string] Add a fast path to String.p.replace (Closed)
Patch Set: Don't scan twice Created 3 years, 8 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/code-stub-assembler.h » ('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 2017 the V8 project authors. All rights reserved. 1 // Copyright 2017 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-gen.h" 5 #include "src/builtins/builtins-regexp-gen.h"
6 #include "src/builtins/builtins-utils-gen.h" 6 #include "src/builtins/builtins-utils-gen.h"
7 #include "src/builtins/builtins.h" 7 #include "src/builtins/builtins.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/code-stub-assembler.h" 9 #include "src/code-stub-assembler.h"
10 #include "src/objects.h" 10 #include "src/objects.h"
11 11
12 namespace v8 { 12 namespace v8 {
13 namespace internal { 13 namespace internal {
14 14
15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode; 15 typedef CodeStubAssembler::RelationalComparisonMode RelationalComparisonMode;
16 16
17 class StringBuiltinsAssembler : public CodeStubAssembler { 17 class StringBuiltinsAssembler : public CodeStubAssembler {
18 public: 18 public:
19 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state) 19 explicit StringBuiltinsAssembler(compiler::CodeAssemblerState* state)
20 : CodeStubAssembler(state) {} 20 : CodeStubAssembler(state) {}
21 21
22 // ES#sec-getsubstitution
23 Node* GetSubstitution(Node* context, Node* subject_string,
24 Node* match_start_index, Node* match_end_index,
25 Node* replace_string);
26
22 protected: 27 protected:
23 Node* DirectStringData(Node* string, Node* string_instance_type) { 28 Node* DirectStringData(Node* string, Node* string_instance_type) {
24 // Compute the effective offset of the first character. 29 // Compute the effective offset of the first character.
25 VARIABLE(var_data, MachineType::PointerRepresentation()); 30 VARIABLE(var_data, MachineType::PointerRepresentation());
26 Label if_sequential(this), if_external(this), if_join(this); 31 Label if_sequential(this), if_external(this), if_join(this);
27 Branch(Word32Equal(Word32And(string_instance_type, 32 Branch(Word32Equal(Word32And(string_instance_type,
28 Int32Constant(kStringRepresentationMask)), 33 Int32Constant(kStringRepresentationMask)),
29 Int32Constant(kSeqStringTag)), 34 Int32Constant(kSeqStringTag)),
30 &if_sequential, &if_external); 35 &if_sequential, &if_external);
31 36
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 110
106 Node* ToSmiBetweenZeroAnd(Node* context, Node* value, Node* limit); 111 Node* ToSmiBetweenZeroAnd(Node* context, Node* value, Node* limit);
107 112
108 Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index, 113 Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index,
109 UnicodeEncoding encoding); 114 UnicodeEncoding encoding);
110 115
111 void StringIndexOf(Node* receiver, Node* instance_type, Node* search_string, 116 void StringIndexOf(Node* receiver, Node* instance_type, Node* search_string,
112 Node* search_string_instance_type, Node* position, 117 Node* search_string_instance_type, Node* position,
113 std::function<void(Node*)> f_return); 118 std::function<void(Node*)> f_return);
114 119
120 Node* IndexOfDollarChar(Node* const context, Node* const string);
121
115 Node* IsNullOrUndefined(Node* const value); 122 Node* IsNullOrUndefined(Node* const value);
116 void RequireObjectCoercible(Node* const context, Node* const value, 123 void RequireObjectCoercible(Node* const context, Node* const value,
117 const char* method_name); 124 const char* method_name);
118 125
119 Node* SmiIsNegative(Node* const value) { 126 Node* SmiIsNegative(Node* const value) {
120 return SmiLessThan(value, SmiConstant(0)); 127 return SmiLessThan(value, SmiConstant(0));
121 } 128 }
122 129
123 // Implements boilerplate logic for {match, split, replace, search} of the 130 // Implements boilerplate logic for {match, split, replace, search} of the
124 // form: 131 // form:
(...skipping 859 matching lines...) Expand 10 before | Expand all | Expand 10 after
984 GotoIf(IsUndefined(maybe_func), &out); 991 GotoIf(IsUndefined(maybe_func), &out);
985 992
986 // Attempt to call the function. 993 // Attempt to call the function.
987 994
988 Node* const result = generic_call(maybe_func); 995 Node* const result = generic_call(maybe_func);
989 Return(result); 996 Return(result);
990 997
991 BIND(&out); 998 BIND(&out);
992 } 999 }
993 1000
1001 compiler::Node* StringBuiltinsAssembler::IndexOfDollarChar(Node* const context,
1002 Node* const string) {
1003 CSA_ASSERT(this, IsString(string));
1004
1005 Node* const dollar_string = HeapConstant(
1006 isolate()->factory()->LookupSingleCharacterStringFromCode('$'));
1007 Node* const dollar_ix = CallBuiltin(Builtins::kStringIndexOf, context, string,
1008 dollar_string, SmiConstant(0));
1009
1010 CSA_ASSERT(this, TaggedIsSmi(dollar_ix));
1011 return dollar_ix;
1012 }
1013
1014 compiler::Node* StringBuiltinsAssembler::GetSubstitution(
1015 Node* context, Node* subject_string, Node* match_start_index,
1016 Node* match_end_index, Node* replace_string) {
1017 CSA_ASSERT(this, IsString(subject_string));
1018 CSA_ASSERT(this, IsString(replace_string));
1019 CSA_ASSERT(this, TaggedIsPositiveSmi(match_start_index));
1020 CSA_ASSERT(this, TaggedIsPositiveSmi(match_end_index));
1021
1022 VARIABLE(var_result, MachineRepresentation::kTagged, replace_string);
1023 Label runtime(this), out(this);
1024
1025 // In this primitive implementation we simply look for the next '$' char in
1026 // {replace_string}. If it doesn't exist, we can simply return
1027 // {replace_string} itself. If it does, then we delegate to
1028 // String::GetSubstitution, passing in the index of the first '$' to avoid
1029 // repeated scanning work.
1030 // TODO(jgruber): Possibly extend this in the future to handle more complex
1031 // cases without runtime calls.
1032
1033 Node* const dollar_index = IndexOfDollarChar(context, replace_string);
1034 Branch(SmiIsNegative(dollar_index), &out, &runtime);
1035
1036 BIND(&runtime);
1037 {
1038 CSA_ASSERT(this, TaggedIsPositiveSmi(dollar_index));
1039
1040 Callable substring_callable = CodeFactory::SubString(isolate());
1041 Node* const matched = CallStub(substring_callable, context, subject_string,
1042 match_start_index, match_end_index);
1043 Node* const replacement_string =
1044 CallRuntime(Runtime::kGetSubstitution, context, matched, subject_string,
1045 match_start_index, replace_string, dollar_index);
1046 var_result.Bind(replacement_string);
1047
1048 Goto(&out);
1049 }
1050
1051 BIND(&out);
1052 return var_result.value();
1053 }
1054
994 // ES6 #sec-string.prototype.replace 1055 // ES6 #sec-string.prototype.replace
995 TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) { 1056 TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
996 Label out(this); 1057 Label out(this);
997 1058
998 Node* const receiver = Parameter(Descriptor::kReceiver); 1059 Node* const receiver = Parameter(Descriptor::kReceiver);
999 Node* const search = Parameter(Descriptor::kSearch); 1060 Node* const search = Parameter(Descriptor::kSearch);
1000 Node* const replace = Parameter(Descriptor::kReplace); 1061 Node* const replace = Parameter(Descriptor::kReplace);
1001 Node* const context = Parameter(Descriptor::kContext); 1062 Node* const context = Parameter(Descriptor::kContext);
1002 1063
1003 Node* const smi_zero = SmiConstant(0); 1064 Node* const smi_zero = SmiConstant(0);
(...skipping 22 matching lines...) Expand all
1026 1087
1027 Callable tostring_callable = CodeFactory::ToString(isolate()); 1088 Callable tostring_callable = CodeFactory::ToString(isolate());
1028 Callable indexof_callable = CodeFactory::StringIndexOf(isolate()); 1089 Callable indexof_callable = CodeFactory::StringIndexOf(isolate());
1029 1090
1030 Node* const subject_string = CallStub(tostring_callable, context, receiver); 1091 Node* const subject_string = CallStub(tostring_callable, context, receiver);
1031 Node* const search_string = CallStub(tostring_callable, context, search); 1092 Node* const search_string = CallStub(tostring_callable, context, search);
1032 1093
1033 Node* const subject_length = LoadStringLength(subject_string); 1094 Node* const subject_length = LoadStringLength(subject_string);
1034 Node* const search_length = LoadStringLength(search_string); 1095 Node* const search_length = LoadStringLength(search_string);
1035 1096
1036 // Fast-path single-char {search}, long {receiver}, and simple string 1097 // Fast-path single-char {search}, long cons {receiver}, and simple string
1037 // {replace}. 1098 // {replace}.
1038 { 1099 {
1039 Label next(this); 1100 Label next(this);
1040 1101
1041 GotoIfNot(SmiEqual(search_length, SmiConstant(1)), &next); 1102 GotoIfNot(SmiEqual(search_length, SmiConstant(1)), &next);
1042 GotoIfNot(SmiGreaterThan(subject_length, SmiConstant(0xFF)), &next); 1103 GotoIfNot(SmiGreaterThan(subject_length, SmiConstant(0xFF)), &next);
1043 GotoIf(TaggedIsSmi(replace), &next); 1104 GotoIf(TaggedIsSmi(replace), &next);
1044 GotoIfNot(IsString(replace), &next); 1105 GotoIfNot(IsString(replace), &next);
1045 1106
1046 Node* const dollar_string = HeapConstant( 1107 Node* const subject_instance_type = LoadInstanceType(subject_string);
1047 isolate()->factory()->LookupSingleCharacterStringFromCode('$')); 1108 GotoIfNot(IsConsStringInstanceType(subject_instance_type), &next);
1048 Node* const dollar_ix = 1109
1049 CallStub(indexof_callable, context, replace, dollar_string, smi_zero); 1110 GotoIf(TaggedIsPositiveSmi(IndexOfDollarChar(context, replace)), &next);
1050 GotoIfNot(SmiIsNegative(dollar_ix), &next);
1051 1111
1052 // Searching by traversing a cons string tree and replace with cons of 1112 // Searching by traversing a cons string tree and replace with cons of
1053 // slices works only when the replaced string is a single character, being 1113 // slices works only when the replaced string is a single character, being
1054 // replaced by a simple string and only pays off for long strings. 1114 // replaced by a simple string and only pays off for long strings.
1055 // TODO(jgruber): Reevaluate if this is still beneficial. 1115 // TODO(jgruber): Reevaluate if this is still beneficial.
1056 // TODO(jgruber): TailCallRuntime when it correctly handles adapter frames. 1116 // TODO(jgruber): TailCallRuntime when it correctly handles adapter frames.
1057 Return(CallRuntime(Runtime::kStringReplaceOneCharWithString, context, 1117 Return(CallRuntime(Runtime::kStringReplaceOneCharWithString, context,
1058 subject_string, search_string, replace)); 1118 subject_string, search_string, replace));
1059 1119
1060 BIND(&next); 1120 BIND(&next);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 Node* const replacement_string = 1189 Node* const replacement_string =
1130 CallStub(tostring_callable, context, replacement); 1190 CallStub(tostring_callable, context, replacement);
1131 var_result.Bind(CallStub(stringadd_callable, context, var_result.value(), 1191 var_result.Bind(CallStub(stringadd_callable, context, var_result.value(),
1132 replacement_string)); 1192 replacement_string));
1133 Goto(&out); 1193 Goto(&out);
1134 } 1194 }
1135 1195
1136 BIND(&if_notcallablereplace); 1196 BIND(&if_notcallablereplace);
1137 { 1197 {
1138 Node* const replace_string = CallStub(tostring_callable, context, replace); 1198 Node* const replace_string = CallStub(tostring_callable, context, replace);
1139 1199 Node* const replacement =
1140 // TODO(jgruber): Simplified GetSubstitution implementation in CSA. 1200 GetSubstitution(context, subject_string, match_start_index,
1141 Node* const matched = CallStub(substring_callable, context, subject_string, 1201 match_end_index, replace_string);
1142 match_start_index, match_end_index); 1202 var_result.Bind(
1143 Node* const replacement_string = 1203 CallStub(stringadd_callable, context, var_result.value(), replacement));
1144 CallRuntime(Runtime::kGetSubstitution, context, matched, subject_string,
1145 match_start_index, replace_string);
1146 var_result.Bind(CallStub(stringadd_callable, context, var_result.value(),
1147 replacement_string));
1148 Goto(&out); 1204 Goto(&out);
1149 } 1205 }
1150 1206
1151 BIND(&out); 1207 BIND(&out);
1152 { 1208 {
1153 Node* const suffix = CallStub(substring_callable, context, subject_string, 1209 Node* const suffix = CallStub(substring_callable, context, subject_string,
1154 match_end_index, subject_length); 1210 match_end_index, subject_length);
1155 Node* const result = 1211 Node* const result =
1156 CallStub(stringadd_callable, context, var_result.value(), suffix); 1212 CallStub(stringadd_callable, context, var_result.value(), suffix);
1157 Return(result); 1213 Return(result);
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after
1650 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context, 1706 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
1651 HeapConstant(factory()->NewStringFromAsciiChecked( 1707 HeapConstant(factory()->NewStringFromAsciiChecked(
1652 "String Iterator.prototype.next", TENURED)), 1708 "String Iterator.prototype.next", TENURED)),
1653 iterator); 1709 iterator);
1654 Unreachable(); 1710 Unreachable();
1655 } 1711 }
1656 } 1712 }
1657 1713
1658 } // namespace internal 1714 } // namespace internal
1659 } // namespace v8 1715 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | src/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698