OLD | NEW |
---|---|
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); | |
Jarin
2016/09/26 12:21:23
What's up with the missing underscores?
| |
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 Loading... | |
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 |
OLD | NEW |