binary-op-assembler.cc 23.6 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/ic/binary-op-assembler.h"

7
#include "src/common/globals.h"
8 9 10 11

namespace v8 {
namespace internal {

12
TNode<Object> BinaryOpAssembler::Generate_AddWithFeedback(
13 14
    const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
    TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
15
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
16 17 18 19
  // Shared entry for floating point addition.
  Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
      check_rhsisoddball(this, Label::kDeferred),
      call_with_oddball_feedback(this), call_with_any_feedback(this),
20
      call_add_stub(this), end(this), bigint(this, Label::kDeferred);
21 22 23 24
  TVARIABLE(Float64T, var_fadd_lhs);
  TVARIABLE(Float64T, var_fadd_rhs);
  TVARIABLE(Smi, var_type_feedback);
  TVARIABLE(Object, var_result);
25 26

  // Check if the {lhs} is a Smi or a HeapObject.
27 28 29 30 31 32
  Label if_lhsissmi(this);
  // If rhs is known to be an Smi we want to fast path Smi operation. This is
  // for AddSmi operation. For the normal Add operation, we want to fast path
  // both Smi and Number operations, so this path should not be marked as
  // Deferred.
  Label if_lhsisnotsmi(this,
33
                       rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
34
  Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
35

36
  BIND(&if_lhsissmi);
37
  {
38
    Comment("lhs is Smi");
39
    TNode<Smi> lhs_smi = CAST(lhs);
40
    if (!rhs_known_smi) {
41 42 43 44 45 46 47
      // Check if the {rhs} is also a Smi.
      Label if_rhsissmi(this), if_rhsisnotsmi(this);
      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);

      BIND(&if_rhsisnotsmi);
      {
        // Check if the {rhs} is a HeapNumber.
48 49
        TNode<HeapObject> rhs_heap_object = CAST(rhs);
        GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
50

51 52
        var_fadd_lhs = SmiToFloat64(lhs_smi);
        var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
53 54 55 56 57
        Goto(&do_fadd);
      }

      BIND(&if_rhsissmi);
    }
58 59

    {
60 61 62 63 64
      Comment("perform smi operation");
      // If rhs is known to be an Smi we want to fast path Smi operation. This
      // is for AddSmi operation. For the normal Add operation, we want to fast
      // path both Smi and Number operations, so this path should not be marked
      // as Deferred.
65
      TNode<Smi> rhs_smi = CAST(rhs);
66
      Label if_overflow(this,
67
                        rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
68
      TNode<Smi> smi_result = TrySmiAdd(lhs_smi, rhs_smi, &if_overflow);
69 70
      // Not overflowed.
      {
71
        var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
72 73
        UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
                       slot_id, update_feedback_mode);
74
        var_result = smi_result;
75 76
        Goto(&end);
      }
77

78
      BIND(&if_overflow);
79
      {
80 81
        var_fadd_lhs = SmiToFloat64(lhs_smi);
        var_fadd_rhs = SmiToFloat64(rhs_smi);
82 83 84 85 86
        Goto(&do_fadd);
      }
    }
  }

87
  BIND(&if_lhsisnotsmi);
88 89
  {
    // Check if {lhs} is a HeapNumber.
90 91
    TNode<HeapObject> lhs_heap_object = CAST(lhs);
    GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
92

93
    if (!rhs_known_smi) {
94 95 96
      // Check if the {rhs} is Smi.
      Label if_rhsissmi(this), if_rhsisnotsmi(this);
      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
97

98 99 100
      BIND(&if_rhsisnotsmi);
      {
        // Check if the {rhs} is a HeapNumber.
101 102
        TNode<HeapObject> rhs_heap_object = CAST(rhs);
        GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
103

104 105
        var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
        var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
106 107
        Goto(&do_fadd);
      }
108

109 110 111
      BIND(&if_rhsissmi);
    }
    {
112 113
      var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
      var_fadd_rhs = SmiToFloat64(CAST(rhs));
114 115 116 117
      Goto(&do_fadd);
    }
  }

118
  BIND(&do_fadd);
119
  {
120
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
121 122
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
123 124 125
    TNode<Float64T> value =
        Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
    TNode<HeapNumber> result = AllocateHeapNumberWithValue(value);
126
    var_result = result;
127 128 129
    Goto(&end);
  }

130
  BIND(&if_lhsisnotnumber);
131 132 133
  {
    // No checks on rhs are done yet. We just know lhs is not a number or Smi.
    Label if_lhsisoddball(this), if_lhsisnotoddball(this);
134
    TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
135 136
    TNode<BoolT> lhs_is_oddball =
        InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
137 138
    Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);

139
    BIND(&if_lhsisoddball);
140 141
    {
      GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
142

143
      // Check if {rhs} is a HeapNumber.
144
      Branch(IsHeapNumber(CAST(rhs)), &call_with_oddball_feedback,
145 146 147
             &check_rhsisoddball);
    }

148
    BIND(&if_lhsisnotoddball);
149
    {
150 151 152 153 154
      // Check if the {rhs} is a smi, and exit the string and bigint check early
      // if it is.
      GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
      TNode<HeapObject> rhs_heap_object = CAST(rhs);

155 156 157 158 159 160
      Label lhs_is_string(this), lhs_is_bigint(this);
      GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string);
      GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint);
      Goto(&call_with_any_feedback);

