LCOV - code coverage report
Current view: top level - src/builtins - builtins-number-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 537 547 98.2 %
Date: 2019-01-20 Functions: 64 74 86.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-math-gen.h"
       6             : #include "src/builtins/builtins-utils-gen.h"
       7             : #include "src/builtins/builtins.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/ic/binary-op-assembler.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : // -----------------------------------------------------------------------------
      15             : // ES6 section 20.1 Number Objects
      16             : 
      17             : class NumberBuiltinsAssembler : public CodeStubAssembler {
      18             :  public:
      19             :   explicit NumberBuiltinsAssembler(compiler::CodeAssemblerState* state)
      20        1064 :       : CodeStubAssembler(state) {}
      21             : 
      22             :  protected:
      23             :   template <typename Descriptor>
      24         336 :   void EmitBitwiseOp(Operation op) {
      25         336 :     Node* left = Parameter(Descriptor::kLeft);
      26         336 :     Node* right = Parameter(Descriptor::kRight);
      27         336 :     Node* context = Parameter(Descriptor::kContext);
      28             : 
      29         336 :     VARIABLE(var_left_word32, MachineRepresentation::kWord32);
      30         672 :     VARIABLE(var_right_word32, MachineRepresentation::kWord32);
      31         672 :     VARIABLE(var_left_bigint, MachineRepresentation::kTagged, left);
      32         672 :     VARIABLE(var_right_bigint, MachineRepresentation::kTagged);
      33         336 :     Label if_left_number(this), do_number_op(this);
      34         336 :     Label if_left_bigint(this), do_bigint_op(this);
      35             : 
      36         336 :     TaggedToWord32OrBigInt(context, left, &if_left_number, &var_left_word32,
      37         336 :                            &if_left_bigint, &var_left_bigint);
      38         336 :     BIND(&if_left_number);
      39         336 :     TaggedToWord32OrBigInt(context, right, &do_number_op, &var_right_word32,
      40             :                            &do_bigint_op, &var_right_bigint);
      41         336 :     BIND(&do_number_op);
      42         672 :     Return(BitwiseOp(var_left_word32.value(), var_right_word32.value(), op));
      43             : 
      44             :     // BigInt cases.
      45         336 :     BIND(&if_left_bigint);
      46         336 :     TaggedToNumeric(context, right, &do_bigint_op, &var_right_bigint);
      47             : 
      48         336 :     BIND(&do_bigint_op);
      49         336 :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context,
      50             :                        var_left_bigint.value(), var_right_bigint.value(),
      51        1008 :                        SmiConstant(op)));
      52         336 :   }
      53             : 
      54             :   template <typename Descriptor>
      55         224 :   void RelationalComparisonBuiltin(Operation op) {
      56         224 :     Node* lhs = Parameter(Descriptor::kLeft);
      57         224 :     Node* rhs = Parameter(Descriptor::kRight);
      58         224 :     Node* context = Parameter(Descriptor::kContext);
      59             : 
      60         448 :     Return(RelationalComparison(op, lhs, rhs, context));
      61         224 :   }
      62             : 
      63             :   template <typename Descriptor>
      64             :   void UnaryOp(Variable* var_input, Label* do_smi, Label* do_double,
      65             :                Variable* var_input_double, Label* do_bigint);
      66             : 
      67             :   template <typename Descriptor>
      68             :   void BinaryOp(Label* smis, Variable* var_left, Variable* var_right,
      69             :                 Label* doubles, Variable* var_left_double,
      70             :                 Variable* var_right_double, Label* bigints);
      71             : };
      72             : 
      73             : // ES6 #sec-number.isfinite
      74         168 : TF_BUILTIN(NumberIsFinite, CodeStubAssembler) {
      75             :   Node* number = Parameter(Descriptor::kNumber);
      76             : 
      77          56 :   Label return_true(this), return_false(this);
      78             : 
      79             :   // Check if {number} is a Smi.
      80         112 :   GotoIf(TaggedIsSmi(number), &return_true);
      81             : 
      82             :   // Check if {number} is a HeapNumber.
      83         112 :   GotoIfNot(IsHeapNumber(number), &return_false);
      84             : 
      85             :   // Check if {number} contains a finite, non-NaN value.
      86         112 :   Node* number_value = LoadHeapNumberValue(number);
      87          56 :   BranchIfFloat64IsNaN(Float64Sub(number_value, number_value), &return_false,
      88         112 :                        &return_true);
      89             : 
      90          56 :   BIND(&return_true);
      91         112 :   Return(TrueConstant());
      92             : 
      93          56 :   BIND(&return_false);
      94         168 :   Return(FalseConstant());
      95          56 : }
      96             : 
      97         168 : TF_BUILTIN(AllocateHeapNumber, CodeStubAssembler) {
      98         112 :   Node* result = AllocateHeapNumber();
      99          56 :   Return(result);
     100          56 : }
     101             : 
     102             : // ES6 #sec-number.isinteger
     103         168 : TF_BUILTIN(NumberIsInteger, CodeStubAssembler) {
     104          56 :   TNode<Object> number = CAST(Parameter(Descriptor::kNumber));
     105         168 :   Return(SelectBooleanConstant(IsInteger(number)));
     106          56 : }
     107             : 
     108             : // ES6 #sec-number.isnan
     109         168 : TF_BUILTIN(NumberIsNaN, CodeStubAssembler) {
     110             :   Node* number = Parameter(Descriptor::kNumber);
     111             : 
     112          56 :   Label return_true(this), return_false(this);
     113             : 
     114             :   // Check if {number} is a Smi.
     115         112 :   GotoIf(TaggedIsSmi(number), &return_false);
     116             : 
     117             :   // Check if {number} is a HeapNumber.
     118         112 :   GotoIfNot(IsHeapNumber(number), &return_false);
     119             : 
     120             :   // Check if {number} contains a NaN value.
     121         112 :   Node* number_value = LoadHeapNumberValue(number);
     122          56 :   BranchIfFloat64IsNaN(number_value, &return_true, &return_false);
     123             : 
     124          56 :   BIND(&return_true);
     125         112 :   Return(TrueConstant());
     126             : 
     127          56 :   BIND(&return_false);
     128         168 :   Return(FalseConstant());
     129          56 : }
     130             : 
     131             : // ES6 #sec-number.issafeinteger
     132         168 : TF_BUILTIN(NumberIsSafeInteger, CodeStubAssembler) {
     133          56 :   TNode<Object> number = CAST(Parameter(Descriptor::kNumber));
     134         168 :   Return(SelectBooleanConstant(IsSafeInteger(number)));
     135          56 : }
     136             : 
     137             : // ES6 #sec-number.parsefloat
     138         168 : TF_BUILTIN(NumberParseFloat, CodeStubAssembler) {
     139             :   Node* context = Parameter(Descriptor::kContext);
     140             : 
     141             :   // We might need to loop once for ToString conversion.
     142          56 :   VARIABLE(var_input, MachineRepresentation::kTagged,
     143             :            Parameter(Descriptor::kString));
     144          56 :   Label loop(this, &var_input);
     145          56 :   Goto(&loop);
     146          56 :   BIND(&loop);
     147             :   {
     148             :     // Load the current {input} value.
     149          56 :     Node* input = var_input.value();
     150             : 
     151             :     // Check if the {input} is a HeapObject or a Smi.
     152          56 :     Label if_inputissmi(this), if_inputisnotsmi(this);
     153         112 :     Branch(TaggedIsSmi(input), &if_inputissmi, &if_inputisnotsmi);
     154             : 
     155          56 :     BIND(&if_inputissmi);
     156             :     {
     157             :       // The {input} is already a Number, no need to do anything.
     158          56 :       Return(input);
     159             :     }
     160             : 
     161          56 :     BIND(&if_inputisnotsmi);
     162             :     {
     163             :       // The {input} is a HeapObject, check if it's already a String.
     164          56 :       Label if_inputisstring(this), if_inputisnotstring(this);
     165         112 :       Node* input_map = LoadMap(input);
     166         112 :       Node* input_instance_type = LoadMapInstanceType(input_map);
     167          56 :       Branch(IsStringInstanceType(input_instance_type), &if_inputisstring,
     168         112 :              &if_inputisnotstring);
     169             : 
     170          56 :       BIND(&if_inputisstring);
     171             :       {
     172             :         // The {input} is already a String, check if {input} contains
     173             :         // a cached array index.
     174          56 :         Label if_inputcached(this), if_inputnotcached(this);
     175         112 :         Node* input_hash = LoadNameHashField(input);
     176             :         Branch(IsClearWord32(input_hash,
     177          56 :                              Name::kDoesNotContainCachedArrayIndexMask),
     178         112 :                &if_inputcached, &if_inputnotcached);
     179             : 
     180          56 :         BIND(&if_inputcached);
     181             :         {
     182             :           // Just return the {input}s cached array index.
     183             :           Node* input_array_index =
     184         112 :               DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash);
     185         112 :           Return(SmiTag(input_array_index));
     186             :         }
     187             : 
     188          56 :         BIND(&if_inputnotcached);
     189             :         {
     190             :           // Need to fall back to the runtime to convert {input} to double.
     191          56 :           Return(CallRuntime(Runtime::kStringParseFloat, context, input));
     192          56 :         }
     193             :       }
     194             : 
     195          56 :       BIND(&if_inputisnotstring);
     196             :       {
     197             :         // The {input} is neither a String nor a Smi, check for HeapNumber.
     198             :         Label if_inputisnumber(this),
     199          56 :             if_inputisnotnumber(this, Label::kDeferred);
     200          56 :         Branch(IsHeapNumberMap(input_map), &if_inputisnumber,
     201         112 :                &if_inputisnotnumber);
     202             : 
     203          56 :         BIND(&if_inputisnumber);
     204             :         {
     205             :           // The {input} is already a Number, take care of -0.
     206          56 :           Label if_inputiszero(this), if_inputisnotzero(this);
     207         112 :           Node* input_value = LoadHeapNumberValue(input);
     208         112 :           Branch(Float64Equal(input_value, Float64Constant(0.0)),
     209         112 :                  &if_inputiszero, &if_inputisnotzero);
     210             : 
     211          56 :           BIND(&if_inputiszero);
     212         112 :           Return(SmiConstant(0));
     213             : 
     214          56 :           BIND(&if_inputisnotzero);
     215         112 :           Return(input);
     216             :         }
     217             : 
     218          56 :         BIND(&if_inputisnotnumber);
     219             :         {
     220             :           // Need to convert the {input} to String first.
     221             :           // TODO(bmeurer): This could be more efficient if necessary.
     222         112 :           var_input.Bind(CallBuiltin(Builtins::kToString, context, input));
     223          56 :           Goto(&loop);
     224          56 :         }
     225          56 :       }
     226          56 :     }
     227          56 :   }
     228          56 : }
     229             : 
     230             : // ES6 #sec-number.parseint
     231         168 : TF_BUILTIN(ParseInt, CodeStubAssembler) {
     232             :   Node* context = Parameter(Descriptor::kContext);
     233             :   Node* input = Parameter(Descriptor::kString);
     234             :   Node* radix = Parameter(Descriptor::kRadix);
     235             : 
     236             :   // Check if {radix} is treated as 10 (i.e. undefined, 0 or 10).
     237          56 :   Label if_radix10(this), if_generic(this, Label::kDeferred);
     238         112 :   GotoIf(IsUndefined(radix), &if_radix10);
     239         112 :   GotoIf(WordEqual(radix, SmiConstant(10)), &if_radix10);
     240         112 :   GotoIf(WordEqual(radix, SmiConstant(0)), &if_radix10);
     241          56 :   Goto(&if_generic);
     242             : 
     243          56 :   BIND(&if_radix10);
     244             :   {
     245             :     // Check if we can avoid the ToString conversion on {input}.
     246          56 :     Label if_inputissmi(this), if_inputisheapnumber(this),
     247          56 :         if_inputisstring(this);
     248         112 :     GotoIf(TaggedIsSmi(input), &if_inputissmi);
     249         112 :     Node* input_map = LoadMap(input);
     250         112 :     GotoIf(IsHeapNumberMap(input_map), &if_inputisheapnumber);
     251         112 :     Node* input_instance_type = LoadMapInstanceType(input_map);
     252          56 :     Branch(IsStringInstanceType(input_instance_type), &if_inputisstring,
     253         112 :            &if_generic);
     254             : 
     255          56 :     BIND(&if_inputissmi);
     256             :     {
     257             :       // Just return the {input}.
     258          56 :       Return(input);
     259             :     }
     260             : 
     261          56 :     BIND(&if_inputisheapnumber);
     262             :     {
     263             :       // Check if the {input} value is in Signed32 range.
     264             :       Label if_inputissigned32(this);
     265         112 :       Node* input_value = LoadHeapNumberValue(input);
     266         112 :       Node* input_value32 = TruncateFloat64ToWord32(input_value);
     267         112 :       GotoIf(Float64Equal(input_value, ChangeInt32ToFloat64(input_value32)),
     268         112 :              &if_inputissigned32);
     269             : 
     270             :       // Check if the absolute {input} value is in the [1,1<<31[ range.
     271             :       // Take the generic path for the range [0,1[ because the result
     272             :       // could be -0.
     273         112 :       Node* input_value_abs = Float64Abs(input_value);
     274             : 
     275         112 :       GotoIfNot(Float64LessThan(input_value_abs, Float64Constant(1u << 31)),
     276         112 :                 &if_generic);
     277         112 :       Branch(Float64LessThanOrEqual(Float64Constant(1), input_value_abs),
     278         112 :              &if_inputissigned32, &if_generic);
     279             : 
     280             :       // Return the truncated int32 value, and return the tagged result.
     281          56 :       BIND(&if_inputissigned32);
     282         112 :       Node* result = ChangeInt32ToTagged(input_value32);
     283          56 :       Return(result);
     284             :     }
     285             : 
     286          56 :     BIND(&if_inputisstring);
     287             :     {
     288             :       // Check if the String {input} has a cached array index.
     289         112 :       Node* input_hash = LoadNameHashField(input);
     290          56 :       GotoIf(IsSetWord32(input_hash, Name::kDoesNotContainCachedArrayIndexMask),
     291         112 :              &if_generic);
     292             : 
     293             :       // Return the cached array index as result.
     294             :       Node* input_index =
     295         112 :           DecodeWordFromWord32<String::ArrayIndexValueBits>(input_hash);
     296         112 :       Node* result = SmiTag(input_index);
     297          56 :       Return(result);
     298          56 :     }
     299             :   }
     300             : 
     301          56 :   BIND(&if_generic);
     302             :   {
     303             :     Node* result = CallRuntime(Runtime::kStringParseInt, context, input, radix);
     304          56 :     Return(result);
     305          56 :   }
     306          56 : }
     307             : 
     308             : // ES6 #sec-number.parseint
     309         168 : TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
     310             :   Node* context = Parameter(Descriptor::kContext);
     311             :   Node* input = Parameter(Descriptor::kString);
     312             :   Node* radix = Parameter(Descriptor::kRadix);
     313         112 :   Return(CallBuiltin(Builtins::kParseInt, context, input, radix));
     314          56 : }
     315             : 
     316             : // ES6 #sec-number.prototype.valueof
     317         168 : TF_BUILTIN(NumberPrototypeValueOf, CodeStubAssembler) {
     318             :   Node* context = Parameter(Descriptor::kContext);
     319             :   Node* receiver = Parameter(Descriptor::kReceiver);
     320             : 
     321             :   Node* result = ToThisValue(context, receiver, PrimitiveType::kNumber,
     322          56 :                              "Number.prototype.valueOf");
     323          56 :   Return(result);
     324          56 : }
     325             : 
     326             : class AddStubAssembler : public CodeStubAssembler {
     327             :  public:
     328             :   explicit AddStubAssembler(compiler::CodeAssemblerState* state)
     329          56 :       : CodeStubAssembler(state) {}
     330             : 
     331             :  protected:
     332         336 :   void ConvertReceiverAndLoop(Variable* var_value, Label* loop, Node* context) {
     333             :     // Call ToPrimitive explicitly without hint (whereas ToNumber
     334             :     // would pass a "number" hint).
     335         336 :     Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
     336        1008 :     var_value->Bind(CallStub(callable, context, var_value->value()));
     337         336 :     Goto(loop);
     338         336 :   }
     339             : 
     340         280 :   void ConvertNonReceiverAndLoop(Variable* var_value, Label* loop,
     341             :                                  Node* context) {
     342             :     var_value->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
     343         840 :                                 var_value->value()));
     344         280 :     Goto(loop);
     345         280 :   }
     346             : 
     347         224 :   void ConvertAndLoop(Variable* var_value, Node* instance_type, Label* loop,
     348             :                       Node* context) {
     349         224 :     Label is_not_receiver(this, Label::kDeferred);
     350         448 :     GotoIfNot(IsJSReceiverInstanceType(instance_type), &is_not_receiver);
     351             : 
     352         224 :     ConvertReceiverAndLoop(var_value, loop, context);
     353             : 
     354         224 :     BIND(&is_not_receiver);
     355         224 :     ConvertNonReceiverAndLoop(var_value, loop, context);
     356         224 :   }
     357             : };
     358             : 
     359         280 : TF_BUILTIN(Add, AddStubAssembler) {
     360             :   Node* context = Parameter(Descriptor::kContext);
     361          56 :   VARIABLE(var_left, MachineRepresentation::kTagged,
     362             :            Parameter(Descriptor::kLeft));
     363         112 :   VARIABLE(var_right, MachineRepresentation::kTagged,
     364             :            Parameter(Descriptor::kRight));
     365             : 
     366             :   // Shared entry for floating point addition.
     367          56 :   Label do_double_add(this);
     368         112 :   VARIABLE(var_left_double, MachineRepresentation::kFloat64);
     369         112 :   VARIABLE(var_right_double, MachineRepresentation::kFloat64);
     370             : 
     371             :   // We might need to loop several times due to ToPrimitive, ToString and/or
     372             :   // ToNumeric conversions.
     373         112 :   VARIABLE(var_result, MachineRepresentation::kTagged);
     374          56 :   Variable* loop_vars[2] = {&var_left, &var_right};
     375         112 :   Label loop(this, 2, loop_vars),
     376          56 :       string_add_convert_left(this, Label::kDeferred),
     377          56 :       string_add_convert_right(this, Label::kDeferred),
     378          56 :       do_bigint_add(this, Label::kDeferred);
     379          56 :   Goto(&loop);
     380          56 :   BIND(&loop);
     381             :   {
     382          56 :     Node* left = var_left.value();
     383          56 :     Node* right = var_right.value();
     384             : 
     385          56 :     Label if_left_smi(this), if_left_heapobject(this);
     386         112 :     Branch(TaggedIsSmi(left), &if_left_smi, &if_left_heapobject);
     387             : 
     388          56 :     BIND(&if_left_smi);
     389             :     {
     390          56 :       Label if_right_smi(this), if_right_heapobject(this);
     391         112 :       Branch(TaggedIsSmi(right), &if_right_smi, &if_right_heapobject);
     392             : 
     393          56 :       BIND(&if_right_smi);
     394             :       {
     395             :         Label if_overflow(this);
     396          56 :         TNode<Smi> result = TrySmiAdd(CAST(left), CAST(right), &if_overflow);
     397          56 :         Return(result);
     398             : 
     399          56 :         BIND(&if_overflow);
     400             :         {
     401         112 :           var_left_double.Bind(SmiToFloat64(left));
     402         112 :           var_right_double.Bind(SmiToFloat64(right));
     403          56 :           Goto(&do_double_add);
     404          56 :         }
     405             :       }  // if_right_smi
     406             : 
     407          56 :       BIND(&if_right_heapobject);
     408             :       {
     409         112 :         Node* right_map = LoadMap(right);
     410             : 
     411             :         Label if_right_not_number(this, Label::kDeferred);
     412         112 :         GotoIfNot(IsHeapNumberMap(right_map), &if_right_not_number);
     413             : 
     414             :         // {right} is a HeapNumber.
     415         112 :         var_left_double.Bind(SmiToFloat64(left));
     416         112 :         var_right_double.Bind(LoadHeapNumberValue(right));
     417          56 :         Goto(&do_double_add);
     418             : 
     419          56 :         BIND(&if_right_not_number);
     420             :         {
     421         112 :           Node* right_instance_type = LoadMapInstanceType(right_map);
     422          56 :           GotoIf(IsStringInstanceType(right_instance_type),
     423         112 :                  &string_add_convert_left);
     424         112 :           GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
     425          56 :           ConvertAndLoop(&var_right, right_instance_type, &loop, context);
     426          56 :         }
     427          56 :       }  // if_right_heapobject
     428             :     }    // if_left_smi
     429             : 
     430          56 :     BIND(&if_left_heapobject);
     431             :     {
     432         112 :       Node* left_map = LoadMap(left);
     433          56 :       Label if_right_smi(this), if_right_heapobject(this);
     434         112 :       Branch(TaggedIsSmi(right), &if_right_smi, &if_right_heapobject);
     435             : 
     436          56 :       BIND(&if_right_smi);
     437             :       {
     438             :         Label if_left_not_number(this, Label::kDeferred);
     439         112 :         GotoIfNot(IsHeapNumberMap(left_map), &if_left_not_number);
     440             : 
     441             :         // {left} is a HeapNumber, {right} is a Smi.
     442         112 :         var_left_double.Bind(LoadHeapNumberValue(left));
     443         112 :         var_right_double.Bind(SmiToFloat64(right));
     444          56 :         Goto(&do_double_add);
     445             : 
     446          56 :         BIND(&if_left_not_number);
     447             :         {
     448         112 :           Node* left_instance_type = LoadMapInstanceType(left_map);
     449          56 :           GotoIf(IsStringInstanceType(left_instance_type),
     450         112 :                  &string_add_convert_right);
     451         112 :           GotoIf(IsBigIntInstanceType(left_instance_type), &do_bigint_add);
     452             :           // {left} is neither a Numeric nor a String, and {right} is a Smi.
     453          56 :           ConvertAndLoop(&var_left, left_instance_type, &loop, context);
     454          56 :         }
     455             :       }  // if_right_smi
     456             : 
     457          56 :       BIND(&if_right_heapobject);
     458             :       {
     459         112 :         Node* right_map = LoadMap(right);
     460             : 
     461          56 :         Label if_left_number(this), if_left_not_number(this, Label::kDeferred);
     462         112 :         Branch(IsHeapNumberMap(left_map), &if_left_number, &if_left_not_number);
     463             : 
     464          56 :         BIND(&if_left_number);
     465             :         {
     466             :           Label if_right_not_number(this, Label::kDeferred);
     467         112 :           GotoIfNot(IsHeapNumberMap(right_map), &if_right_not_number);
     468             : 
     469             :           // Both {left} and {right} are HeapNumbers.
     470         112 :           var_left_double.Bind(LoadHeapNumberValue(left));
     471         112 :           var_right_double.Bind(LoadHeapNumberValue(right));
     472          56 :           Goto(&do_double_add);
     473             : 
     474          56 :           BIND(&if_right_not_number);
     475             :           {
     476         112 :             Node* right_instance_type = LoadMapInstanceType(right_map);
     477          56 :             GotoIf(IsStringInstanceType(right_instance_type),
     478         112 :                    &string_add_convert_left);
     479         112 :             GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
     480             :             // {left} is a HeapNumber, {right} is neither Number nor String.
     481          56 :             ConvertAndLoop(&var_right, right_instance_type, &loop, context);
     482          56 :           }
     483             :         }  // if_left_number
     484             : 
     485          56 :         BIND(&if_left_not_number);
     486             :         {
     487             :           Label if_left_bigint(this);
     488         112 :           Node* left_instance_type = LoadMapInstanceType(left_map);
     489          56 :           GotoIf(IsStringInstanceType(left_instance_type),
     490         112 :                  &string_add_convert_right);
     491         112 :           Node* right_instance_type = LoadMapInstanceType(right_map);
     492          56 :           GotoIf(IsStringInstanceType(right_instance_type),
     493         112 :                  &string_add_convert_left);
     494         112 :           GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
     495          56 :           Label if_left_not_receiver(this, Label::kDeferred);
     496          56 :           Label if_right_not_receiver(this, Label::kDeferred);
     497          56 :           GotoIfNot(IsJSReceiverInstanceType(left_instance_type),
     498         112 :                     &if_left_not_receiver);
     499             :           // {left} is a JSReceiver, convert it first.
     500          56 :           ConvertReceiverAndLoop(&var_left, &loop, context);
     501             : 
     502          56 :           BIND(&if_left_bigint);
     503             :           {
     504             :             // {right} is a HeapObject, but not a String. Jump to
     505             :             // {do_bigint_add} if {right} is already a Numeric.
     506         112 :             GotoIf(IsBigIntInstanceType(right_instance_type), &do_bigint_add);
     507         112 :             GotoIf(IsHeapNumberMap(right_map), &do_bigint_add);
     508          56 :             ConvertAndLoop(&var_right, right_instance_type, &loop, context);
     509             :           }
     510             : 
     511          56 :           BIND(&if_left_not_receiver);
     512          56 :           GotoIfNot(IsJSReceiverInstanceType(right_instance_type),
     513         112 :                     &if_right_not_receiver);
     514             :           // {left} is a Primitive, but {right} is a JSReceiver, so convert
     515             :           // {right} with priority.
     516          56 :           ConvertReceiverAndLoop(&var_right, &loop, context);
     517             : 
     518          56 :           BIND(&if_right_not_receiver);
     519             :           // Neither {left} nor {right} are JSReceivers.
     520         112 :           ConvertNonReceiverAndLoop(&var_left, &loop, context);
     521          56 :         }
     522          56 :       }  // if_right_heapobject
     523          56 :     }    // if_left_heapobject
     524             :   }
     525          56 :   BIND(&string_add_convert_left);
     526             :   {
     527             :     // Convert {left} to a String and concatenate it with the String {right}.
     528             :     TailCallBuiltin(Builtins::kStringAdd_ConvertLeft, context, var_left.value(),
     529         112 :                     var_right.value());
     530             :   }
     531             : 
     532          56 :   BIND(&string_add_convert_right);
     533             :   {
     534             :     // Convert {right} to a String and concatenate it with the String {left}.
     535             :     TailCallBuiltin(Builtins::kStringAdd_ConvertRight, context,
     536         112 :                     var_left.value(), var_right.value());
     537             :   }
     538             : 
     539          56 :   BIND(&do_bigint_add);
     540             :   {
     541             :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     542         112 :                        var_right.value(), SmiConstant(Operation::kAdd)));
     543             :   }
     544             : 
     545          56 :   BIND(&do_double_add);
     546             :   {
     547         224 :     Node* value = Float64Add(var_left_double.value(), var_right_double.value());
     548         112 :     Return(AllocateHeapNumberWithValue(value));
     549          56 :   }
     550          56 : }
     551             : 
     552             : template <typename Descriptor>
     553         224 : void NumberBuiltinsAssembler::UnaryOp(Variable* var_input, Label* do_smi,
     554             :                                       Label* do_double,
     555             :                                       Variable* var_input_double,
     556             :                                       Label* do_bigint) {
     557             :   DCHECK_EQ(var_input->rep(), MachineRepresentation::kTagged);
     558             :   DCHECK_IMPLIES(var_input_double != nullptr,
     559             :                  var_input_double->rep() == MachineRepresentation::kFloat64);
     560             : 
     561         224 :   Node* context = Parameter(Descriptor::kContext);
     562         224 :   var_input->Bind(Parameter(Descriptor::kValue));
     563             : 
     564             :   // We might need to loop for ToNumeric conversion.
     565         448 :   Label loop(this, {var_input});
     566         224 :   Goto(&loop);
     567         224 :   BIND(&loop);
     568         224 :   Node* input = var_input->value();
     569             : 
     570         224 :   Label not_number(this);
     571         448 :   GotoIf(TaggedIsSmi(input), do_smi);
     572         448 :   GotoIfNot(IsHeapNumber(input), &not_number);
     573         224 :   if (var_input_double != nullptr) {
     574         112 :     var_input_double->Bind(LoadHeapNumberValue(input));
     575             :   }
     576         224 :   Goto(do_double);
     577             : 
     578         224 :   BIND(&not_number);
     579         448 :   GotoIf(IsBigInt(input), do_bigint);
     580         448 :   var_input->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context, input));
     581         448 :   Goto(&loop);
     582         224 : }
     583             : 
     584             : template <typename Descriptor>
     585         280 : void NumberBuiltinsAssembler::BinaryOp(Label* smis, Variable* var_left,
     586             :                                        Variable* var_right, Label* doubles,
     587             :                                        Variable* var_left_double,
     588             :                                        Variable* var_right_double,
     589             :                                        Label* bigints) {
     590             :   DCHECK_EQ(var_left->rep(), MachineRepresentation::kTagged);
     591             :   DCHECK_EQ(var_right->rep(), MachineRepresentation::kTagged);
     592             :   DCHECK_IMPLIES(var_left_double != nullptr,
     593             :                  var_left_double->rep() == MachineRepresentation::kFloat64);
     594             :   DCHECK_IMPLIES(var_right_double != nullptr,
     595             :                  var_right_double->rep() == MachineRepresentation::kFloat64);
     596             :   DCHECK_EQ(var_left_double == nullptr, var_right_double == nullptr);
     597             : 
     598         280 :   Node* context = Parameter(Descriptor::kContext);
     599         280 :   var_left->Bind(Parameter(Descriptor::kLeft));
     600         280 :   var_right->Bind(Parameter(Descriptor::kRight));
     601             : 
     602             :   // We might need to loop for ToNumeric conversions.
     603         560 :   Label loop(this, {var_left, var_right});
     604         280 :   Goto(&loop);
     605         280 :   BIND(&loop);
     606             : 
     607         280 :   Label left_not_smi(this), right_not_smi(this);
     608         280 :   Label left_not_number(this), right_not_number(this);
     609         840 :   GotoIfNot(TaggedIsSmi(var_left->value()), &left_not_smi);
     610         840 :   GotoIf(TaggedIsSmi(var_right->value()), smis);
     611             : 
     612             :   // At this point, var_left is a Smi but var_right is not.
     613         840 :   GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
     614         280 :   if (var_left_double != nullptr) {
     615         672 :     var_left_double->Bind(SmiToFloat64(var_left->value()));
     616         672 :     var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
     617             :   }
     618         280 :   Goto(doubles);
     619             : 
     620         280 :   BIND(&left_not_smi);
     621             :   {
     622         840 :     GotoIfNot(IsHeapNumber(var_left->value()), &left_not_number);
     623         840 :     GotoIfNot(TaggedIsSmi(var_right->value()), &right_not_smi);
     624             : 
     625             :     // At this point, var_left is a HeapNumber and var_right is a Smi.
     626         280 :     if (var_left_double != nullptr) {
     627         672 :       var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
     628         672 :       var_right_double->Bind(SmiToFloat64(var_right->value()));
     629             :     }
     630         280 :     Goto(doubles);
     631             :   }
     632             : 
     633         280 :   BIND(&right_not_smi);
     634             :   {
     635         840 :     GotoIfNot(IsHeapNumber(var_right->value()), &right_not_number);
     636         280 :     if (var_left_double != nullptr) {
     637         672 :       var_left_double->Bind(LoadHeapNumberValue(var_left->value()));
     638         672 :       var_right_double->Bind(LoadHeapNumberValue(var_right->value()));
     639             :     }
     640         280 :     Goto(doubles);
     641             :   }
     642             : 
     643         280 :   BIND(&left_not_number);
     644             :   {
     645             :     Label left_bigint(this);
     646         840 :     GotoIf(IsBigInt(var_left->value()), &left_bigint);
     647         280 :     var_left->Bind(
     648         840 :         CallBuiltin(Builtins::kNonNumberToNumeric, context, var_left->value()));
     649         280 :     Goto(&loop);
     650             : 
     651         280 :     BIND(&left_bigint);
     652             :     {
     653             :       // Jump to {bigints} if {var_right} is already a Numeric.
     654         840 :       GotoIf(TaggedIsSmi(var_right->value()), bigints);
     655         840 :       GotoIf(IsBigInt(var_right->value()), bigints);
     656         840 :       GotoIf(IsHeapNumber(var_right->value()), bigints);
     657         280 :       var_right->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
     658         840 :                                   var_right->value()));
     659         280 :       Goto(&loop);
     660         280 :     }
     661             :   }
     662             : 
     663         280 :   BIND(&right_not_number);
     664             :   {
     665         840 :     GotoIf(IsBigInt(var_right->value()), bigints);
     666         280 :     var_right->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context,
     667         840 :                                 var_right->value()));
     668         280 :     Goto(&loop);
     669         280 :   }
     670         280 : }
     671             : 
     672         280 : TF_BUILTIN(Subtract, NumberBuiltinsAssembler) {
     673          56 :   VARIABLE(var_left, MachineRepresentation::kTagged);
     674         112 :   VARIABLE(var_right, MachineRepresentation::kTagged);
     675         112 :   VARIABLE(var_left_double, MachineRepresentation::kFloat64);
     676         112 :   VARIABLE(var_right_double, MachineRepresentation::kFloat64);
     677          56 :   Label do_smi_sub(this), do_double_sub(this), do_bigint_sub(this);
     678             : 
     679             :   BinaryOp<Descriptor>(&do_smi_sub, &var_left, &var_right, &do_double_sub,
     680          56 :                        &var_left_double, &var_right_double, &do_bigint_sub);
     681             : 
     682          56 :   BIND(&do_smi_sub);
     683             :   {
     684             :     Label if_overflow(this);
     685          56 :     TNode<Smi> result = TrySmiSub(CAST(var_left.value()),
     686         112 :                                   CAST(var_right.value()), &if_overflow);
     687          56 :     Return(result);
     688             : 
     689          56 :     BIND(&if_overflow);
     690             :     {
     691         168 :       var_left_double.Bind(SmiToFloat64(var_left.value()));
     692         168 :       var_right_double.Bind(SmiToFloat64(var_right.value()));
     693          56 :       Goto(&do_double_sub);
     694          56 :     }
     695             :   }
     696             : 
     697          56 :   BIND(&do_double_sub);
     698             :   {
     699         224 :     Node* value = Float64Sub(var_left_double.value(), var_right_double.value());
     700         112 :     Return(AllocateHeapNumberWithValue(value));
     701             :   }
     702             : 
     703          56 :   BIND(&do_bigint_sub);
     704             :   {
     705             :     Node* context = Parameter(Descriptor::kContext);
     706             :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     707         112 :                        var_right.value(), SmiConstant(Operation::kSubtract)));
     708          56 :   }
     709          56 : }
     710             : 
     711         224 : TF_BUILTIN(BitwiseNot, NumberBuiltinsAssembler) {
     712             :   Node* context = Parameter(Descriptor::kContext);
     713          56 :   VARIABLE(var_input, MachineRepresentation::kTagged);
     714          56 :   Label do_number(this), do_bigint(this);
     715             : 
     716          56 :   UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
     717             : 
     718          56 :   BIND(&do_number);
     719             :   {
     720             :     TailCallBuiltin(Builtins::kBitwiseXor, context, var_input.value(),
     721         112 :                     SmiConstant(-1));
     722             :   }
     723             : 
     724          56 :   BIND(&do_bigint);
     725             :   {
     726             :     Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
     727         112 :                        SmiConstant(Operation::kBitwiseNot)));
     728          56 :   }
     729          56 : }
     730             : 
     731         224 : TF_BUILTIN(Decrement, NumberBuiltinsAssembler) {
     732             :   Node* context = Parameter(Descriptor::kContext);
     733          56 :   VARIABLE(var_input, MachineRepresentation::kTagged);
     734          56 :   Label do_number(this), do_bigint(this);
     735             : 
     736          56 :   UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
     737             : 
     738          56 :   BIND(&do_number);
     739             :   {
     740             :     TailCallBuiltin(Builtins::kSubtract, context, var_input.value(),
     741         112 :                     SmiConstant(1));
     742             :   }
     743             : 
     744          56 :   BIND(&do_bigint);
     745             :   {
     746             :     Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
     747         112 :                        SmiConstant(Operation::kDecrement)));
     748          56 :   }
     749          56 : }
     750             : 
     751         224 : TF_BUILTIN(Increment, NumberBuiltinsAssembler) {
     752             :   Node* context = Parameter(Descriptor::kContext);
     753          56 :   VARIABLE(var_input, MachineRepresentation::kTagged);
     754          56 :   Label do_number(this), do_bigint(this);
     755             : 
     756          56 :   UnaryOp<Descriptor>(&var_input, &do_number, &do_number, nullptr, &do_bigint);
     757             : 
     758          56 :   BIND(&do_number);
     759             :   {
     760         112 :     TailCallBuiltin(Builtins::kAdd, context, var_input.value(), SmiConstant(1));
     761             :   }
     762             : 
     763          56 :   BIND(&do_bigint);
     764             :   {
     765             :     Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
     766         112 :                        SmiConstant(Operation::kIncrement)));
     767          56 :   }
     768          56 : }
     769             : 
     770         280 : TF_BUILTIN(Negate, NumberBuiltinsAssembler) {
     771          56 :   VARIABLE(var_input, MachineRepresentation::kTagged);
     772         112 :   VARIABLE(var_input_double, MachineRepresentation::kFloat64);
     773          56 :   Label do_smi(this), do_double(this), do_bigint(this);
     774             : 
     775             :   UnaryOp<Descriptor>(&var_input, &do_smi, &do_double, &var_input_double,
     776          56 :                       &do_bigint);
     777             : 
     778          56 :   BIND(&do_smi);
     779         112 :   { Return(SmiMul(CAST(var_input.value()), SmiConstant(-1))); }
     780             : 
     781          56 :   BIND(&do_double);
     782             :   {
     783         224 :     Node* value = Float64Mul(var_input_double.value(), Float64Constant(-1));
     784         112 :     Return(AllocateHeapNumberWithValue(value));
     785             :   }
     786             : 
     787          56 :   BIND(&do_bigint);
     788             :   {
     789             :     Node* context = Parameter(Descriptor::kContext);
     790             :     Return(CallRuntime(Runtime::kBigIntUnaryOp, context, var_input.value(),
     791         112 :                        SmiConstant(Operation::kNegate)));
     792          56 :   }
     793          56 : }
     794             : 
     795         280 : TF_BUILTIN(Multiply, NumberBuiltinsAssembler) {
     796          56 :   VARIABLE(var_left, MachineRepresentation::kTagged);
     797         112 :   VARIABLE(var_right, MachineRepresentation::kTagged);
     798         112 :   VARIABLE(var_left_double, MachineRepresentation::kFloat64);
     799         112 :   VARIABLE(var_right_double, MachineRepresentation::kFloat64);
     800          56 :   Label do_smi_mul(this), do_double_mul(this), do_bigint_mul(this);
     801             : 
     802             :   BinaryOp<Descriptor>(&do_smi_mul, &var_left, &var_right, &do_double_mul,
     803          56 :                        &var_left_double, &var_right_double, &do_bigint_mul);
     804             : 
     805          56 :   BIND(&do_smi_mul);
     806             :   // The result is not necessarily a smi, in case of overflow.
     807         112 :   Return(SmiMul(CAST(var_left.value()), CAST(var_right.value())));
     808             : 
     809          56 :   BIND(&do_double_mul);
     810         224 :   Node* value = Float64Mul(var_left_double.value(), var_right_double.value());
     811         112 :   Return(AllocateHeapNumberWithValue(value));
     812             : 
     813          56 :   BIND(&do_bigint_mul);
     814             :   {
     815             :     Node* context = Parameter(Descriptor::kContext);
     816             :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     817         112 :                        var_right.value(), SmiConstant(Operation::kMultiply)));
     818          56 :   }
     819          56 : }
     820             : 
     821         280 : TF_BUILTIN(Divide, NumberBuiltinsAssembler) {
     822          56 :   VARIABLE(var_left, MachineRepresentation::kTagged);
     823         112 :   VARIABLE(var_right, MachineRepresentation::kTagged);
     824         112 :   VARIABLE(var_left_double, MachineRepresentation::kFloat64);
     825         112 :   VARIABLE(var_right_double, MachineRepresentation::kFloat64);
     826          56 :   Label do_smi_div(this), do_double_div(this), do_bigint_div(this);
     827             : 
     828             :   BinaryOp<Descriptor>(&do_smi_div, &var_left, &var_right, &do_double_div,
     829          56 :                        &var_left_double, &var_right_double, &do_bigint_div);
     830             : 
     831          56 :   BIND(&do_smi_div);
     832             :   {
     833             :     // TODO(jkummerow): Consider just always doing a double division.
     834             :     Label bailout(this);
     835          56 :     TNode<Smi> dividend = CAST(var_left.value());
     836          56 :     TNode<Smi> divisor = CAST(var_right.value());
     837             : 
     838             :     // Do floating point division if {divisor} is zero.
     839         112 :     GotoIf(SmiEqual(divisor, SmiConstant(0)), &bailout);
     840             : 
     841             :     // Do floating point division if {dividend} is zero and {divisor} is
     842             :     // negative.
     843          56 :     Label dividend_is_zero(this), dividend_is_not_zero(this);
     844          56 :     Branch(SmiEqual(dividend, SmiConstant(0)), &dividend_is_zero,
     845         112 :            &dividend_is_not_zero);
     846             : 
     847          56 :     BIND(&dividend_is_zero);
     848             :     {
     849         112 :       GotoIf(SmiLessThan(divisor, SmiConstant(0)), &bailout);
     850          56 :       Goto(&dividend_is_not_zero);
     851             :     }
     852          56 :     BIND(&dividend_is_not_zero);
     853             : 
     854         112 :     Node* untagged_divisor = SmiToInt32(divisor);
     855         112 :     Node* untagged_dividend = SmiToInt32(dividend);
     856             : 
     857             :     // Do floating point division if {dividend} is kMinInt (or kMinInt - 1
     858             :     // if the Smi size is 31) and {divisor} is -1.
     859          56 :     Label divisor_is_minus_one(this), divisor_is_not_minus_one(this);
     860         112 :     Branch(Word32Equal(untagged_divisor, Int32Constant(-1)),
     861         112 :            &divisor_is_minus_one, &divisor_is_not_minus_one);
     862             : 
     863          56 :     BIND(&divisor_is_minus_one);
     864             :     {
     865             :       GotoIf(Word32Equal(
     866             :                  untagged_dividend,
     867         112 :                  Int32Constant(kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
     868         112 :              &bailout);
     869          56 :       Goto(&divisor_is_not_minus_one);
     870             :     }
     871          56 :     BIND(&divisor_is_not_minus_one);
     872             : 
     873             :     // TODO(epertoso): consider adding a machine instruction that returns
     874             :     // both the result and the remainder.
     875         112 :     Node* untagged_result = Int32Div(untagged_dividend, untagged_divisor);
     876         112 :     Node* truncated = Int32Mul(untagged_result, untagged_divisor);
     877             :     // Do floating point division if the remainder is not 0.
     878         112 :     GotoIf(Word32NotEqual(untagged_dividend, truncated), &bailout);
     879         112 :     Return(SmiFromInt32(untagged_result));
     880             : 
     881             :     // Bailout: convert {dividend} and {divisor} to double and do double
     882             :     // division.
     883          56 :     BIND(&bailout);
     884             :     {
     885         112 :       var_left_double.Bind(SmiToFloat64(dividend));
     886         112 :       var_right_double.Bind(SmiToFloat64(divisor));
     887          56 :       Goto(&do_double_div);
     888          56 :     }
     889             :   }
     890             : 
     891          56 :   BIND(&do_double_div);
     892             :   {
     893         224 :     Node* value = Float64Div(var_left_double.value(), var_right_double.value());
     894         112 :     Return(AllocateHeapNumberWithValue(value));
     895             :   }
     896             : 
     897          56 :   BIND(&do_bigint_div);
     898             :   {
     899             :     Node* context = Parameter(Descriptor::kContext);
     900             :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     901         112 :                        var_right.value(), SmiConstant(Operation::kDivide)));
     902          56 :   }
     903          56 : }
     904             : 
     905         280 : TF_BUILTIN(Modulus, NumberBuiltinsAssembler) {
     906          56 :   VARIABLE(var_left, MachineRepresentation::kTagged);
     907         112 :   VARIABLE(var_right, MachineRepresentation::kTagged);
     908         112 :   VARIABLE(var_left_double, MachineRepresentation::kFloat64);
     909         112 :   VARIABLE(var_right_double, MachineRepresentation::kFloat64);
     910          56 :   Label do_smi_mod(this), do_double_mod(this), do_bigint_mod(this);
     911             : 
     912             :   BinaryOp<Descriptor>(&do_smi_mod, &var_left, &var_right, &do_double_mod,
     913          56 :                        &var_left_double, &var_right_double, &do_bigint_mod);
     914             : 
     915          56 :   BIND(&do_smi_mod);
     916         112 :   Return(SmiMod(CAST(var_left.value()), CAST(var_right.value())));
     917             : 
     918          56 :   BIND(&do_double_mod);
     919         224 :   Node* value = Float64Mod(var_left_double.value(), var_right_double.value());
     920         112 :   Return(AllocateHeapNumberWithValue(value));
     921             : 
     922          56 :   BIND(&do_bigint_mod);
     923             :   {
     924             :     Node* context = Parameter(Descriptor::kContext);
     925             :     Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     926         112 :                        var_right.value(), SmiConstant(Operation::kModulus)));
     927          56 :   }
     928          56 : }
     929             : 
     930         280 : TF_BUILTIN(Exponentiate, NumberBuiltinsAssembler) {
     931          56 :   VARIABLE(var_left, MachineRepresentation::kTagged);
     932         112 :   VARIABLE(var_right, MachineRepresentation::kTagged);
     933          56 :   Label do_number_exp(this), do_bigint_exp(this);
     934             :   Node* context = Parameter(Descriptor::kContext);
     935             : 
     936             :   BinaryOp<Descriptor>(&do_number_exp, &var_left, &var_right, &do_number_exp,
     937          56 :                        nullptr, nullptr, &do_bigint_exp);
     938             : 
     939          56 :   BIND(&do_number_exp);
     940             :   {
     941             :     MathBuiltinsAssembler math_asm(state());
     942         112 :     Return(math_asm.MathPow(context, var_left.value(), var_right.value()));
     943             :   }
     944             : 
     945          56 :   BIND(&do_bigint_exp);
     946             :   Return(CallRuntime(Runtime::kBigIntBinaryOp, context, var_left.value(),
     947         168 :                      var_right.value(), SmiConstant(Operation::kExponentiate)));
     948          56 : }
     949             : 
     950         168 : TF_BUILTIN(ShiftLeft, NumberBuiltinsAssembler) {
     951          56 :   EmitBitwiseOp<Descriptor>(Operation::kShiftLeft);
     952           0 : }
     953             : 
     954         168 : TF_BUILTIN(ShiftRight, NumberBuiltinsAssembler) {
     955          56 :   EmitBitwiseOp<Descriptor>(Operation::kShiftRight);
     956           0 : }
     957             : 
     958         168 : TF_BUILTIN(ShiftRightLogical, NumberBuiltinsAssembler) {
     959          56 :   EmitBitwiseOp<Descriptor>(Operation::kShiftRightLogical);
     960           0 : }
     961             : 
     962         168 : TF_BUILTIN(BitwiseAnd, NumberBuiltinsAssembler) {
     963          56 :   EmitBitwiseOp<Descriptor>(Operation::kBitwiseAnd);
     964           0 : }
     965             : 
     966         168 : TF_BUILTIN(BitwiseOr, NumberBuiltinsAssembler) {
     967          56 :   EmitBitwiseOp<Descriptor>(Operation::kBitwiseOr);
     968           0 : }
     969             : 
     970         168 : TF_BUILTIN(BitwiseXor, NumberBuiltinsAssembler) {
     971          56 :   EmitBitwiseOp<Descriptor>(Operation::kBitwiseXor);
     972           0 : }
     973             : 
     974         168 : TF_BUILTIN(LessThan, NumberBuiltinsAssembler) {
     975          56 :   RelationalComparisonBuiltin<Descriptor>(Operation::kLessThan);
     976           0 : }
     977             : 
     978         168 : TF_BUILTIN(LessThanOrEqual, NumberBuiltinsAssembler) {
     979          56 :   RelationalComparisonBuiltin<Descriptor>(Operation::kLessThanOrEqual);
     980           0 : }
     981             : 
     982         168 : TF_BUILTIN(GreaterThan, NumberBuiltinsAssembler) {
     983          56 :   RelationalComparisonBuiltin<Descriptor>(Operation::kGreaterThan);
     984           0 : }
     985             : 
     986         168 : TF_BUILTIN(GreaterThanOrEqual, NumberBuiltinsAssembler) {
     987          56 :   RelationalComparisonBuiltin<Descriptor>(Operation::kGreaterThanOrEqual);
     988           0 : }
     989             : 
     990         168 : TF_BUILTIN(Equal, CodeStubAssembler) {
     991             :   Node* lhs = Parameter(Descriptor::kLeft);
     992             :   Node* rhs = Parameter(Descriptor::kRight);
     993             :   Node* context = Parameter(Descriptor::kContext);
     994             : 
     995         112 :   Return(Equal(lhs, rhs, context));
     996          56 : }
     997             : 
     998         168 : TF_BUILTIN(StrictEqual, CodeStubAssembler) {
     999             :   Node* lhs = Parameter(Descriptor::kLeft);
    1000             :   Node* rhs = Parameter(Descriptor::kRight);
    1001             : 
    1002         112 :   Return(StrictEqual(lhs, rhs));
    1003          56 : }
    1004             : 
    1005             : }  // namespace internal
    1006       94089 : }  // namespace v8

Generated by: LCOV version 1.10