Home | History | Annotate | Download | only in builtins
      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 )
     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 )
     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 )
     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 )
    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 )
    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 )
    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 )
    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 )
    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 ] ] )
    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 )
    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 ] )
    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 ( )
    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
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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