      BIND(&lhs_is_bigint);
161
      Branch(IsBigInt(rhs_heap_object), &bigint, &call_with_any_feedback);
162

163
      BIND(&lhs_is_string);
164 165
      {
        TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs_heap_object);
166

167 168 169 170
        // Exit unless {rhs} is a string. Since {lhs} is a string we no longer
        // need an Oddball check.
        GotoIfNot(IsStringInstanceType(rhs_instance_type),
                  &call_with_any_feedback);
171

172
        var_type_feedback = SmiConstant(BinaryOperationFeedback::kString);
173 174
        UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
                       slot_id, update_feedback_mode);
175
        var_result =
176
            CallBuiltin(Builtin::kStringAdd_CheckNone, context(), lhs, rhs);
177

178 179
        Goto(&end);
      }
180 181 182
    }
  }

183
  BIND(&check_rhsisoddball);
184 185 186
  {
    // Check if rhs is an oddball. At this point we know lhs is either a
    // Smi or number or oddball and rhs is not a number or Smi.
187
    TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
188 189
    TNode<BoolT> rhs_is_oddball =
        InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
190
    GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
191
    Goto(&call_with_any_feedback);
192 193
  }

194 195
  BIND(&bigint);
  {
196 197
    // Both {lhs} and {rhs} are of BigInt type.
    Label bigint_too_big(this);
198
    var_result = CallBuiltin(Builtin::kBigIntAddNoThrow, context(), lhs, rhs);
199 200 201
    // Check for sentinel that signals BigIntTooBig exception.
    GotoIf(TaggedIsSmi(var_result.value()), &bigint_too_big);

202
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt);
203 204
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
205
    Goto(&end);
206 207 208 209

    BIND(&bigint_too_big);
    {
      // Update feedback to prevent deopt loop.
210 211
      UpdateFeedback(SmiConstant(BinaryOperationFeedback::kAny),
                     maybe_feedback_vector(), slot_id, update_feedback_mode);
212
      ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
213
    }
214 215
  }

216
  BIND(&call_with_oddball_feedback);
217
  {
218
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
219 220 221
    Goto(&call_add_stub);
  }

222
  BIND(&call_with_any_feedback);
223
  {
224
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
225 226 227
    Goto(&call_add_stub);
  }

228
  BIND(&call_add_stub);
229
  {
230 231
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
232
    var_result = CallBuiltin(Builtin::kAdd, context(), lhs, rhs);
233 234 235
    Goto(&end);
  }

236
  BIND(&end);
237 238 239
  return var_result.value();
}

240
TNode<Object> BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
241 242
    const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
    TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
