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

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

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

Powered by Google App Engine
This is Rietveld 408576698