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 template <Signedness signed_result = kSigned> |
| 20 void BitwiseOp(std::function<Node*(Node* lhs, Node* rhs)> body) { |
| 21 Node* left = Parameter(0); |
| 22 Node* right = Parameter(1); |
| 23 Node* context = Parameter(2); |
| 24 |
| 25 Node* lhs_value = TruncateTaggedToWord32(context, left); |
| 26 Node* rhs_value = TruncateTaggedToWord32(context, right); |
| 27 Node* value = body(lhs_value, rhs_value); |
| 28 Node* result = signed_result == kSigned ? ChangeInt32ToTagged(value) |
| 29 : ChangeUint32ToTagged(value); |
| 30 Return(result); |
| 31 } |
| 32 |
| 33 template <Signedness signed_result = kSigned> |
| 34 void BitwiseShiftOp(std::function<Node*(Node* lhs, Node* shift_count)> body) { |
| 35 BitwiseOp<signed_result>([this, body](Node* lhs, Node* rhs) { |
| 36 Node* shift_count = Word32And(rhs, Int32Constant(0x1f)); |
| 37 return body(lhs, shift_count); |
| 38 }); |
| 39 } |
| 40 |
| 41 void RelationalComparisonBuiltin(RelationalComparisonMode mode) { |
| 42 Node* lhs = Parameter(0); |
| 43 Node* rhs = Parameter(1); |
| 44 Node* context = Parameter(2); |
| 45 |
| 46 Return(RelationalComparison(mode, lhs, rhs, context)); |
| 47 } |
| 48 }; |
| 49 |
12 // ----------------------------------------------------------------------------- | 50 // ----------------------------------------------------------------------------- |
13 // ES6 section 20.1 Number Objects | 51 // ES6 section 20.1 Number Objects |
14 | 52 |
15 // ES6 section 20.1.2.2 Number.isFinite ( number ) | 53 // ES6 section 20.1.2.2 Number.isFinite ( number ) |
16 void Builtins::Generate_NumberIsFinite(compiler::CodeAssemblerState* state) { | 54 TF_BUILTIN(NumberIsFinite, CodeStubAssembler) { |
17 typedef CodeStubAssembler::Label Label; | 55 Node* number = Parameter(1); |
18 typedef compiler::Node Node; | 56 |
19 CodeStubAssembler assembler(state); | 57 Label return_true(this), return_false(this); |
20 | 58 |
21 Node* number = assembler.Parameter(1); | 59 // Check if {number} is a Smi. |
22 | 60 GotoIf(TaggedIsSmi(number), &return_true); |
23 Label return_true(&assembler), return_false(&assembler); | 61 |
24 | 62 // Check if {number} is a HeapNumber. |
25 // Check if {number} is a Smi. | 63 GotoUnless(IsHeapNumberMap(LoadMap(number)), &return_false); |
26 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | |
27 | |
28 // Check if {number} is a HeapNumber. | |
29 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
30 assembler.HeapNumberMapConstant()), | |
31 &return_false); | |
32 | 64 |
33 // Check if {number} contains a finite, non-NaN value. | 65 // Check if {number} contains a finite, non-NaN value. |
34 Node* number_value = assembler.LoadHeapNumberValue(number); | 66 Node* number_value = LoadHeapNumberValue(number); |
35 assembler.BranchIfFloat64IsNaN( | 67 BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false, |
36 assembler.Float64Sub(number_value, number_value), &return_false, | 68 &return_true); |
37 &return_true); | 69 |
38 | 70 Bind(&return_true); |
39 assembler.Bind(&return_true); | 71 Return(BooleanConstant(true)); |
40 assembler.Return(assembler.BooleanConstant(true)); | 72 |
41 | 73 Bind(&return_false); |
42 assembler.Bind(&return_false); | 74 Return(BooleanConstant(false)); |
43 assembler.Return(assembler.BooleanConstant(false)); | |
44 } | 75 } |
45 | 76 |
46 // ES6 section 20.1.2.3 Number.isInteger ( number ) | 77 // ES6 section 20.1.2.3 Number.isInteger ( number ) |
47 void Builtins::Generate_NumberIsInteger(compiler::CodeAssemblerState* state) { | 78 TF_BUILTIN(NumberIsInteger, CodeStubAssembler) { |
48 typedef CodeStubAssembler::Label Label; | 79 Node* number = Parameter(1); |
49 typedef compiler::Node Node; | 80 |
50 CodeStubAssembler assembler(state); | 81 Label return_true(this), return_false(this); |
51 | 82 |
52 Node* number = assembler.Parameter(1); | 83 // Check if {number} is a Smi. |
53 | 84 GotoIf(TaggedIsSmi(number), &return_true); |
54 Label return_true(&assembler), return_false(&assembler); | 85 |
55 | 86 // Check if {number} is a HeapNumber. |
56 // Check if {number} is a Smi. | 87 GotoUnless(IsHeapNumberMap(LoadMap(number)), &return_false); |
57 assembler.GotoIf(assembler.TaggedIsSmi(number), &return_true); | |
58 | |
59 // Check if {number} is a HeapNumber. | |
60 assembler.GotoUnless(assembler.WordEqual(assembler.LoadMap(number), | |
61 assembler.HeapNumberMapConstant()), | |
62 &return_false); | |
63 | 88 |
64 // Load the actual value of {number}. | 89 // Load the actual value of {number}. |
65 Node* number_value = assembler.LoadHeapNumberValue(number); | 90 Node* number_value = LoadHeapNumberValue(number); |
66 | 91 |
67 // Truncate the value of {number} to an integer (or an infinity). | 92 // Truncate the value of {number} to an integer (or an infinity). |
68 Node* integer = assembler.Float64Trunc(number_value); | 93 Node* integer = Float64Trunc(number_value); |
69 | 94 |
70 // Check if {number}s value matches the integer (ruling out the infinities). | 95 // Check if {number}s value matches the integer (ruling out the infinities). |
71 assembler.Branch( | 96 Branch(Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
72 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 97 &return_true, &return_false); |
73 assembler.Float64Constant(0.0)), | 98 |
74 &return_true, &return_false); | 99 Bind(&return_true); |
75 | 100 Return(BooleanConstant(true)); |
76 assembler.Bind(&return_true); | 101 |
77 assembler.Return(assembler.BooleanConstant(true)); | 102 Bind(&return_false); |
78 | 103 Return(BooleanConstant(false)); |
79 assembler.Bind(&return_false); | |
80 assembler.Return(assembler.BooleanConstant(false)); | |
81 } | 104 } |
82 | 105 |
83 // ES6 section 20.1.2.4 Number.isNaN ( number ) | 106 // ES6 section 20.1.2.4 Number.isNaN ( number ) |
84 void Builtins::Generate_NumberIsNaN(compiler::CodeAssemblerState* state) { | 107 TF_BUILTIN(NumberIsNaN, CodeStubAssembler) { |
85 typedef CodeStubAssembler::Label Label; | 108 Node* number = Parameter(1); |
86 typedef compiler::Node Node; | 109 |
87 CodeStubAssembler assembler(state); | 110 Label return_true(this), return_false(this); |
88 | 111 |
89 Node* number = assembler.Parameter(1); | 112 // Check if {number} is a Smi. |
90 | 113 GotoIf(TaggedIsSmi(number), &return_false); |
91 Label return_true(&assembler), return_false(&assembler); | 114 |
92 | 115 // Check if {number} is a HeapNumber. |
93 // Check if {number} is a Smi. | 116 GotoUnless(IsHeapNumberMap(LoadMap(number)), &return_false); |
94 assembler.GotoIf(assembler.TaggedIsSmi(number), &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 | 117 |
101 // Check if {number} contains a NaN value. | 118 // Check if {number} contains a NaN value. |
102 Node* number_value = assembler.LoadHeapNumberValue(number); | 119 Node* number_value = LoadHeapNumberValue(number); |
103 assembler.BranchIfFloat64IsNaN(number_value, &return_true, &return_false); | 120 BranchIfFloat64IsNaN(number_value, &return_true, &return_false); |
104 | 121 |
105 assembler.Bind(&return_true); | 122 Bind(&return_true); |
106 assembler.Return(assembler.BooleanConstant(true)); | 123 Return(BooleanConstant(true)); |
107 | 124 |
108 assembler.Bind(&return_false); | 125 Bind(&return_false); |
109 assembler.Return(assembler.BooleanConstant(false)); | 126 Return(BooleanConstant(false)); |
110 } | 127 } |
111 | 128 |
112 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) | 129 // ES6 section 20.1.2.5 Number.isSafeInteger ( number ) |
113 void Builtins::Generate_NumberIsSafeInteger( | 130 TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) { |
114 compiler::CodeAssemblerState* state) { | 131 Node* number = Parameter(1); |
115 typedef CodeStubAssembler::Label Label; | 132 |
116 typedef compiler::Node Node; | 133 Label return_true(this), return_false(this); |
117 CodeStubAssembler assembler(state); | 134 |
118 | 135 // Check if {number} is a Smi. |
119 Node* number = assembler.Parameter(1); | 136 GotoIf(TaggedIsSmi(number), &return_true); |
120 | 137 |
121 Label return_true(&assembler), return_false(&assembler); | 138 // Check if {number} is a HeapNumber. |
122 | 139 GotoUnless(IsHeapNumberMap(LoadMap(number)), &return_false); |
123 // Check if {number} is a Smi. | |
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 | 140 |
131 // Load the actual value of {number}. | 141 // Load the actual value of {number}. |
132 Node* number_value = assembler.LoadHeapNumberValue(number); | 142 Node* number_value = LoadHeapNumberValue(number); |
133 | 143 |
134 // Truncate the value of {number} to an integer (or an infinity). | 144 // Truncate the value of {number} to an integer (or an infinity). |
135 Node* integer = assembler.Float64Trunc(number_value); | 145 Node* integer = Float64Trunc(number_value); |
136 | 146 |
137 // Check if {number}s value matches the integer (ruling out the infinities). | 147 // Check if {number}s value matches the integer (ruling out the infinities). |
138 assembler.GotoUnless( | 148 GotoUnless( |
139 assembler.Float64Equal(assembler.Float64Sub(number_value, integer), | 149 Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)), |
140 assembler.Float64Constant(0.0)), | |
141 &return_false); | 150 &return_false); |
142 | 151 |
143 // Check if the {integer} value is in safe integer range. | 152 // Check if the {integer} value is in safe integer range. |
144 assembler.Branch(assembler.Float64LessThanOrEqual( | 153 Branch(Float64LessThanOrEqual(Float64Abs(integer), |
145 assembler.Float64Abs(integer), | 154 Float64Constant(kMaxSafeInteger)), |
146 assembler.Float64Constant(kMaxSafeInteger)), | 155 &return_true, &return_false); |
147 &return_true, &return_false); | 156 |
148 | 157 Bind(&return_true); |
149 assembler.Bind(&return_true); | 158 Return(BooleanConstant(true)); |
150 assembler.Return(assembler.BooleanConstant(true)); | 159 |
151 | 160 Bind(&return_false); |
152 assembler.Bind(&return_false); | 161 Return(BooleanConstant(false)); |
153 assembler.Return(assembler.BooleanConstant(false)); | |
154 } | 162 } |
155 | 163 |
156 // ES6 section 20.1.2.12 Number.parseFloat ( string ) | 164 // ES6 section 20.1.2.12 Number.parseFloat ( string ) |
157 void Builtins::Generate_NumberParseFloat(compiler::CodeAssemblerState* state) { | 165 TF_BUILTIN(NumberParseFloat, CodeStubAssembler) { |
158 typedef CodeStubAssembler::Label Label; | 166 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 | 167 |
165 // We might need to loop once for ToString conversion. | 168 // We might need to loop once for ToString conversion. |
166 Variable var_input(&assembler, MachineRepresentation::kTagged); | 169 Variable var_input(this, MachineRepresentation::kTagged); |
167 Label loop(&assembler, &var_input); | 170 Label loop(this, &var_input); |
168 var_input.Bind(assembler.Parameter(1)); | 171 var_input.Bind(Parameter(1)); |
169 assembler.Goto(&loop); | 172 Goto(&loop); |
170 assembler.Bind(&loop); | 173 Bind(&loop); |
171 { | 174 { |
172 // Load the current {input} value. | 175 // Load the current {input} value. |
173 Node* input = var_input.value(); | 176 Node* input = var_input.value(); |
174 | 177 |
175 // Check if the {input} is a HeapObject or a Smi. | 178 // Check if the {input} is a HeapObject or a Smi. |
176 Label if_inputissmi(&assembler), if_inputisnotsmi(&assembler); | 179 Label if_inputissmi(this), if_inputisnotsmi(this); |
177 assembler.Branch(assembler.TaggedIsSmi(input), &if_inputissmi, | 180 Branch(TaggedIsSmi(input), &if_inputissmi, &if_inputisnotsmi); |
178 &if_inputisnotsmi); | 181 |
179 | 182 Bind(&if_inputissmi); |
180 assembler.Bind(&if_inputissmi); | |
181 { | 183 { |
182 // The {input} is already a Number, no need to do anything. | 184 // The {input} is already a Number, no need to do anything. |
183 assembler.Return(input); | 185 Return(input); |
184 } | 186 } |
185 | 187 |
186 assembler.Bind(&if_inputisnotsmi); | 188 Bind(&if_inputisnotsmi); |
187 { | 189 { |
188 // The {input} is a HeapObject, check if it's already a String. | 190 // The {input} is a HeapObject, check if it's already a String. |
189 Label if_inputisstring(&assembler), if_inputisnotstring(&assembler); | 191 Label if_inputisstring(this), if_inputisnotstring(this); |
190 Node* input_map = assembler.LoadMap(input); | 192 Node* input_map = LoadMap(input); |
191 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 193 Node* input_instance_type = LoadMapInstanceType(input_map); |
192 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | 194 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
193 &if_inputisstring, &if_inputisnotstring); | 195 &if_inputisnotstring); |
194 | 196 |
195 assembler.Bind(&if_inputisstring); | 197 Bind(&if_inputisstring); |
196 { | 198 { |
197 // The {input} is already a String, check if {input} contains | 199 // The {input} is already a String, check if {input} contains |
198 // a cached array index. | 200 // a cached array index. |
199 Label if_inputcached(&assembler), if_inputnotcached(&assembler); | 201 Label if_inputcached(this), if_inputnotcached(this); |
200 Node* input_hash = assembler.LoadNameHashField(input); | 202 Node* input_hash = LoadNameHashField(input); |
201 Node* input_bit = assembler.Word32And( | 203 Node* input_bit = Word32And( |
202 input_hash, | 204 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
203 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 205 Branch(Word32Equal(input_bit, Int32Constant(0)), &if_inputcached, |
204 assembler.Branch( | 206 &if_inputnotcached); |
205 assembler.Word32Equal(input_bit, assembler.Int32Constant(0)), | 207 |
206 &if_inputcached, &if_inputnotcached); | 208 Bind(&if_inputcached); |
207 | |
208 assembler.Bind(&if_inputcached); | |
209 { | 209 { |
210 // Just return the {input}s cached array index. | 210 // Just return the {input}s cached array index. |
211 Node* input_array_index = | 211 Node* input_array_index = |
212 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 212 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
213 input_hash); | 213 Return(SmiTag(input_array_index)); |
214 assembler.Return(assembler.SmiTag(input_array_index)); | 214 } |
215 } | 215 |
216 | 216 Bind(&if_inputnotcached); |
217 assembler.Bind(&if_inputnotcached); | |
218 { | 217 { |
219 // Need to fall back to the runtime to convert {input} to double. | 218 // Need to fall back to the runtime to convert {input} to double. |
220 assembler.Return(assembler.CallRuntime(Runtime::kStringParseFloat, | 219 Return(CallRuntime(Runtime::kStringParseFloat, context, input)); |
221 context, input)); | |
222 } | 220 } |
223 } | 221 } |
224 | 222 |
225 assembler.Bind(&if_inputisnotstring); | 223 Bind(&if_inputisnotstring); |
226 { | 224 { |
227 // The {input} is neither a String nor a Smi, check for HeapNumber. | 225 // The {input} is neither a String nor a Smi, check for HeapNumber. |
228 Label if_inputisnumber(&assembler), | 226 Label if_inputisnumber(this), |
229 if_inputisnotnumber(&assembler, Label::kDeferred); | 227 if_inputisnotnumber(this, Label::kDeferred); |
230 assembler.Branch( | 228 Branch(IsHeapNumberMap(input_map), &if_inputisnumber, |
231 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 229 &if_inputisnotnumber); |
232 &if_inputisnumber, &if_inputisnotnumber); | 230 |
233 | 231 Bind(&if_inputisnumber); |
234 assembler.Bind(&if_inputisnumber); | |
235 { | 232 { |
236 // The {input} is already a Number, take care of -0. | 233 // The {input} is already a Number, take care of -0. |
237 Label if_inputiszero(&assembler), if_inputisnotzero(&assembler); | 234 Label if_inputiszero(this), if_inputisnotzero(this); |
238 Node* input_value = assembler.LoadHeapNumberValue(input); | 235 Node* input_value = LoadHeapNumberValue(input); |
239 assembler.Branch(assembler.Float64Equal( | 236 Branch(Float64Equal(input_value, Float64Constant(0.0)), |
240 input_value, assembler.Float64Constant(0.0)), | 237 &if_inputiszero, &if_inputisnotzero); |
241 &if_inputiszero, &if_inputisnotzero); | 238 |
242 | 239 Bind(&if_inputiszero); |
243 assembler.Bind(&if_inputiszero); | 240 Return(SmiConstant(0)); |
244 assembler.Return(assembler.SmiConstant(0)); | 241 |
245 | 242 Bind(&if_inputisnotzero); |
246 assembler.Bind(&if_inputisnotzero); | 243 Return(input); |
247 assembler.Return(input); | 244 } |
248 } | 245 |
249 | 246 Bind(&if_inputisnotnumber); |
250 assembler.Bind(&if_inputisnotnumber); | |
251 { | 247 { |
252 // Need to convert the {input} to String first. | 248 // Need to convert the {input} to String first. |
253 // TODO(bmeurer): This could be more efficient if necessary. | 249 // TODO(bmeurer): This could be more efficient if necessary. |
254 Callable callable = CodeFactory::ToString(assembler.isolate()); | 250 Callable callable = CodeFactory::ToString(isolate()); |
255 var_input.Bind(assembler.CallStub(callable, context, input)); | 251 var_input.Bind(CallStub(callable, context, input)); |
256 assembler.Goto(&loop); | 252 Goto(&loop); |
257 } | 253 } |
258 } | 254 } |
259 } | 255 } |
260 } | 256 } |
261 } | 257 } |
262 | 258 |
263 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) | 259 // ES6 section 20.1.2.13 Number.parseInt ( string, radix ) |
264 void Builtins::Generate_NumberParseInt(compiler::CodeAssemblerState* state) { | 260 TF_BUILTIN(NumberParseInt, CodeStubAssembler) { |
265 typedef CodeStubAssembler::Label Label; | 261 Node* input = Parameter(1); |
266 typedef compiler::Node Node; | 262 Node* radix = Parameter(2); |
267 CodeStubAssembler assembler(state); | 263 Node* context = Parameter(5); |
268 | |
269 Node* input = assembler.Parameter(1); | |
270 Node* radix = assembler.Parameter(2); | |
271 Node* context = assembler.Parameter(5); | |
272 | 264 |
273 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). | 265 // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10). |
274 Label if_radix10(&assembler), if_generic(&assembler, Label::kDeferred); | 266 Label if_radix10(this), if_generic(this, Label::kDeferred); |
275 assembler.GotoIf(assembler.WordEqual(radix, assembler.UndefinedConstant()), | 267 GotoIf(WordEqual(radix, UndefinedConstant()), &if_radix10); |
276 &if_radix10); | 268 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(10))), &if_radix10); |
277 assembler.GotoIf( | 269 GotoIf(WordEqual(radix, SmiConstant(Smi::FromInt(0))), &if_radix10); |
278 assembler.WordEqual(radix, assembler.SmiConstant(Smi::FromInt(10))), | 270 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 | 271 |
285 assembler.Bind(&if_radix10); | 272 Bind(&if_radix10); |
286 { | 273 { |
287 // Check if we can avoid the ToString conversion on {input}. | 274 // Check if we can avoid the ToString conversion on {input}. |
288 Label if_inputissmi(&assembler), if_inputisheapnumber(&assembler), | 275 Label if_inputissmi(this), if_inputisheapnumber(this), |
289 if_inputisstring(&assembler); | 276 if_inputisstring(this); |
290 assembler.GotoIf(assembler.TaggedIsSmi(input), &if_inputissmi); | 277 GotoIf(TaggedIsSmi(input), &if_inputissmi); |
291 Node* input_map = assembler.LoadMap(input); | 278 Node* input_map = LoadMap(input); |
292 assembler.GotoIf( | 279 GotoIf(IsHeapNumberMap(input_map), &if_inputisheapnumber); |
293 assembler.WordEqual(input_map, assembler.HeapNumberMapConstant()), | 280 Node* input_instance_type = LoadMapInstanceType(input_map); |
294 &if_inputisheapnumber); | 281 Branch(IsStringInstanceType(input_instance_type), &if_inputisstring, |
295 Node* input_instance_type = assembler.LoadMapInstanceType(input_map); | 282 &if_generic); |
296 assembler.Branch(assembler.IsStringInstanceType(input_instance_type), | |
297 &if_inputisstring, &if_generic); | |
298 | 283 |
299 assembler.Bind(&if_inputissmi); | 284 Bind(&if_inputissmi); |
300 { | 285 { |
301 // Just return the {input}. | 286 // Just return the {input}. |
302 assembler.Return(input); | 287 Return(input); |
303 } | 288 } |
304 | 289 |
305 assembler.Bind(&if_inputisheapnumber); | 290 Bind(&if_inputisheapnumber); |
306 { | 291 { |
307 // Check if the {input} value is in Signed32 range. | 292 // Check if the {input} value is in Signed32 range. |
308 Label if_inputissigned32(&assembler); | 293 Label if_inputissigned32(this); |
309 Node* input_value = assembler.LoadHeapNumberValue(input); | 294 Node* input_value = LoadHeapNumberValue(input); |
310 Node* input_value32 = assembler.TruncateFloat64ToWord32(input_value); | 295 Node* input_value32 = TruncateFloat64ToWord32(input_value); |
311 assembler.GotoIf( | 296 GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)), |
312 assembler.Float64Equal(input_value, | 297 &if_inputissigned32); |
313 assembler.ChangeInt32ToFloat64(input_value32)), | |
314 &if_inputissigned32); | |
315 | 298 |
316 // Check if the absolute {input} value is in the ]0.01,1e9[ range. | 299 // Check if the absolute {input} value is in the ]0.01,1e9[ range. |
317 Node* input_value_abs = assembler.Float64Abs(input_value); | 300 Node* input_value_abs = Float64Abs(input_value); |
318 | 301 |
319 assembler.GotoUnless(assembler.Float64LessThan( | 302 GotoUnless(Float64LessThan(input_value_abs, Float64Constant(1e9)), |
320 input_value_abs, assembler.Float64Constant(1e9)), | 303 &if_generic); |
321 &if_generic); | 304 Branch(Float64LessThan(Float64Constant(0.01), input_value_abs), |
322 assembler.Branch(assembler.Float64LessThan( | 305 &if_inputissigned32, &if_generic); |
323 assembler.Float64Constant(0.01), input_value_abs), | |
324 &if_inputissigned32, &if_generic); | |
325 | 306 |
326 // Return the truncated int32 value, and return the tagged result. | 307 // Return the truncated int32 value, and return the tagged result. |
327 assembler.Bind(&if_inputissigned32); | 308 Bind(&if_inputissigned32); |
328 Node* result = assembler.ChangeInt32ToTagged(input_value32); | 309 Node* result = ChangeInt32ToTagged(input_value32); |
329 assembler.Return(result); | 310 Return(result); |
330 } | 311 } |
331 | 312 |
332 assembler.Bind(&if_inputisstring); | 313 Bind(&if_inputisstring); |
333 { | 314 { |
334 // Check if the String {input} has a cached array index. | 315 // Check if the String {input} has a cached array index. |
335 Node* input_hash = assembler.LoadNameHashField(input); | 316 Node* input_hash = LoadNameHashField(input); |
336 Node* input_bit = assembler.Word32And( | 317 Node* input_bit = Word32And( |
337 input_hash, | 318 input_hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
338 assembler.Int32Constant(String::kContainsCachedArrayIndexMask)); | 319 GotoIf(Word32NotEqual(input_bit, Int32Constant(0)), &if_generic); |
339 assembler.GotoIf( | |
340 assembler.Word32NotEqual(input_bit, assembler.Int32Constant(0)), | |
341 &if_generic); | |
342 | 320 |
343 // Return the cached array index as result. | 321 // Return the cached array index as result. |
344 Node* input_index = | 322 Node* input_index = |
345 assembler.DecodeWordFromWord32<String::ArrayIndexValueBits>( | 323 DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash); |
346 input_hash); | 324 Node* result = SmiTag(input_index); |
347 Node* result = assembler.SmiTag(input_index); | 325 Return(result); |
348 assembler.Return(result); | |
349 } | 326 } |
350 } | 327 } |
351 | 328 |
352 assembler.Bind(&if_generic); | 329 Bind(&if_generic); |
353 { | 330 { |
354 Node* result = | 331 Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix); |
355 assembler.CallRuntime(Runtime::kStringParseInt, context, input, radix); | 332 Return(result); |
356 assembler.Return(result); | |
357 } | 333 } |
358 } | 334 } |
359 | 335 |
360 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) | 336 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) |
361 BUILTIN(NumberPrototypeToExponential) { | 337 BUILTIN(NumberPrototypeToExponential) { |
362 HandleScope scope(isolate); | 338 HandleScope scope(isolate); |
363 Handle<Object> value = args.at<Object>(0); | 339 Handle<Object> value = args.at<Object>(0); |
364 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | 340 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); |
365 | 341 |
366 // Unwrap the receiver {value}. | 342 // Unwrap the receiver {value}. |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 : isolate->heap()->infinity_string(); | 535 : isolate->heap()->infinity_string(); |
560 } | 536 } |
561 char* const str = | 537 char* const str = |
562 DoubleToRadixCString(value_number, static_cast<int>(radix_number)); | 538 DoubleToRadixCString(value_number, static_cast<int>(radix_number)); |
563 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | 539 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); |
564 DeleteArray(str); | 540 DeleteArray(str); |
565 return *result; | 541 return *result; |
566 } | 542 } |
567 | 543 |
568 // ES6 section 20.1.3.7 Number.prototype.valueOf ( ) | 544 // ES6 section 20.1.3.7 Number.prototype.valueOf ( ) |
569 void Builtins::Generate_NumberPrototypeValueOf( | 545 TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) { |
570 compiler::CodeAssemblerState* state) { | 546 Node* receiver = Parameter(0); |
571 typedef compiler::Node Node; | 547 Node* context = Parameter(3); |
572 CodeStubAssembler assembler(state); | 548 |
573 | 549 Node* result = ToThisValue(context, receiver, PrimitiveType::kNumber, |
574 Node* receiver = assembler.Parameter(0); | 550 "Number.prototype.valueOf"); |
575 Node* context = assembler.Parameter(3); | 551 Return(result); |
576 | |
577 Node* result = assembler.ToThisValue( | |
578 context, receiver, PrimitiveType::kNumber, "Number.prototype.valueOf"); | |
579 assembler.Return(result); | |
580 } | 552 } |
581 | 553 |
582 // static | 554 TF_BUILTIN(Add, CodeStubAssembler) { |
583 void Builtins::Generate_Add(compiler::CodeAssemblerState* state) { | 555 Node* left = Parameter(0); |
584 typedef CodeStubAssembler::Label Label; | 556 Node* right = Parameter(1); |
585 typedef compiler::Node Node; | 557 Node* context = Parameter(2); |
586 typedef CodeStubAssembler::Variable Variable; | |
587 CodeStubAssembler assembler(state); | |
588 | |
589 Node* left = assembler.Parameter(0); | |
590 Node* right = assembler.Parameter(1); | |
591 Node* context = assembler.Parameter(2); | |
592 | 558 |
593 // Shared entry for floating point addition. | 559 // Shared entry for floating point addition. |
594 Label do_fadd(&assembler); | 560 Label do_fadd(this); |
595 Variable var_fadd_lhs(&assembler, MachineRepresentation::kFloat64), | 561 Variable var_fadd_lhs(this, MachineRepresentation::kFloat64), |
596 var_fadd_rhs(&assembler, MachineRepresentation::kFloat64); | 562 var_fadd_rhs(this, MachineRepresentation::kFloat64); |
597 | 563 |
598 // We might need to loop several times due to ToPrimitive, ToString and/or | 564 // We might need to loop several times due to ToPrimitive, ToString and/or |
599 // ToNumber conversions. | 565 // ToNumber conversions. |
600 Variable var_lhs(&assembler, MachineRepresentation::kTagged), | 566 Variable var_lhs(this, MachineRepresentation::kTagged), |
601 var_rhs(&assembler, MachineRepresentation::kTagged), | 567 var_rhs(this, MachineRepresentation::kTagged), |
602 var_result(&assembler, MachineRepresentation::kTagged); | 568 var_result(this, MachineRepresentation::kTagged); |
603 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | 569 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
604 Label loop(&assembler, 2, loop_vars), end(&assembler), | 570 Label loop(this, 2, loop_vars), end(this), |
605 string_add_convert_left(&assembler, Label::kDeferred), | 571 string_add_convert_left(this, Label::kDeferred), |
606 string_add_convert_right(&assembler, Label::kDeferred); | 572 string_add_convert_right(this, Label::kDeferred); |
607 var_lhs.Bind(left); | 573 var_lhs.Bind(left); |
608 var_rhs.Bind(right); | 574 var_rhs.Bind(right); |
609 assembler.Goto(&loop); | 575 Goto(&loop); |
610 assembler.Bind(&loop); | 576 Bind(&loop); |
611 { | 577 { |
612 // Load the current {lhs} and {rhs} values. | 578 // Load the current {lhs} and {rhs} values. |
613 Node* lhs = var_lhs.value(); | 579 Node* lhs = var_lhs.value(); |
614 Node* rhs = var_rhs.value(); | 580 Node* rhs = var_rhs.value(); |
615 | 581 |
616 // Check if the {lhs} is a Smi or a HeapObject. | 582 // Check if the {lhs} is a Smi or a HeapObject. |
617 Label if_lhsissmi(&assembler), if_lhsisnotsmi(&assembler); | 583 Label if_lhsissmi(this), if_lhsisnotsmi(this); |
618 assembler.Branch(assembler.TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | 584 Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
619 | 585 |
620 assembler.Bind(&if_lhsissmi); | 586 Bind(&if_lhsissmi); |
621 { | 587 { |
622 // Check if the {rhs} is also a Smi. | 588 // Check if the {rhs} is also a Smi. |
623 Label if_rhsissmi(&assembler), if_rhsisnotsmi(&assembler); | 589 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
624 assembler.Branch(assembler.TaggedIsSmi(rhs), &if_rhsissmi, | 590 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
625 &if_rhsisnotsmi); | 591 |
626 | 592 Bind(&if_rhsissmi); |
627 assembler.Bind(&if_rhsissmi); | |
628 { | 593 { |
629 // Try fast Smi addition first. | 594 // Try fast Smi addition first. |
630 Node* pair = | 595 Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs), |
631 assembler.IntPtrAddWithOverflow(assembler.BitcastTaggedToWord(lhs), | 596 BitcastTaggedToWord(rhs)); |
632 assembler.BitcastTaggedToWord(rhs)); | 597 Node* overflow = Projection(1, pair); |
633 Node* overflow = assembler.Projection(1, pair); | |
634 | 598 |
635 // Check if the Smi additon overflowed. | 599 // Check if the Smi additon overflowed. |
636 Label if_overflow(&assembler), if_notoverflow(&assembler); | 600 Label if_overflow(this), if_notoverflow(this); |
637 assembler.Branch(overflow, &if_overflow, &if_notoverflow); | 601 Branch(overflow, &if_overflow, &if_notoverflow); |
638 | 602 |
639 assembler.Bind(&if_overflow); | 603 Bind(&if_overflow); |
640 { | 604 { |
641 var_fadd_lhs.Bind(assembler.SmiToFloat64(lhs)); | 605 var_fadd_lhs.Bind(SmiToFloat64(lhs)); |
642 var_fadd_rhs.Bind(assembler.SmiToFloat64(rhs)); | 606 var_fadd_rhs.Bind(SmiToFloat64(rhs)); |
643 assembler.Goto(&do_fadd); | 607 Goto(&do_fadd); |
644 } | 608 } |
645 | 609 |
646 assembler.Bind(&if_notoverflow); | 610 Bind(&if_notoverflow); |
647 var_result.Bind( | 611 var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); |
648 assembler.BitcastWordToTaggedSigned(assembler.Projection(0, pair))); | 612 Goto(&end); |
649 assembler.Goto(&end); | |
650 } | 613 } |
651 | 614 |
652 assembler.Bind(&if_rhsisnotsmi); | 615 Bind(&if_rhsisnotsmi); |
653 { | 616 { |
654 // Load the map of {rhs}. | 617 // Load the map of {rhs}. |
655 Node* rhs_map = assembler.LoadMap(rhs); | 618 Node* rhs_map = LoadMap(rhs); |
656 | 619 |
657 // Check if the {rhs} is a HeapNumber. | 620 // Check if the {rhs} is a HeapNumber. |
658 Label if_rhsisnumber(&assembler), | 621 Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
659 if_rhsisnotnumber(&assembler, Label::kDeferred); | 622 Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber); |
660 assembler.Branch(assembler.IsHeapNumberMap(rhs_map), &if_rhsisnumber, | 623 |
661 &if_rhsisnotnumber); | 624 Bind(&if_rhsisnumber); |
662 | 625 { |
663 assembler.Bind(&if_rhsisnumber); | 626 var_fadd_lhs.Bind(SmiToFloat64(lhs)); |
664 { | 627 var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); |
665 var_fadd_lhs.Bind(assembler.SmiToFloat64(lhs)); | 628 Goto(&do_fadd); |
666 var_fadd_rhs.Bind(assembler.LoadHeapNumberValue(rhs)); | |
667 assembler.Goto(&do_fadd); | |
668 } | 629 } |
669 | 630 |
670 assembler.Bind(&if_rhsisnotnumber); | 631 Bind(&if_rhsisnotnumber); |
671 { | 632 { |
672 // Load the instance type of {rhs}. | 633 // Load the instance type of {rhs}. |
673 Node* rhs_instance_type = assembler.LoadMapInstanceType(rhs_map); | 634 Node* rhs_instance_type = LoadMapInstanceType(rhs_map); |
674 | 635 |
675 // Check if the {rhs} is a String. | 636 // Check if the {rhs} is a String. |
676 Label if_rhsisstring(&assembler, Label::kDeferred), | 637 Label if_rhsisstring(this, Label::kDeferred), |
677 if_rhsisnotstring(&assembler, Label::kDeferred); | 638 if_rhsisnotstring(this, Label::kDeferred); |
678 assembler.Branch(assembler.IsStringInstanceType(rhs_instance_type), | 639 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
679 &if_rhsisstring, &if_rhsisnotstring); | 640 &if_rhsisnotstring); |
680 | 641 |
681 assembler.Bind(&if_rhsisstring); | 642 Bind(&if_rhsisstring); |
682 { | 643 { |
683 var_lhs.Bind(lhs); | 644 var_lhs.Bind(lhs); |
684 var_rhs.Bind(rhs); | 645 var_rhs.Bind(rhs); |
685 assembler.Goto(&string_add_convert_left); | 646 Goto(&string_add_convert_left); |
686 } | 647 } |
687 | 648 |
688 assembler.Bind(&if_rhsisnotstring); | 649 Bind(&if_rhsisnotstring); |
689 { | 650 { |
690 // Check if {rhs} is a JSReceiver. | 651 // Check if {rhs} is a JSReceiver. |
691 Label if_rhsisreceiver(&assembler, Label::kDeferred), | 652 Label if_rhsisreceiver(this, Label::kDeferred), |
692 if_rhsisnotreceiver(&assembler, Label::kDeferred); | 653 if_rhsisnotreceiver(this, Label::kDeferred); |
693 assembler.Branch( | 654 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
694 assembler.IsJSReceiverInstanceType(rhs_instance_type), | 655 &if_rhsisreceiver, &if_rhsisnotreceiver); |
695 &if_rhsisreceiver, &if_rhsisnotreceiver); | 656 |
696 | 657 Bind(&if_rhsisreceiver); |
697 assembler.Bind(&if_rhsisreceiver); | |
698 { | 658 { |
699 // Convert {rhs} to a primitive first passing no hint. | 659 // Convert {rhs} to a primitive first passing no hint. |
700 Callable callable = | 660 Callable callable = |
701 CodeFactory::NonPrimitiveToPrimitive(assembler.isolate()); | 661 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
702 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 662 var_rhs.Bind(CallStub(callable, context, rhs)); |
703 assembler.Goto(&loop); | 663 Goto(&loop); |
704 } | 664 } |
705 | 665 |
706 assembler.Bind(&if_rhsisnotreceiver); | 666 Bind(&if_rhsisnotreceiver); |
707 { | 667 { |
708 // Convert {rhs} to a Number first. | 668 // Convert {rhs} to a Number first. |
709 Callable callable = | 669 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
710 CodeFactory::NonNumberToNumber(assembler.isolate()); | 670 var_rhs.Bind(CallStub(callable, context, rhs)); |
711 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 671 Goto(&loop); |
712 assembler.Goto(&loop); | |
713 } | 672 } |
714 } | 673 } |
715 } | 674 } |
716 } | 675 } |
717 } | 676 } |
718 | 677 |
719 assembler.Bind(&if_lhsisnotsmi); | 678 Bind(&if_lhsisnotsmi); |
720 { | 679 { |
721 // Load the map and instance type of {lhs}. | 680 // Load the map and instance type of {lhs}. |
722 Node* lhs_instance_type = assembler.LoadInstanceType(lhs); | 681 Node* lhs_instance_type = LoadInstanceType(lhs); |
723 | 682 |
724 // Check if {lhs} is a String. | 683 // Check if {lhs} is a String. |
725 Label if_lhsisstring(&assembler), if_lhsisnotstring(&assembler); | 684 Label if_lhsisstring(this), if_lhsisnotstring(this); |
726 assembler.Branch(assembler.IsStringInstanceType(lhs_instance_type), | 685 Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring, |
727 &if_lhsisstring, &if_lhsisnotstring); | 686 &if_lhsisnotstring); |
728 | 687 |
729 assembler.Bind(&if_lhsisstring); | 688 Bind(&if_lhsisstring); |
730 { | 689 { |
731 var_lhs.Bind(lhs); | 690 var_lhs.Bind(lhs); |
732 var_rhs.Bind(rhs); | 691 var_rhs.Bind(rhs); |
733 assembler.Goto(&string_add_convert_right); | 692 Goto(&string_add_convert_right); |
734 } | 693 } |
735 | 694 |
736 assembler.Bind(&if_lhsisnotstring); | 695 Bind(&if_lhsisnotstring); |
737 { | 696 { |
738 // Check if {rhs} is a Smi. | 697 // Check if {rhs} is a Smi. |
739 Label if_rhsissmi(&assembler), if_rhsisnotsmi(&assembler); | 698 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
740 assembler.Branch(assembler.TaggedIsSmi(rhs), &if_rhsissmi, | 699 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
741 &if_rhsisnotsmi); | 700 |
742 | 701 Bind(&if_rhsissmi); |
743 assembler.Bind(&if_rhsissmi); | |
744 { | 702 { |
745 // Check if {lhs} is a Number. | 703 // Check if {lhs} is a Number. |
746 Label if_lhsisnumber(&assembler), | 704 Label if_lhsisnumber(this), if_lhsisnotnumber(this, Label::kDeferred); |
747 if_lhsisnotnumber(&assembler, Label::kDeferred); | 705 Branch( |
748 assembler.Branch( | 706 Word32Equal(lhs_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), |
749 assembler.Word32Equal(lhs_instance_type, | |
750 assembler.Int32Constant(HEAP_NUMBER_TYPE)), | |
751 &if_lhsisnumber, &if_lhsisnotnumber); | 707 &if_lhsisnumber, &if_lhsisnotnumber); |
752 | 708 |
753 assembler.Bind(&if_lhsisnumber); | 709 Bind(&if_lhsisnumber); |
754 { | 710 { |
755 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. | 711 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. |
756 var_fadd_lhs.Bind(assembler.LoadHeapNumberValue(lhs)); | 712 var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); |
757 var_fadd_rhs.Bind(assembler.SmiToFloat64(rhs)); | 713 var_fadd_rhs.Bind(SmiToFloat64(rhs)); |
758 assembler.Goto(&do_fadd); | 714 Goto(&do_fadd); |
759 } | 715 } |
760 | 716 |
761 assembler.Bind(&if_lhsisnotnumber); | 717 Bind(&if_lhsisnotnumber); |
762 { | 718 { |
763 // The {lhs} is neither a Number nor a String, and the {rhs} is a | 719 // The {lhs} is neither a Number nor a String, and the {rhs} is a |
764 // Smi. | 720 // Smi. |
765 Label if_lhsisreceiver(&assembler, Label::kDeferred), | 721 Label if_lhsisreceiver(this, Label::kDeferred), |
766 if_lhsisnotreceiver(&assembler, Label::kDeferred); | 722 if_lhsisnotreceiver(this, Label::kDeferred); |
767 assembler.Branch( | 723 Branch(IsJSReceiverInstanceType(lhs_instance_type), |
768 assembler.IsJSReceiverInstanceType(lhs_instance_type), | 724 &if_lhsisreceiver, &if_lhsisnotreceiver); |
769 &if_lhsisreceiver, &if_lhsisnotreceiver); | 725 |
770 | 726 Bind(&if_lhsisreceiver); |
771 assembler.Bind(&if_lhsisreceiver); | |
772 { | 727 { |
773 // Convert {lhs} to a primitive first passing no hint. | 728 // Convert {lhs} to a primitive first passing no hint. |
774 Callable callable = | 729 Callable callable = |
775 CodeFactory::NonPrimitiveToPrimitive(assembler.isolate()); | 730 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
776 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 731 var_lhs.Bind(CallStub(callable, context, lhs)); |
777 assembler.Goto(&loop); | 732 Goto(&loop); |
778 } | 733 } |
779 | 734 |
780 assembler.Bind(&if_lhsisnotreceiver); | 735 Bind(&if_lhsisnotreceiver); |
781 { | 736 { |
782 // Convert {lhs} to a Number first. | 737 // Convert {lhs} to a Number first. |
783 Callable callable = | 738 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
784 CodeFactory::NonNumberToNumber(assembler.isolate()); | 739 var_lhs.Bind(CallStub(callable, context, lhs)); |
785 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 740 Goto(&loop); |
786 assembler.Goto(&loop); | |
787 } | 741 } |
788 } | 742 } |
789 } | 743 } |
790 | 744 |
791 assembler.Bind(&if_rhsisnotsmi); | 745 Bind(&if_rhsisnotsmi); |
792 { | 746 { |
793 // Load the instance type of {rhs}. | 747 // Load the instance type of {rhs}. |
794 Node* rhs_instance_type = assembler.LoadInstanceType(rhs); | 748 Node* rhs_instance_type = LoadInstanceType(rhs); |
795 | 749 |
796 // Check if {rhs} is a String. | 750 // Check if {rhs} is a String. |
797 Label if_rhsisstring(&assembler), if_rhsisnotstring(&assembler); | 751 Label if_rhsisstring(this), if_rhsisnotstring(this); |
798 assembler.Branch(assembler.IsStringInstanceType(rhs_instance_type), | 752 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring, |
799 &if_rhsisstring, &if_rhsisnotstring); | 753 &if_rhsisnotstring); |
800 | 754 |
801 assembler.Bind(&if_rhsisstring); | 755 Bind(&if_rhsisstring); |
802 { | 756 { |
803 var_lhs.Bind(lhs); | 757 var_lhs.Bind(lhs); |
804 var_rhs.Bind(rhs); | 758 var_rhs.Bind(rhs); |
805 assembler.Goto(&string_add_convert_left); | 759 Goto(&string_add_convert_left); |
806 } | 760 } |
807 | 761 |
808 assembler.Bind(&if_rhsisnotstring); | 762 Bind(&if_rhsisnotstring); |
809 { | 763 { |
810 // Check if {lhs} is a HeapNumber. | 764 // Check if {lhs} is a HeapNumber. |
811 Label if_lhsisnumber(&assembler), if_lhsisnotnumber(&assembler); | 765 Label if_lhsisnumber(this), if_lhsisnotnumber(this); |
812 assembler.Branch(assembler.Word32Equal( | 766 Branch( |
813 lhs_instance_type, | 767 Word32Equal(lhs_instance_type, Int32Constant(HEAP_NUMBER_TYPE)), |
814 assembler.Int32Constant(HEAP_NUMBER_TYPE)), | 768 &if_lhsisnumber, &if_lhsisnotnumber); |
815 &if_lhsisnumber, &if_lhsisnotnumber); | 769 |
816 | 770 Bind(&if_lhsisnumber); |
817 assembler.Bind(&if_lhsisnumber); | |
818 { | 771 { |
819 // Check if {rhs} is also a HeapNumber. | 772 // Check if {rhs} is also a HeapNumber. |
820 Label if_rhsisnumber(&assembler), | 773 Label if_rhsisnumber(this), |
821 if_rhsisnotnumber(&assembler, Label::kDeferred); | 774 if_rhsisnotnumber(this, Label::kDeferred); |
822 assembler.Branch(assembler.Word32Equal( | 775 Branch(Word32Equal(rhs_instance_type, |
823 rhs_instance_type, | 776 Int32Constant(HEAP_NUMBER_TYPE)), |
824 assembler.Int32Constant(HEAP_NUMBER_TYPE)), | 777 &if_rhsisnumber, &if_rhsisnotnumber); |
825 &if_rhsisnumber, &if_rhsisnotnumber); | 778 |
826 | 779 Bind(&if_rhsisnumber); |
827 assembler.Bind(&if_rhsisnumber); | |
828 { | 780 { |
829 // Perform a floating point addition. | 781 // Perform a floating point addition. |
830 var_fadd_lhs.Bind(assembler.LoadHeapNumberValue(lhs)); | 782 var_fadd_lhs.Bind(LoadHeapNumberValue(lhs)); |
831 var_fadd_rhs.Bind(assembler.LoadHeapNumberValue(rhs)); | 783 var_fadd_rhs.Bind(LoadHeapNumberValue(rhs)); |
832 assembler.Goto(&do_fadd); | 784 Goto(&do_fadd); |
833 } | 785 } |
834 | 786 |
835 assembler.Bind(&if_rhsisnotnumber); | 787 Bind(&if_rhsisnotnumber); |
836 { | 788 { |
837 // Check if {rhs} is a JSReceiver. | 789 // Check if {rhs} is a JSReceiver. |
838 Label if_rhsisreceiver(&assembler, Label::kDeferred), | 790 Label if_rhsisreceiver(this, Label::kDeferred), |
839 if_rhsisnotreceiver(&assembler, Label::kDeferred); | 791 if_rhsisnotreceiver(this, Label::kDeferred); |
840 assembler.Branch( | 792 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
841 assembler.IsJSReceiverInstanceType(rhs_instance_type), | 793 &if_rhsisreceiver, &if_rhsisnotreceiver); |
842 &if_rhsisreceiver, &if_rhsisnotreceiver); | 794 |
843 | 795 Bind(&if_rhsisreceiver); |
844 assembler.Bind(&if_rhsisreceiver); | |
845 { | 796 { |
846 // Convert {rhs} to a primitive first passing no hint. | 797 // Convert {rhs} to a primitive first passing no hint. |
847 Callable callable = | 798 Callable callable = |
848 CodeFactory::NonPrimitiveToPrimitive(assembler.isolate()); | 799 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
849 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 800 var_rhs.Bind(CallStub(callable, context, rhs)); |
850 assembler.Goto(&loop); | 801 Goto(&loop); |
851 } | 802 } |
852 | 803 |
853 assembler.Bind(&if_rhsisnotreceiver); | 804 Bind(&if_rhsisnotreceiver); |
854 { | 805 { |
855 // Convert {rhs} to a Number first. | 806 // Convert {rhs} to a Number first. |
856 Callable callable = | 807 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
857 CodeFactory::NonNumberToNumber(assembler.isolate()); | 808 var_rhs.Bind(CallStub(callable, context, rhs)); |
858 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 809 Goto(&loop); |
859 assembler.Goto(&loop); | |
860 } | 810 } |
861 } | 811 } |
862 } | 812 } |
863 | 813 |
864 assembler.Bind(&if_lhsisnotnumber); | 814 Bind(&if_lhsisnotnumber); |
865 { | 815 { |
866 // Check if {lhs} is a JSReceiver. | 816 // Check if {lhs} is a JSReceiver. |
867 Label if_lhsisreceiver(&assembler, Label::kDeferred), | 817 Label if_lhsisreceiver(this, Label::kDeferred), |
868 if_lhsisnotreceiver(&assembler); | 818 if_lhsisnotreceiver(this); |
869 assembler.Branch( | 819 Branch(IsJSReceiverInstanceType(lhs_instance_type), |
870 assembler.IsJSReceiverInstanceType(lhs_instance_type), | 820 &if_lhsisreceiver, &if_lhsisnotreceiver); |
871 &if_lhsisreceiver, &if_lhsisnotreceiver); | 821 |
872 | 822 Bind(&if_lhsisreceiver); |
873 assembler.Bind(&if_lhsisreceiver); | |
874 { | 823 { |
875 // Convert {lhs} to a primitive first passing no hint. | 824 // Convert {lhs} to a primitive first passing no hint. |
876 Callable callable = | 825 Callable callable = |
877 CodeFactory::NonPrimitiveToPrimitive(assembler.isolate()); | 826 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
878 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 827 var_lhs.Bind(CallStub(callable, context, lhs)); |
879 assembler.Goto(&loop); | 828 Goto(&loop); |
880 } | 829 } |
881 | 830 |
882 assembler.Bind(&if_lhsisnotreceiver); | 831 Bind(&if_lhsisnotreceiver); |
883 { | 832 { |
884 // Check if {rhs} is a JSReceiver. | 833 // Check if {rhs} is a JSReceiver. |
885 Label if_rhsisreceiver(&assembler, Label::kDeferred), | 834 Label if_rhsisreceiver(this, Label::kDeferred), |
886 if_rhsisnotreceiver(&assembler, Label::kDeferred); | 835 if_rhsisnotreceiver(this, Label::kDeferred); |
887 assembler.Branch( | 836 Branch(IsJSReceiverInstanceType(rhs_instance_type), |
888 assembler.IsJSReceiverInstanceType(rhs_instance_type), | 837 &if_rhsisreceiver, &if_rhsisnotreceiver); |
889 &if_rhsisreceiver, &if_rhsisnotreceiver); | 838 |
890 | 839 Bind(&if_rhsisreceiver); |
891 assembler.Bind(&if_rhsisreceiver); | |
892 { | 840 { |
893 // Convert {rhs} to a primitive first passing no hint. | 841 // Convert {rhs} to a primitive first passing no hint. |
894 Callable callable = | 842 Callable callable = |
895 CodeFactory::NonPrimitiveToPrimitive(assembler.isolate()); | 843 CodeFactory::NonPrimitiveToPrimitive(isolate()); |
896 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 844 var_rhs.Bind(CallStub(callable, context, rhs)); |
897 assembler.Goto(&loop); | 845 Goto(&loop); |
898 } | 846 } |
899 | 847 |
900 assembler.Bind(&if_rhsisnotreceiver); | 848 Bind(&if_rhsisnotreceiver); |
901 { | 849 { |
902 // Convert {lhs} to a Number first. | 850 // Convert {lhs} to a Number first. |
903 Callable callable = | 851 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
904 CodeFactory::NonNumberToNumber(assembler.isolate()); | 852 var_lhs.Bind(CallStub(callable, context, lhs)); |
905 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 853 Goto(&loop); |
906 assembler.Goto(&loop); | |
907 } | 854 } |
908 } | 855 } |
909 } | 856 } |
910 } | 857 } |
911 } | 858 } |
912 } | 859 } |
913 } | 860 } |
914 } | 861 } |
915 assembler.Bind(&string_add_convert_left); | 862 Bind(&string_add_convert_left); |
| 863 { |
| 864 // Convert {lhs}, which is a Smi, to a String and concatenate the |
| 865 // resulting string with the String {rhs}. |
| 866 Callable callable = |
| 867 CodeFactory::StringAdd(isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); |
| 868 var_result.Bind( |
| 869 CallStub(callable, context, var_lhs.value(), var_rhs.value())); |
| 870 Goto(&end); |
| 871 } |
| 872 |
| 873 Bind(&string_add_convert_right); |
916 { | 874 { |
917 // Convert {lhs}, which is a Smi, to a String and concatenate the | 875 // Convert {lhs}, which is a Smi, to a String and concatenate the |
918 // resulting string with the String {rhs}. | 876 // resulting string with the String {rhs}. |
919 Callable callable = CodeFactory::StringAdd( | 877 Callable callable = CodeFactory::StringAdd( |
920 assembler.isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); | 878 isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); |
921 var_result.Bind(assembler.CallStub(callable, context, var_lhs.value(), | 879 var_result.Bind( |
922 var_rhs.value())); | 880 CallStub(callable, context, var_lhs.value(), var_rhs.value())); |
923 assembler.Goto(&end); | 881 Goto(&end); |
924 } | 882 } |
925 | 883 |
926 assembler.Bind(&string_add_convert_right); | 884 Bind(&do_fadd); |
927 { | |
928 // Convert {lhs}, which is a Smi, to a String and concatenate the | |
929 // resulting string with the String {rhs}. | |
930 Callable callable = CodeFactory::StringAdd( | |
931 assembler.isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); | |
932 var_result.Bind(assembler.CallStub(callable, context, var_lhs.value(), | |
933 var_rhs.value())); | |
934 assembler.Goto(&end); | |
935 } | |
936 | |
937 assembler.Bind(&do_fadd); | |
938 { | 885 { |
939 Node* lhs_value = var_fadd_lhs.value(); | 886 Node* lhs_value = var_fadd_lhs.value(); |
940 Node* rhs_value = var_fadd_rhs.value(); | 887 Node* rhs_value = var_fadd_rhs.value(); |
941 Node* value = assembler.Float64Add(lhs_value, rhs_value); | 888 Node* value = Float64Add(lhs_value, rhs_value); |
942 Node* result = assembler.AllocateHeapNumberWithValue(value); | 889 Node* result = AllocateHeapNumberWithValue(value); |
943 var_result.Bind(result); | 890 var_result.Bind(result); |
944 assembler.Goto(&end); | 891 Goto(&end); |
945 } | 892 } |
946 assembler.Bind(&end); | 893 Bind(&end); |
947 assembler.Return(var_result.value()); | 894 Return(var_result.value()); |
948 } | 895 } |
949 | 896 |
950 void Builtins::Generate_Subtract(compiler::CodeAssemblerState* state) { | 897 TF_BUILTIN(Subtract, CodeStubAssembler) { |
951 typedef CodeStubAssembler::Label Label; | 898 Node* left = Parameter(0); |
952 typedef compiler::Node Node; | 899 Node* right = Parameter(1); |
953 typedef CodeStubAssembler::Variable Variable; | 900 Node* context = Parameter(2); |
954 CodeStubAssembler assembler(state); | |
955 | |
956 Node* left = assembler.Parameter(0); | |
957 Node* right = assembler.Parameter(1); | |
958 Node* context = assembler.Parameter(2); | |
959 | 901 |
960 // Shared entry for floating point subtraction. | 902 // Shared entry for floating point subtraction. |
961 Label do_fsub(&assembler), end(&assembler); | 903 Label do_fsub(this), end(this); |
962 Variable var_fsub_lhs(&assembler, MachineRepresentation::kFloat64), | 904 Variable var_fsub_lhs(this, MachineRepresentation::kFloat64), |
963 var_fsub_rhs(&assembler, MachineRepresentation::kFloat64); | 905 var_fsub_rhs(this, MachineRepresentation::kFloat64); |
964 | 906 |
965 // We might need to loop several times due to ToPrimitive and/or ToNumber | 907 // We might need to loop several times due to ToPrimitive and/or ToNumber |
966 // conversions. | 908 // conversions. |
967 Variable var_lhs(&assembler, MachineRepresentation::kTagged), | 909 Variable var_lhs(this, MachineRepresentation::kTagged), |
968 var_rhs(&assembler, MachineRepresentation::kTagged), | 910 var_rhs(this, MachineRepresentation::kTagged), |
969 var_result(&assembler, MachineRepresentation::kTagged); | 911 var_result(this, MachineRepresentation::kTagged); |
970 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; | 912 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
971 Label loop(&assembler, 2, loop_vars); | 913 Label loop(this, 2, loop_vars); |
972 var_lhs.Bind(left); | 914 var_lhs.Bind(left); |
973 var_rhs.Bind(right); | 915 var_rhs.Bind(right); |
974 assembler.Goto(&loop); | 916 Goto(&loop); |
975 assembler.Bind(&loop); | 917 Bind(&loop); |
976 { | 918 { |
977 // Load the current {lhs} and {rhs} values. | 919 // Load the current {lhs} and {rhs} values. |
978 Node* lhs = var_lhs.value(); | 920 Node* lhs = var_lhs.value(); |
979 Node* rhs = var_rhs.value(); | 921 Node* rhs = var_rhs.value(); |
980 | 922 |
981 // Check if the {lhs} is a Smi or a HeapObject. | 923 // Check if the {lhs} is a Smi or a HeapObject. |
982 Label if_lhsissmi(&assembler), if_lhsisnotsmi(&assembler); | 924 Label if_lhsissmi(this), if_lhsisnotsmi(this); |
983 assembler.Branch(assembler.TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); | 925 Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
984 | 926 |
985 assembler.Bind(&if_lhsissmi); | 927 Bind(&if_lhsissmi); |
986 { | 928 { |
987 // Check if the {rhs} is also a Smi. | 929 // Check if the {rhs} is also a Smi. |
988 Label if_rhsissmi(&assembler), if_rhsisnotsmi(&assembler); | 930 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
989 assembler.Branch(assembler.TaggedIsSmi(rhs), &if_rhsissmi, | 931 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
990 &if_rhsisnotsmi); | 932 |
991 | 933 Bind(&if_rhsissmi); |
992 assembler.Bind(&if_rhsissmi); | |
993 { | 934 { |
994 // Try a fast Smi subtraction first. | 935 // Try a fast Smi subtraction first. |
995 Node* pair = | 936 Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs), |
996 assembler.IntPtrSubWithOverflow(assembler.BitcastTaggedToWord(lhs), | 937 BitcastTaggedToWord(rhs)); |
997 assembler.BitcastTaggedToWord(rhs)); | 938 Node* overflow = Projection(1, pair); |
998 Node* overflow = assembler.Projection(1, pair); | |
999 | 939 |
1000 // Check if the Smi subtraction overflowed. | 940 // Check if the Smi subtraction overflowed. |
1001 Label if_overflow(&assembler), if_notoverflow(&assembler); | 941 Label if_overflow(this), if_notoverflow(this); |
1002 assembler.Branch(overflow, &if_overflow, &if_notoverflow); | 942 Branch(overflow, &if_overflow, &if_notoverflow); |
1003 | 943 |
1004 assembler.Bind(&if_overflow); | 944 Bind(&if_overflow); |
1005 { | 945 { |
1006 // The result doesn't fit into Smi range. | 946 // The result doesn't fit into Smi range. |
1007 var_fsub_lhs.Bind(assembler.SmiToFloat64(lhs)); | 947 var_fsub_lhs.Bind(SmiToFloat64(lhs)); |
1008 var_fsub_rhs.Bind(assembler.SmiToFloat64(rhs)); | 948 var_fsub_rhs.Bind(SmiToFloat64(rhs)); |
1009 assembler.Goto(&do_fsub); | 949 Goto(&do_fsub); |
1010 } | 950 } |
1011 | 951 |
1012 assembler.Bind(&if_notoverflow); | 952 Bind(&if_notoverflow); |
1013 var_result.Bind( | 953 var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair))); |
1014 assembler.BitcastWordToTaggedSigned(assembler.Projection(0, pair))); | 954 Goto(&end); |
1015 assembler.Goto(&end); | 955 } |
1016 } | 956 |
1017 | 957 Bind(&if_rhsisnotsmi); |
1018 assembler.Bind(&if_rhsisnotsmi); | |
1019 { | 958 { |
1020 // Load the map of the {rhs}. | 959 // Load the map of the {rhs}. |
1021 Node* rhs_map = assembler.LoadMap(rhs); | 960 Node* rhs_map = LoadMap(rhs); |
1022 | 961 |
1023 // Check if {rhs} is a HeapNumber. | 962 // Check if {rhs} is a HeapNumber. |
1024 Label if_rhsisnumber(&assembler), | 963 Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
1025 if_rhsisnotnumber(&assembler, Label::kDeferred); | 964 Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber); |
1026 assembler.Branch(assembler.IsHeapNumberMap(rhs_map), &if_rhsisnumber, | 965 |
1027 &if_rhsisnotnumber); | 966 Bind(&if_rhsisnumber); |
1028 | |
1029 assembler.Bind(&if_rhsisnumber); | |
1030 { | 967 { |
1031 // Perform a floating point subtraction. | 968 // Perform a floating point subtraction. |
1032 var_fsub_lhs.Bind(assembler.SmiToFloat64(lhs)); | 969 var_fsub_lhs.Bind(SmiToFloat64(lhs)); |
1033 var_fsub_rhs.Bind(assembler.LoadHeapNumberValue(rhs)); | 970 var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); |
1034 assembler.Goto(&do_fsub); | 971 Goto(&do_fsub); |
1035 } | 972 } |
1036 | 973 |
1037 assembler.Bind(&if_rhsisnotnumber); | 974 Bind(&if_rhsisnotnumber); |
1038 { | 975 { |
1039 // Convert the {rhs} to a Number first. | 976 // Convert the {rhs} to a Number first. |
1040 Callable callable = | 977 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1041 CodeFactory::NonNumberToNumber(assembler.isolate()); | 978 var_rhs.Bind(CallStub(callable, context, rhs)); |
1042 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 979 Goto(&loop); |
1043 assembler.Goto(&loop); | 980 } |
1044 } | 981 } |
1045 } | 982 } |
1046 } | 983 |
1047 | 984 Bind(&if_lhsisnotsmi); |
1048 assembler.Bind(&if_lhsisnotsmi); | |
1049 { | 985 { |
1050 // Load the map of the {lhs}. | 986 // Load the map of the {lhs}. |
1051 Node* lhs_map = assembler.LoadMap(lhs); | 987 Node* lhs_map = LoadMap(lhs); |
1052 | 988 |
1053 // Check if the {lhs} is a HeapNumber. | 989 // Check if the {lhs} is a HeapNumber. |
1054 Label if_lhsisnumber(&assembler), | 990 Label if_lhsisnumber(this), if_lhsisnotnumber(this, Label::kDeferred); |
1055 if_lhsisnotnumber(&assembler, Label::kDeferred); | 991 Node* number_map = HeapNumberMapConstant(); |
1056 Node* number_map = assembler.HeapNumberMapConstant(); | 992 Branch(WordEqual(lhs_map, number_map), &if_lhsisnumber, |
1057 assembler.Branch(assembler.WordEqual(lhs_map, number_map), | 993 &if_lhsisnotnumber); |
1058 &if_lhsisnumber, &if_lhsisnotnumber); | 994 |
1059 | 995 Bind(&if_lhsisnumber); |
1060 assembler.Bind(&if_lhsisnumber); | |
1061 { | 996 { |
1062 // Check if the {rhs} is a Smi. | 997 // Check if the {rhs} is a Smi. |
1063 Label if_rhsissmi(&assembler), if_rhsisnotsmi(&assembler); | 998 Label if_rhsissmi(this), if_rhsisnotsmi(this); |
1064 assembler.Branch(assembler.TaggedIsSmi(rhs), &if_rhsissmi, | 999 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi); |
1065 &if_rhsisnotsmi); | 1000 |
1066 | 1001 Bind(&if_rhsissmi); |
1067 assembler.Bind(&if_rhsissmi); | |
1068 { | 1002 { |
1069 // Perform a floating point subtraction. | 1003 // Perform a floating point subtraction. |
1070 var_fsub_lhs.Bind(assembler.LoadHeapNumberValue(lhs)); | 1004 var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); |
1071 var_fsub_rhs.Bind(assembler.SmiToFloat64(rhs)); | 1005 var_fsub_rhs.Bind(SmiToFloat64(rhs)); |
1072 assembler.Goto(&do_fsub); | 1006 Goto(&do_fsub); |
1073 } | 1007 } |
1074 | 1008 |
1075 assembler.Bind(&if_rhsisnotsmi); | 1009 Bind(&if_rhsisnotsmi); |
1076 { | 1010 { |
1077 // Load the map of the {rhs}. | 1011 // Load the map of the {rhs}. |
1078 Node* rhs_map = assembler.LoadMap(rhs); | 1012 Node* rhs_map = LoadMap(rhs); |
1079 | 1013 |
1080 // Check if the {rhs} is a HeapNumber. | 1014 // Check if the {rhs} is a HeapNumber. |
1081 Label if_rhsisnumber(&assembler), | 1015 Label if_rhsisnumber(this), if_rhsisnotnumber(this, Label::kDeferred); |
1082 if_rhsisnotnumber(&assembler, Label::kDeferred); | 1016 Branch(WordEqual(rhs_map, number_map), &if_rhsisnumber, |
1083 assembler.Branch(assembler.WordEqual(rhs_map, number_map), | 1017 &if_rhsisnotnumber); |
1084 &if_rhsisnumber, &if_rhsisnotnumber); | 1018 |
1085 | 1019 Bind(&if_rhsisnumber); |
1086 assembler.Bind(&if_rhsisnumber); | |
1087 { | 1020 { |
1088 // Perform a floating point subtraction. | 1021 // Perform a floating point subtraction. |
1089 var_fsub_lhs.Bind(assembler.LoadHeapNumberValue(lhs)); | 1022 var_fsub_lhs.Bind(LoadHeapNumberValue(lhs)); |
1090 var_fsub_rhs.Bind(assembler.LoadHeapNumberValue(rhs)); | 1023 var_fsub_rhs.Bind(LoadHeapNumberValue(rhs)); |
1091 assembler.Goto(&do_fsub); | 1024 Goto(&do_fsub); |
1092 } | 1025 } |
1093 | 1026 |
1094 assembler.Bind(&if_rhsisnotnumber); | 1027 Bind(&if_rhsisnotnumber); |
1095 { | 1028 { |
1096 // Convert the {rhs} to a Number first. | 1029 // Convert the {rhs} to a Number first. |
1097 Callable callable = | 1030 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1098 CodeFactory::NonNumberToNumber(assembler.isolate()); | 1031 var_rhs.Bind(CallStub(callable, context, rhs)); |
1099 var_rhs.Bind(assembler.CallStub(callable, context, rhs)); | 1032 Goto(&loop); |
1100 assembler.Goto(&loop); | |
1101 } | 1033 } |
1102 } | 1034 } |
1103 } | 1035 } |
1104 | 1036 |
1105 assembler.Bind(&if_lhsisnotnumber); | 1037 Bind(&if_lhsisnotnumber); |
1106 { | 1038 { |
1107 // Convert the {lhs} to a Number first. | 1039 // Convert the {lhs} to a Number first. |
1108 Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); | 1040 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1109 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 1041 var_lhs.Bind(CallStub(callable, context, lhs)); |
1110 assembler.Goto(&loop); | 1042 Goto(&loop); |
1111 } | 1043 } |
1112 } | 1044 } |
1113 } | 1045 } |
1114 | 1046 |
1115 assembler.Bind(&do_fsub); | 1047 Bind(&do_fsub); |
1116 { | 1048 { |
1117 Node* lhs_value = var_fsub_lhs.value(); | 1049 Node* lhs_value = var_fsub_lhs.value(); |
1118 Node* rhs_value = var_fsub_rhs.value(); | 1050 Node* rhs_value = var_fsub_rhs.value(); |
1119 Node* value = assembler.Float64Sub(lhs_value, rhs_value); | 1051 Node* value = Float64Sub(lhs_value, rhs_value); |
1120 var_result.Bind(assembler.AllocateHeapNumberWithValue(value)); | 1052 var_result.Bind(AllocateHeapNumberWithValue(value)); |
1121 assembler.Goto(&end); | 1053 Goto(&end); |
1122 } | 1054 } |
1123 assembler.Bind(&end); | 1055 Bind(&end); |
1124 assembler.Return(var_result.value()); | 1056 Return(var_result.value()); |
1125 } | 1057 } |
1126 | 1058 |
1127 void Builtins::Generate_Multiply(compiler::CodeAssemblerState* state) { | 1059 TF_BUILTIN(Multiply, CodeStubAssembler) { |
1128 typedef CodeStubAssembler::Label Label; | 1060 Node* left = Parameter(0); |
1129 typedef compiler::Node Node; | 1061 Node* right = Parameter(1); |
1130 typedef CodeStubAssembler::Variable Variable; | 1062 Node* context = Parameter(2); |
1131 CodeStubAssembler assembler(state); | |
1132 | |
1133 Node* left = assembler.Parameter(0); | |
1134 Node* right = assembler.Parameter(1); | |
1135 Node* context = assembler.Parameter(2); | |
1136 | 1063 |
1137 // Shared entry point for floating point multiplication. | 1064 // Shared entry point for floating point multiplication. |
1138 Label do_fmul(&assembler), return_result(&assembler); | 1065 Label do_fmul(this), return_result(this); |
1139 Variable var_lhs_float64(&assembler, MachineRepresentation::kFloat64), | 1066 Variable var_lhs_float64(this, MachineRepresentation::kFloat64), |
1140 var_rhs_float64(&assembler, MachineRepresentation::kFloat64); | 1067 var_rhs_float64(this, MachineRepresentation::kFloat64); |
1141 | 1068 |
1142 Node* number_map = assembler.HeapNumberMapConstant(); | 1069 Node* number_map = HeapNumberMapConstant(); |
1143 | 1070 |
1144 // We might need to loop one or two times due to ToNumber conversions. | 1071 // We might need to loop one or two times due to ToNumber conversions. |
1145 Variable var_lhs(&assembler, MachineRepresentation::kTagged), | 1072 Variable var_lhs(this, MachineRepresentation::kTagged), |
1146 var_rhs(&assembler, MachineRepresentation::kTagged), | 1073 var_rhs(this, MachineRepresentation::kTagged), |
1147 var_result(&assembler, MachineRepresentation::kTagged); | 1074 var_result(this, MachineRepresentation::kTagged); |
1148 Variable* loop_variables[] = {&var_lhs, &var_rhs}; | 1075 Variable* loop_variables[] = {&var_lhs, &var_rhs}; |
1149 Label loop(&assembler, 2, loop_variables); | 1076 Label loop(this, 2, loop_variables); |
1150 var_lhs.Bind(left); | 1077 var_lhs.Bind(left); |
1151 var_rhs.Bind(right); | 1078 var_rhs.Bind(right); |
1152 assembler.Goto(&loop); | 1079 Goto(&loop); |
1153 assembler.Bind(&loop); | 1080 Bind(&loop); |
1154 { | 1081 { |
1155 Node* lhs = var_lhs.value(); | 1082 Node* lhs = var_lhs.value(); |
1156 Node* rhs = var_rhs.value(); | 1083 Node* rhs = var_rhs.value(); |
1157 | 1084 |
1158 Label lhs_is_smi(&assembler), lhs_is_not_smi(&assembler); | 1085 Label lhs_is_smi(this), lhs_is_not_smi(this); |
1159 assembler.Branch(assembler.TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); | 1086 Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); |
1160 | 1087 |
1161 assembler.Bind(&lhs_is_smi); | 1088 Bind(&lhs_is_smi); |
1162 { | 1089 { |
1163 Label rhs_is_smi(&assembler), rhs_is_not_smi(&assembler); | 1090 Label rhs_is_smi(this), rhs_is_not_smi(this); |
1164 assembler.Branch(assembler.TaggedIsSmi(rhs), &rhs_is_smi, | 1091 Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); |
1165 &rhs_is_not_smi); | 1092 |
1166 | 1093 Bind(&rhs_is_smi); |
1167 assembler.Bind(&rhs_is_smi); | |
1168 { | 1094 { |
1169 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, | 1095 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, |
1170 // in case of overflow. | 1096 // in case of overflow. |
1171 var_result.Bind(assembler.SmiMul(lhs, rhs)); | 1097 var_result.Bind(SmiMul(lhs, rhs)); |
1172 assembler.Goto(&return_result); | 1098 Goto(&return_result); |
1173 } | 1099 } |
1174 | 1100 |
1175 assembler.Bind(&rhs_is_not_smi); | 1101 Bind(&rhs_is_not_smi); |
1176 { | 1102 { |
1177 Node* rhs_map = assembler.LoadMap(rhs); | 1103 Node* rhs_map = LoadMap(rhs); |
1178 | 1104 |
1179 // Check if {rhs} is a HeapNumber. | 1105 // Check if {rhs} is a HeapNumber. |
1180 Label rhs_is_number(&assembler), | 1106 Label rhs_is_number(this), rhs_is_not_number(this, Label::kDeferred); |
1181 rhs_is_not_number(&assembler, Label::kDeferred); | 1107 Branch(WordEqual(rhs_map, number_map), &rhs_is_number, |
1182 assembler.Branch(assembler.WordEqual(rhs_map, number_map), | 1108 &rhs_is_not_number); |
1183 &rhs_is_number, &rhs_is_not_number); | 1109 |
1184 | 1110 Bind(&rhs_is_number); |
1185 assembler.Bind(&rhs_is_number); | |
1186 { | 1111 { |
1187 // Convert {lhs} to a double and multiply it with the value of {rhs}. | 1112 // Convert {lhs} to a double and multiply it with the value of {rhs}. |
1188 var_lhs_float64.Bind(assembler.SmiToFloat64(lhs)); | 1113 var_lhs_float64.Bind(SmiToFloat64(lhs)); |
1189 var_rhs_float64.Bind(assembler.LoadHeapNumberValue(rhs)); | 1114 var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); |
1190 assembler.Goto(&do_fmul); | 1115 Goto(&do_fmul); |
1191 } | 1116 } |
1192 | 1117 |
1193 assembler.Bind(&rhs_is_not_number); | 1118 Bind(&rhs_is_not_number); |
1194 { | 1119 { |
1195 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | 1120 // Multiplication is commutative, swap {lhs} with {rhs} and loop. |
1196 var_lhs.Bind(rhs); | 1121 var_lhs.Bind(rhs); |
1197 var_rhs.Bind(lhs); | 1122 var_rhs.Bind(lhs); |
1198 assembler.Goto(&loop); | 1123 Goto(&loop); |
1199 } | 1124 } |
1200 } | 1125 } |
1201 } | 1126 } |
1202 | 1127 |
1203 assembler.Bind(&lhs_is_not_smi); | 1128 Bind(&lhs_is_not_smi); |
1204 { | 1129 { |
1205 Node* lhs_map = assembler.LoadMap(lhs); | 1130 Node* lhs_map = LoadMap(lhs); |
1206 | 1131 |
1207 // Check if {lhs} is a HeapNumber. | 1132 // Check if {lhs} is a HeapNumber. |
1208 Label lhs_is_number(&assembler), | 1133 Label lhs_is_number(this), lhs_is_not_number(this, Label::kDeferred); |
1209 lhs_is_not_number(&assembler, Label::kDeferred); | 1134 Branch(WordEqual(lhs_map, number_map), &lhs_is_number, |
1210 assembler.Branch(assembler.WordEqual(lhs_map, number_map), &lhs_is_number, | 1135 &lhs_is_not_number); |
1211 &lhs_is_not_number); | 1136 |
1212 | 1137 Bind(&lhs_is_number); |
1213 assembler.Bind(&lhs_is_number); | |
1214 { | 1138 { |
1215 // Check if {rhs} is a Smi. | 1139 // Check if {rhs} is a Smi. |
1216 Label rhs_is_smi(&assembler), rhs_is_not_smi(&assembler); | 1140 Label rhs_is_smi(this), rhs_is_not_smi(this); |
1217 assembler.Branch(assembler.TaggedIsSmi(rhs), &rhs_is_smi, | 1141 Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi); |
1218 &rhs_is_not_smi); | 1142 |
1219 | 1143 Bind(&rhs_is_smi); |
1220 assembler.Bind(&rhs_is_smi); | |
1221 { | 1144 { |
1222 // Convert {rhs} to a double and multiply it with the value of {lhs}. | 1145 // Convert {rhs} to a double and multiply it with the value of {lhs}. |
1223 var_lhs_float64.Bind(assembler.LoadHeapNumberValue(lhs)); | 1146 var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); |
1224 var_rhs_float64.Bind(assembler.SmiToFloat64(rhs)); | 1147 var_rhs_float64.Bind(SmiToFloat64(rhs)); |
1225 assembler.Goto(&do_fmul); | 1148 Goto(&do_fmul); |
1226 } | 1149 } |
1227 | 1150 |
1228 assembler.Bind(&rhs_is_not_smi); | 1151 Bind(&rhs_is_not_smi); |
1229 { | 1152 { |
1230 Node* rhs_map = assembler.LoadMap(rhs); | 1153 Node* rhs_map = LoadMap(rhs); |
1231 | 1154 |
1232 // Check if {rhs} is a HeapNumber. | 1155 // Check if {rhs} is a HeapNumber. |
1233 Label rhs_is_number(&assembler), | 1156 Label rhs_is_number(this), rhs_is_not_number(this, Label::kDeferred); |
1234 rhs_is_not_number(&assembler, Label::kDeferred); | 1157 Branch(WordEqual(rhs_map, number_map), &rhs_is_number, |
1235 assembler.Branch(assembler.WordEqual(rhs_map, number_map), | 1158 &rhs_is_not_number); |
1236 &rhs_is_number, &rhs_is_not_number); | 1159 |
1237 | 1160 Bind(&rhs_is_number); |
1238 assembler.Bind(&rhs_is_number); | |
1239 { | 1161 { |
1240 // Both {lhs} and {rhs} are HeapNumbers. Load their values and | 1162 // Both {lhs} and {rhs} are HeapNumbers. Load their values and |
1241 // multiply them. | 1163 // multiply them. |
1242 var_lhs_float64.Bind(assembler.LoadHeapNumberValue(lhs)); | 1164 var_lhs_float64.Bind(LoadHeapNumberValue(lhs)); |
1243 var_rhs_float64.Bind(assembler.LoadHeapNumberValue(rhs)); | 1165 var_rhs_float64.Bind(LoadHeapNumberValue(rhs)); |
1244 assembler.Goto(&do_fmul); | 1166 Goto(&do_fmul); |
1245 } | 1167 } |
1246 | 1168 |
1247 assembler.Bind(&rhs_is_not_number); | 1169 Bind(&rhs_is_not_number); |
1248 { | 1170 { |
1249 // Multiplication is commutative, swap {lhs} with {rhs} and loop. | 1171 // Multiplication is commutative, swap {lhs} with {rhs} and loop. |
1250 var_lhs.Bind(rhs); | 1172 var_lhs.Bind(rhs); |
1251 var_rhs.Bind(lhs); | 1173 var_rhs.Bind(lhs); |
1252 assembler.Goto(&loop); | 1174 Goto(&loop); |
1253 } | 1175 } |
1254 } | 1176 } |
1255 } | 1177 } |
1256 | 1178 |
1257 assembler.Bind(&lhs_is_not_number); | 1179 Bind(&lhs_is_not_number); |
1258 { | 1180 { |
1259 // Convert {lhs} to a Number and loop. | 1181 // Convert {lhs} to a Number and loop. |
1260 Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); | 1182 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1261 var_lhs.Bind(assembler.CallStub(callable, context, lhs)); | 1183 var_lhs.Bind(CallStub(callable, context, lhs)); |
1262 assembler.Goto(&loop); | 1184 Goto(&loop); |
1263 } | 1185 } |
1264 } | 1186 } |
1265 } | 1187 } |
1266 | 1188 |
1267 assembler.Bind(&do_fmul); | 1189 Bind(&do_fmul); |
1268 { | 1190 { |
1269 Node* value = | 1191 Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); |
1270 assembler.Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); | 1192 Node* result = AllocateHeapNumberWithValue(value); |
1271 Node* result = assembler.AllocateHeapNumberWithValue(value); | |
1272 var_result.Bind(result); | 1193 var_result.Bind(result); |
1273 assembler.Goto(&return_result); | 1194 Goto(&return_result); |
1274 } | 1195 } |
1275 | 1196 |
1276 assembler.Bind(&return_result); | 1197 Bind(&return_result); |
1277 assembler.Return(var_result.value()); | 1198 Return(var_result.value()); |
1278 } | 1199 } |
1279 | 1200 |
1280 void Builtins::Generate_Divide(compiler::CodeAssemblerState* state) { | 1201 TF_BUILTIN(Divide, CodeStubAssembler) { |
1281 typedef CodeStubAssembler::Label Label; | 1202 Node* left = Parameter(0); |
1282 typedef compiler::Node Node; | 1203 Node* right = Parameter(1); |
1283 typedef CodeStubAssembler::Variable Variable; | 1204 Node* context = Parameter(2); |
1284 CodeStubAssembler assembler(state); | |
1285 | |
1286 Node* left = assembler.Parameter(0); | |
1287 Node* right = assembler.Parameter(1); | |
1288 Node* context = assembler.Parameter(2); | |
1289 | 1205 |
1290 // Shared entry point for floating point division. | 1206 // Shared entry point for floating point division. |
1291 Label do_fdiv(&assembler), end(&assembler); | 1207 Label do_fdiv(this), end(this); |
1292 Variable var_dividend_float64(&assembler, MachineRepresentation::kFloat64), | 1208 Variable var_dividend_float64(this, MachineRepresentation::kFloat64), |
1293 var_divisor_float64(&assembler, MachineRepresentation::kFloat64); | 1209 var_divisor_float64(this, MachineRepresentation::kFloat64); |
1294 | 1210 |
1295 Node* number_map = assembler.HeapNumberMapConstant(); | 1211 Node* number_map = HeapNumberMapConstant(); |
1296 | 1212 |
1297 // We might need to loop one or two times due to ToNumber conversions. | 1213 // We might need to loop one or two times due to ToNumber conversions. |
1298 Variable var_dividend(&assembler, MachineRepresentation::kTagged), | 1214 Variable var_dividend(this, MachineRepresentation::kTagged), |
1299 var_divisor(&assembler, MachineRepresentation::kTagged), | 1215 var_divisor(this, MachineRepresentation::kTagged), |
1300 var_result(&assembler, MachineRepresentation::kTagged); | 1216 var_result(this, MachineRepresentation::kTagged); |
1301 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | 1217 Variable* loop_variables[] = {&var_dividend, &var_divisor}; |
1302 Label loop(&assembler, 2, loop_variables); | 1218 Label loop(this, 2, loop_variables); |
1303 var_dividend.Bind(left); | 1219 var_dividend.Bind(left); |
1304 var_divisor.Bind(right); | 1220 var_divisor.Bind(right); |
1305 assembler.Goto(&loop); | 1221 Goto(&loop); |
1306 assembler.Bind(&loop); | 1222 Bind(&loop); |
1307 { | 1223 { |
1308 Node* dividend = var_dividend.value(); | 1224 Node* dividend = var_dividend.value(); |
1309 Node* divisor = var_divisor.value(); | 1225 Node* divisor = var_divisor.value(); |
1310 | 1226 |
1311 Label dividend_is_smi(&assembler), dividend_is_not_smi(&assembler); | 1227 Label dividend_is_smi(this), dividend_is_not_smi(this); |
1312 assembler.Branch(assembler.TaggedIsSmi(dividend), ÷nd_is_smi, | 1228 Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); |
1313 ÷nd_is_not_smi); | 1229 |
1314 | 1230 Bind(÷nd_is_smi); |
1315 assembler.Bind(÷nd_is_smi); | |
1316 { | 1231 { |
1317 Label divisor_is_smi(&assembler), divisor_is_not_smi(&assembler); | 1232 Label divisor_is_smi(this), divisor_is_not_smi(this); |
1318 assembler.Branch(assembler.TaggedIsSmi(divisor), &divisor_is_smi, | 1233 Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); |
1319 &divisor_is_not_smi); | 1234 |
1320 | 1235 Bind(&divisor_is_smi); |
1321 assembler.Bind(&divisor_is_smi); | 1236 { |
1322 { | 1237 Label bailout(this); |
1323 Label bailout(&assembler); | |
1324 | 1238 |
1325 // Do floating point division if {divisor} is zero. | 1239 // Do floating point division if {divisor} is zero. |
1326 assembler.GotoIf( | 1240 GotoIf(WordEqual(divisor, IntPtrConstant(0)), &bailout); |
1327 assembler.WordEqual(divisor, assembler.IntPtrConstant(0)), | |
1328 &bailout); | |
1329 | 1241 |
1330 // Do floating point division {dividend} is zero and {divisor} is | 1242 // Do floating point division {dividend} is zero and {divisor} is |
1331 // negative. | 1243 // negative. |
1332 Label dividend_is_zero(&assembler), dividend_is_not_zero(&assembler); | 1244 Label dividend_is_zero(this), dividend_is_not_zero(this); |
1333 assembler.Branch( | 1245 Branch(WordEqual(dividend, IntPtrConstant(0)), ÷nd_is_zero, |
1334 assembler.WordEqual(dividend, assembler.IntPtrConstant(0)), | 1246 ÷nd_is_not_zero); |
1335 ÷nd_is_zero, ÷nd_is_not_zero); | 1247 |
1336 | 1248 Bind(÷nd_is_zero); |
1337 assembler.Bind(÷nd_is_zero); | 1249 { |
1338 { | 1250 GotoIf(IntPtrLessThan(divisor, IntPtrConstant(0)), &bailout); |
1339 assembler.GotoIf( | 1251 Goto(÷nd_is_not_zero); |
1340 assembler.IntPtrLessThan(divisor, assembler.IntPtrConstant(0)), | 1252 } |
1341 &bailout); | 1253 Bind(÷nd_is_not_zero); |
1342 assembler.Goto(÷nd_is_not_zero); | 1254 |
1343 } | 1255 Node* untagged_divisor = SmiUntag(divisor); |
1344 assembler.Bind(÷nd_is_not_zero); | 1256 Node* untagged_dividend = SmiUntag(dividend); |
1345 | |
1346 Node* untagged_divisor = assembler.SmiUntag(divisor); | |
1347 Node* untagged_dividend = assembler.SmiUntag(dividend); | |
1348 | 1257 |
1349 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 | 1258 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 |
1350 // if the Smi size is 31) and {divisor} is -1. | 1259 // if the Smi size is 31) and {divisor} is -1. |
1351 Label divisor_is_minus_one(&assembler), | 1260 Label divisor_is_minus_one(this), divisor_is_not_minus_one(this); |
1352 divisor_is_not_minus_one(&assembler); | 1261 Branch(Word32Equal(untagged_divisor, Int32Constant(-1)), |
1353 assembler.Branch(assembler.Word32Equal(untagged_divisor, | 1262 &divisor_is_minus_one, &divisor_is_not_minus_one); |
1354 assembler.Int32Constant(-1)), | 1263 |
1355 &divisor_is_minus_one, &divisor_is_not_minus_one); | 1264 Bind(&divisor_is_minus_one); |
1356 | 1265 { |
1357 assembler.Bind(&divisor_is_minus_one); | 1266 GotoIf( |
1358 { | 1267 Word32Equal(untagged_dividend, |
1359 assembler.GotoIf( | 1268 Int32Constant(kSmiValueSize == 32 ? kMinInt |
1360 assembler.Word32Equal( | 1269 : (kMinInt >> 1))), |
1361 untagged_dividend, | |
1362 assembler.Int32Constant( | |
1363 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), | |
1364 &bailout); | 1270 &bailout); |
1365 assembler.Goto(&divisor_is_not_minus_one); | 1271 Goto(&divisor_is_not_minus_one); |
1366 } | 1272 } |
1367 assembler.Bind(&divisor_is_not_minus_one); | 1273 Bind(&divisor_is_not_minus_one); |
1368 | 1274 |
1369 // TODO(epertoso): consider adding a machine instruction that returns | 1275 // TODO(epertoso): consider adding a machine instruction that returns |
1370 // both the result and the remainder. | 1276 // both the result and the remainder. |
1371 Node* untagged_result = | 1277 Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor); |
1372 assembler.Int32Div(untagged_dividend, untagged_divisor); | 1278 Node* truncated = Int32Mul(untagged_result, untagged_divisor); |
1373 Node* truncated = assembler.Int32Mul(untagged_result, untagged_divisor); | |
1374 // Do floating point division if the remainder is not 0. | 1279 // Do floating point division if the remainder is not 0. |
1375 assembler.GotoIf(assembler.Word32NotEqual(untagged_dividend, truncated), | 1280 GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout); |
1376 &bailout); | 1281 var_result.Bind(SmiTag(untagged_result)); |
1377 var_result.Bind(assembler.SmiTag(untagged_result)); | 1282 Goto(&end); |
1378 assembler.Goto(&end); | |
1379 | 1283 |
1380 // Bailout: convert {dividend} and {divisor} to double and do double | 1284 // Bailout: convert {dividend} and {divisor} to double and do double |
1381 // division. | 1285 // division. |
1382 assembler.Bind(&bailout); | 1286 Bind(&bailout); |
1383 { | 1287 { |
1384 var_dividend_float64.Bind(assembler.SmiToFloat64(dividend)); | 1288 var_dividend_float64.Bind(SmiToFloat64(dividend)); |
1385 var_divisor_float64.Bind(assembler.SmiToFloat64(divisor)); | 1289 var_divisor_float64.Bind(SmiToFloat64(divisor)); |
1386 assembler.Goto(&do_fdiv); | 1290 Goto(&do_fdiv); |
1387 } | 1291 } |
1388 } | 1292 } |
1389 | 1293 |
1390 assembler.Bind(&divisor_is_not_smi); | 1294 Bind(&divisor_is_not_smi); |
1391 { | 1295 { |
1392 Node* divisor_map = assembler.LoadMap(divisor); | 1296 Node* divisor_map = LoadMap(divisor); |
1393 | 1297 |
1394 // Check if {divisor} is a HeapNumber. | 1298 // Check if {divisor} is a HeapNumber. |
1395 Label divisor_is_number(&assembler), | 1299 Label divisor_is_number(this), |
1396 divisor_is_not_number(&assembler, Label::kDeferred); | 1300 divisor_is_not_number(this, Label::kDeferred); |
1397 assembler.Branch(assembler.WordEqual(divisor_map, number_map), | 1301 Branch(WordEqual(divisor_map, number_map), &divisor_is_number, |
1398 &divisor_is_number, &divisor_is_not_number); | 1302 &divisor_is_not_number); |
1399 | 1303 |
1400 assembler.Bind(&divisor_is_number); | 1304 Bind(&divisor_is_number); |
1401 { | 1305 { |
1402 // Convert {dividend} to a double and divide it with the value of | 1306 // Convert {dividend} to a double and divide it with the value of |
1403 // {divisor}. | 1307 // {divisor}. |
1404 var_dividend_float64.Bind(assembler.SmiToFloat64(dividend)); | 1308 var_dividend_float64.Bind(SmiToFloat64(dividend)); |
1405 var_divisor_float64.Bind(assembler.LoadHeapNumberValue(divisor)); | 1309 var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); |
1406 assembler.Goto(&do_fdiv); | 1310 Goto(&do_fdiv); |
1407 } | 1311 } |
1408 | 1312 |
1409 assembler.Bind(&divisor_is_not_number); | 1313 Bind(&divisor_is_not_number); |
1410 { | 1314 { |
1411 // Convert {divisor} to a number and loop. | 1315 // Convert {divisor} to a number and loop. |
1412 Callable callable = | 1316 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1413 CodeFactory::NonNumberToNumber(assembler.isolate()); | 1317 var_divisor.Bind(CallStub(callable, context, divisor)); |
1414 var_divisor.Bind(assembler.CallStub(callable, context, divisor)); | 1318 Goto(&loop); |
1415 assembler.Goto(&loop); | 1319 } |
1416 } | 1320 } |
1417 } | 1321 } |
1418 } | 1322 |
1419 | 1323 Bind(÷nd_is_not_smi); |
1420 assembler.Bind(÷nd_is_not_smi); | |
1421 { | 1324 { |
1422 Node* dividend_map = assembler.LoadMap(dividend); | 1325 Node* dividend_map = LoadMap(dividend); |
1423 | 1326 |
1424 // Check if {dividend} is a HeapNumber. | 1327 // Check if {dividend} is a HeapNumber. |
1425 Label dividend_is_number(&assembler), | 1328 Label dividend_is_number(this), |
1426 dividend_is_not_number(&assembler, Label::kDeferred); | 1329 dividend_is_not_number(this, Label::kDeferred); |
1427 assembler.Branch(assembler.WordEqual(dividend_map, number_map), | 1330 Branch(WordEqual(dividend_map, number_map), ÷nd_is_number, |
1428 ÷nd_is_number, ÷nd_is_not_number); | 1331 ÷nd_is_not_number); |
1429 | 1332 |
1430 assembler.Bind(÷nd_is_number); | 1333 Bind(÷nd_is_number); |
1431 { | 1334 { |
1432 // Check if {divisor} is a Smi. | 1335 // Check if {divisor} is a Smi. |
1433 Label divisor_is_smi(&assembler), divisor_is_not_smi(&assembler); | 1336 Label divisor_is_smi(this), divisor_is_not_smi(this); |
1434 assembler.Branch(assembler.TaggedIsSmi(divisor), &divisor_is_smi, | 1337 Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); |
1435 &divisor_is_not_smi); | 1338 |
1436 | 1339 Bind(&divisor_is_smi); |
1437 assembler.Bind(&divisor_is_smi); | |
1438 { | 1340 { |
1439 // Convert {divisor} to a double and use it for a floating point | 1341 // Convert {divisor} to a double and use it for a floating point |
1440 // division. | 1342 // division. |
1441 var_dividend_float64.Bind(assembler.LoadHeapNumberValue(dividend)); | 1343 var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); |
1442 var_divisor_float64.Bind(assembler.SmiToFloat64(divisor)); | 1344 var_divisor_float64.Bind(SmiToFloat64(divisor)); |
1443 assembler.Goto(&do_fdiv); | 1345 Goto(&do_fdiv); |
1444 } | 1346 } |
1445 | 1347 |
1446 assembler.Bind(&divisor_is_not_smi); | 1348 Bind(&divisor_is_not_smi); |
1447 { | 1349 { |
1448 Node* divisor_map = assembler.LoadMap(divisor); | 1350 Node* divisor_map = LoadMap(divisor); |
1449 | 1351 |
1450 // Check if {divisor} is a HeapNumber. | 1352 // Check if {divisor} is a HeapNumber. |
1451 Label divisor_is_number(&assembler), | 1353 Label divisor_is_number(this), |
1452 divisor_is_not_number(&assembler, Label::kDeferred); | 1354 divisor_is_not_number(this, Label::kDeferred); |
1453 assembler.Branch(assembler.WordEqual(divisor_map, number_map), | 1355 Branch(WordEqual(divisor_map, number_map), &divisor_is_number, |
1454 &divisor_is_number, &divisor_is_not_number); | 1356 &divisor_is_not_number); |
1455 | 1357 |
1456 assembler.Bind(&divisor_is_number); | 1358 Bind(&divisor_is_number); |
1457 { | 1359 { |
1458 // Both {dividend} and {divisor} are HeapNumbers. Load their values | 1360 // Both {dividend} and {divisor} are HeapNumbers. Load their values |
1459 // and divide them. | 1361 // and divide them. |
1460 var_dividend_float64.Bind(assembler.LoadHeapNumberValue(dividend)); | 1362 var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); |
1461 var_divisor_float64.Bind(assembler.LoadHeapNumberValue(divisor)); | 1363 var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); |
1462 assembler.Goto(&do_fdiv); | 1364 Goto(&do_fdiv); |
1463 } | 1365 } |
1464 | 1366 |
1465 assembler.Bind(&divisor_is_not_number); | 1367 Bind(&divisor_is_not_number); |
1466 { | 1368 { |
1467 // Convert {divisor} to a number and loop. | 1369 // Convert {divisor} to a number and loop. |
1468 Callable callable = | 1370 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1469 CodeFactory::NonNumberToNumber(assembler.isolate()); | 1371 var_divisor.Bind(CallStub(callable, context, divisor)); |
1470 var_divisor.Bind(assembler.CallStub(callable, context, divisor)); | 1372 Goto(&loop); |
1471 assembler.Goto(&loop); | |
1472 } | 1373 } |
1473 } | 1374 } |
1474 } | 1375 } |
1475 | 1376 |
1476 assembler.Bind(÷nd_is_not_number); | 1377 Bind(÷nd_is_not_number); |
1477 { | 1378 { |
1478 // Convert {dividend} to a Number and loop. | 1379 // Convert {dividend} to a Number and loop. |
1479 Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); | 1380 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1480 var_dividend.Bind(assembler.CallStub(callable, context, dividend)); | 1381 var_dividend.Bind(CallStub(callable, context, dividend)); |
1481 assembler.Goto(&loop); | 1382 Goto(&loop); |
1482 } | 1383 } |
1483 } | 1384 } |
1484 } | 1385 } |
1485 | 1386 |
1486 assembler.Bind(&do_fdiv); | 1387 Bind(&do_fdiv); |
1487 { | 1388 { |
1488 Node* value = assembler.Float64Div(var_dividend_float64.value(), | 1389 Node* value = |
1489 var_divisor_float64.value()); | 1390 Float64Div(var_dividend_float64.value(), var_divisor_float64.value()); |
1490 var_result.Bind(assembler.AllocateHeapNumberWithValue(value)); | 1391 var_result.Bind(AllocateHeapNumberWithValue(value)); |
1491 assembler.Goto(&end); | 1392 Goto(&end); |
1492 } | 1393 } |
1493 assembler.Bind(&end); | 1394 Bind(&end); |
1494 assembler.Return(var_result.value()); | 1395 Return(var_result.value()); |
1495 } | 1396 } |
1496 | 1397 |
1497 void Builtins::Generate_Modulus(compiler::CodeAssemblerState* state) { | 1398 TF_BUILTIN(Modulus, CodeStubAssembler) { |
1498 typedef CodeStubAssembler::Label Label; | 1399 Node* left = Parameter(0); |
1499 typedef compiler::Node Node; | 1400 Node* right = Parameter(1); |
1500 typedef CodeStubAssembler::Variable Variable; | 1401 Node* context = Parameter(2); |
1501 CodeStubAssembler assembler(state); | 1402 |
1502 | 1403 Variable var_result(this, MachineRepresentation::kTagged); |
1503 Node* left = assembler.Parameter(0); | 1404 Label return_result(this, &var_result); |
1504 Node* right = assembler.Parameter(1); | |
1505 Node* context = assembler.Parameter(2); | |
1506 | |
1507 Variable var_result(&assembler, MachineRepresentation::kTagged); | |
1508 Label return_result(&assembler, &var_result); | |
1509 | 1405 |
1510 // Shared entry point for floating point modulus. | 1406 // Shared entry point for floating point modulus. |
1511 Label do_fmod(&assembler); | 1407 Label do_fmod(this); |
1512 Variable var_dividend_float64(&assembler, MachineRepresentation::kFloat64), | 1408 Variable var_dividend_float64(this, MachineRepresentation::kFloat64), |
1513 var_divisor_float64(&assembler, MachineRepresentation::kFloat64); | 1409 var_divisor_float64(this, MachineRepresentation::kFloat64); |
1514 | 1410 |
1515 Node* number_map = assembler.HeapNumberMapConstant(); | 1411 Node* number_map = HeapNumberMapConstant(); |
1516 | 1412 |
1517 // We might need to loop one or two times due to ToNumber conversions. | 1413 // We might need to loop one or two times due to ToNumber conversions. |
1518 Variable var_dividend(&assembler, MachineRepresentation::kTagged), | 1414 Variable var_dividend(this, MachineRepresentation::kTagged), |
1519 var_divisor(&assembler, MachineRepresentation::kTagged); | 1415 var_divisor(this, MachineRepresentation::kTagged); |
1520 Variable* loop_variables[] = {&var_dividend, &var_divisor}; | 1416 Variable* loop_variables[] = {&var_dividend, &var_divisor}; |
1521 Label loop(&assembler, 2, loop_variables); | 1417 Label loop(this, 2, loop_variables); |
1522 var_dividend.Bind(left); | 1418 var_dividend.Bind(left); |
1523 var_divisor.Bind(right); | 1419 var_divisor.Bind(right); |
1524 assembler.Goto(&loop); | 1420 Goto(&loop); |
1525 assembler.Bind(&loop); | 1421 Bind(&loop); |
1526 { | 1422 { |
1527 Node* dividend = var_dividend.value(); | 1423 Node* dividend = var_dividend.value(); |
1528 Node* divisor = var_divisor.value(); | 1424 Node* divisor = var_divisor.value(); |
1529 | 1425 |
1530 Label dividend_is_smi(&assembler), dividend_is_not_smi(&assembler); | 1426 Label dividend_is_smi(this), dividend_is_not_smi(this); |
1531 assembler.Branch(assembler.TaggedIsSmi(dividend), ÷nd_is_smi, | 1427 Branch(TaggedIsSmi(dividend), ÷nd_is_smi, ÷nd_is_not_smi); |
1532 ÷nd_is_not_smi); | 1428 |
1533 | 1429 Bind(÷nd_is_smi); |
1534 assembler.Bind(÷nd_is_smi); | |
1535 { | 1430 { |
1536 Label dividend_is_not_zero(&assembler); | 1431 Label dividend_is_not_zero(this); |
1537 Label divisor_is_smi(&assembler), divisor_is_not_smi(&assembler); | 1432 Label divisor_is_smi(this), divisor_is_not_smi(this); |
1538 assembler.Branch(assembler.TaggedIsSmi(divisor), &divisor_is_smi, | 1433 Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); |
1539 &divisor_is_not_smi); | 1434 |
1540 | 1435 Bind(&divisor_is_smi); |
1541 assembler.Bind(&divisor_is_smi); | |
1542 { | 1436 { |
1543 // Compute the modulus of two Smis. | 1437 // Compute the modulus of two Smis. |
1544 var_result.Bind(assembler.SmiMod(dividend, divisor)); | 1438 var_result.Bind(SmiMod(dividend, divisor)); |
1545 assembler.Goto(&return_result); | 1439 Goto(&return_result); |
1546 } | 1440 } |
1547 | 1441 |
1548 assembler.Bind(&divisor_is_not_smi); | 1442 Bind(&divisor_is_not_smi); |
1549 { | 1443 { |
1550 Node* divisor_map = assembler.LoadMap(divisor); | 1444 Node* divisor_map = LoadMap(divisor); |
1551 | 1445 |
1552 // Check if {divisor} is a HeapNumber. | 1446 // Check if {divisor} is a HeapNumber. |
1553 Label divisor_is_number(&assembler), | 1447 Label divisor_is_number(this), |
1554 divisor_is_not_number(&assembler, Label::kDeferred); | 1448 divisor_is_not_number(this, Label::kDeferred); |
1555 assembler.Branch(assembler.WordEqual(divisor_map, number_map), | 1449 Branch(WordEqual(divisor_map, number_map), &divisor_is_number, |
1556 &divisor_is_number, &divisor_is_not_number); | 1450 &divisor_is_not_number); |
1557 | 1451 |
1558 assembler.Bind(&divisor_is_number); | 1452 Bind(&divisor_is_number); |
1559 { | 1453 { |
1560 // Convert {dividend} to a double and compute its modulus with the | 1454 // Convert {dividend} to a double and compute its modulus with the |
1561 // value of {dividend}. | 1455 // value of {dividend}. |
1562 var_dividend_float64.Bind(assembler.SmiToFloat64(dividend)); | 1456 var_dividend_float64.Bind(SmiToFloat64(dividend)); |
1563 var_divisor_float64.Bind(assembler.LoadHeapNumberValue(divisor)); | 1457 var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); |
1564 assembler.Goto(&do_fmod); | 1458 Goto(&do_fmod); |
1565 } | 1459 } |
1566 | 1460 |
1567 assembler.Bind(&divisor_is_not_number); | 1461 Bind(&divisor_is_not_number); |
1568 { | 1462 { |
1569 // Convert {divisor} to a number and loop. | 1463 // Convert {divisor} to a number and loop. |
1570 Callable callable = | 1464 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1571 CodeFactory::NonNumberToNumber(assembler.isolate()); | 1465 var_divisor.Bind(CallStub(callable, context, divisor)); |
1572 var_divisor.Bind(assembler.CallStub(callable, context, divisor)); | 1466 Goto(&loop); |
1573 assembler.Goto(&loop); | 1467 } |
1574 } | 1468 } |
1575 } | 1469 } |
1576 } | 1470 |
1577 | 1471 Bind(÷nd_is_not_smi); |
1578 assembler.Bind(÷nd_is_not_smi); | |
1579 { | 1472 { |
1580 Node* dividend_map = assembler.LoadMap(dividend); | 1473 Node* dividend_map = LoadMap(dividend); |
1581 | 1474 |
1582 // Check if {dividend} is a HeapNumber. | 1475 // Check if {dividend} is a HeapNumber. |
1583 Label dividend_is_number(&assembler), | 1476 Label dividend_is_number(this), |
1584 dividend_is_not_number(&assembler, Label::kDeferred); | 1477 dividend_is_not_number(this, Label::kDeferred); |
1585 assembler.Branch(assembler.WordEqual(dividend_map, number_map), | 1478 Branch(WordEqual(dividend_map, number_map), ÷nd_is_number, |
1586 ÷nd_is_number, ÷nd_is_not_number); | 1479 ÷nd_is_not_number); |
1587 | 1480 |
1588 assembler.Bind(÷nd_is_number); | 1481 Bind(÷nd_is_number); |
1589 { | 1482 { |
1590 // Check if {divisor} is a Smi. | 1483 // Check if {divisor} is a Smi. |
1591 Label divisor_is_smi(&assembler), divisor_is_not_smi(&assembler); | 1484 Label divisor_is_smi(this), divisor_is_not_smi(this); |
1592 assembler.Branch(assembler.TaggedIsSmi(divisor), &divisor_is_smi, | 1485 Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi); |
1593 &divisor_is_not_smi); | 1486 |
1594 | 1487 Bind(&divisor_is_smi); |
1595 assembler.Bind(&divisor_is_smi); | |
1596 { | 1488 { |
1597 // Convert {divisor} to a double and compute {dividend}'s modulus with | 1489 // Convert {divisor} to a double and compute {dividend}'s modulus with |
1598 // it. | 1490 // it. |
1599 var_dividend_float64.Bind(assembler.LoadHeapNumberValue(dividend)); | 1491 var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); |
1600 var_divisor_float64.Bind(assembler.SmiToFloat64(divisor)); | 1492 var_divisor_float64.Bind(SmiToFloat64(divisor)); |
1601 assembler.Goto(&do_fmod); | 1493 Goto(&do_fmod); |
1602 } | 1494 } |
1603 | 1495 |
1604 assembler.Bind(&divisor_is_not_smi); | 1496 Bind(&divisor_is_not_smi); |
1605 { | 1497 { |
1606 Node* divisor_map = assembler.LoadMap(divisor); | 1498 Node* divisor_map = LoadMap(divisor); |
1607 | 1499 |
1608 // Check if {divisor} is a HeapNumber. | 1500 // Check if {divisor} is a HeapNumber. |
1609 Label divisor_is_number(&assembler), | 1501 Label divisor_is_number(this), |
1610 divisor_is_not_number(&assembler, Label::kDeferred); | 1502 divisor_is_not_number(this, Label::kDeferred); |
1611 assembler.Branch(assembler.WordEqual(divisor_map, number_map), | 1503 Branch(WordEqual(divisor_map, number_map), &divisor_is_number, |
1612 &divisor_is_number, &divisor_is_not_number); | 1504 &divisor_is_not_number); |
1613 | 1505 |
1614 assembler.Bind(&divisor_is_number); | 1506 Bind(&divisor_is_number); |
1615 { | 1507 { |
1616 // Both {dividend} and {divisor} are HeapNumbers. Load their values | 1508 // Both {dividend} and {divisor} are HeapNumbers. Load their values |
1617 // and compute their modulus. | 1509 // and compute their modulus. |
1618 var_dividend_float64.Bind(assembler.LoadHeapNumberValue(dividend)); | 1510 var_dividend_float64.Bind(LoadHeapNumberValue(dividend)); |
1619 var_divisor_float64.Bind(assembler.LoadHeapNumberValue(divisor)); | 1511 var_divisor_float64.Bind(LoadHeapNumberValue(divisor)); |
1620 assembler.Goto(&do_fmod); | 1512 Goto(&do_fmod); |
1621 } | 1513 } |
1622 | 1514 |
1623 assembler.Bind(&divisor_is_not_number); | 1515 Bind(&divisor_is_not_number); |
1624 { | 1516 { |
1625 // Convert {divisor} to a number and loop. | 1517 // Convert {divisor} to a number and loop. |
1626 Callable callable = | 1518 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1627 CodeFactory::NonNumberToNumber(assembler.isolate()); | 1519 var_divisor.Bind(CallStub(callable, context, divisor)); |
1628 var_divisor.Bind(assembler.CallStub(callable, context, divisor)); | 1520 Goto(&loop); |
1629 assembler.Goto(&loop); | |
1630 } | 1521 } |
1631 } | 1522 } |
1632 } | 1523 } |
1633 | 1524 |
1634 assembler.Bind(÷nd_is_not_number); | 1525 Bind(÷nd_is_not_number); |
1635 { | 1526 { |
1636 // Convert {dividend} to a Number and loop. | 1527 // Convert {dividend} to a Number and loop. |
1637 Callable callable = CodeFactory::NonNumberToNumber(assembler.isolate()); | 1528 Callable callable = CodeFactory::NonNumberToNumber(isolate()); |
1638 var_dividend.Bind(assembler.CallStub(callable, context, dividend)); | 1529 var_dividend.Bind(CallStub(callable, context, dividend)); |
1639 assembler.Goto(&loop); | 1530 Goto(&loop); |
1640 } | 1531 } |
1641 } | 1532 } |
1642 } | 1533 } |
1643 | 1534 |
1644 assembler.Bind(&do_fmod); | 1535 Bind(&do_fmod); |
1645 { | 1536 { |
1646 Node* value = assembler.Float64Mod(var_dividend_float64.value(), | 1537 Node* value = |
1647 var_divisor_float64.value()); | 1538 Float64Mod(var_dividend_float64.value(), var_divisor_float64.value()); |
1648 var_result.Bind(assembler.AllocateHeapNumberWithValue(value)); | 1539 var_result.Bind(AllocateHeapNumberWithValue(value)); |
1649 assembler.Goto(&return_result); | 1540 Goto(&return_result); |
1650 } | 1541 } |
1651 | 1542 |
1652 assembler.Bind(&return_result); | 1543 Bind(&return_result); |
1653 assembler.Return(var_result.value()); | 1544 Return(var_result.value()); |
1654 } | 1545 } |
1655 | 1546 |
1656 void Builtins::Generate_ShiftLeft(compiler::CodeAssemblerState* state) { | 1547 TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) { |
1657 using compiler::Node; | 1548 BitwiseShiftOp([this](Node* lhs, Node* shift_count) { |
1658 CodeStubAssembler assembler(state); | 1549 return Word32Shl(lhs, shift_count); |
1659 | 1550 }); |
1660 Node* left = assembler.Parameter(0); | 1551 } |
1661 Node* right = assembler.Parameter(1); | 1552 |
1662 Node* context = assembler.Parameter(2); | 1553 TF_BUILTIN(ShiftRight, NumberBuiltinsAssembler) { |
1663 | 1554 BitwiseShiftOp([this](Node* lhs, Node* shift_count) { |
1664 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | 1555 return Word32Sar(lhs, shift_count); |
1665 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | 1556 }); |
1666 Node* shift_count = | 1557 } |
1667 assembler.Word32And(rhs_value, assembler.Int32Constant(0x1f)); | 1558 |
1668 Node* value = assembler.Word32Shl(lhs_value, shift_count); | 1559 TF_BUILTIN(ShiftRightLogical, NumberBuiltinsAssembler) { |
1669 Node* result = assembler.ChangeInt32ToTagged(value); | 1560 BitwiseShiftOp<kUnsigned>([this](Node* lhs, Node* shift_count) { |
1670 assembler.Return(result); | 1561 return Word32Shr(lhs, shift_count); |
1671 } | 1562 }); |
1672 | 1563 } |
1673 void Builtins::Generate_ShiftRight(compiler::CodeAssemblerState* state) { | 1564 |
1674 using compiler::Node; | 1565 TF_BUILTIN(BitwiseAnd, NumberBuiltinsAssembler) { |
1675 CodeStubAssembler assembler(state); | 1566 BitwiseOp([this](Node* lhs, Node* rhs) { return Word32And(lhs, rhs); }); |
1676 | 1567 } |
1677 Node* left = assembler.Parameter(0); | 1568 |
1678 Node* right = assembler.Parameter(1); | 1569 TF_BUILTIN(BitwiseOr, NumberBuiltinsAssembler) { |
1679 Node* context = assembler.Parameter(2); | 1570 BitwiseOp([this](Node* lhs, Node* rhs) { return Word32Or(lhs, rhs); }); |
1680 | 1571 } |
1681 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | 1572 |
1682 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | 1573 TF_BUILTIN(BitwiseXor, NumberBuiltinsAssembler) { |
1683 Node* shift_count = | 1574 BitwiseOp([this](Node* lhs, Node* rhs) { return Word32Xor(lhs, rhs); }); |
1684 assembler.Word32And(rhs_value, assembler.Int32Constant(0x1f)); | 1575 } |
1685 Node* value = assembler.Word32Sar(lhs_value, shift_count); | 1576 |
1686 Node* result = assembler.ChangeInt32ToTagged(value); | 1577 TF_BUILTIN(LessThan, NumberBuiltinsAssembler) { |
1687 assembler.Return(result); | 1578 RelationalComparisonBuiltin(kLessThan); |
1688 } | 1579 } |
1689 | 1580 |
1690 void Builtins::Generate_ShiftRightLogical(compiler::CodeAssemblerState* state) { | 1581 TF_BUILTIN(LessThanOrEqual, NumberBuiltinsAssembler) { |
1691 using compiler::Node; | 1582 RelationalComparisonBuiltin(kLessThanOrEqual); |
1692 CodeStubAssembler assembler(state); | 1583 } |
1693 | 1584 |
1694 Node* left = assembler.Parameter(0); | 1585 TF_BUILTIN(GreaterThan, NumberBuiltinsAssembler) { |
1695 Node* right = assembler.Parameter(1); | 1586 RelationalComparisonBuiltin(kGreaterThan); |
1696 Node* context = assembler.Parameter(2); | 1587 } |
1697 | 1588 |
1698 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | 1589 TF_BUILTIN(GreaterThanOrEqual, NumberBuiltinsAssembler) { |
1699 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | 1590 RelationalComparisonBuiltin(kGreaterThanOrEqual); |
1700 Node* shift_count = | 1591 } |
1701 assembler.Word32And(rhs_value, assembler.Int32Constant(0x1f)); | 1592 |
1702 Node* value = assembler.Word32Shr(lhs_value, shift_count); | 1593 TF_BUILTIN(Equal, CodeStubAssembler) { |
1703 Node* result = assembler.ChangeUint32ToTagged(value); | 1594 Node* lhs = Parameter(0); |
1704 assembler.Return(result); | 1595 Node* rhs = Parameter(1); |
1705 } | 1596 Node* context = Parameter(2); |
1706 | 1597 |
1707 void Builtins::Generate_BitwiseAnd(compiler::CodeAssemblerState* state) { | 1598 Return(Equal(kDontNegateResult, lhs, rhs, context)); |
1708 CodeStubAssembler assembler(state); | 1599 } |
1709 using compiler::Node; | 1600 |
1710 | 1601 TF_BUILTIN(NotEqual, CodeStubAssembler) { |
1711 Node* left = assembler.Parameter(0); | 1602 Node* lhs = Parameter(0); |
1712 Node* right = assembler.Parameter(1); | 1603 Node* rhs = Parameter(1); |
1713 Node* context = assembler.Parameter(2); | 1604 Node* context = Parameter(2); |
1714 | 1605 |
1715 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | 1606 Return(Equal(kNegateResult, lhs, rhs, context)); |
1716 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | 1607 } |
1717 Node* value = assembler.Word32And(lhs_value, rhs_value); | 1608 |
1718 Node* result = assembler.ChangeInt32ToTagged(value); | 1609 TF_BUILTIN(StrictEqual, CodeStubAssembler) { |
1719 assembler.Return(result); | 1610 Node* lhs = Parameter(0); |
1720 } | 1611 Node* rhs = Parameter(1); |
1721 | 1612 Node* context = Parameter(2); |
1722 void Builtins::Generate_BitwiseOr(compiler::CodeAssemblerState* state) { | 1613 |
1723 CodeStubAssembler assembler(state); | 1614 Return(StrictEqual(kDontNegateResult, lhs, rhs, context)); |
1724 using compiler::Node; | 1615 } |
1725 | 1616 |
1726 Node* left = assembler.Parameter(0); | 1617 TF_BUILTIN(StrictNotEqual, CodeStubAssembler) { |
1727 Node* right = assembler.Parameter(1); | 1618 Node* lhs = Parameter(0); |
1728 Node* context = assembler.Parameter(2); | 1619 Node* rhs = Parameter(1); |
1729 | 1620 Node* context = Parameter(2); |
1730 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | 1621 |
1731 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | 1622 Return(StrictEqual(kNegateResult, lhs, rhs, context)); |
1732 Node* value = assembler.Word32Or(lhs_value, rhs_value); | |
1733 Node* result = assembler.ChangeInt32ToTagged(value); | |
1734 assembler.Return(result); | |
1735 } | |
1736 | |
1737 void Builtins::Generate_BitwiseXor(compiler::CodeAssemblerState* state) { | |
1738 CodeStubAssembler assembler(state); | |
1739 using compiler::Node; | |
1740 | |
1741 Node* left = assembler.Parameter(0); | |
1742 Node* right = assembler.Parameter(1); | |
1743 Node* context = assembler.Parameter(2); | |
1744 | |
1745 Node* lhs_value = assembler.TruncateTaggedToWord32(context, left); | |
1746 Node* rhs_value = assembler.TruncateTaggedToWord32(context, right); | |
1747 Node* value = assembler.Word32Xor(lhs_value, rhs_value); | |
1748 Node* result = assembler.ChangeInt32ToTagged(value); | |
1749 assembler.Return(result); | |
1750 } | |
1751 | |
1752 void Builtins::Generate_LessThan(compiler::CodeAssemblerState* state) { | |
1753 CodeStubAssembler assembler(state); | |
1754 compiler::Node* lhs = assembler.Parameter(0); | |
1755 compiler::Node* rhs = assembler.Parameter(1); | |
1756 compiler::Node* context = assembler.Parameter(2); | |
1757 | |
1758 assembler.Return(assembler.RelationalComparison(CodeStubAssembler::kLessThan, | |
1759 lhs, rhs, context)); | |
1760 } | |
1761 | |
1762 void Builtins::Generate_LessThanOrEqual(compiler::CodeAssemblerState* state) { | |
1763 CodeStubAssembler assembler(state); | |
1764 compiler::Node* lhs = assembler.Parameter(0); | |
1765 compiler::Node* rhs = assembler.Parameter(1); | |
1766 compiler::Node* context = assembler.Parameter(2); | |
1767 | |
1768 assembler.Return(assembler.RelationalComparison( | |
1769 CodeStubAssembler::kLessThanOrEqual, lhs, rhs, context)); | |
1770 } | |
1771 | |
1772 void Builtins::Generate_GreaterThan(compiler::CodeAssemblerState* state) { | |
1773 CodeStubAssembler assembler(state); | |
1774 compiler::Node* lhs = assembler.Parameter(0); | |
1775 compiler::Node* rhs = assembler.Parameter(1); | |
1776 compiler::Node* context = assembler.Parameter(2); | |
1777 | |
1778 assembler.Return(assembler.RelationalComparison( | |
1779 CodeStubAssembler::kGreaterThan, lhs, rhs, context)); | |
1780 } | |
1781 | |
1782 void Builtins::Generate_GreaterThanOrEqual( | |
1783 compiler::CodeAssemblerState* state) { | |
1784 CodeStubAssembler assembler(state); | |
1785 compiler::Node* lhs = assembler.Parameter(0); | |
1786 compiler::Node* rhs = assembler.Parameter(1); | |
1787 compiler::Node* context = assembler.Parameter(2); | |
1788 | |
1789 assembler.Return(assembler.RelationalComparison( | |
1790 CodeStubAssembler::kGreaterThanOrEqual, lhs, rhs, context)); | |
1791 } | |
1792 | |
1793 void Builtins::Generate_Equal(compiler::CodeAssemblerState* state) { | |
1794 CodeStubAssembler assembler(state); | |
1795 compiler::Node* lhs = assembler.Parameter(0); | |
1796 compiler::Node* rhs = assembler.Parameter(1); | |
1797 compiler::Node* context = assembler.Parameter(2); | |
1798 | |
1799 assembler.Return( | |
1800 assembler.Equal(CodeStubAssembler::kDontNegateResult, lhs, rhs, context)); | |
1801 } | |
1802 | |
1803 void Builtins::Generate_NotEqual(compiler::CodeAssemblerState* state) { | |
1804 CodeStubAssembler assembler(state); | |
1805 compiler::Node* lhs = assembler.Parameter(0); | |
1806 compiler::Node* rhs = assembler.Parameter(1); | |
1807 compiler::Node* context = assembler.Parameter(2); | |
1808 | |
1809 assembler.Return( | |
1810 assembler.Equal(CodeStubAssembler::kNegateResult, lhs, rhs, context)); | |
1811 } | |
1812 | |
1813 void Builtins::Generate_StrictEqual(compiler::CodeAssemblerState* state) { | |
1814 CodeStubAssembler assembler(state); | |
1815 compiler::Node* lhs = assembler.Parameter(0); | |
1816 compiler::Node* rhs = assembler.Parameter(1); | |
1817 compiler::Node* context = assembler.Parameter(2); | |
1818 | |
1819 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kDontNegateResult, | |
1820 lhs, rhs, context)); | |
1821 } | |
1822 | |
1823 void Builtins::Generate_StrictNotEqual(compiler::CodeAssemblerState* state) { | |
1824 CodeStubAssembler assembler(state); | |
1825 compiler::Node* lhs = assembler.Parameter(0); | |
1826 compiler::Node* rhs = assembler.Parameter(1); | |
1827 compiler::Node* context = assembler.Parameter(2); | |
1828 | |
1829 assembler.Return(assembler.StrictEqual(CodeStubAssembler::kNegateResult, lhs, | |
1830 rhs, context)); | |
1831 } | 1623 } |
1832 | 1624 |
1833 } // namespace internal | 1625 } // namespace internal |
1834 } // namespace v8 | 1626 } // namespace v8 |
OLD | NEW |