LCOV - code coverage report
Current view: top level - src/builtins - builtins-number-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 715 719 99.4 %
Date: 2017-04-26 Functions: 58 62 93.5 %

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

Generated by: LCOV version 1.10