243
    const SmiOperation& smiOperation, const FloatOperation& floatOperation,
244
    Operation op, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
245 246
  Label do_float_operation(this), end(this), call_stub(this),
      check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this),
247
      if_lhsisnotnumber(this, Label::kDeferred),
248
      if_both_bigint(this, Label::kDeferred);
249 250 251 252
  TVARIABLE(Float64T, var_float_lhs);
  TVARIABLE(Float64T, var_float_rhs);
  TVARIABLE(Smi, var_type_feedback);
  TVARIABLE(Object, var_result);
253

254 255 256 257 258 259
  Label if_lhsissmi(this);
  // If rhs is known to be an Smi (in the SubSmi, MulSmi, DivSmi, ModSmi
  // bytecode handlers) we want to fast path Smi operation. For the normal
  // operation, we want to fast path both Smi and Number operations, so this
  // path should not be marked as Deferred.
  Label if_lhsisnotsmi(this,
260
                       rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
261
  Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
262

263
  // Check if the {lhs} is a Smi or a HeapObject.
264
  BIND(&if_lhsissmi);
265
  {
266
    Comment("lhs is Smi");
267
    TNode<Smi> lhs_smi = CAST(lhs);
268
    if (!rhs_known_smi) {
269 270 271
      // Check if the {rhs} is also a Smi.
      Label if_rhsissmi(this), if_rhsisnotsmi(this);
      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
272

273
      BIND(&if_rhsisnotsmi);
274
      {
275
        // Check if {rhs} is a HeapNumber.
276 277
        TNode<HeapObject> rhs_heap_object = CAST(rhs);
        GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
278 279

        // Perform a floating point operation.
280 281
        var_float_lhs = SmiToFloat64(lhs_smi);
        var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
282
        Goto(&do_float_operation);
283 284
      }

285
      BIND(&if_rhsissmi);
286 287 288
    }

    {
289
      Comment("perform smi operation");
290
      var_result = smiOperation(lhs_smi, CAST(rhs), &var_type_feedback);
291 292
      UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
                     slot_id, update_feedback_mode);
293
      Goto(&end);
294 295 296
    }
  }

297
  BIND(&if_lhsisnotsmi);
298
  {
299
    Comment("lhs is not Smi");
300
    // Check if the {lhs} is a HeapNumber.
301 302
    TNode<HeapObject> lhs_heap_object = CAST(lhs);
    GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
303

304
    if (!rhs_known_smi) {
305 306 307
      // Check if the {rhs} is a Smi.
      Label if_rhsissmi(this), if_rhsisnotsmi(this);
      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
308

309 310 311
      BIND(&if_rhsisnotsmi);
      {
        // Check if the {rhs} is a HeapNumber.
312 313
        TNode<HeapObject> rhs_heap_object = CAST(rhs);
        GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
314 315

        // Perform a floating point operation.
316 317
        var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
        var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
318 319 320 321
        Goto(&do_float_operation);
      }

      BIND(&if_rhsissmi);
322 323 324
    }

    {
325
      // Perform floating point operation.
326 327
      var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
      var_float_rhs = SmiToFloat64(CAST(rhs));
328
      Goto(&do_float_operation);
329 330 331
    }
  }

332
  BIND(&do_float_operation);
333
  {
334
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
335 336
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
337 338 339 340
    TNode<Float64T> lhs_value = var_float_lhs.value();
    TNode<Float64T> rhs_value = var_float_rhs.value();
    TNode<Float64T> value = floatOperation(lhs_value, rhs_value);
    var_result = AllocateHeapNumberWithValue(value);
341 342 343
    Goto(&end);
  }

344
  BIND(&if_lhsisnotnumber);
