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