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