345 346
  {
    // No checks on rhs are done yet. We just know lhs is not a number or Smi.
347
    Label if_left_bigint(this), if_left_oddball(this);
348
    TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
349
    GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
350 351
    TNode<BoolT> lhs_is_oddball =
        InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
352
    Branch(lhs_is_oddball, &if_left_oddball, &call_with_any_feedback);
353

354
    BIND(&if_left_oddball);
355
    {
356 357 358 359 360
      Label if_rhsissmi(this), if_rhsisnotsmi(this);
      Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);

      BIND(&if_rhsissmi);
      {
361 362
        var_type_feedback =
            SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
363 364 365 366 367 368
        Goto(&call_stub);
      }

      BIND(&if_rhsisnotsmi);
      {
        // Check if {rhs} is a HeapNumber.
369
        GotoIfNot(IsHeapNumber(CAST(rhs)), &check_rhsisoddball);
370

371 372
        var_type_feedback =
            SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
373 374
        Goto(&call_stub);
      }
375 376
    }

377
    BIND(&if_left_bigint);
378
    {
379
      GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
380
      Branch(IsBigInt(CAST(rhs)), &if_both_bigint, &call_with_any_feedback);
381 382 383
    }
  }

384
  BIND(&check_rhsisoddball);
385 386 387
  {
    // Check if rhs is an oddball. At this point we know lhs is either a
    // Smi or number or oddball and rhs is not a number or Smi.
388
    TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
389 390
    TNode<BoolT> rhs_is_oddball =
        InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
391 392
    GotoIfNot(rhs_is_oddball, &call_with_any_feedback);

393
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
394
    Goto(&call_stub);
395 396
  }

397
  BIND(&if_both_bigint);
398
  {
399
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt);
400 401
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
402 403 404
    if (op == Operation::kSubtract) {
      Label bigint_too_big(this);
      var_result =
405
          CallBuiltin(Builtin::kBigIntSubtractNoThrow, context(), lhs, rhs);
406 407 408 409 410 411 412 413

      // Check for sentinel that signals BigIntTooBig exception.
      GotoIf(TaggedIsSmi(var_result.value()), &bigint_too_big);
      Goto(&end);

      BIND(&bigint_too_big);
      {
        // Update feedback to prevent deopt loop.
414 415
        UpdateFeedback(SmiConstant(BinaryOperationFeedback::kAny),
                       maybe_feedback_vector(), slot_id, update_feedback_mode);
416
        ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
417
      }
418
    } else {
419
      var_result = CallRuntime(Runtime::kBigIntBinaryOp, context(), lhs, rhs,
420
                               SmiConstant(op));
421
      Goto(&end);
422
    }
423 424
  }

425
  BIND(&call_with_any_feedback);
426
  {
427
    var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
428 429 430 431 432
    Goto(&call_stub);
  }

  BIND(&call_stub);
  {
433 434
    UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
                   update_feedback_mode);
435
    TNode<Object> result;
436 437
    switch (op) {
      case Operation::kSubtract:
438
        result = CallBuiltin(Builtin::kSubtract, context(), lhs, rhs);
439
        break;
440
      case Operation::kMultiply:
441
        result = CallBuiltin(Builtin::kMultiply, context(), lhs, rhs);
442
        break;
443
      case Operation::kDivide:
444
        result = CallBuiltin(Builtin::kDivide, context(), lhs, rhs);
445
        break;
446
      case Operation::kModulus:
447
        result = CallBuiltin(Builtin::kModulus, context(), lhs, rhs);
448 449 450 451
        break;
      default:
        UNREACHABLE();
    }
452
    var_result = result;
453 454 455
    Goto(&end);
  }

456
  BIND(&end);
457 458 459
  return var_result.value();
}

460
TNode<Object> BinaryOpAssembler::Generate_SubtractWithFeedback(
461 462
    const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
    TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
463
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
464 465
  auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
                         TVariable<Smi>* var_type_feedback) {
466 467
    Label end(this);
    TVARIABLE(Number, var_result);
468 469 470 471
    // If rhs is known to be an Smi (for SubSmi) we want to fast path Smi
    // operation. For the normal Sub operation, we want to fast path both
    // Smi and Number operations, so this path should not be marked as Deferred.
    Label if_overflow(this,
472
                      rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
473 474
    var_result = TrySmiSub(lhs, rhs, &if_overflow);
    *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
475
    Goto(&end);
476

477
    BIND(&if_overflow);
478
    {
479
      *var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
480
      TNode<Float64T> value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
481
      var_result = AllocateHeapNumberWithValue(value);
482
      Goto(&end);
483 484
    }

485 486 487
    BIND(&end);
    return var_result.value();
  };
488
  auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
489 490 491
    return Float64Sub(lhs, rhs);
  };
  return Generate_BinaryOperationWithFeedback(
492
      context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
493
      floatFunction, Operation::kSubtract, update_feedback_mode, rhs_known_smi);
494
}
495

496
TNode<Object> BinaryOpAssembler::Generate_MultiplyWithFeedback(
497 498
    const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
    TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
499
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
500 501 502 503
  auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
                         TVariable<Smi>* var_type_feedback) {
    TNode<Number> result = SmiMul(lhs, rhs);
    *var_type_feedback = SelectSmiConstant(
504
        TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
505
        BinaryOperationFeedback::kNumber);
506 507
    return result;
  };
508
  auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
509 510 511
    return Float64Mul(lhs, rhs);
  };
  return Generate_BinaryOperationWithFeedback(
512
      context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
513
      floatFunction, Operation::kMultiply, update_feedback_mode, rhs_known_smi);
514 515
}

516
TNode<Object> BinaryOpAssembler::Generate_DivideWithFeedback(
517 518
    const LazyNode<Context>& context, TNode<Object> dividend,
    TNode<Object> divisor, TNode<UintPtrT> slot_id,
519 520
    const LazyNode<HeapObject>& maybe_feedback_vector,
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
521 522 523
  auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
                         TVariable<Smi>* var_type_feedback) {
    TVARIABLE(Object, var_result);
524 525 526
    // If rhs is known to be an Smi (for DivSmi) we want to fast path Smi
    // operation. For the normal Div operation, we want to fast path both
    // Smi and Number operations, so this path should not be marked as Deferred.
527
    Label bailout(this, rhs_known_smi ? Label::kDeferred : Label::kNonDeferred),
528
        end(this);
529 530
    var_result = TrySmiDiv(lhs, rhs, &bailout);
    *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
531
    Goto(&end);
532

533
    BIND(&bailout);
534
    {
535 536
      *var_type_feedback =
          SmiConstant(BinaryOperationFeedback::kSignedSmallInputs);
537
      TNode<Float64T> value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
538
      var_result = AllocateHeapNumberWithValue(value);
539 540 541
      Goto(&end);
    }

542 543 544
    BIND(&end);
    return var_result.value();
  };
545
  auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
546 547 548
    return Float64Div(lhs, rhs);
  };
  return Generate_BinaryOperationWithFeedback(
549
      context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
550
      floatFunction, Operation::kDivide, update_feedback_mode, rhs_known_smi);
551 552
}

553
TNode<Object> BinaryOpAssembler::Generate_ModulusWithFeedback(
554 555
    const LazyNode<Context>& context, TNode<Object> dividend,
    TNode<Object> divisor, TNode<UintPtrT> slot_id,
556 557
    const LazyNode<HeapObject>& maybe_feedback_vector,
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
558 559 560 561
  auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
                         TVariable<Smi>* var_type_feedback) {
    TNode<Number> result = SmiMod(lhs, rhs);
    *var_type_feedback = SelectSmiConstant(
562
        TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
563
        BinaryOperationFeedback::kNumber);
564 565
    return result;
  };
566
  auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
567 568 569
    return Float64Mod(lhs, rhs);
  };
  return Generate_BinaryOperationWithFeedback(
570
      context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
571
      floatFunction, Operation::kModulus, update_feedback_mode, rhs_known_smi);
572 573
}

574
TNode<Object> BinaryOpAssembler::Generate_ExponentiateWithFeedback(
575 576
    const LazyNode<Context>& context, TNode<Object> base,
    TNode<Object> exponent, TNode<UintPtrT> slot_id,
577 578
    const LazyNode<HeapObject>& maybe_feedback_vector,
    UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
579
  // We currently don't optimize exponentiation based on feedback.
580
  TNode<Smi> dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
581 582
  UpdateFeedback(dummy_feedback, maybe_feedback_vector(), slot_id,
                 update_feedback_mode);
583
  return CallBuiltin(Builtin::kExponentiate, context(), base, exponent);
584 585
}

586 587
TNode<Object> BinaryOpAssembler::Generate_BitwiseBinaryOpWithOptionalFeedback(
    Operation bitwise_op, TNode<Object> left, TNode<Object> right,
588
    const LazyNode<Context>& context, TVariable<Smi>* feedback) {
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
  TVARIABLE(Object, result);
  TVARIABLE(Smi, var_left_feedback);
  TVARIABLE(Smi, var_right_feedback);
  TVARIABLE(Word32T, var_left_word32);
  TVARIABLE(Word32T, var_right_word32);
  TVARIABLE(BigInt, var_left_bigint);
  TVARIABLE(BigInt, var_right_bigint);
  // These are the variables that are passed to BigIntBinaryOp. They are not
  // guaranteed to be BigInts because the Runtime call handles throwing
  // exceptions when only one side is a BigInt.
  TVARIABLE(Object, var_left_maybe_bigint, left);
  TVARIABLE(Numeric, var_right_maybe_bigint);
  Label done(this);
  Label if_left_number(this), do_number_op(this);
  Label if_left_bigint(this), do_bigint_op(this);

  TaggedToWord32OrBigIntWithFeedback(
606
      context(), left, &if_left_number, &var_left_word32, &if_left_bigint,
607 608 609 610 611 612
      &var_left_bigint, feedback ? &var_left_feedback : nullptr);

  Label right_is_bigint(this);
  BIND(&if_left_number);
  {
    TaggedToWord32OrBigIntWithFeedback(
613
        context(), right, &do_number_op, &var_right_word32, &right_is_bigint,
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
        &var_right_bigint, feedback ? &var_right_feedback : nullptr);
  }

  BIND(&right_is_bigint);
  {
    // At this point it's guaranteed that the op will fail because the RHS is a
    // BigInt while the LHS is not, but that's ok because the Runtime call will
    // throw the exception.
    var_right_maybe_bigint = var_right_bigint.value();
    Goto(&do_bigint_op);
  }

  BIND(&do_number_op);
  {
    result = BitwiseOp(var_left_word32.value(), var_right_word32.value(),
                       bitwise_op);

    if (feedback) {
      TNode<Smi> result_type = SelectSmiConstant(
          TaggedIsSmi(result.value()), BinaryOperationFeedback::kSignedSmall,
          BinaryOperationFeedback::kNumber);
      TNode<Smi> input_feedback =
          SmiOr(var_left_feedback.value(), var_right_feedback.value());
      *feedback = SmiOr(result_type, input_feedback);
    }
    Goto(&done);
  }

  // BigInt cases.
  BIND(&if_left_bigint);
  {
645
    TaggedToNumericWithFeedback(context(), right, &var_right_maybe_bigint,
646 647 648 649 650 651 652 653 654 655 656
                                &var_right_feedback);
    var_left_maybe_bigint = var_left_bigint.value();
    Goto(&do_bigint_op);
  }

  BIND(&do_bigint_op);
  {
    if (feedback) {
      *feedback = SmiOr(var_left_feedback.value(), var_right_feedback.value());
    }
    result = CallRuntime(
657
        Runtime::kBigIntBinaryOp, context(), var_left_maybe_bigint.value(),
658 659 660 661 662 663 664 665
        var_right_maybe_bigint.value(), SmiConstant(bitwise_op));
    Goto(&done);
  }

  BIND(&done);
  return result.value();
}

666 667
}  // namespace internal
}  // namespace v8