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