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