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

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

Issue 2614973003: [cleanup] Refactor builtins-string.cc to use TF_BUILTIN macro (Closed)
Patch Set: Created 3 years, 11 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 | no next file » | 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-utils.h" 5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h" 6 #include "src/builtins/builtins.h"
7 #include "src/code-factory.h" 7 #include "src/code-factory.h"
8 #include "src/code-stub-assembler.h" 8 #include "src/code-stub-assembler.h"
9 #include "src/regexp/regexp-utils.h" 9 #include "src/regexp/regexp-utils.h"
10 10
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 45
46 void BranchIfSimpleOneByteStringInstanceType(Node* instance_type, 46 void BranchIfSimpleOneByteStringInstanceType(Node* instance_type,
47 Label* if_true, 47 Label* if_true,
48 Label* if_false) { 48 Label* if_false) {
49 const int kMask = kStringRepresentationMask | kStringEncodingMask; 49 const int kMask = kStringRepresentationMask | kStringEncodingMask;
50 const int kType = kOneByteStringTag | kSeqStringTag; 50 const int kType = kOneByteStringTag | kSeqStringTag;
51 Branch(Word32Equal(Word32And(instance_type, Int32Constant(kMask)), 51 Branch(Word32Equal(Word32And(instance_type, Int32Constant(kMask)),
52 Int32Constant(kType)), 52 Int32Constant(kType)),
53 if_true, if_false); 53 if_true, if_false);
54 } 54 }
55
56 void GenerateStringEqual(ResultMode mode);
57 void GenerateStringRelationalComparison(RelationalComparisonMode mode);
58
59 Node* ToSmiBetweenZeroAnd(Node* context, Node* value, Node* limit);
60
61 Node* LoadSurrogatePairAt(Node* string, Node* length, Node* index,
62 UnicodeEncoding encoding);
55 }; 63 };
56 64
57 namespace { 65 void StringBuiltinsAssembler::GenerateStringEqual(ResultMode mode) {
58
59 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
60 // Here's pseudo-code for the algorithm below in case of kDontNegateResult 66 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
61 // mode; for kNegateResult mode we properly negate the result. 67 // mode; for kNegateResult mode we properly negate the result.
62 // 68 //
63 // if (lhs == rhs) return true; 69 // if (lhs == rhs) return true;
64 // if (lhs->length() != rhs->length()) return false; 70 // if (lhs->length() != rhs->length()) return false;
65 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) { 71 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
66 // return false; 72 // return false;
67 // } 73 // }
68 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) { 74 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
69 // for (i = 0; i != lhs->length(); ++i) { 75 // for (i = 0; i != lhs->length(); ++i) {
70 // if (lhs[i] != rhs[i]) return false; 76 // if (lhs[i] != rhs[i]) return false;
71 // } 77 // }
72 // return true; 78 // return true;
73 // } 79 // }
74 // return %StringEqual(lhs, rhs); 80 // return %StringEqual(lhs, rhs);
75 81
76 typedef CodeStubAssembler::Label Label; 82 Node* lhs = Parameter(0);
77 typedef compiler::Node Node; 83 Node* rhs = Parameter(1);
78 typedef CodeStubAssembler::Variable Variable; 84 Node* context = Parameter(2);
79 85
80 Node* lhs = assembler->Parameter(0); 86 Label if_equal(this), if_notequal(this);
81 Node* rhs = assembler->Parameter(1);
82 Node* context = assembler->Parameter(2);
83
84 Label if_equal(assembler), if_notequal(assembler);
85 87
86 // Fast check to see if {lhs} and {rhs} refer to the same String object. 88 // Fast check to see if {lhs} and {rhs} refer to the same String object.
87 Label if_same(assembler), if_notsame(assembler); 89 GotoIf(WordEqual(lhs, rhs), &if_equal);
88 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
89 90
90 assembler->Bind(&if_same); 91 // Load the length of {lhs} and {rhs}.
91 assembler->Goto(&if_equal); 92 Node* lhs_length = LoadStringLength(lhs);
93 Node* rhs_length = LoadStringLength(rhs);
92 94
93 assembler->Bind(&if_notsame); 95 // Strings with different lengths cannot be equal.
96 GotoIf(WordNotEqual(lhs_length, rhs_length), &if_notequal);
97
98 // Load instance types of {lhs} and {rhs}.
99 Node* lhs_instance_type = LoadInstanceType(lhs);
100 Node* rhs_instance_type = LoadInstanceType(rhs);
101
102 // Combine the instance types into a single 16-bit value, so we can check
103 // both of them at once.
104 Node* both_instance_types = Word32Or(
105 lhs_instance_type, Word32Shl(rhs_instance_type, Int32Constant(8)));
106
107 // Check if both {lhs} and {rhs} are internalized. Since we already know
108 // that they're not the same object, they're not equal in that case.
109 int const kBothInternalizedMask =
110 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
111 int const kBothInternalizedTag = kInternalizedTag | (kInternalizedTag << 8);
112 GotoIf(Word32Equal(Word32And(both_instance_types,
113 Int32Constant(kBothInternalizedMask)),
114 Int32Constant(kBothInternalizedTag)),
115 &if_notequal);
116
117 // Check that both {lhs} and {rhs} are flat one-byte strings.
118 int const kBothSeqOneByteStringMask =
119 kStringEncodingMask | kStringRepresentationMask |
120 ((kStringEncodingMask | kStringRepresentationMask) << 8);
121 int const kBothSeqOneByteStringTag =
122 kOneByteStringTag | kSeqStringTag |
123 ((kOneByteStringTag | kSeqStringTag) << 8);
124 Label if_bothonebyteseqstrings(this), if_notbothonebyteseqstrings(this);
125 Branch(Word32Equal(Word32And(both_instance_types,
126 Int32Constant(kBothSeqOneByteStringMask)),
127 Int32Constant(kBothSeqOneByteStringTag)),
128 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
129
130 Bind(&if_bothonebyteseqstrings);
94 { 131 {
95 // The {lhs} and {rhs} don't refer to the exact same String object. 132 // Compute the effective offset of the first character.
133 Node* begin =
134 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag);
96 135
97 // Load the length of {lhs} and {rhs}. 136 // Compute the first offset after the string from the length.
98 Node* lhs_length = assembler->LoadStringLength(lhs); 137 Node* end = IntPtrAdd(begin, SmiUntag(lhs_length));
99 Node* rhs_length = assembler->LoadStringLength(rhs);
100 138
101 // Check if the lengths of {lhs} and {rhs} are equal. 139 // Loop over the {lhs} and {rhs} strings to see if they are equal.
102 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler); 140 Variable var_offset(this, MachineType::PointerRepresentation());
103 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length), 141 Label loop(this, &var_offset);
104 &if_lengthisequal, &if_lengthisnotequal); 142 var_offset.Bind(begin);
143 Goto(&loop);
144 Bind(&loop);
145 {
146 // If {offset} equals {end}, no difference was found, so the
147 // strings are equal.
148 Node* offset = var_offset.value();
149 GotoIf(WordEqual(offset, end), &if_equal);
105 150
106 assembler->Bind(&if_lengthisequal); 151 // Load the next characters from {lhs} and {rhs}.
107 { 152 Node* lhs_value = Load(MachineType::Uint8(), lhs, offset);
108 // Load instance types of {lhs} and {rhs}. 153 Node* rhs_value = Load(MachineType::Uint8(), rhs, offset);
109 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
110 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
111 154
112 // Combine the instance types into a single 16-bit value, so we can check 155 // Check if the characters match.
113 // both of them at once. 156 GotoIf(Word32NotEqual(lhs_value, rhs_value), &if_notequal);
114 Node* both_instance_types = assembler->Word32Or(
115 lhs_instance_type,
116 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
117 157
118 // Check if both {lhs} and {rhs} are internalized. 158 // Advance to next character.
119 int const kBothInternalizedMask = 159 var_offset.Bind(IntPtrAdd(offset, IntPtrConstant(1)));
120 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8); 160 Goto(&loop);
121 int const kBothInternalizedTag = 161 }
122 kInternalizedTag | (kInternalizedTag << 8);
123 Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
124 assembler->Branch(assembler->Word32Equal(
125 assembler->Word32And(both_instance_types,
126 assembler->Int32Constant(
127 kBothInternalizedMask)),
128 assembler->Int32Constant(kBothInternalizedTag)),
129 &if_bothinternalized, &if_notbothinternalized);
130
131 assembler->Bind(&if_bothinternalized);
132 {
133 // Fast negative check for internalized-to-internalized equality.
134 assembler->Goto(&if_notequal);
135 }
136
137 assembler->Bind(&if_notbothinternalized);
138 {
139 // Check that both {lhs} and {rhs} are flat one-byte strings.
140 int const kBothSeqOneByteStringMask =
141 kStringEncodingMask | kStringRepresentationMask |
142 ((kStringEncodingMask | kStringRepresentationMask) << 8);
143 int const kBothSeqOneByteStringTag =
144 kOneByteStringTag | kSeqStringTag |
145 ((kOneByteStringTag | kSeqStringTag) << 8);
146 Label if_bothonebyteseqstrings(assembler),
147 if_notbothonebyteseqstrings(assembler);
148 assembler->Branch(
149 assembler->Word32Equal(
150 assembler->Word32And(
151 both_instance_types,
152 assembler->Int32Constant(kBothSeqOneByteStringMask)),
153 assembler->Int32Constant(kBothSeqOneByteStringTag)),
154 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
155
156 assembler->Bind(&if_bothonebyteseqstrings);
157 {
158 // Compute the effective offset of the first character.
159 Node* begin = assembler->IntPtrConstant(
160 SeqOneByteString::kHeaderSize - kHeapObjectTag);
161
162 // Compute the first offset after the string from the length.
163 Node* end =
164 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
165
166 // Loop over the {lhs} and {rhs} strings to see if they are equal.
167 Variable var_offset(assembler, MachineType::PointerRepresentation());
168 Label loop(assembler, &var_offset);
169 var_offset.Bind(begin);
170 assembler->Goto(&loop);
171 assembler->Bind(&loop);
172 {
173 // Check if {offset} equals {end}.
174 Node* offset = var_offset.value();
175 Label if_done(assembler), if_notdone(assembler);
176 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
177 &if_notdone);
178
179 assembler->Bind(&if_notdone);
180 {
181 // Load the next characters from {lhs} and {rhs}.
182 Node* lhs_value =
183 assembler->Load(MachineType::Uint8(), lhs, offset);
184 Node* rhs_value =
185 assembler->Load(MachineType::Uint8(), rhs, offset);
186
187 // Check if the characters match.
188 Label if_valueissame(assembler), if_valueisnotsame(assembler);
189 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
190 &if_valueissame, &if_valueisnotsame);
191
192 assembler->Bind(&if_valueissame);
193 {
194 // Advance to next character.
195 var_offset.Bind(
196 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
197 }
198 assembler->Goto(&loop);
199
200 assembler->Bind(&if_valueisnotsame);
201 assembler->Goto(&if_notequal);
202 }
203
204 assembler->Bind(&if_done);
205 assembler->Goto(&if_equal);
206 }
207 } 162 }
208 163
209 assembler->Bind(&if_notbothonebyteseqstrings); 164 Bind(&if_notbothonebyteseqstrings);
210 { 165 {
211 // TODO(bmeurer): Add fast case support for flattened cons strings; 166 // TODO(bmeurer): Add fast case support for flattened cons strings;
212 // also add support for two byte string equality checks. 167 // also add support for two byte string equality checks.
213 Runtime::FunctionId function_id = 168 Runtime::FunctionId function_id =
214 (mode == ResultMode::kDontNegateResult) 169 (mode == ResultMode::kDontNegateResult)
215 ? Runtime::kStringEqual 170 ? Runtime::kStringEqual
216 : Runtime::kStringNotEqual; 171 : Runtime::kStringNotEqual;
217 assembler->TailCallRuntime(function_id, context, lhs, rhs); 172 TailCallRuntime(function_id, context, lhs, rhs);
218 } 173 }
174
175 Bind(&if_equal);
176 Return(BooleanConstant(mode == ResultMode::kDontNegateResult));
177
178 Bind(&if_notequal);
179 Return(BooleanConstant(mode == ResultMode::kNegateResult));
180 }
181
182 void StringBuiltinsAssembler::GenerateStringRelationalComparison(
183 RelationalComparisonMode mode) {
184 Node* lhs = Parameter(0);
185 Node* rhs = Parameter(1);
186 Node* context = Parameter(2);
187
188 Label if_less(this), if_equal(this), if_greater(this);
189
190 // Fast check to see if {lhs} and {rhs} refer to the same String object.
191 GotoIf(WordEqual(lhs, rhs), &if_equal);
192
193 // Load instance types of {lhs} and {rhs}.
194 Node* lhs_instance_type = LoadInstanceType(lhs);
195 Node* rhs_instance_type = LoadInstanceType(rhs);
196
197 // Combine the instance types into a single 16-bit value, so we can check
198 // both of them at once.
199 Node* both_instance_types = Word32Or(
200 lhs_instance_type, Word32Shl(rhs_instance_type, Int32Constant(8)));
201
202 // Check that both {lhs} and {rhs} are flat one-byte strings.
203 int const kBothSeqOneByteStringMask =
204 kStringEncodingMask | kStringRepresentationMask |
205 ((kStringEncodingMask | kStringRepresentationMask) << 8);
206 int const kBothSeqOneByteStringTag =
207 kOneByteStringTag | kSeqStringTag |
208 ((kOneByteStringTag | kSeqStringTag) << 8);
209 Label if_bothonebyteseqstrings(this), if_notbothonebyteseqstrings(this);
210 Branch(Word32Equal(Word32And(both_instance_types,
211 Int32Constant(kBothSeqOneByteStringMask)),
212 Int32Constant(kBothSeqOneByteStringTag)),
213 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
214
215 Bind(&if_bothonebyteseqstrings);
216 {
217 // Load the length of {lhs} and {rhs}.
218 Node* lhs_length = LoadStringLength(lhs);
219 Node* rhs_length = LoadStringLength(rhs);
220
221 // Determine the minimum length.
222 Node* length = SmiMin(lhs_length, rhs_length);
223
224 // Compute the effective offset of the first character.
225 Node* begin =
226 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag);
227
228 // Compute the first offset after the string from the length.
229 Node* end = IntPtrAdd(begin, SmiUntag(length));
230
231 // Loop over the {lhs} and {rhs} strings to see if they are equal.
232 Variable var_offset(this, MachineType::PointerRepresentation());
233 Label loop(this, &var_offset);
234 var_offset.Bind(begin);
235 Goto(&loop);
236 Bind(&loop);
237 {
238 // Check if {offset} equals {end}.
239 Node* offset = var_offset.value();
240 Label if_done(this), if_notdone(this);
241 Branch(WordEqual(offset, end), &if_done, &if_notdone);
242
243 Bind(&if_notdone);
244 {
245 // Load the next characters from {lhs} and {rhs}.
246 Node* lhs_value = Load(MachineType::Uint8(), lhs, offset);
247 Node* rhs_value = Load(MachineType::Uint8(), rhs, offset);
248
249 // Check if the characters match.
250 Label if_valueissame(this), if_valueisnotsame(this);
251 Branch(Word32Equal(lhs_value, rhs_value), &if_valueissame,
252 &if_valueisnotsame);
253
254 Bind(&if_valueissame);
255 {
256 // Advance to next character.
257 var_offset.Bind(IntPtrAdd(offset, IntPtrConstant(1)));
258 }
259 Goto(&loop);
260
261 Bind(&if_valueisnotsame);
262 Branch(Uint32LessThan(lhs_value, rhs_value), &if_less, &if_greater);
263 }
264
265 Bind(&if_done);
266 {
267 // All characters up to the min length are equal, decide based on
268 // string length.
269 GotoIf(SmiEqual(lhs_length, rhs_length), &if_equal);
270 BranchIfSmiLessThan(lhs_length, rhs_length, &if_less, &if_greater);
219 } 271 }
220 } 272 }
221
222 assembler->Bind(&if_lengthisnotequal);
223 {
224 // Mismatch in length of {lhs} and {rhs}, cannot be equal.
225 assembler->Goto(&if_notequal);
226 } 273 }
227 } 274
228 275 Bind(&if_notbothonebyteseqstrings);
229 assembler->Bind(&if_equal);
230 assembler->Return(
231 assembler->BooleanConstant(mode == ResultMode::kDontNegateResult));
232
233 assembler->Bind(&if_notequal);
234 assembler->Return(
235 assembler->BooleanConstant(mode == ResultMode::kNegateResult));
236 }
237
238
239 void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
240 RelationalComparisonMode mode) {
241 typedef CodeStubAssembler::Label Label;
242 typedef compiler::Node Node;
243 typedef CodeStubAssembler::Variable Variable;
244
245 Node* lhs = assembler->Parameter(0);
246 Node* rhs = assembler->Parameter(1);
247 Node* context = assembler->Parameter(2);
248
249 Label if_less(assembler), if_equal(assembler), if_greater(assembler);
250
251 // Fast check to see if {lhs} and {rhs} refer to the same String object.
252 Label if_same(assembler), if_notsame(assembler);
253 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
254
255 assembler->Bind(&if_same);
256 assembler->Goto(&if_equal);
257
258 assembler->Bind(&if_notsame);
259 {
260 // Load instance types of {lhs} and {rhs}.
261 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
262 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
263
264 // Combine the instance types into a single 16-bit value, so we can check
265 // both of them at once.
266 Node* both_instance_types = assembler->Word32Or(
267 lhs_instance_type,
268 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
269
270 // Check that both {lhs} and {rhs} are flat one-byte strings.
271 int const kBothSeqOneByteStringMask =
272 kStringEncodingMask | kStringRepresentationMask |
273 ((kStringEncodingMask | kStringRepresentationMask) << 8);
274 int const kBothSeqOneByteStringTag =
275 kOneByteStringTag | kSeqStringTag |
276 ((kOneByteStringTag | kSeqStringTag) << 8);
277 Label if_bothonebyteseqstrings(assembler),
278 if_notbothonebyteseqstrings(assembler);
279 assembler->Branch(assembler->Word32Equal(
280 assembler->Word32And(both_instance_types,
281 assembler->Int32Constant(
282 kBothSeqOneByteStringMask)),
283 assembler->Int32Constant(kBothSeqOneByteStringTag)),
284 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
285
286 assembler->Bind(&if_bothonebyteseqstrings);
287 {
288 // Load the length of {lhs} and {rhs}.
289 Node* lhs_length = assembler->LoadStringLength(lhs);
290 Node* rhs_length = assembler->LoadStringLength(rhs);
291
292 // Determine the minimum length.
293 Node* length = assembler->SmiMin(lhs_length, rhs_length);
294
295 // Compute the effective offset of the first character.
296 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
297 kHeapObjectTag);
298
299 // Compute the first offset after the string from the length.
300 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
301
302 // Loop over the {lhs} and {rhs} strings to see if they are equal.
303 Variable var_offset(assembler, MachineType::PointerRepresentation());
304 Label loop(assembler, &var_offset);
305 var_offset.Bind(begin);
306 assembler->Goto(&loop);
307 assembler->Bind(&loop);
308 {
309 // Check if {offset} equals {end}.
310 Node* offset = var_offset.value();
311 Label if_done(assembler), if_notdone(assembler);
312 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
313 &if_notdone);
314
315 assembler->Bind(&if_notdone);
316 {
317 // Load the next characters from {lhs} and {rhs}.
318 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
319 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
320
321 // Check if the characters match.
322 Label if_valueissame(assembler), if_valueisnotsame(assembler);
323 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
324 &if_valueissame, &if_valueisnotsame);
325
326 assembler->Bind(&if_valueissame);
327 {
328 // Advance to next character.
329 var_offset.Bind(
330 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
331 }
332 assembler->Goto(&loop);
333
334 assembler->Bind(&if_valueisnotsame);
335 assembler->Branch(assembler->Uint32LessThan(lhs_value, rhs_value),
336 &if_less, &if_greater);
337 }
338
339 assembler->Bind(&if_done);
340 {
341 // All characters up to the min length are equal, decide based on
342 // string length.
343 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
344 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
345 &if_lengthisequal, &if_lengthisnotequal);
346
347 assembler->Bind(&if_lengthisequal);
348 assembler->Goto(&if_equal);
349
350 assembler->Bind(&if_lengthisnotequal);
351 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
352 &if_greater);
353 }
354 }
355 }
356
357 assembler->Bind(&if_notbothonebyteseqstrings);
358 { 276 {
359 // TODO(bmeurer): Add fast case support for flattened cons strings; 277 // TODO(bmeurer): Add fast case support for flattened cons strings;
360 // also add support for two byte string relational comparisons. 278 // also add support for two byte string relational comparisons.
361 switch (mode) { 279 switch (mode) {
362 case RelationalComparisonMode::kLessThan: 280 case RelationalComparisonMode::kLessThan:
363 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs, 281 TailCallRuntime(Runtime::kStringLessThan, context, lhs, rhs);
364 rhs);
365 break; 282 break;
366 case RelationalComparisonMode::kLessThanOrEqual: 283 case RelationalComparisonMode::kLessThanOrEqual:
367 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context, 284 TailCallRuntime(Runtime::kStringLessThanOrEqual, context, lhs, rhs);
368 lhs, rhs);
369 break; 285 break;
370 case RelationalComparisonMode::kGreaterThan: 286 case RelationalComparisonMode::kGreaterThan:
371 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, 287 TailCallRuntime(Runtime::kStringGreaterThan, context, lhs, rhs);
372 rhs);
373 break; 288 break;
374 case RelationalComparisonMode::kGreaterThanOrEqual: 289 case RelationalComparisonMode::kGreaterThanOrEqual:
375 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual, 290 TailCallRuntime(Runtime::kStringGreaterThanOrEqual, context, lhs,
376 context, lhs, rhs); 291 rhs);
377 break; 292 break;
378 } 293 }
379 } 294 }
295
296 Bind(&if_less);
297 switch (mode) {
298 case RelationalComparisonMode::kLessThan:
299 case RelationalComparisonMode::kLessThanOrEqual:
300 Return(BooleanConstant(true));
301 break;
302
303 case RelationalComparisonMode::kGreaterThan:
304 case RelationalComparisonMode::kGreaterThanOrEqual:
305 Return(BooleanConstant(false));
306 break;
380 } 307 }
381 308
382 assembler->Bind(&if_less); 309 Bind(&if_equal);
310 switch (mode) {
311 case RelationalComparisonMode::kLessThan:
312 case RelationalComparisonMode::kGreaterThan:
313 Return(BooleanConstant(false));
314 break;
315
316 case RelationalComparisonMode::kLessThanOrEqual:
317 case RelationalComparisonMode::kGreaterThanOrEqual:
318 Return(BooleanConstant(true));
319 break;
320 }
321
322 Bind(&if_greater);
383 switch (mode) { 323 switch (mode) {
384 case RelationalComparisonMode::kLessThan: 324 case RelationalComparisonMode::kLessThan:
385 case RelationalComparisonMode::kLessThanOrEqual: 325 case RelationalComparisonMode::kLessThanOrEqual:
386 assembler->Return(assembler->BooleanConstant(true)); 326 Return(BooleanConstant(false));
387 break; 327 break;
388 328
389 case RelationalComparisonMode::kGreaterThan: 329 case RelationalComparisonMode::kGreaterThan:
390 case RelationalComparisonMode::kGreaterThanOrEqual: 330 case RelationalComparisonMode::kGreaterThanOrEqual:
391 assembler->Return(assembler->BooleanConstant(false)); 331 Return(BooleanConstant(true));
392 break; 332 break;
393 } 333 }
394 334 }
395 assembler->Bind(&if_equal); 335
396 switch (mode) { 336 TF_BUILTIN(StringEqual, StringBuiltinsAssembler) {
397 case RelationalComparisonMode::kLessThan: 337 GenerateStringEqual(ResultMode::kDontNegateResult);
398 case RelationalComparisonMode::kGreaterThan: 338 }
399 assembler->Return(assembler->BooleanConstant(false)); 339
400 break; 340 TF_BUILTIN(StringNotEqual, StringBuiltinsAssembler) {
401 341 GenerateStringEqual(ResultMode::kNegateResult);
402 case RelationalComparisonMode::kLessThanOrEqual: 342 }
403 case RelationalComparisonMode::kGreaterThanOrEqual: 343
404 assembler->Return(assembler->BooleanConstant(true)); 344 TF_BUILTIN(StringLessThan, StringBuiltinsAssembler) {
405 break; 345 GenerateStringRelationalComparison(RelationalComparisonMode::kLessThan);
406 } 346 }
407 347
408 assembler->Bind(&if_greater); 348 TF_BUILTIN(StringLessThanOrEqual, StringBuiltinsAssembler) {
409 switch (mode) {
410 case RelationalComparisonMode::kLessThan:
411 case RelationalComparisonMode::kLessThanOrEqual:
412 assembler->Return(assembler->BooleanConstant(false));
413 break;
414
415 case RelationalComparisonMode::kGreaterThan:
416 case RelationalComparisonMode::kGreaterThanOrEqual:
417 assembler->Return(assembler->BooleanConstant(true));
418 break;
419 }
420 }
421
422 } // namespace
423
424 // static
425 void Builtins::Generate_StringEqual(compiler::CodeAssemblerState* state) {
426 CodeStubAssembler assembler(state);
427 GenerateStringEqual(&assembler, ResultMode::kDontNegateResult);
428 }
429
430 // static
431 void Builtins::Generate_StringNotEqual(compiler::CodeAssemblerState* state) {
432 CodeStubAssembler assembler(state);
433 GenerateStringEqual(&assembler, ResultMode::kNegateResult);
434 }
435
436 // static
437 void Builtins::Generate_StringLessThan(compiler::CodeAssemblerState* state) {
438 CodeStubAssembler assembler(state);
439 GenerateStringRelationalComparison(&assembler,
440 RelationalComparisonMode::kLessThan);
441 }
442
443 // static
444 void Builtins::Generate_StringLessThanOrEqual(
445 compiler::CodeAssemblerState* state) {
446 CodeStubAssembler assembler(state);
447 GenerateStringRelationalComparison( 349 GenerateStringRelationalComparison(
448 &assembler, RelationalComparisonMode::kLessThanOrEqual); 350 RelationalComparisonMode::kLessThanOrEqual);
449 } 351 }
450 352
451 // static 353 TF_BUILTIN(StringGreaterThan, StringBuiltinsAssembler) {
452 void Builtins::Generate_StringGreaterThan(compiler::CodeAssemblerState* state) { 354 GenerateStringRelationalComparison(RelationalComparisonMode::kGreaterThan);
453 CodeStubAssembler assembler(state); 355 }
454 GenerateStringRelationalComparison(&assembler, 356
455 RelationalComparisonMode::kGreaterThan); 357 TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) {
456 }
457
458 // static
459 void Builtins::Generate_StringGreaterThanOrEqual(
460 compiler::CodeAssemblerState* state) {
461 CodeStubAssembler assembler(state);
462 GenerateStringRelationalComparison( 358 GenerateStringRelationalComparison(
463 &assembler, RelationalComparisonMode::kGreaterThanOrEqual); 359 RelationalComparisonMode::kGreaterThanOrEqual);
464 } 360 }
465 361
466 // static 362 TF_BUILTIN(StringCharAt, CodeStubAssembler) {
467 void Builtins::Generate_StringCharAt(compiler::CodeAssemblerState* state) { 363 Node* receiver = Parameter(0);
468 typedef compiler::Node Node; 364 Node* position = Parameter(1);
469 CodeStubAssembler assembler(state);
470
471 Node* receiver = assembler.Parameter(0);
472 Node* position = assembler.Parameter(1);
473 365
474 // Load the character code at the {position} from the {receiver}. 366 // Load the character code at the {position} from the {receiver}.
475 Node* code = assembler.StringCharCodeAt(receiver, position, 367 Node* code = StringCharCodeAt(receiver, position,
476 CodeStubAssembler::INTPTR_PARAMETERS); 368 CodeStubAssembler::INTPTR_PARAMETERS);
477 369
478 // And return the single character string with only that {code} 370 // And return the single character string with only that {code}
479 Node* result = assembler.StringFromCharCode(code); 371 Node* result = StringFromCharCode(code);
480 assembler.Return(result); 372 Return(result);
481 } 373 }
482 374
483 // static 375 TF_BUILTIN(StringCharCodeAt, CodeStubAssembler) {
484 void Builtins::Generate_StringCharCodeAt(compiler::CodeAssemblerState* state) { 376 Node* receiver = Parameter(0);
485 typedef compiler::Node Node; 377 Node* position = Parameter(1);
486 CodeStubAssembler assembler(state);
487
488 Node* receiver = assembler.Parameter(0);
489 Node* position = assembler.Parameter(1);
490 378
491 // Load the character code at the {position} from the {receiver}. 379 // Load the character code at the {position} from the {receiver}.
492 Node* code = assembler.StringCharCodeAt(receiver, position, 380 Node* code = StringCharCodeAt(receiver, position,
493 CodeStubAssembler::INTPTR_PARAMETERS); 381 CodeStubAssembler::INTPTR_PARAMETERS);
494 382
495 // And return it as TaggedSigned value. 383 // And return it as TaggedSigned value.
496 // TODO(turbofan): Allow builtins to return values untagged. 384 // TODO(turbofan): Allow builtins to return values untagged.
497 Node* result = assembler.SmiFromWord32(code); 385 Node* result = SmiFromWord32(code);
498 assembler.Return(result); 386 Return(result);
499 } 387 }
500 388
501 // ----------------------------------------------------------------------------- 389 // -----------------------------------------------------------------------------
502 // ES6 section 21.1 String Objects 390 // ES6 section 21.1 String Objects
503 391
504 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 392 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
505 void Builtins::Generate_StringFromCharCode( 393 TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
506 compiler::CodeAssemblerState* state) { 394 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
507 typedef CodeStubAssembler::Label Label; 395 Node* context = Parameter(BuiltinDescriptor::kContext);
508 typedef compiler::Node Node; 396
509 typedef CodeStubAssembler::Variable Variable; 397 CodeStubArguments arguments(this, argc);
510 CodeStubAssembler assembler(state);
511
512 Node* argc = assembler.Parameter(BuiltinDescriptor::kArgumentsCount);
513 Node* context = assembler.Parameter(BuiltinDescriptor::kContext);
514
515 CodeStubArguments arguments(&assembler, argc);
516 // From now on use word-size argc value. 398 // From now on use word-size argc value.
517 argc = arguments.GetLength(); 399 argc = arguments.GetLength();
518 400
519 // Check if we have exactly one argument (plus the implicit receiver), i.e. 401 // Check if we have exactly one argument (plus the implicit receiver), i.e.
520 // if the parent frame is not an arguments adaptor frame. 402 // if the parent frame is not an arguments adaptor frame.
521 Label if_oneargument(&assembler), if_notoneargument(&assembler); 403 Label if_oneargument(this), if_notoneargument(this);
522 assembler.Branch(assembler.WordEqual(argc, assembler.IntPtrConstant(1)), 404 Branch(WordEqual(argc, IntPtrConstant(1)), &if_oneargument,
523 &if_oneargument, &if_notoneargument); 405 &if_notoneargument);
524 406
525 assembler.Bind(&if_oneargument); 407 Bind(&if_oneargument);
526 { 408 {
527 // Single argument case, perform fast single character string cache lookup 409 // Single argument case, perform fast single character string cache lookup
528 // for one-byte code units, or fall back to creating a single character 410 // for one-byte code units, or fall back to creating a single character
529 // string on the fly otherwise. 411 // string on the fly otherwise.
530 Node* code = arguments.AtIndex(0); 412 Node* code = arguments.AtIndex(0);
531 Node* code32 = assembler.TruncateTaggedToWord32(context, code); 413 Node* code32 = TruncateTaggedToWord32(context, code);
532 Node* code16 = assembler.Word32And( 414 Node* code16 = Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit));
533 code32, assembler.Int32Constant(String::kMaxUtf16CodeUnit)); 415 Node* result = StringFromCharCode(code16);
534 Node* result = assembler.StringFromCharCode(code16);
535 arguments.PopAndReturn(result); 416 arguments.PopAndReturn(result);
536 } 417 }
537 418
538 Node* code16 = nullptr; 419 Node* code16 = nullptr;
539 assembler.Bind(&if_notoneargument); 420 Bind(&if_notoneargument);
540 { 421 {
541 Label two_byte(&assembler); 422 Label two_byte(this);
542 // Assume that the resulting string contains only one-byte characters. 423 // Assume that the resulting string contains only one-byte characters.
543 Node* one_byte_result = assembler.AllocateSeqOneByteString(context, argc); 424 Node* one_byte_result = AllocateSeqOneByteString(context, argc);
544 425
545 Variable max_index(&assembler, MachineType::PointerRepresentation()); 426 Variable max_index(this, MachineType::PointerRepresentation());
546 max_index.Bind(assembler.IntPtrConstant(0)); 427 max_index.Bind(IntPtrConstant(0));
547 428
548 // Iterate over the incoming arguments, converting them to 8-bit character 429 // Iterate over the incoming arguments, converting them to 8-bit character
549 // codes. Stop if any of the conversions generates a code that doesn't fit 430 // codes. Stop if any of the conversions generates a code that doesn't fit
550 // in 8 bits. 431 // in 8 bits.
551 CodeStubAssembler::VariableList vars({&max_index}, assembler.zone()); 432 CodeStubAssembler::VariableList vars({&max_index}, zone());
552 arguments.ForEach(vars, [&assembler, context, &two_byte, &max_index, 433 arguments.ForEach(vars, [this, context, &two_byte, &max_index, &code16,
553 &code16, one_byte_result](Node* arg) { 434 one_byte_result](Node* arg) {
554 Node* code32 = assembler.TruncateTaggedToWord32(context, arg); 435 Node* code32 = TruncateTaggedToWord32(context, arg);
555 code16 = assembler.Word32And( 436 code16 = Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit));
556 code32, assembler.Int32Constant(String::kMaxUtf16CodeUnit)); 437
557 438 GotoIf(
558 assembler.GotoIf( 439 Int32GreaterThan(code16, Int32Constant(String::kMaxOneByteCharCode)),
559 assembler.Int32GreaterThan(
560 code16, assembler.Int32Constant(String::kMaxOneByteCharCode)),
561 &two_byte); 440 &two_byte);
562 441
563 // The {code16} fits into the SeqOneByteString {one_byte_result}. 442 // The {code16} fits into the SeqOneByteString {one_byte_result}.
564 Node* offset = assembler.ElementOffsetFromIndex( 443 Node* offset = ElementOffsetFromIndex(
565 max_index.value(), UINT8_ELEMENTS, 444 max_index.value(), UINT8_ELEMENTS,
566 CodeStubAssembler::INTPTR_PARAMETERS, 445 CodeStubAssembler::INTPTR_PARAMETERS,
567 SeqOneByteString::kHeaderSize - kHeapObjectTag); 446 SeqOneByteString::kHeaderSize - kHeapObjectTag);
568 assembler.StoreNoWriteBarrier(MachineRepresentation::kWord8, 447 StoreNoWriteBarrier(MachineRepresentation::kWord8, one_byte_result,
569 one_byte_result, offset, code16); 448 offset, code16);
570 max_index.Bind( 449 max_index.Bind(IntPtrAdd(max_index.value(), IntPtrConstant(1)));
571 assembler.IntPtrAdd(max_index.value(), assembler.IntPtrConstant(1)));
572 }); 450 });
573 arguments.PopAndReturn(one_byte_result); 451 arguments.PopAndReturn(one_byte_result);
574 452
575 assembler.Bind(&two_byte); 453 Bind(&two_byte);
576 454
577 // At least one of the characters in the string requires a 16-bit 455 // At least one of the characters in the string requires a 16-bit
578 // representation. Allocate a SeqTwoByteString to hold the resulting 456 // representation. Allocate a SeqTwoByteString to hold the resulting
579 // string. 457 // string.
580 Node* two_byte_result = assembler.AllocateSeqTwoByteString(context, argc); 458 Node* two_byte_result = AllocateSeqTwoByteString(context, argc);
581 459
582 // Copy the characters that have already been put in the 8-bit string into 460 // Copy the characters that have already been put in the 8-bit string into
583 // their corresponding positions in the new 16-bit string. 461 // their corresponding positions in the new 16-bit string.
584 Node* zero = assembler.IntPtrConstant(0); 462 Node* zero = IntPtrConstant(0);
585 assembler.CopyStringCharacters(one_byte_result, two_byte_result, zero, zero, 463 CopyStringCharacters(one_byte_result, two_byte_result, zero, zero,
586 max_index.value(), String::ONE_BYTE_ENCODING, 464 max_index.value(), String::ONE_BYTE_ENCODING,
587 String::TWO_BYTE_ENCODING, 465 String::TWO_BYTE_ENCODING,
588 CodeStubAssembler::INTPTR_PARAMETERS); 466 CodeStubAssembler::INTPTR_PARAMETERS);
589 467
590 // Write the character that caused the 8-bit to 16-bit fault. 468 // Write the character that caused the 8-bit to 16-bit fault.
591 Node* max_index_offset = assembler.ElementOffsetFromIndex( 469 Node* max_index_offset =
592 max_index.value(), UINT16_ELEMENTS, 470 ElementOffsetFromIndex(max_index.value(), UINT16_ELEMENTS,
593 CodeStubAssembler::INTPTR_PARAMETERS, 471 CodeStubAssembler::INTPTR_PARAMETERS,
594 SeqTwoByteString::kHeaderSize - kHeapObjectTag); 472 SeqTwoByteString::kHeaderSize - kHeapObjectTag);
595 assembler.StoreNoWriteBarrier(MachineRepresentation::kWord16, 473 StoreNoWriteBarrier(MachineRepresentation::kWord16, two_byte_result,
596 two_byte_result, max_index_offset, code16); 474 max_index_offset, code16);
597 max_index.Bind( 475 max_index.Bind(IntPtrAdd(max_index.value(), IntPtrConstant(1)));
598 assembler.IntPtrAdd(max_index.value(), assembler.IntPtrConstant(1)));
599 476
600 // Resume copying the passed-in arguments from the same place where the 477 // Resume copying the passed-in arguments from the same place where the
601 // 8-bit copy stopped, but this time copying over all of the characters 478 // 8-bit copy stopped, but this time copying over all of the characters
602 // using a 16-bit representation. 479 // using a 16-bit representation.
603 arguments.ForEach( 480 arguments.ForEach(
604 vars, 481 vars,
605 [&assembler, context, two_byte_result, &max_index](Node* arg) { 482 [this, context, two_byte_result, &max_index](Node* arg) {
606 Node* code32 = assembler.TruncateTaggedToWord32(context, arg); 483 Node* code32 = TruncateTaggedToWord32(context, arg);
607 Node* code16 = assembler.Word32And( 484 Node* code16 =
608 code32, assembler.Int32Constant(String::kMaxUtf16CodeUnit)); 485 Word32And(code32, Int32Constant(String::kMaxUtf16CodeUnit));
609 486
610 Node* offset = assembler.ElementOffsetFromIndex( 487 Node* offset = ElementOffsetFromIndex(
611 max_index.value(), UINT16_ELEMENTS, 488 max_index.value(), UINT16_ELEMENTS,
612 CodeStubAssembler::INTPTR_PARAMETERS, 489 CodeStubAssembler::INTPTR_PARAMETERS,
613 SeqTwoByteString::kHeaderSize - kHeapObjectTag); 490 SeqTwoByteString::kHeaderSize - kHeapObjectTag);
614 assembler.StoreNoWriteBarrier(MachineRepresentation::kWord16, 491 StoreNoWriteBarrier(MachineRepresentation::kWord16, two_byte_result,
615 two_byte_result, offset, code16); 492 offset, code16);
616 max_index.Bind(assembler.IntPtrAdd(max_index.value(), 493 max_index.Bind(IntPtrAdd(max_index.value(), IntPtrConstant(1)));
617 assembler.IntPtrConstant(1)));
618 }, 494 },
619 max_index.value()); 495 max_index.value());
620 496
621 arguments.PopAndReturn(two_byte_result); 497 arguments.PopAndReturn(two_byte_result);
622 } 498 }
623 } 499 }
624 500
625 namespace { // for String.fromCodePoint 501 namespace { // for String.fromCodePoint
626 502
627 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { 503 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 585
710 CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(), 586 CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(),
711 one_byte_buffer.length()); 587 one_byte_buffer.length());
712 CopyChars(result->GetChars() + one_byte_buffer.length(), 588 CopyChars(result->GetChars() + one_byte_buffer.length(),
713 two_byte_buffer.ToConstVector().start(), two_byte_buffer.length()); 589 two_byte_buffer.ToConstVector().start(), two_byte_buffer.length());
714 590
715 return *result; 591 return *result;
716 } 592 }
717 593
718 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 594 // ES6 section 21.1.3.1 String.prototype.charAt ( pos )
719 void Builtins::Generate_StringPrototypeCharAt( 595 TF_BUILTIN(StringPrototypeCharAt, CodeStubAssembler) {
720 compiler::CodeAssemblerState* state) { 596 Node* receiver = Parameter(0);
721 typedef CodeStubAssembler::Label Label; 597 Node* position = Parameter(1);
722 typedef compiler::Node Node; 598 Node* context = Parameter(4);
723 CodeStubAssembler assembler(state);
724
725 Node* receiver = assembler.Parameter(0);
726 Node* position = assembler.Parameter(1);
727 Node* context = assembler.Parameter(4);
728 599
729 // Check that {receiver} is coercible to Object and convert it to a String. 600 // Check that {receiver} is coercible to Object and convert it to a String.
730 receiver = 601 receiver = ToThisString(context, receiver, "String.prototype.charAt");
731 assembler.ToThisString(context, receiver, "String.prototype.charAt");
732 602
733 // Convert the {position} to a Smi and check that it's in bounds of the 603 // Convert the {position} to a Smi and check that it's in bounds of the
734 // {receiver}. 604 // {receiver}.
735 { 605 {
736 Label return_emptystring(&assembler, Label::kDeferred); 606 Label return_emptystring(this, Label::kDeferred);
737 position = assembler.ToInteger(context, position, 607 position =
738 CodeStubAssembler::kTruncateMinusZero); 608 ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero);
739 assembler.GotoUnless(assembler.TaggedIsSmi(position), &return_emptystring); 609 GotoUnless(TaggedIsSmi(position), &return_emptystring);
740 610
741 // Determine the actual length of the {receiver} String. 611 // Determine the actual length of the {receiver} String.
742 Node* receiver_length = 612 Node* receiver_length = LoadObjectField(receiver, String::kLengthOffset);
743 assembler.LoadObjectField(receiver, String::kLengthOffset);
744 613
745 // Return "" if the Smi {position} is outside the bounds of the {receiver}. 614 // Return "" if the Smi {position} is outside the bounds of the {receiver}.
746 Label if_positioninbounds(&assembler); 615 Label if_positioninbounds(this);
747 assembler.Branch(assembler.SmiAboveOrEqual(position, receiver_length), 616 Branch(SmiAboveOrEqual(position, receiver_length), &return_emptystring,
748 &return_emptystring, &if_positioninbounds); 617 &if_positioninbounds);
749 618
750 assembler.Bind(&return_emptystring); 619 Bind(&return_emptystring);
751 assembler.Return(assembler.EmptyStringConstant()); 620 Return(EmptyStringConstant());
752 621
753 assembler.Bind(&if_positioninbounds); 622 Bind(&if_positioninbounds);
754 } 623 }
755 624
756 // Load the character code at the {position} from the {receiver}. 625 // Load the character code at the {position} from the {receiver}.
757 Node* code = assembler.StringCharCodeAt(receiver, position); 626 Node* code = StringCharCodeAt(receiver, position);
758 627
759 // And return the single character string with only that {code}. 628 // And return the single character string with only that {code}.
760 Node* result = assembler.StringFromCharCode(code); 629 Node* result = StringFromCharCode(code);
761 assembler.Return(result); 630 Return(result);
762 } 631 }
763 632
764 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 633 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
765 void Builtins::Generate_StringPrototypeCharCodeAt( 634 TF_BUILTIN(StringPrototypeCharCodeAt, CodeStubAssembler) {
766 compiler::CodeAssemblerState* state) { 635 Node* receiver = Parameter(0);
767 typedef CodeStubAssembler::Label Label; 636 Node* position = Parameter(1);
768 typedef compiler::Node Node; 637 Node* context = Parameter(4);
769 CodeStubAssembler assembler(state);
770
771 Node* receiver = assembler.Parameter(0);
772 Node* position = assembler.Parameter(1);
773 Node* context = assembler.Parameter(4);
774 638
775 // Check that {receiver} is coercible to Object and convert it to a String. 639 // Check that {receiver} is coercible to Object and convert it to a String.
776 receiver = 640 receiver = ToThisString(context, receiver, "String.prototype.charCodeAt");
777 assembler.ToThisString(context, receiver, "String.prototype.charCodeAt");
778 641
779 // Convert the {position} to a Smi and check that it's in bounds of the 642 // Convert the {position} to a Smi and check that it's in bounds of the
780 // {receiver}. 643 // {receiver}.
781 { 644 {
782 Label return_nan(&assembler, Label::kDeferred); 645 Label return_nan(this, Label::kDeferred);
783 position = assembler.ToInteger(context, position, 646 position =
784 CodeStubAssembler::kTruncateMinusZero); 647 ToInteger(context, position, CodeStubAssembler::kTruncateMinusZero);
785 assembler.GotoUnless(assembler.TaggedIsSmi(position), &return_nan); 648 GotoUnless(TaggedIsSmi(position), &return_nan);
786 649
787 // Determine the actual length of the {receiver} String. 650 // Determine the actual length of the {receiver} String.
788 Node* receiver_length = 651 Node* receiver_length = LoadObjectField(receiver, String::kLengthOffset);
789 assembler.LoadObjectField(receiver, String::kLengthOffset);
790 652
791 // Return NaN if the Smi {position} is outside the bounds of the {receiver}. 653 // Return NaN if the Smi {position} is outside the bounds of the {receiver}.
792 Label if_positioninbounds(&assembler); 654 Label if_positioninbounds(this);
793 assembler.Branch(assembler.SmiAboveOrEqual(position, receiver_length), 655 Branch(SmiAboveOrEqual(position, receiver_length), &return_nan,
794 &return_nan, &if_positioninbounds); 656 &if_positioninbounds);
795 657
796 assembler.Bind(&return_nan); 658 Bind(&return_nan);
797 assembler.Return(assembler.NaNConstant()); 659 Return(NaNConstant());
798 660
799 assembler.Bind(&if_positioninbounds); 661 Bind(&if_positioninbounds);
800 } 662 }
801 663
802 // Load the character at the {position} from the {receiver}. 664 // Load the character at the {position} from the {receiver}.
803 Node* value = assembler.StringCharCodeAt(receiver, position); 665 Node* value = StringCharCodeAt(receiver, position);
804 Node* result = assembler.SmiFromWord32(value); 666 Node* result = SmiFromWord32(value);
805 assembler.Return(result); 667 Return(result);
806 } 668 }
807 669
808 // ES6 section 21.1.3.6 670 // ES6 section 21.1.3.6
809 // String.prototype.endsWith ( searchString [ , endPosition ] ) 671 // String.prototype.endsWith ( searchString [ , endPosition ] )
810 BUILTIN(StringPrototypeEndsWith) { 672 BUILTIN(StringPrototypeEndsWith) {
811 HandleScope handle_scope(isolate); 673 HandleScope handle_scope(isolate);
812 TO_THIS_STRING(str, "String.prototype.endsWith"); 674 TO_THIS_STRING(str, "String.prototype.endsWith");
813 675
814 // Check if the search string is a regExp and fail if it is. 676 // Check if the search string is a regExp and fail if it is.
815 Handle<Object> search = args.atOrUndefined(isolate, 1); 677 Handle<Object> search = args.atOrUndefined(isolate, 1);
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD"); 979 isolate->factory()->NewStringFromStaticChars("NFC, NFD, NFKC, NFKD");
1118 THROW_NEW_ERROR_RETURN_FAILURE( 980 THROW_NEW_ERROR_RETURN_FAILURE(
1119 isolate, 981 isolate,
1120 NewRangeError(MessageTemplate::kNormalizationForm, valid_forms)); 982 NewRangeError(MessageTemplate::kNormalizationForm, valid_forms));
1121 } 983 }
1122 984
1123 return *string; 985 return *string;
1124 } 986 }
1125 987
1126 // ES6 section B.2.3.1 String.prototype.substr ( start, length ) 988 // ES6 section B.2.3.1 String.prototype.substr ( start, length )
1127 void Builtins::Generate_StringPrototypeSubstr( 989 TF_BUILTIN(StringPrototypeSubstr, CodeStubAssembler) {
1128 compiler::CodeAssemblerState* state) { 990 Label out(this), handle_length(this);
1129 typedef CodeStubAssembler::Label Label; 991
1130 typedef compiler::Node Node; 992 Variable var_start(this, MachineRepresentation::kTagged);
1131 typedef CodeStubAssembler::Variable Variable; 993 Variable var_length(this, MachineRepresentation::kTagged);
1132 CodeStubAssembler a(state); 994
1133 995 Node* const receiver = Parameter(0);
1134 Label out(&a), handle_length(&a); 996 Node* const start = Parameter(1);
1135 997 Node* const length = Parameter(2);
1136 Variable var_start(&a, MachineRepresentation::kTagged); 998 Node* const context = Parameter(5);
1137 Variable var_length(&a, MachineRepresentation::kTagged); 999
1138 1000 Node* const zero = SmiConstant(Smi::kZero);
1139 Node* const receiver = a.Parameter(0);
1140 Node* const start = a.Parameter(1);
1141 Node* const length = a.Parameter(2);
1142 Node* const context = a.Parameter(5);
1143
1144 Node* const zero = a.SmiConstant(Smi::kZero);
1145 1001
1146 // Check that {receiver} is coercible to Object and convert it to a String. 1002 // Check that {receiver} is coercible to Object and convert it to a String.
1147 Node* const string = 1003 Node* const string =
1148 a.ToThisString(context, receiver, "String.prototype.substr"); 1004 ToThisString(context, receiver, "String.prototype.substr");
1149 1005
1150 Node* const string_length = a.LoadStringLength(string); 1006 Node* const string_length = LoadStringLength(string);
1151 1007
1152 // Conversions and bounds-checks for {start}. 1008 // Conversions and bounds-checks for {start}.
1153 { 1009 {
1154 Node* const start_int = 1010 Node* const start_int =
1155 a.ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero); 1011 ToInteger(context, start, CodeStubAssembler::kTruncateMinusZero);
1156 1012
1157 Label if_issmi(&a), if_isheapnumber(&a, Label::kDeferred); 1013 Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
1158 a.Branch(a.TaggedIsSmi(start_int), &if_issmi, &if_isheapnumber); 1014 Branch(TaggedIsSmi(start_int), &if_issmi, &if_isheapnumber);
1159 1015
1160 a.Bind(&if_issmi); 1016 Bind(&if_issmi);
1161 { 1017 {
1162 Node* const length_plus_start = a.SmiAdd(string_length, start_int); 1018 Node* const length_plus_start = SmiAdd(string_length, start_int);
1163 var_start.Bind(a.Select(a.SmiLessThan(start_int, zero), 1019 var_start.Bind(Select(SmiLessThan(start_int, zero),
1164 [&] { return a.SmiMax(length_plus_start, zero); }, 1020 [&] { return SmiMax(length_plus_start, zero); },
1165 [&] { return start_int; }, 1021 [&] { return start_int; },
1166 MachineRepresentation::kTagged)); 1022 MachineRepresentation::kTagged));
1167 a.Goto(&handle_length); 1023 Goto(&handle_length);
1168 } 1024 }
1169 1025
1170 a.Bind(&if_isheapnumber); 1026 Bind(&if_isheapnumber);
1171 { 1027 {
1172 // If {start} is a heap number, it is definitely out of bounds. If it is 1028 // If {start} is a heap number, it is definitely out of bounds. If it is
1173 // negative, {start} = max({string_length} + {start}),0) = 0'. If it is 1029 // negative, {start} = max({string_length} + {start}),0) = 0'. If it is
1174 // positive, set {start} to {string_length} which ultimately results in 1030 // positive, set {start} to {string_length} which ultimately results in
1175 // returning an empty string. 1031 // returning an empty string.
1176 Node* const float_zero = a.Float64Constant(0.); 1032 Node* const float_zero = Float64Constant(0.);
1177 Node* const start_float = a.LoadHeapNumberValue(start_int); 1033 Node* const start_float = LoadHeapNumberValue(start_int);
1178 var_start.Bind(a.SelectTaggedConstant( 1034 var_start.Bind(SelectTaggedConstant(
1179 a.Float64LessThan(start_float, float_zero), zero, string_length)); 1035 Float64LessThan(start_float, float_zero), zero, string_length));
1180 a.Goto(&handle_length); 1036 Goto(&handle_length);
1181 } 1037 }
1182 } 1038 }
1183 1039
1184 // Conversions and bounds-checks for {length}. 1040 // Conversions and bounds-checks for {length}.
1185 a.Bind(&handle_length); 1041 Bind(&handle_length);
1186 { 1042 {
1187 Label if_issmi(&a), if_isheapnumber(&a, Label::kDeferred); 1043 Label if_issmi(this), if_isheapnumber(this, Label::kDeferred);
1188 1044
1189 // Default to {string_length} if {length} is undefined. 1045 // Default to {string_length} if {length} is undefined.
1190 { 1046 {
1191 Label if_isundefined(&a, Label::kDeferred), if_isnotundefined(&a); 1047 Label if_isundefined(this, Label::kDeferred), if_isnotundefined(this);
1192 a.Branch(a.WordEqual(length, a.UndefinedConstant()), &if_isundefined, 1048 Branch(WordEqual(length, UndefinedConstant()), &if_isundefined,
1193 &if_isnotundefined); 1049 &if_isnotundefined);
1194 1050
1195 a.Bind(&if_isundefined); 1051 Bind(&if_isundefined);
1196 var_length.Bind(string_length); 1052 var_length.Bind(string_length);
1197 a.Goto(&if_issmi); 1053 Goto(&if_issmi);
1198 1054
1199 a.Bind(&if_isnotundefined); 1055 Bind(&if_isnotundefined);
1200 var_length.Bind( 1056 var_length.Bind(
1201 a.ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero)); 1057 ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero));
1202 } 1058 }
1203 1059
1204 a.Branch(a.TaggedIsSmi(var_length.value()), &if_issmi, &if_isheapnumber); 1060 Branch(TaggedIsSmi(var_length.value()), &if_issmi, &if_isheapnumber);
1205 1061
1206 // Set {length} to min(max({length}, 0), {string_length} - {start} 1062 // Set {length} to min(max({length}, 0), {string_length} - {start}
1207 a.Bind(&if_issmi); 1063 Bind(&if_issmi);
1208 { 1064 {
1209 Node* const positive_length = a.SmiMax(var_length.value(), zero); 1065 Node* const positive_length = SmiMax(var_length.value(), zero);
1210 1066
1211 Node* const minimal_length = a.SmiSub(string_length, var_start.value()); 1067 Node* const minimal_length = SmiSub(string_length, var_start.value());
1212 var_length.Bind(a.SmiMin(positive_length, minimal_length)); 1068 var_length.Bind(SmiMin(positive_length, minimal_length));
1213 1069
1214 a.GotoUnless(a.SmiLessThanOrEqual(var_length.value(), zero), &out); 1070 GotoUnless(SmiLessThanOrEqual(var_length.value(), zero), &out);
1215 a.Return(a.EmptyStringConstant()); 1071 Return(EmptyStringConstant());
1216 } 1072 }
1217 1073
1218 a.Bind(&if_isheapnumber); 1074 Bind(&if_isheapnumber);
1219 { 1075 {
1220 // If {length} is a heap number, it is definitely out of bounds. There are 1076 // If {length} is a heap number, it is definitely out of bounds. There are
1221 // two cases according to the spec: if it is negative, "" is returned; if 1077 // two cases according to the spec: if it is negative, "" is returned; if
1222 // it is positive, then length is set to {string_length} - {start}. 1078 // it is positive, then length is set to {string_length} - {start}.
1223 1079
1224 CSA_ASSERT(&a, a.IsHeapNumberMap(a.LoadMap(var_length.value()))); 1080 CSA_ASSERT(this, IsHeapNumberMap(LoadMap(var_length.value())));
1225 1081
1226 Label if_isnegative(&a), if_ispositive(&a); 1082 Label if_isnegative(this), if_ispositive(this);
1227 Node* const float_zero = a.Float64Constant(0.); 1083 Node* const float_zero = Float64Constant(0.);
1228 Node* const length_float = a.LoadHeapNumberValue(var_length.value()); 1084 Node* const length_float = LoadHeapNumberValue(var_length.value());
1229 a.Branch(a.Float64LessThan(length_float, float_zero), &if_isnegative, 1085 Branch(Float64LessThan(length_float, float_zero), &if_isnegative,
1230 &if_ispositive); 1086 &if_ispositive);
1231 1087
1232 a.Bind(&if_isnegative); 1088 Bind(&if_isnegative);
1233 a.Return(a.EmptyStringConstant()); 1089 Return(EmptyStringConstant());
1234 1090
1235 a.Bind(&if_ispositive); 1091 Bind(&if_ispositive);
1236 { 1092 {
1237 var_length.Bind(a.SmiSub(string_length, var_start.value())); 1093 var_length.Bind(SmiSub(string_length, var_start.value()));
1238 a.GotoUnless(a.SmiLessThanOrEqual(var_length.value(), zero), &out); 1094 GotoUnless(SmiLessThanOrEqual(var_length.value(), zero), &out);
1239 a.Return(a.EmptyStringConstant()); 1095 Return(EmptyStringConstant());
1240 } 1096 }
1241 } 1097 }
1242 } 1098 }
1243 1099
1244 a.Bind(&out); 1100 Bind(&out);
1245 { 1101 {
1246 Node* const end = a.SmiAdd(var_start.value(), var_length.value()); 1102 Node* const end = SmiAdd(var_start.value(), var_length.value());
1247 Node* const result = a.SubString(context, string, var_start.value(), end); 1103 Node* const result = SubString(context, string, var_start.value(), end);
1248 a.Return(result); 1104 Return(result);
1249 } 1105 }
1250 } 1106 }
1251 1107
1252 namespace { 1108 compiler::Node* StringBuiltinsAssembler::ToSmiBetweenZeroAnd(Node* context,
1253 1109 Node* value,
1254 compiler::Node* ToSmiBetweenZeroAnd(CodeStubAssembler* a, 1110 Node* limit) {
1255 compiler::Node* context, 1111 Label out(this);
1256 compiler::Node* value, 1112 Variable var_result(this, MachineRepresentation::kTagged);
1257 compiler::Node* limit) {
1258 typedef CodeStubAssembler::Label Label;
1259 typedef compiler::Node Node;
1260 typedef CodeStubAssembler::Variable Variable;
1261
1262 Label out(a);
1263 Variable var_result(a, MachineRepresentation::kTagged);
1264 1113
1265 Node* const value_int = 1114 Node* const value_int =
1266 a->ToInteger(context, value, CodeStubAssembler::kTruncateMinusZero); 1115 this->ToInteger(context, value, CodeStubAssembler::kTruncateMinusZero);
1267 1116
1268 Label if_issmi(a), if_isnotsmi(a, Label::kDeferred); 1117 Label if_issmi(this), if_isnotsmi(this, Label::kDeferred);
1269 a->Branch(a->TaggedIsSmi(value_int), &if_issmi, &if_isnotsmi); 1118 Branch(TaggedIsSmi(value_int), &if_issmi, &if_isnotsmi);
1270 1119
1271 a->Bind(&if_issmi); 1120 Bind(&if_issmi);
1272 { 1121 {
1273 Label if_isinbounds(a), if_isoutofbounds(a, Label::kDeferred); 1122 Label if_isinbounds(this), if_isoutofbounds(this, Label::kDeferred);
1274 a->Branch(a->SmiAbove(value_int, limit), &if_isoutofbounds, &if_isinbounds); 1123 Branch(SmiAbove(value_int, limit), &if_isoutofbounds, &if_isinbounds);
1275 1124
1276 a->Bind(&if_isinbounds); 1125 Bind(&if_isinbounds);
1277 { 1126 {
1278 var_result.Bind(value_int); 1127 var_result.Bind(value_int);
1279 a->Goto(&out); 1128 Goto(&out);
1280 } 1129 }
1281 1130
1282 a->Bind(&if_isoutofbounds); 1131 Bind(&if_isoutofbounds);
1283 { 1132 {
1284 Node* const zero = a->SmiConstant(Smi::kZero); 1133 Node* const zero = SmiConstant(Smi::kZero);
1285 var_result.Bind(a->SelectTaggedConstant(a->SmiLessThan(value_int, zero), 1134 var_result.Bind(
1286 zero, limit)); 1135 SelectTaggedConstant(SmiLessThan(value_int, zero), zero, limit));
1287 a->Goto(&out); 1136 Goto(&out);
1288 } 1137 }
1289 } 1138 }
1290 1139
1291 a->Bind(&if_isnotsmi); 1140 Bind(&if_isnotsmi);
1292 { 1141 {
1293 // {value} is a heap number - in this case, it is definitely out of bounds. 1142 // {value} is a heap number - in this case, it is definitely out of bounds.
1294 CSA_ASSERT(a, a->IsHeapNumberMap(a->LoadMap(value_int))); 1143 CSA_ASSERT(this, IsHeapNumberMap(LoadMap(value_int)));
1295 1144
1296 Node* const float_zero = a->Float64Constant(0.); 1145 Node* const float_zero = Float64Constant(0.);
1297 Node* const smi_zero = a->SmiConstant(Smi::kZero); 1146 Node* const smi_zero = SmiConstant(Smi::kZero);
1298 Node* const value_float = a->LoadHeapNumberValue(value_int); 1147 Node* const value_float = LoadHeapNumberValue(value_int);
1299 var_result.Bind(a->SelectTaggedConstant( 1148 var_result.Bind(SelectTaggedConstant(
1300 a->Float64LessThan(value_float, float_zero), smi_zero, limit)); 1149 Float64LessThan(value_float, float_zero), smi_zero, limit));
1301 a->Goto(&out); 1150 Goto(&out);
1302 } 1151 }
1303 1152
1304 a->Bind(&out); 1153 Bind(&out);
1305 return var_result.value(); 1154 return var_result.value();
1306 } 1155 }
1307 1156
1308 } // namespace
1309
1310 // ES6 section 21.1.3.19 String.prototype.substring ( start, end ) 1157 // ES6 section 21.1.3.19 String.prototype.substring ( start, end )
1311 void Builtins::Generate_StringPrototypeSubstring( 1158 TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) {
1312 compiler::CodeAssemblerState* state) { 1159 Label out(this);
1313 typedef CodeStubAssembler::Label Label; 1160
1314 typedef compiler::Node Node; 1161 Variable var_start(this, MachineRepresentation::kTagged);
1315 typedef CodeStubAssembler::Variable Variable; 1162 Variable var_end(this, MachineRepresentation::kTagged);
1316 CodeStubAssembler a(state); 1163
1317 1164 Node* const receiver = Parameter(0);
1318 Label out(&a); 1165 Node* const start = Parameter(1);
1319 1166 Node* const end = Parameter(2);
1320 Variable var_start(&a, MachineRepresentation::kTagged); 1167 Node* const context = Parameter(5);
1321 Variable var_end(&a, MachineRepresentation::kTagged);
1322
1323 Node* const receiver = a.Parameter(0);
1324 Node* const start = a.Parameter(1);
1325 Node* const end = a.Parameter(2);
1326 Node* const context = a.Parameter(5);
1327 1168
1328 // Check that {receiver} is coercible to Object and convert it to a String. 1169 // Check that {receiver} is coercible to Object and convert it to a String.
1329 Node* const string = 1170 Node* const string =
1330 a.ToThisString(context, receiver, "String.prototype.substring"); 1171 ToThisString(context, receiver, "String.prototype.substring");
1331 1172
1332 Node* const length = a.LoadStringLength(string); 1173 Node* const length = LoadStringLength(string);
1333 1174
1334 // Conversion and bounds-checks for {start}. 1175 // Conversion and bounds-checks for {start}.
1335 var_start.Bind(ToSmiBetweenZeroAnd(&a, context, start, length)); 1176 var_start.Bind(ToSmiBetweenZeroAnd(context, start, length));
1336 1177
1337 // Conversion and bounds-checks for {end}. 1178 // Conversion and bounds-checks for {end}.
1338 { 1179 {
1339 var_end.Bind(length); 1180 var_end.Bind(length);
1340 a.GotoIf(a.WordEqual(end, a.UndefinedConstant()), &out); 1181 GotoIf(WordEqual(end, UndefinedConstant()), &out);
1341 1182
1342 var_end.Bind(ToSmiBetweenZeroAnd(&a, context, end, length)); 1183 var_end.Bind(ToSmiBetweenZeroAnd(context, end, length));
1343 1184
1344 Label if_endislessthanstart(&a); 1185 Label if_endislessthanstart(this);
1345 a.Branch(a.SmiLessThan(var_end.value(), var_start.value()), 1186 Branch(SmiLessThan(var_end.value(), var_start.value()),
1346 &if_endislessthanstart, &out); 1187 &if_endislessthanstart, &out);
1347 1188
1348 a.Bind(&if_endislessthanstart); 1189 Bind(&if_endislessthanstart);
1349 { 1190 {
1350 Node* const tmp = var_end.value(); 1191 Node* const tmp = var_end.value();
1351 var_end.Bind(var_start.value()); 1192 var_end.Bind(var_start.value());
1352 var_start.Bind(tmp); 1193 var_start.Bind(tmp);
1353 a.Goto(&out); 1194 Goto(&out);
1354 } 1195 }
1355 } 1196 }
1356 1197
1357 a.Bind(&out); 1198 Bind(&out);
1358 { 1199 {
1359 Node* result = 1200 Node* result =
1360 a.SubString(context, string, var_start.value(), var_end.value()); 1201 SubString(context, string, var_start.value(), var_end.value());
1361 a.Return(result); 1202 Return(result);
1362 } 1203 }
1363 } 1204 }
1364 1205
1365 BUILTIN(StringPrototypeStartsWith) { 1206 BUILTIN(StringPrototypeStartsWith) {
1366 HandleScope handle_scope(isolate); 1207 HandleScope handle_scope(isolate);
1367 TO_THIS_STRING(str, "String.prototype.startsWith"); 1208 TO_THIS_STRING(str, "String.prototype.startsWith");
1368 1209
1369 // Check if the search string is a regExp and fail if it is. 1210 // Check if the search string is a regExp and fail if it is.
1370 Handle<Object> search = args.atOrUndefined(isolate, 1); 1211 Handle<Object> search = args.atOrUndefined(isolate, 1);
1371 Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search); 1212 Maybe<bool> is_reg_exp = RegExpUtils::IsRegExp(isolate, search);
1372 if (is_reg_exp.IsNothing()) { 1213 if (is_reg_exp.IsNothing()) {
1373 DCHECK(isolate->has_pending_exception()); 1214 DCHECK(isolate->has_pending_exception());
1374 return isolate->heap()->exception(); 1215 return isolate->heap()->exception();
(...skipping 28 matching lines...) Expand all
1403 1244
1404 for (int i = 0; i < search_string->length(); i++) { 1245 for (int i = 0; i < search_string->length(); i++) {
1405 if (str_reader.Get(start + i) != search_reader.Get(i)) { 1246 if (str_reader.Get(start + i) != search_reader.Get(i)) {
1406 return isolate->heap()->false_value(); 1247 return isolate->heap()->false_value();
1407 } 1248 }
1408 } 1249 }
1409 return isolate->heap()->true_value(); 1250 return isolate->heap()->true_value();
1410 } 1251 }
1411 1252
1412 // ES6 section 21.1.3.25 String.prototype.toString () 1253 // ES6 section 21.1.3.25 String.prototype.toString ()
1413 void Builtins::Generate_StringPrototypeToString( 1254 TF_BUILTIN(StringPrototypeToString, CodeStubAssembler) {
1414 compiler::CodeAssemblerState* state) { 1255 Node* receiver = Parameter(0);
1415 typedef compiler::Node Node; 1256 Node* context = Parameter(3);
1416 CodeStubAssembler assembler(state);
1417 1257
1418 Node* receiver = assembler.Parameter(0); 1258 Node* result = ToThisValue(context, receiver, PrimitiveType::kString,
1419 Node* context = assembler.Parameter(3); 1259 "String.prototype.toString");
1420 1260 Return(result);
1421 Node* result = assembler.ToThisValue(
1422 context, receiver, PrimitiveType::kString, "String.prototype.toString");
1423 assembler.Return(result);
1424 } 1261 }
1425 1262
1426 // ES6 section 21.1.3.27 String.prototype.trim () 1263 // ES6 section 21.1.3.27 String.prototype.trim ()
1427 BUILTIN(StringPrototypeTrim) { 1264 BUILTIN(StringPrototypeTrim) {
1428 HandleScope scope(isolate); 1265 HandleScope scope(isolate);
1429 TO_THIS_STRING(string, "String.prototype.trim"); 1266 TO_THIS_STRING(string, "String.prototype.trim");
1430 return *String::Trim(string, String::kTrim); 1267 return *String::Trim(string, String::kTrim);
1431 } 1268 }
1432 1269
1433 // Non-standard WebKit extension 1270 // Non-standard WebKit extension
1434 BUILTIN(StringPrototypeTrimLeft) { 1271 BUILTIN(StringPrototypeTrimLeft) {
1435 HandleScope scope(isolate); 1272 HandleScope scope(isolate);
1436 TO_THIS_STRING(string, "String.prototype.trimLeft"); 1273 TO_THIS_STRING(string, "String.prototype.trimLeft");
1437 return *String::Trim(string, String::kTrimLeft); 1274 return *String::Trim(string, String::kTrimLeft);
1438 } 1275 }
1439 1276
1440 // Non-standard WebKit extension 1277 // Non-standard WebKit extension
1441 BUILTIN(StringPrototypeTrimRight) { 1278 BUILTIN(StringPrototypeTrimRight) {
1442 HandleScope scope(isolate); 1279 HandleScope scope(isolate);
1443 TO_THIS_STRING(string, "String.prototype.trimRight"); 1280 TO_THIS_STRING(string, "String.prototype.trimRight");
1444 return *String::Trim(string, String::kTrimRight); 1281 return *String::Trim(string, String::kTrimRight);
1445 } 1282 }
1446 1283
1447 // ES6 section 21.1.3.28 String.prototype.valueOf ( ) 1284 // ES6 section 21.1.3.28 String.prototype.valueOf ( )
1448 void Builtins::Generate_StringPrototypeValueOf( 1285 TF_BUILTIN(StringPrototypeValueOf, CodeStubAssembler) {
1449 compiler::CodeAssemblerState* state) { 1286 Node* receiver = Parameter(0);
1450 typedef compiler::Node Node; 1287 Node* context = Parameter(3);
1451 CodeStubAssembler assembler(state);
1452 1288
1453 Node* receiver = assembler.Parameter(0); 1289 Node* result = ToThisValue(context, receiver, PrimitiveType::kString,
1454 Node* context = assembler.Parameter(3); 1290 "String.prototype.valueOf");
1455 1291 Return(result);
1456 Node* result = assembler.ToThisValue(
1457 context, receiver, PrimitiveType::kString, "String.prototype.valueOf");
1458 assembler.Return(result);
1459 } 1292 }
1460 1293
1461 void Builtins::Generate_StringPrototypeIterator( 1294 TF_BUILTIN(StringPrototypeIterator, CodeStubAssembler) {
1462 compiler::CodeAssemblerState* state) { 1295 Node* receiver = Parameter(0);
1463 typedef compiler::Node Node; 1296 Node* context = Parameter(3);
1464 CodeStubAssembler assembler(state);
1465 1297
1466 Node* receiver = assembler.Parameter(0); 1298 Node* string =
1467 Node* context = assembler.Parameter(3); 1299 ToThisString(context, receiver, "String.prototype[Symbol.iterator]");
1468 1300
1469 Node* string = assembler.ToThisString(context, receiver, 1301 Node* native_context = LoadNativeContext(context);
1470 "String.prototype[Symbol.iterator]"); 1302 Node* map =
1471 1303 LoadContextElement(native_context, Context::STRING_ITERATOR_MAP_INDEX);
1472 Node* native_context = assembler.LoadNativeContext(context); 1304 Node* iterator = Allocate(JSStringIterator::kSize);
1473 Node* map = assembler.LoadContextElement(native_context, 1305 StoreMapNoWriteBarrier(iterator, map);
1474 Context::STRING_ITERATOR_MAP_INDEX); 1306 StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset,
1475 Node* iterator = assembler.Allocate(JSStringIterator::kSize); 1307 Heap::kEmptyFixedArrayRootIndex);
1476 assembler.StoreMapNoWriteBarrier(iterator, map); 1308 StoreObjectFieldRoot(iterator, JSObject::kElementsOffset,
1477 assembler.StoreObjectFieldRoot(iterator, JSValue::kPropertiesOffset, 1309 Heap::kEmptyFixedArrayRootIndex);
1478 Heap::kEmptyFixedArrayRootIndex); 1310 StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kStringOffset,
1479 assembler.StoreObjectFieldRoot(iterator, JSObject::kElementsOffset, 1311 string);
1480 Heap::kEmptyFixedArrayRootIndex); 1312 Node* index = SmiConstant(Smi::kZero);
1481 assembler.StoreObjectFieldNoWriteBarrier( 1313 StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kNextIndexOffset,
1482 iterator, JSStringIterator::kStringOffset, string); 1314 index);
1483 Node* index = assembler.SmiConstant(Smi::kZero); 1315 Return(iterator);
1484 assembler.StoreObjectFieldNoWriteBarrier(
1485 iterator, JSStringIterator::kNextIndexOffset, index);
1486 assembler.Return(iterator);
1487 } 1316 }
1488 1317
1489 namespace {
1490
1491 // Return the |word32| codepoint at {index}. Supports SeqStrings and 1318 // Return the |word32| codepoint at {index}. Supports SeqStrings and
1492 // ExternalStrings. 1319 // ExternalStrings.
1493 compiler::Node* LoadSurrogatePairInternal(CodeStubAssembler* assembler, 1320 compiler::Node* StringBuiltinsAssembler::LoadSurrogatePairAt(
1494 compiler::Node* string, 1321 compiler::Node* string, compiler::Node* length, compiler::Node* index,
1495 compiler::Node* length, 1322 UnicodeEncoding encoding) {
1496 compiler::Node* index, 1323 Label handle_surrogate_pair(this), return_result(this);
1497 UnicodeEncoding encoding) { 1324 Variable var_result(this, MachineRepresentation::kWord32);
1498 typedef CodeStubAssembler::Label Label; 1325 Variable var_trail(this, MachineRepresentation::kWord32);
1499 typedef compiler::Node Node; 1326 var_result.Bind(StringCharCodeAt(string, index));
1500 typedef CodeStubAssembler::Variable Variable; 1327 var_trail.Bind(Int32Constant(0));
1501 Label handle_surrogate_pair(assembler), return_result(assembler);
1502 Variable var_result(assembler, MachineRepresentation::kWord32);
1503 Variable var_trail(assembler, MachineRepresentation::kWord32);
1504 var_result.Bind(assembler->StringCharCodeAt(string, index));
1505 var_trail.Bind(assembler->Int32Constant(0));
1506 1328
1507 assembler->GotoIf(assembler->Word32NotEqual( 1329 GotoIf(Word32NotEqual(Word32And(var_result.value(), Int32Constant(0xFC00)),
1508 assembler->Word32And(var_result.value(), 1330 Int32Constant(0xD800)),
1509 assembler->Int32Constant(0xFC00)), 1331 &return_result);
1510 assembler->Int32Constant(0xD800)), 1332 Node* next_index = SmiAdd(index, SmiConstant(Smi::FromInt(1)));
1511 &return_result);
1512 Node* next_index =
1513 assembler->SmiAdd(index, assembler->SmiConstant(Smi::FromInt(1)));
1514 1333
1515 assembler->GotoUnless(assembler->SmiLessThan(next_index, length), 1334 GotoUnless(SmiLessThan(next_index, length), &return_result);
1516 &return_result); 1335 var_trail.Bind(StringCharCodeAt(string, next_index));
1517 var_trail.Bind(assembler->StringCharCodeAt(string, next_index)); 1336 Branch(Word32Equal(Word32And(var_trail.value(), Int32Constant(0xFC00)),
1518 assembler->Branch(assembler->Word32Equal( 1337 Int32Constant(0xDC00)),
1519 assembler->Word32And(var_trail.value(), 1338 &handle_surrogate_pair, &return_result);
1520 assembler->Int32Constant(0xFC00)),
1521 assembler->Int32Constant(0xDC00)),
1522 &handle_surrogate_pair, &return_result);
1523 1339
1524 assembler->Bind(&handle_surrogate_pair); 1340 Bind(&handle_surrogate_pair);
1525 { 1341 {
1526 Node* lead = var_result.value(); 1342 Node* lead = var_result.value();
1527 Node* trail = var_trail.value(); 1343 Node* trail = var_trail.value();
1528 1344
1529 // Check that this path is only taken if a surrogate pair is found 1345 // Check that this path is only taken if a surrogate pair is found
1530 CSA_SLOW_ASSERT(assembler, assembler->Uint32GreaterThanOrEqual( 1346 CSA_SLOW_ASSERT(this,
1531 lead, assembler->Int32Constant(0xD800))); 1347 Uint32GreaterThanOrEqual(lead, Int32Constant(0xD800)));
1532 CSA_SLOW_ASSERT(assembler, assembler->Uint32LessThan( 1348 CSA_SLOW_ASSERT(this, Uint32LessThan(lead, Int32Constant(0xDC00)));
1533 lead, assembler->Int32Constant(0xDC00))); 1349 CSA_SLOW_ASSERT(this,
1534 CSA_SLOW_ASSERT(assembler, assembler->Uint32GreaterThanOrEqual( 1350 Uint32GreaterThanOrEqual(trail, Int32Constant(0xDC00)));
1535 trail, assembler->Int32Constant(0xDC00))); 1351 CSA_SLOW_ASSERT(this, Uint32LessThan(trail, Int32Constant(0xE000)));
1536 CSA_SLOW_ASSERT(assembler, assembler->Uint32LessThan(
1537 trail, assembler->Int32Constant(0xE000)));
1538 1352
1539 switch (encoding) { 1353 switch (encoding) {
1540 case UnicodeEncoding::UTF16: 1354 case UnicodeEncoding::UTF16:
1541 var_result.Bind(assembler->Word32Or( 1355 var_result.Bind(Word32Or(
1542 // Need to swap the order for big-endian platforms 1356 // Need to swap the order for big-endian platforms
1543 #if V8_TARGET_BIG_ENDIAN 1357 #if V8_TARGET_BIG_ENDIAN
1544 assembler->Word32Shl(lead, assembler->Int32Constant(16)), trail)); 1358 Word32Shl(lead, Int32Constant(16)), trail));
1545 #else 1359 #else
1546 assembler->Word32Shl(trail, assembler->Int32Constant(16)), lead)); 1360 Word32Shl(trail, Int32Constant(16)), lead));
1547 #endif 1361 #endif
1548 break; 1362 break;
1549 1363
1550 case UnicodeEncoding::UTF32: { 1364 case UnicodeEncoding::UTF32: {
1551 // Convert UTF16 surrogate pair into |word32| code point, encoded as 1365 // Convert UTF16 surrogate pair into |word32| code point, encoded as
1552 // UTF32. 1366 // UTF32.
1553 Node* surrogate_offset = 1367 Node* surrogate_offset =
1554 assembler->Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00); 1368 Int32Constant(0x10000 - (0xD800 << 10) - 0xDC00);
1555 1369
1556 // (lead << 10) + trail + SURROGATE_OFFSET 1370 // (lead << 10) + trail + SURROGATE_OFFSET
1557 var_result.Bind(assembler->Int32Add( 1371 var_result.Bind(Int32Add(WordShl(lead, Int32Constant(10)),
1558 assembler->WordShl(lead, assembler->Int32Constant(10)), 1372 Int32Add(trail, surrogate_offset)));
1559 assembler->Int32Add(trail, surrogate_offset)));
1560 break; 1373 break;
1561 } 1374 }
1562 } 1375 }
1563 assembler->Goto(&return_result); 1376 Goto(&return_result);
1564 } 1377 }
1565 1378
1566 assembler->Bind(&return_result); 1379 Bind(&return_result);
1567 return var_result.value(); 1380 return var_result.value();
1568 } 1381 }
1569 1382
1570 compiler::Node* LoadSurrogatePairAt(CodeStubAssembler* assembler, 1383 TF_BUILTIN(StringIteratorPrototypeNext, StringBuiltinsAssembler) {
1571 compiler::Node* string, 1384 Variable var_value(this, MachineRepresentation::kTagged);
1572 compiler::Node* length, 1385 Variable var_done(this, MachineRepresentation::kTagged);
1573 compiler::Node* index) {
1574 return LoadSurrogatePairInternal(assembler, string, length, index,
1575 UnicodeEncoding::UTF16);
1576 }
1577 1386
1578 } // namespace 1387 var_value.Bind(UndefinedConstant());
1388 var_done.Bind(BooleanConstant(true));
1579 1389
1580 void Builtins::Generate_StringIteratorPrototypeNext( 1390 Label throw_bad_receiver(this), next_codepoint(this), return_result(this);
1581 compiler::CodeAssemblerState* state) {
1582 typedef CodeStubAssembler::Label Label;
1583 typedef compiler::Node Node;
1584 typedef CodeStubAssembler::Variable Variable;
1585 CodeStubAssembler assembler(state);
1586 1391
1587 Variable var_value(&assembler, MachineRepresentation::kTagged); 1392 Node* iterator = Parameter(0);
1588 Variable var_done(&assembler, MachineRepresentation::kTagged); 1393 Node* context = Parameter(3);
1589 1394
1590 var_value.Bind(assembler.UndefinedConstant()); 1395 GotoIf(TaggedIsSmi(iterator), &throw_bad_receiver);
1591 var_done.Bind(assembler.BooleanConstant(true)); 1396 GotoUnless(Word32Equal(LoadInstanceType(iterator),
1397 Int32Constant(JS_STRING_ITERATOR_TYPE)),
1398 &throw_bad_receiver);
1592 1399
1593 Label throw_bad_receiver(&assembler), next_codepoint(&assembler), 1400 Node* string = LoadObjectField(iterator, JSStringIterator::kStringOffset);
1594 return_result(&assembler); 1401 Node* position =
1402 LoadObjectField(iterator, JSStringIterator::kNextIndexOffset);
1403 Node* length = LoadObjectField(string, String::kLengthOffset);
1595 1404
1596 Node* iterator = assembler.Parameter(0); 1405 Branch(SmiLessThan(position, length), &next_codepoint, &return_result);
1597 Node* context = assembler.Parameter(3);
1598 1406
1599 assembler.GotoIf(assembler.TaggedIsSmi(iterator), &throw_bad_receiver); 1407 Bind(&next_codepoint);
1600 assembler.GotoUnless(
1601 assembler.Word32Equal(assembler.LoadInstanceType(iterator),
1602 assembler.Int32Constant(JS_STRING_ITERATOR_TYPE)),
1603 &throw_bad_receiver);
1604
1605 Node* string =
1606 assembler.LoadObjectField(iterator, JSStringIterator::kStringOffset);
1607 Node* position =
1608 assembler.LoadObjectField(iterator, JSStringIterator::kNextIndexOffset);
1609 Node* length = assembler.LoadObjectField(string, String::kLengthOffset);
1610
1611 assembler.Branch(assembler.SmiLessThan(position, length), &next_codepoint,
1612 &return_result);
1613
1614 assembler.Bind(&next_codepoint);
1615 { 1408 {
1616 Node* ch = LoadSurrogatePairAt(&assembler, string, length, position); 1409 UnicodeEncoding encoding = UnicodeEncoding::UTF16;
1617 Node* value = assembler.StringFromCodePoint(ch, UnicodeEncoding::UTF16); 1410 Node* ch = LoadSurrogatePairAt(string, length, position, encoding);
1411 Node* value = StringFromCodePoint(ch, encoding);
1618 var_value.Bind(value); 1412 var_value.Bind(value);
1619 Node* length = assembler.LoadObjectField(value, String::kLengthOffset); 1413 Node* length = LoadObjectField(value, String::kLengthOffset);
1620 assembler.StoreObjectFieldNoWriteBarrier( 1414 StoreObjectFieldNoWriteBarrier(iterator, JSStringIterator::kNextIndexOffset,
1621 iterator, JSStringIterator::kNextIndexOffset, 1415 SmiAdd(position, length));
1622 assembler.SmiAdd(position, length)); 1416 var_done.Bind(BooleanConstant(false));
1623 var_done.Bind(assembler.BooleanConstant(false)); 1417 Goto(&return_result);
1624 assembler.Goto(&return_result);
1625 } 1418 }
1626 1419
1627 assembler.Bind(&return_result); 1420 Bind(&return_result);
1628 { 1421 {
1629 Node* native_context = assembler.LoadNativeContext(context); 1422 Node* native_context = LoadNativeContext(context);
1630 Node* map = assembler.LoadContextElement( 1423 Node* map =
1631 native_context, Context::ITERATOR_RESULT_MAP_INDEX); 1424 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
1632 Node* result = assembler.Allocate(JSIteratorResult::kSize); 1425 Node* result = Allocate(JSIteratorResult::kSize);
1633 assembler.StoreMapNoWriteBarrier(result, map); 1426 StoreMapNoWriteBarrier(result, map);
1634 assembler.StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset, 1427 StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOffset,
1635 Heap::kEmptyFixedArrayRootIndex); 1428 Heap::kEmptyFixedArrayRootIndex);
1636 assembler.StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset, 1429 StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
1637 Heap::kEmptyFixedArrayRootIndex); 1430 Heap::kEmptyFixedArrayRootIndex);
1638 assembler.StoreObjectFieldNoWriteBarrier( 1431 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset,
1639 result, JSIteratorResult::kValueOffset, var_value.value()); 1432 var_value.value());
1640 assembler.StoreObjectFieldNoWriteBarrier( 1433 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset,
1641 result, JSIteratorResult::kDoneOffset, var_done.value()); 1434 var_done.value());
1642 assembler.Return(result); 1435 Return(result);
1643 } 1436 }
1644 1437
1645 assembler.Bind(&throw_bad_receiver); 1438 Bind(&throw_bad_receiver);
1646 { 1439 {
1647 // The {receiver} is not a valid JSGeneratorObject. 1440 // The {receiver} is not a valid JSGeneratorObject.
1648 Node* result = assembler.CallRuntime( 1441 Node* result =
1649 Runtime::kThrowIncompatibleMethodReceiver, context, 1442 CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
1650 assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked( 1443 HeapConstant(factory()->NewStringFromAsciiChecked(
1651 "String Iterator.prototype.next", TENURED)), 1444 "String Iterator.prototype.next", TENURED)),
1652 iterator); 1445 iterator);
1653 assembler.Return(result); // Never reached. 1446 Return(result); // Never reached.
1654 } 1447 }
1655 } 1448 }
1656 1449
1657 } // namespace internal 1450 } // namespace internal
1658 } // namespace v8 1451 } // namespace v8
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698