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

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

Issue 2363333003: [turbofan] Lower StringEqual and friends in EffectControlLinearizer. (Closed)
Patch Set: Preinitialize interface descriptors and drop TODO. Created 4 years, 2 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 | « src/builtins/builtins.h ('k') | src/code-factory.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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.h" 5 #include "src/builtins/builtins.h"
6 #include "src/builtins/builtins-utils.h" 6 #include "src/builtins/builtins-utils.h"
7 7
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 9
10 namespace v8 { 10 namespace v8 {
11 namespace internal { 11 namespace internal {
12 12
13 namespace {
14
15 enum ResultMode { kDontNegateResult, kNegateResult };
16
17 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
18 // Here's pseudo-code for the algorithm below in case of kDontNegateResult
19 // mode; for kNegateResult mode we properly negate the result.
20 //
21 // if (lhs == rhs) return true;
22 // if (lhs->length() != rhs->length()) return false;
23 // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
24 // return false;
25 // }
26 // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
27 // for (i = 0; i != lhs->length(); ++i) {
28 // if (lhs[i] != rhs[i]) return false;
29 // }
30 // return true;
31 // }
32 // return %StringEqual(lhs, rhs);
33
34 typedef CodeStubAssembler::Label Label;
35 typedef compiler::Node Node;
36 typedef CodeStubAssembler::Variable Variable;
37
38 Node* lhs = assembler->Parameter(0);
39 Node* rhs = assembler->Parameter(1);
40 Node* context = assembler->Parameter(2);
41
42 Label if_equal(assembler), if_notequal(assembler);
43
44 // Fast check to see if {lhs} and {rhs} refer to the same String object.
45 Label if_same(assembler), if_notsame(assembler);
46 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
47
48 assembler->Bind(&if_same);
49 assembler->Goto(&if_equal);
50
51 assembler->Bind(&if_notsame);
52 {
53 // The {lhs} and {rhs} don't refer to the exact same String object.
54
55 // Load the length of {lhs} and {rhs}.
56 Node* lhs_length = assembler->LoadStringLength(lhs);
57 Node* rhs_length = assembler->LoadStringLength(rhs);
58
59 // Check if the lengths of {lhs} and {rhs} are equal.
60 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
61 assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
62 &if_lengthisequal, &if_lengthisnotequal);
63
64 assembler->Bind(&if_lengthisequal);
65 {
66 // Load instance types of {lhs} and {rhs}.
67 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
68 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
69
70 // Combine the instance types into a single 16-bit value, so we can check
71 // both of them at once.
72 Node* both_instance_types = assembler->Word32Or(
73 lhs_instance_type,
74 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
75
76 // Check if both {lhs} and {rhs} are internalized.
77 int const kBothInternalizedMask =
78 kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
79 int const kBothInternalizedTag =
80 kInternalizedTag | (kInternalizedTag << 8);
81 Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
82 assembler->Branch(assembler->Word32Equal(
83 assembler->Word32And(both_instance_types,
84 assembler->Int32Constant(
85 kBothInternalizedMask)),
86 assembler->Int32Constant(kBothInternalizedTag)),
87 &if_bothinternalized, &if_notbothinternalized);
88
89 assembler->Bind(&if_bothinternalized);
90 {
91 // Fast negative check for internalized-to-internalized equality.
92 assembler->Goto(&if_notequal);
93 }
94
95 assembler->Bind(&if_notbothinternalized);
96 {
97 // Check that both {lhs} and {rhs} are flat one-byte strings.
98 int const kBothSeqOneByteStringMask =
99 kStringEncodingMask | kStringRepresentationMask |
100 ((kStringEncodingMask | kStringRepresentationMask) << 8);
101 int const kBothSeqOneByteStringTag =
102 kOneByteStringTag | kSeqStringTag |
103 ((kOneByteStringTag | kSeqStringTag) << 8);
104 Label if_bothonebyteseqstrings(assembler),
105 if_notbothonebyteseqstrings(assembler);
106 assembler->Branch(
107 assembler->Word32Equal(
108 assembler->Word32And(
109 both_instance_types,
110 assembler->Int32Constant(kBothSeqOneByteStringMask)),
111 assembler->Int32Constant(kBothSeqOneByteStringTag)),
112 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
113
114 assembler->Bind(&if_bothonebyteseqstrings);
115 {
116 // Compute the effective offset of the first character.
117 Node* begin = assembler->IntPtrConstant(
118 SeqOneByteString::kHeaderSize - kHeapObjectTag);
119
120 // Compute the first offset after the string from the length.
121 Node* end =
122 assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
123
124 // Loop over the {lhs} and {rhs} strings to see if they are equal.
125 Variable var_offset(assembler, MachineType::PointerRepresentation());
126 Label loop(assembler, &var_offset);
127 var_offset.Bind(begin);
128 assembler->Goto(&loop);
129 assembler->Bind(&loop);
130 {
131 // Check if {offset} equals {end}.
132 Node* offset = var_offset.value();
133 Label if_done(assembler), if_notdone(assembler);
134 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
135 &if_notdone);
136
137 assembler->Bind(&if_notdone);
138 {
139 // Load the next characters from {lhs} and {rhs}.
140 Node* lhs_value =
141 assembler->Load(MachineType::Uint8(), lhs, offset);
142 Node* rhs_value =
143 assembler->Load(MachineType::Uint8(), rhs, offset);
144
145 // Check if the characters match.
146 Label if_valueissame(assembler), if_valueisnotsame(assembler);
147 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
148 &if_valueissame, &if_valueisnotsame);
149
150 assembler->Bind(&if_valueissame);
151 {
152 // Advance to next character.
153 var_offset.Bind(
154 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
155 }
156 assembler->Goto(&loop);
157
158 assembler->Bind(&if_valueisnotsame);
159 assembler->Goto(&if_notequal);
160 }
161
162 assembler->Bind(&if_done);
163 assembler->Goto(&if_equal);
164 }
165 }
166
167 assembler->Bind(&if_notbothonebyteseqstrings);
168 {
169 // TODO(bmeurer): Add fast case support for flattened cons strings;
170 // also add support for two byte string equality checks.
171 Runtime::FunctionId function_id = (mode == kDontNegateResult)
172 ? Runtime::kStringEqual
173 : Runtime::kStringNotEqual;
174 assembler->TailCallRuntime(function_id, context, lhs, rhs);
175 }
176 }
177 }
178
179 assembler->Bind(&if_lengthisnotequal);
180 {
181 // Mismatch in length of {lhs} and {rhs}, cannot be equal.
182 assembler->Goto(&if_notequal);
183 }
184 }
185
186 assembler->Bind(&if_equal);
187 assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
188
189 assembler->Bind(&if_notequal);
190 assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
191 }
192
193 enum RelationalComparisonMode {
194 kLessThan,
195 kLessThanOrEqual,
196 kGreaterThan,
197 kGreaterThanOrEqual
198 };
199
200 void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
201 RelationalComparisonMode mode) {
202 typedef CodeStubAssembler::Label Label;
203 typedef compiler::Node Node;
204 typedef CodeStubAssembler::Variable Variable;
205
206 Node* lhs = assembler->Parameter(0);
207 Node* rhs = assembler->Parameter(1);
208 Node* context = assembler->Parameter(2);
209
210 Label if_less(assembler), if_equal(assembler), if_greater(assembler);
211
212 // Fast check to see if {lhs} and {rhs} refer to the same String object.
213 Label if_same(assembler), if_notsame(assembler);
214 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
215
216 assembler->Bind(&if_same);
217 assembler->Goto(&if_equal);
218
219 assembler->Bind(&if_notsame);
220 {
221 // Load instance types of {lhs} and {rhs}.
222 Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
223 Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
224
225 // Combine the instance types into a single 16-bit value, so we can check
226 // both of them at once.
227 Node* both_instance_types = assembler->Word32Or(
228 lhs_instance_type,
229 assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
230
231 // Check that both {lhs} and {rhs} are flat one-byte strings.
232 int const kBothSeqOneByteStringMask =
233 kStringEncodingMask | kStringRepresentationMask |
234 ((kStringEncodingMask | kStringRepresentationMask) << 8);
235 int const kBothSeqOneByteStringTag =
236 kOneByteStringTag | kSeqStringTag |
237 ((kOneByteStringTag | kSeqStringTag) << 8);
238 Label if_bothonebyteseqstrings(assembler),
239 if_notbothonebyteseqstrings(assembler);
240 assembler->Branch(assembler->Word32Equal(
241 assembler->Word32And(both_instance_types,
242 assembler->Int32Constant(
243 kBothSeqOneByteStringMask)),
244 assembler->Int32Constant(kBothSeqOneByteStringTag)),
245 &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
246
247 assembler->Bind(&if_bothonebyteseqstrings);
248 {
249 // Load the length of {lhs} and {rhs}.
250 Node* lhs_length = assembler->LoadStringLength(lhs);
251 Node* rhs_length = assembler->LoadStringLength(rhs);
252
253 // Determine the minimum length.
254 Node* length = assembler->SmiMin(lhs_length, rhs_length);
255
256 // Compute the effective offset of the first character.
257 Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
258 kHeapObjectTag);
259
260 // Compute the first offset after the string from the length.
261 Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
262
263 // Loop over the {lhs} and {rhs} strings to see if they are equal.
264 Variable var_offset(assembler, MachineType::PointerRepresentation());
265 Label loop(assembler, &var_offset);
266 var_offset.Bind(begin);
267 assembler->Goto(&loop);
268 assembler->Bind(&loop);
269 {
270 // Check if {offset} equals {end}.
271 Node* offset = var_offset.value();
272 Label if_done(assembler), if_notdone(assembler);
273 assembler->Branch(assembler->WordEqual(offset, end), &if_done,
274 &if_notdone);
275
276 assembler->Bind(&if_notdone);
277 {
278 // Load the next characters from {lhs} and {rhs}.
279 Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
280 Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
281
282 // Check if the characters match.
283 Label if_valueissame(assembler), if_valueisnotsame(assembler);
284 assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
285 &if_valueissame, &if_valueisnotsame);
286
287 assembler->Bind(&if_valueissame);
288 {
289 // Advance to next character.
290 var_offset.Bind(
291 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
292 }
293 assembler->Goto(&loop);
294
295 assembler->Bind(&if_valueisnotsame);
296 assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
297 &if_less, &if_greater);
298 }
299
300 assembler->Bind(&if_done);
301 {
302 // All characters up to the min length are equal, decide based on
303 // string length.
304 Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
305 assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
306 &if_lengthisequal, &if_lengthisnotequal);
307
308 assembler->Bind(&if_lengthisequal);
309 assembler->Goto(&if_equal);
310
311 assembler->Bind(&if_lengthisnotequal);
312 assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
313 &if_greater);
314 }
315 }
316 }
317
318 assembler->Bind(&if_notbothonebyteseqstrings);
319 {
320 // TODO(bmeurer): Add fast case support for flattened cons strings;
321 // also add support for two byte string relational comparisons.
322 switch (mode) {
323 case kLessThan:
324 assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
325 rhs);
326 break;
327 case kLessThanOrEqual:
328 assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
329 lhs, rhs);
330 break;
331 case kGreaterThan:
332 assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
333 rhs);
334 break;
335 case kGreaterThanOrEqual:
336 assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
337 context, lhs, rhs);
338 break;
339 }
340 }
341 }
342
343 assembler->Bind(&if_less);
344 switch (mode) {
345 case kLessThan:
346 case kLessThanOrEqual:
347 assembler->Return(assembler->BooleanConstant(true));
348 break;
349
350 case kGreaterThan:
351 case kGreaterThanOrEqual:
352 assembler->Return(assembler->BooleanConstant(false));
353 break;
354 }
355
356 assembler->Bind(&if_equal);
357 switch (mode) {
358 case kLessThan:
359 case kGreaterThan:
360 assembler->Return(assembler->BooleanConstant(false));
361 break;
362
363 case kLessThanOrEqual:
364 case kGreaterThanOrEqual:
365 assembler->Return(assembler->BooleanConstant(true));
366 break;
367 }
368
369 assembler->Bind(&if_greater);
370 switch (mode) {
371 case kLessThan:
372 case kLessThanOrEqual:
373 assembler->Return(assembler->BooleanConstant(false));
374 break;
375
376 case kGreaterThan:
377 case kGreaterThanOrEqual:
378 assembler->Return(assembler->BooleanConstant(true));
379 break;
380 }
381 }
382
383 } // namespace
384
385 // static
386 void Builtins::Generate_StringEqual(CodeStubAssembler* assembler) {
387 GenerateStringEqual(assembler, kDontNegateResult);
388 }
389
390 // static
391 void Builtins::Generate_StringNotEqual(CodeStubAssembler* assembler) {
392 GenerateStringEqual(assembler, kNegateResult);
393 }
394
395 // static
396 void Builtins::Generate_StringLessThan(CodeStubAssembler* assembler) {
397 GenerateStringRelationalComparison(assembler, kLessThan);
398 }
399
400 // static
401 void Builtins::Generate_StringLessThanOrEqual(CodeStubAssembler* assembler) {
402 GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
403 }
404
405 // static
406 void Builtins::Generate_StringGreaterThan(CodeStubAssembler* assembler) {
407 GenerateStringRelationalComparison(assembler, kGreaterThan);
408 }
409
410 // static
411 void Builtins::Generate_StringGreaterThanOrEqual(CodeStubAssembler* assembler) {
412 GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
413 }
414
13 // ----------------------------------------------------------------------------- 415 // -----------------------------------------------------------------------------
14 // ES6 section 21.1 String Objects 416 // ES6 section 21.1 String Objects
15 417
16 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 418 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
17 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { 419 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) {
18 typedef CodeStubAssembler::Label Label; 420 typedef CodeStubAssembler::Label Label;
19 typedef compiler::Node Node; 421 typedef compiler::Node Node;
20 typedef CodeStubAssembler::Variable Variable; 422 typedef CodeStubAssembler::Variable Variable;
21 423
22 Node* code = assembler->Parameter(1); 424 Node* code = assembler->Parameter(1);
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 } 967 }
566 968
567 iterator->set_string(isolate->heap()->empty_string()); 969 iterator->set_string(isolate->heap()->empty_string());
568 970
569 return *isolate->factory()->NewJSIteratorResult( 971 return *isolate->factory()->NewJSIteratorResult(
570 isolate->factory()->undefined_value(), true); 972 isolate->factory()->undefined_value(), true);
571 } 973 }
572 974
573 } // namespace internal 975 } // namespace internal
574 } // namespace v8 976 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698