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 | 9 |
9 namespace v8 { | 10 namespace v8 { |
10 namespace internal { | 11 namespace internal { |
11 | 12 |
| 13 class NumberBuiltinsAssembler : public CodeStubAssembler { |
| 14 public: |
| 15 explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state) |
| 16 : CodeStubAssembler(state) {} |
| 17 |
| 18 protected: |
| 19 // TODO(jkummerow): Add useful helpers here, and derive from |
| 20 // NumberBuiltinsAssembler below. |
| 21 }; |
| 22 |
12 // ----------------------------------------------------------------------------- | 23 // ----------------------------------------------------------------------------- |
13 // ES6 section 20.1 Number Objects | 24 // ES6 section 20.1 Number Objects |
14 | 25 |
15 // ES6 section 20.1.2.2 Number.isFinite ( number ) | 26 // ES6 section 20.1.2.2 Number.isFinite ( number ) |
16 void Builtins::Generate_NumberIsFinite(compiler::CodeAssemblerState* state) { | 27 TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { |
17 typedef CodeStubAssembler::Label Label; | 28 Node* number = Parameter(1); |
18 typedef compiler::Node Node; | 29 |
19 CodeStubAssembler assembler(state); | 30 Label return_true(this), return_false(this); |
20 | 31 |
21 Node* number = assembler.Parameter(1); | 32 // Check if {number} is a Smi. |
22 | 33 GotoIf(TaggedIsSmi(number), &return_true); |
23 Label return_true(&assembler), return_false(&assembler); | 34 |
24 | 35 // Check if {number} is a HeapNumber. |
25 // Check if {number} is a Smi. | 36 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
26 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | 37 &return_false); |
27 | |
28 // Check if {number} is a HeapNumber. | |
29 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
30 assembler.HeapNumberMapConstant()), | |
31 &return_false); | |
32 | 38 |
33 // Check if {number} contains a finite, non-NaN value. | 39 // Check if {number} contains a finite, non-NaN value. |
34 Node* number_value = assembler.LoadHeapNumberValue(number); | 40 Node* number_value = LoadHeapNumberValue(number); |
35 assembler.BranchIfFloat64IsNaN( | 41 BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false, |
36 assembler.Float64Sub(number_value, number_value), &return_false, | 42 &return_true); |
37 &return_true); | 43 |
38 | 44 Bind(&return_true); |
39 assembler.Bind(&return_true); | 45 Return(BooleanConstant(true)); |
40 assembler.Return(assembler.BooleanConstant(true)); | 46 |
41 | 47 Bind(&return_false); |
42 assembler.Bind(&return_false); | 48 Return(BooleanConstant(false)); |
43 assembler.Return(assembler.BooleanConstant(false)); | |
44 } | 49 } |
45 | 50 |
46 // ES6 section 20.1.2.3 Number.isInteger ( number ) | 51 // ES6 section 20.1.2.3 Number.isInteger ( number ) |
47 void Builtins::Generate_NumberIsInteger(compiler::CodeAssemblerState* state) { | 52 TF_BUILTIN(NumberIsInteger, CodeStubAssembler) { |
48 typedef CodeStubAssembler::Label Label; | 53 Node* number = Parameter(1); |
49 typedef compiler::Node Node; | 54 |
50 CodeStubAssembler assembler(state); | 55 Label return_true(this), return_false(this); |
51 | 56 |
52 Node* number = assembler.Parameter(1); | 57 // Check if {number} is a Smi. |
53 | 58 GotoIf(TaggedIsSmi(number), &return_true); |
54 Label return_true(&assembler), return_false(&assembler); | 59 |
55 | 60 // Check if {number} is a HeapNumber. |
56 // Check if {number} is a Smi. | 61 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
57 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | 62 &return_false); |
58 | |
59 // Check if {number} is a HeapNumber. | |
60 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
61 assembler.HeapNumberMapConstant()), | |
62 &return_false); | |
63 | 63 |
64 // Load the actual value of {number}. | 64 // Load the actual value of {number}. |
65 Node* number_value = assembler.LoadHeapNumberValue(number); | 65 Node* number_value = LoadHeapNumberValue(number); |
66 | 66 |
67 // Truncate the value of {number} to an integer (or an infinity). | 67 // Truncate the value of {number} to an integer (or an infinity). |
68 Node* integer = assembler.Float64Trunc(number_value); | 68 Node* integer = Float64Trunc(number_value); |
69 | 69 |
70 // Check if {number}s value matches the integer (ruling out the infinities). | 70 // Check if {number}s value matches the integer (ruling out the infinities). |
71 assembler.Branch( | 71 Branch(Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
72 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 72 &return_true, &return_false); |
73 assembler.Float64Constant(0.0)), | 73 |
74 &return_true, &return_false); | 74 Bind(&return_true); |
75 | 75 Return(BooleanConstant(true)); |
76 assembler.Bind(&return_true); | 76 |
77 assembler.Return(assembler.BooleanConstant(true)); | 77 Bind(&return_false); |
78 | 78 Return(BooleanConstant(false)); |
79 assembler.Bind(&return_false); | |
80 assembler.Return(assembler.BooleanConstant(false)); | |
81 } | 79 } |
82 | 80 |
83 // ES6 section 20.1.2.4 Number.isNaN ( number ) | 81 // ES6 section 20.1.2.4 Number.isNaN ( number ) |
84 void Builtins::Generate_NumberIsNaN(compiler::CodeAssemblerState* state) { | 82 TF_BUILTIN(NumberIsNaN, CodeStubAssembler) { |
85 typedef CodeStubAssembler::Label Label; | 83 Node* number = Parameter(1); |
86 typedef compiler::Node Node; | 84 |
87 CodeStubAssembler assembler(state); | 85 Label return_true(this), return_false(this); |
88 | 86 |
89 Node* number = assembler.Parameter(1); | 87 // Check if {number} is a Smi. |
90 | 88 GotoIf(TaggedIsSmi(number), &return_false); |
91 Label return_true(&assembler), return_false(&assembler); | 89 |
92 | 90 // Check if {number} is a HeapNumber. |
93 // Check if {number} is a Smi. | 91 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
94 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_false); | 92 &return_false); |
95 | |
96 // Check if {number} is a HeapNumber. | |
97 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
98 assembler.HeapNumberMapConstant()), | |
99 &return_false); | |
100 | 93 |
101 // Check if {number} contains a NaN value. | 94 // Check if {number} contains a NaN value. |
102 Node* number_value = assembler.LoadHeapNumberValue(number); | 95 Node* number_value = LoadHeapNumberValue(number); |
103 assembler.BranchIfFloat64IsNaN(number_value, &return_true, &return_false); | 96 BranchIfFloat64IsNaN(number_value, &return_true, &return_false); |
104 | 97 |
105 assembler.Bind(&return_true); | 98 Bind(&return_true); |
106 assembler.Return(assembler.BooleanConstant(true)); | 99 Return(BooleanConstant(true)); |
107 | 100 |
108 assembler.Bind(&return_false); | 101 Bind(&return_false); |
109 assembler.Return(assembler.BooleanConstant(false)); | 102 Return(BooleanConstant(false)); |
110 } | 103 } |
111 | 104 |
112 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) | 105 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) |
113 void Builtins::Generate_NumberIsSafeInteger( | 106 TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) { |
114 compiler::CodeAssemblerState* state) { | 107 Node* number = Parameter(1); |
115 typedef CodeStubAssembler::Label Label; | 108 |
116 typedef compiler::Node Node; | 109 Label return_true(this), return_false(this); |
117 CodeStubAssembler assembler(state); | 110 |
118 | 111 // Check if {number} is a Smi. |
119 Node* number = assembler.Parameter(1); | 112 GotoIf(TaggedIsSmi(number), &return_true); |
120 | 113 |
121 Label return_true(&assembler), return_false(&assembler); | 114 // Check if {number} is a HeapNumber. |
122 | 115 GotoUnless(WordEqual(LoadMap(number), HeapNumberMapConstant()), |
123 // Check if {number} is a Smi. | 116 &return_false); |
124 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | |
125 | |
126 // Check if {number} is a HeapNumber. | |
127 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
128 assembler.HeapNumberMapConstant()), | |
129 &return_false); | |
130 | 117 |
131 // Load the actual value of {number}. | 118 // Load the actual value of {number}. |
132 Node* number_value = assembler.LoadHeapNumberValue(number); | 119 Node* number_value = LoadHeapNumberValue(number); |
133 | 120 |
134 // Truncate the value of {number} to an integer (or an infinity). | 121 // Truncate the value of {number} to an integer (or an infinity). |
135 Node* integer = assembler.Float64Trunc(number_value); | 122 Node* integer = Float64Trunc(number_value); |
136 | 123 |
137 // Check if {number}s value matches the integer (ruling out the infinities). | 124 // Check if {number}s value matches the integer (ruling out the infinities). |
138 assembler.GotoUnless( | 125 GotoUnless( |
139 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 126 Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
140 assembler.Float64Constant(0.0)), | |
141 &return_false); | 127 &return_false); |
142 | 128 |
143 // Check if the {integer} value is in safe integer range. | 129 // Check if the {integer} value is in safe integer range. |
144 assembler.Branch(assembler.Float64LessThanOrEqual( | 130 Branch(Float64LessThanOrEqual(Float64Abs(integer), |
145 assembler.Float64Abs(integer), | 131 Float64Constant(kMaxSafeInteger)), |
146 assembler.Float64Constant(kMaxSafeInteger)), | 132 &return_true, &return_false); |
147 &return_true, &return_false); | 133 |
148 | 134 Bind(&return_true); |
149 assembler.Bind(&return_true); | 135 Return(BooleanConstant(true)); |
150 assembler.Return(assembler.BooleanConstant(true)); | 136 |
151 | 137 Bind(&return_false); |
152 assembler.Bind(&return_false); | 138 Return(BooleanConstant(false)); |
153 assembler.Return(assembler.BooleanConstant(false)); | |
154 } | 139 } |
155 | 140 |
156 // ES6 section 20.1.2.12 Number.parseFloat ( string ) | 141 // ES6 section 20.1.2.12 Number.parseFloat ( string ) |
157 void Builtins::Generate_NumberParseFloat(compiler::CodeAssemblerState* state) { | 142 TF_BUILTIN(NumberParseFloat, CodeStubAssembler) { |
158 typedef CodeStubAssembler::Label Label; | 143 Node* context = Parameter(4); |
159 typedef compiler::Node Node; | |
160 typedef CodeStubAssembler::Variable Variable; | |
161 CodeStubAssembler assembler(state); | |
162 | |
163 Node* context = assembler.Parameter(4); | |
164 | 144 |
165 // We might need to loop once for ToString conversion. | 145 // We might need to loop once for ToString conversion. |
166 Variable var_input(&assembler, MachineRepresentation::kTagged); | 146 Variable var_input(this, MachineRepresentation::kTagged); |
167 Label loop(&assembler, &var_input); | 147 Label loop(this, &var_input); |
168 var_input.Bind(assembler.Parameter(1)); | 148 var_input.Bind(Parameter(1)); |
169 assembler.Goto(&loop); | 149 Goto(&loop); |
170 assembler.Bind(&loop); | 150 Bind(&loop); |
171 { | 151 { |
172 // Load the current {input} value. | 152 // Load the current {input} value. |
173 Node* input = var_input.value(); | 153 Node* input = var_input.value(); |
174 | 154 |
175 // Check if the {input} is a HeapObject or a Smi. | 155 // Check if the {input} is a HeapObject or a Smi. |
176 Label if_inputissmi(&assembler), if_inputisnotsmi(&assembler); | 156 Label if_inputissmi(this), if_inputisnotsmi(this); |
177 assembler.Branch(assembler.TaggedIsSmi(input), &if_inputissmi, | 157 Branch(TaggedIsSmi(input), &if_inputissmi, &if_inputisnotsmi); |
178 &if_inputisnotsmi); | 158 |
179 | 159 Bind(&if_inputissmi); |
180 assembler.Bind(&if_inputissmi); | |
181 { | 160 { |
182 // The {input} is already a Number, no need to do anything. | 161 // The {input} is already a Number, no need to do anything. |
183 assembler.Return(input); | 162 Return(input); |
184 } | 163 } |
185 | 164 |
186 assembler.Bind(&if_inputisnotsmi); | 165 Bind(&if_inputisnotsmi); |
187 { | 166 { |
188 // The {input} is a HeapObject, check if it's already a String. | 167 // The {input} is a HeapObject, check if it's already a String. |
189 Label if_inputisstring(&assembler), if_inputisnotstring(&assembler); | 168 Label if_inputisstring(this), if_inputisnotstring(this); |
190 Node* input_map = assembler.LoadMap(input); | 169 Node* input_map = LoadMap(input); |
191 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 170 Node* input_instance_type = LoadMapInstanceType(input_map); |
192 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | 171 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
193 &if_inputisstring, &if_inputisnotstring); | 172 &if_inputisnotstring); |
194 | 173 |
195 assembler.Bind(&if_inputisstring); | 174 Bind(&if_inputisstring); |
196 { | 175 { |
197 // The {input} is already a String, check if {input} contains | 176 // The {input} is already a String, check if {input} contains |
198 // a cached array index. | 177 // a cached array index. |
199 Label if_inputcached(&assembler), if_inputnotcached(&assembler); | 178 Label if_inputcached(this), if_inputnotcached(this); |
200 Node* input_hash = assembler.LoadNameHashField(input); | 179 Node* input_hash = LoadNameHashField(input); |
201 Node* input_bit = assembler.Word32And( | 180 Node* input_bit = Word32And( |
202 input_hash, | 181 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
203 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 182 Branch(Word32Equal(input_bit, Int32Constant(0)), &if_inputcached, |
204 assembler.Branch( | 183 &if_inputnotcached); |
205 assembler.Word32Equal(input_bit, assembler.Int32Constant(0)), | 184 |
206 &if_inputcached, &if_inputnotcached); | 185 Bind(&if_inputcached); |
207 | |
208 assembler.Bind(&if_inputcached); | |
209 { | 186 { |
210 // Just return the {input}s cached array index. | 187 // Just return the {input}s cached array index. |
211 Node* input_array_index = | 188 Node* input_array_index = |
212 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 189 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
213 input_hash); | 190 Return(SmiTag(input_array_index)); |
214 assembler.Return(assembler.SmiTag(input_array_index)); | 191 } |
215 } | 192 |
216 | 193 Bind(&if_inputnotcached); |
217 assembler.Bind(&if_inputnotcached); | |
218 { | 194 { |
219 // Need to fall back to the runtime to convert {input} to double. | 195 // Need to fall back to the runtime to convert {input} to double. |
220 assembler.Return(assembler.CallRuntime(Runtime::kStringParseFloat, | 196 Return(CallRuntime(Runtime::kStringParseFloat, context, input)); |
221 context, input)); | |
222 } | 197 } |
223 } | 198 } |
224 | 199 |
225 assembler.Bind(&if_inputisnotstring); | 200 Bind(&if_inputisnotstring); |
226 { | 201 { |
227 // The {input} is neither a String nor a Smi, check for HeapNumber. | 202 // The {input} is neither a String nor a Smi, check for HeapNumber. |
228 Label if_inputisnumber(&assembler), | 203 Label if_inputisnumber(this), |
229 if_inputisnotnumber(&assembler, Label::kDeferred); | 204 if_inputisnotnumber(this, Label::kDeferred); |
230 assembler.Branch( | 205 Branch(WordEqual(input_map, HeapNumberMapConstant()), &if_inputisnumber, |
231 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 206 &if_inputisnotnumber); |
232 &if_inputisnumber, &if_inputisnotnumber); | 207 |
233 | 208 Bind(&if_inputisnumber); |
234 assembler.Bind(&if_inputisnumber); | |
235 { | 209 { |
236 // The {input} is already a Number, take care of -0. | 210 // The {input} is already a Number, take care of -0. |
237 Label if_inputiszero(&assembler), if_inputisnotzero(&assembler); | 211 Label if_inputiszero(this), if_inputisnotzero(this); |
238 Node* input_value = assembler.LoadHeapNumberValue(input); | 212 Node* input_value = LoadHeapNumberValue(input); |
239 assembler.Branch(assembler.Float64Equal( | 213 Branch(Float64Equal(input_value, Float64Constant(0.0)), |
240 input_value, assembler.Float64Constant(0.0)), | 214 &if_inputiszero, &if_inputisnotzero); |
241 &if_inputiszero, &if_inputisnotzero); | 215 |
242 | 216 Bind(&if_inputiszero); |
243 assembler.Bind(&if_inputiszero); | 217 Return(SmiConstant(0)); |
244 assembler.Return(assembler.SmiConstant(0)); | 218 |
245 | 219 Bind(&if_inputisnotzero); |
246 assembler.Bind(&if_inputisnotzero); | 220 Return(input); |
247 assembler.Return(input); | 221 } |
248 } | 222 |
249 | 223 Bind(&if_inputisnotnumber); |
250 assembler.Bind(&if_inputisnotnumber); | |
251 { | 224 { |
252 // Need to convert the {input} to String first. | 225 // Need to convert the {input} to String first. |
253 // TODO(bmeurer): This could be more efficient if necessary. | 226 // TODO(bmeurer): This could be more efficient if necessary. |
254 Callable callable = CodeFactory::ToString(assembler.isolate()); | 227 Callable callable = CodeFactory::ToString(isolate()); |
255 var_input.Bind(assembler.CallStub(callable, context, input)); | 228 var_input.Bind(CallStub(callable, context, input)); |
256 assembler.Goto(&loop); | 229 Goto(&loop); |
257 } | 230 } |
258 } | 231 } |
259 } | 232 } |
260 } | 233 } |
261 } | 234 } |
262 | 235 |
263 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) | 236 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) |
264 void Builtins::Generate_NumberParseInt(compiler::CodeAssemblerState* state) { | 237 TF_BUILTIN(NumberParseInt, CodeStubAssembler) { |
265 typedef CodeStubAssembler::Label Label; | 238 Node* input = Parameter(1); |
266 typedef compiler::Node Node; | 239 Node* radix = Parameter(2); |
267 CodeStubAssembler assembler(state); | 240 Node* context = Parameter(5); |
268 | |
269 Node* input = assembler.Parameter(1); | |
270 Node* radix = assembler.Parameter(2); | |
271 Node* context = assembler.Parameter(5); | |
272 | 241 |
273 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). | 242 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). |
274 Label if_radix10(&assembler), if_generic(&assembler, Label::kDeferred); | 243 Label if_radix10(this), if_generic(this, Label::kDeferred); |
275 assembler.GotoIf(assembler.WordEqual(radix, assembler.UndefinedConstant()), | 244 GotoIf(WordEqual(radix, UndefinedConstant()), &if_radix10); |
276 &if_radix10); | 245 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(10))), &if_radix10); |
277 assembler.GotoIf( | 246 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(0))), &if_radix10); |
278 assembler.WordEqual(radix, assembler.SmiConstant(Smi::FromInt(10))), | 247 Goto(&if_generic); |
279 &if_radix10); | |
280 assembler.GotoIf( | |
281 assembler.WordEqual(radix, assembler.SmiConstant(Smi::FromInt(0))), | |
282 &if_radix10); | |
283 assembler.Goto(&if_generic); | |
284 | 248 |
285 assembler.Bind(&if_radix10); | 249 Bind(&if_radix10); |
286 { | 250 { |
287 // Check if we can avoid the ToString conversion on {input}. | 251 // Check if we can avoid the ToString conversion on {input}. |
288 Label if_inputissmi(&assembler), if_inputisheapnumber(&assembler), | 252 Label if_inputissmi(this), if_inputisheapnumber(this), |
289 if_inputisstring(&assembler); | 253 if_inputisstring(this); |
290 assembler.GotoIf(assembler.TaggedIsSmi(input), &if_inputissmi); | 254 GotoIf(TaggedIsSmi(input), &if_inputissmi); |
291 Node* input_map = assembler.LoadMap(input); | 255 Node* input_map = LoadMap(input); |
292 assembler.GotoIf( | 256 GotoIf(WordEqual(input_map, HeapNumberMapConstant()), |
293 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 257 &if_inputisheapnumber); |
294 &if_inputisheapnumber); | 258 Node* input_instance_type = LoadMapInstanceType(input_map); |
295 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 259 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
296 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | 260 &if_generic); |
297 &if_inputisstring, &if_generic); | |
298 | 261 |
299 assembler.Bind(&if_inputissmi); | 262 Bind(&if_inputissmi); |
300 { | 263 { |
301 // Just return the {input}. | 264 // Just return the {input}. |
302 assembler.Return(input); | 265 Return(input); |
303 } | 266 } |
304 | 267 |
305 assembler.Bind(&if_inputisheapnumber); | 268 Bind(&if_inputisheapnumber); |
306 { | 269 { |
307 // Check if the {input} value is in Signed32 range. | 270 // Check if the {input} value is in Signed32 range. |
308 Label if_inputissigned32(&assembler); | 271 Label if_inputissigned32(this); |
309 Node* input_value = assembler.LoadHeapNumberValue(input); | 272 Node* input_value = LoadHeapNumberValue(input); |
310 Node* input_value32 = assembler.TruncateFloat64ToWord32(input_value); | 273 Node* input_value32 = TruncateFloat64ToWord32(input_value); |
311 assembler.GotoIf( | 274 GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)), |
312 assembler.Float64Equal(input_value, | 275 &if_inputissigned32); |
313 assembler.ChangeInt32ToFloat64(input_value32)), | |
314 &if_inputissigned32); | |
315 | 276 |
316 // Check if the absolute {input} value is in the ]0.01,1e9[ range. | 277 // Check if the absolute {input} value is in the ]0.01,1e9[ range. |
317 Node* input_value_abs = assembler.Float64Abs(input_value); | 278 Node* input_value_abs = Float64Abs(input_value); |
318 | 279 |
319 assembler.GotoUnless(assembler.Float64LessThan( | 280 GotoUnless(Float64LessThan(input_value_abs, Float64Constant(1e9)), |
320 input_value_abs, assembler.Float64Constant(1e9)), | 281 &if_generic); |
321 &if_generic); | 282 Branch(Float64LessThan(Float64Constant(0.01), input_value_abs), |
322 assembler.Branch(assembler.Float64LessThan( | 283 &if_inputissigned32, &if_generic); |
323 assembler.Float64Constant(0.01), input_value_abs), | |
324 &if_inputissigned32, &if_generic); | |
325 | 284 |
326 // Return the truncated int32 value, and return the tagged result. | 285 // Return the truncated int32 value, and return the tagged result. |
327 assembler.Bind(&if_inputissigned32); | 286 Bind(&if_inputissigned32); |
328 Node* result = assembler.ChangeInt32ToTagged(input_value32); | 287 Node* result = ChangeInt32ToTagged(input_value32); |
329 assembler.Return(result); | 288 Return(result); |
330 } | 289 } |
331 | 290 |
332 assembler.Bind(&if_inputisstring); | 291 Bind(&if_inputisstring); |
333 { | 292 { |
334 // Check if the String {input} has a cached array index. | 293 // Check if the String {input} has a cached array index. |
335 Node* input_hash = assembler.LoadNameHashField(input); | 294 Node* input_hash = LoadNameHashField(input); |
336 Node* input_bit = assembler.Word32And( | 295 Node* input_bit = Word32And( |
337 input_hash, | 296 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
338 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 297 GotoIf(Word32NotEqual(input_bit, Int32Constant(0)), &if_generic); |
339 assembler.GotoIf( | |
340 assembler.Word32NotEqual(input_bit, assembler.Int32Constant(0)), | |
341 &if_generic); | |
342 | 298 |
343 // Return the cached array index as result. | 299 // Return the cached array index as result. |
344 Node* input_index = | 300 Node* input_index = |
345 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 301 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
346 input_hash); | 302 Node* result = SmiTag(input_index); |
347 Node* result = assembler.SmiTag(input_index); | 303 Return(result); |
348 assembler.Return(result); | |
349 } | 304 } |
350 } | 305 } |
351 | 306 |
352 assembler.Bind(&if_generic); | 307 Bind(&if_generic); |
353 { | 308 { |
354 Node* result = | 309 Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix); |
355 assembler.CallRuntime(Runtime::kStringParseInt, context, input, radix); | 310 Return(result); |
356 assembler.Return(result); | |
357 } | 311 } |
358 } | 312 } |
359 | 313 |
360 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) | 314 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) |
361 BUILTIN(NumberPrototypeToExponential) { | 315 BUILTIN(NumberPrototypeToExponential) { |
362 HandleScope scope(isolate); | 316 HandleScope scope(isolate); |
363 Handle<Object> value = args.at<Object>(0); | 317 Handle<Object> value = args.at<Object>(0); |
364 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | 318 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); |
365 | 319 |
366 // Unwrap the receiver {value}. | 320 // Unwrap the receiver {value}. |
(...skipping 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1825 compiler::Node* lhs = assembler.Parameter(0); | 1779 compiler::Node* lhs = assembler.Parameter(0); |
1826 compiler::Node* rhs = assembler.Parameter(1); | 1780 compiler::Node* rhs = assembler.Parameter(1); |
1827 compiler::Node* context = assembler.Parameter(2); | 1781 compiler::Node* context = assembler.Parameter(2); |
1828 | 1782 |
1829 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kNegateResult, lhs, | 1783 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kNegateResult, lhs, |
1830 rhs, context)); | 1784 rhs, context)); |
1831 } | 1785 } |
1832 | 1786 |
1833 } // namespace internal | 1787 } // namespace internal |
1834 } // namespace v8 | 1788 } // namespace v8 |
OLD | NEW |