OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |