effect-control-linearizer.cc 146 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2015 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/compiler/effect-control-linearizer.h"

#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
9
#include "src/compiler/compiler-source-position-table.h"
10 11
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
12
#include "src/compiler/node-matchers.h"
13 14 15
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/schedule.h"
16
#include "src/factory-inl.h"
17 18 19 20 21

namespace v8 {
namespace internal {
namespace compiler {

22 23 24 25 26 27
EffectControlLinearizer::EffectControlLinearizer(
    JSGraph* js_graph, Schedule* schedule, Zone* temp_zone,
    SourcePositionTable* source_positions)
    : js_graph_(js_graph),
      schedule_(schedule),
      temp_zone_(temp_zone),
28
      source_positions_(source_positions),
29 30
      graph_assembler_(js_graph, nullptr, nullptr, temp_zone),
      frame_state_zapper_(nullptr) {}
31 32 33 34 35 36 37 38 39 40 41 42 43 44

Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); }
CommonOperatorBuilder* EffectControlLinearizer::common() const {
  return js_graph_->common();
}
SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const {
  return js_graph_->simplified();
}
MachineOperatorBuilder* EffectControlLinearizer::machine() const {
  return js_graph_->machine();
}

namespace {

45
struct BlockEffectControlData {
46 47
  Node* current_effect = nullptr;       // New effect.
  Node* current_control = nullptr;      // New control.
48
  Node* current_frame_state = nullptr;  // New frame state.
49 50
};

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
class BlockEffectControlMap {
 public:
  explicit BlockEffectControlMap(Zone* temp_zone) : map_(temp_zone) {}

  BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) {
    return map_[std::make_pair(from->rpo_number(), to->rpo_number())];
  }

  const BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) const {
    return map_.at(std::make_pair(from->rpo_number(), to->rpo_number()));
  }

 private:
  typedef std::pair<int32_t, int32_t> Key;
  typedef ZoneMap<Key, BlockEffectControlData> Map;

  Map map_;
};

70 71 72 73 74 75 76 77 78
// Effect phis that need to be updated after the first pass.
struct PendingEffectPhi {
  Node* effect_phi;
  BasicBlock* block;

  PendingEffectPhi(Node* effect_phi, BasicBlock* block)
      : effect_phi(effect_phi), block(block) {}
};

79 80
void UpdateEffectPhi(Node* node, BasicBlock* block,
                     BlockEffectControlMap* block_effects) {
81 82 83
  // Update all inputs to an effect phi with the effects from the given
  // block->effect map.
  DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
84 85
  DCHECK_EQ(static_cast<size_t>(node->op()->EffectInputCount()),
            block->PredecessorCount());
86 87 88
  for (int i = 0; i < node->op()->EffectInputCount(); i++) {
    Node* input = node->InputAt(i);
    BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
89 90
    const BlockEffectControlData& block_effect =
        block_effects->For(predecessor, block);
91 92
    if (input != block_effect.current_effect) {
      node->ReplaceInput(i, block_effect.current_effect);
93 94 95 96
    }
  }
}

97
void UpdateBlockControl(BasicBlock* block,
98
                        BlockEffectControlMap* block_effects) {
99 100 101 102 103 104 105
  Node* control = block->NodeAt(0);
  DCHECK(NodeProperties::IsControl(control));

  // Do not rewire the end node.
  if (control->opcode() == IrOpcode::kEnd) return;

  // Update all inputs to the given control node with the correct control.
106
  DCHECK(control->opcode() == IrOpcode::kMerge ||
107 108 109 110
         static_cast<size_t>(control->op()->ControlInputCount()) ==
             block->PredecessorCount());
  if (static_cast<size_t>(control->op()->ControlInputCount()) !=
      block->PredecessorCount()) {
111 112
    return;  // We already re-wired the control inputs of this node.
  }
113 114 115
  for (int i = 0; i < control->op()->ControlInputCount(); i++) {
    Node* input = NodeProperties::GetControlInput(control, i);
    BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
116 117 118 119 120
    const BlockEffectControlData& block_effect =
        block_effects->For(predecessor, block);
    if (input != block_effect.current_control) {
      NodeProperties::ReplaceControlInput(control, block_effect.current_control,
                                          i);
121 122 123 124
    }
  }
}

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
bool HasIncomingBackEdges(BasicBlock* block) {
  for (BasicBlock* pred : block->predecessors()) {
    if (pred->rpo_number() >= block->rpo_number()) {
      return true;
    }
  }
  return false;
}

void RemoveRegionNode(Node* node) {
  DCHECK(IrOpcode::kFinishRegion == node->opcode() ||
         IrOpcode::kBeginRegion == node->opcode());
  // Update the value/context uses to the value input of the finish node and
  // the effect uses to the effect input.
  for (Edge edge : node->use_edges()) {
    DCHECK(!edge.from()->IsDead());
    if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(NodeProperties::GetEffectInput(node));
    } else {
      DCHECK(!NodeProperties::IsControlEdge(edge));
      DCHECK(!NodeProperties::IsFrameStateEdge(edge));
      edge.UpdateTo(node->InputAt(0));
    }
  }
  node->Kill();
}

152 153
void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
                    Graph* graph, CommonOperatorBuilder* common,
154 155
                    BlockEffectControlMap* block_effects,
                    SourcePositionTable* source_positions) {
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  DCHECK_EQ(IrOpcode::kBranch, node->opcode());

  // This optimization is a special case of (super)block cloning. It takes an
  // input graph as shown below and clones the Branch node for every predecessor
  // to the Merge, essentially removing the Merge completely. This avoids
  // materializing the bit for the Phi and may offer potential for further
  // branch folding optimizations (i.e. because one or more inputs to the Phi is
  // a constant). Note that there may be more Phi nodes hanging off the Merge,
  // but we can only a certain subset of them currently (actually only Phi and
  // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control
  // input).

  //   Control1 ... ControlN
  //      ^            ^
  //      |            |   Cond1 ... CondN
  //      +----+  +----+     ^         ^
  //           |  |          |         |
  //           |  |     +----+         |
  //          Merge<--+ | +------------+
  //            ^      \|/
  //            |      Phi
  //            |       |
  //          Branch----+
  //            ^
  //            |
  //      +-----+-----+
  //      |           |
  //    IfTrue     IfFalse
  //      ^           ^
  //      |           |

  // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this:

  // Control1 Cond1 ... ControlN CondN
  //    ^      ^           ^      ^
  //    \      /           \      /
  //     Branch     ...     Branch
  //       ^                  ^
  //       |                  |
  //   +---+---+          +---+----+
  //   |       |          |        |
  // IfTrue IfFalse ... IfTrue  IfFalse
  //   ^       ^          ^        ^
  //   |       |          |        |
  //   +--+ +-------------+        |
  //      | |  +--------------+ +--+
  //      | |                 | |
  //     Merge               Merge
  //       ^                   ^
  //       |                   |

207 208
  SourcePositionTable::Scope scope(source_positions,
                                   source_positions->GetSourcePosition(node));
209 210 211 212 213 214 215 216 217 218 219
  Node* branch = node;
  Node* cond = NodeProperties::GetValueInput(branch, 0);
  if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return;
  Node* merge = NodeProperties::GetControlInput(branch);
  if (merge->opcode() != IrOpcode::kMerge ||
      NodeProperties::GetControlInput(cond) != merge) {
    return;
  }
  // Grab the IfTrue/IfFalse projections of the Branch.
  BranchMatcher matcher(branch);
  // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
220
  NodeVector phis(temp_zone);
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  for (Node* const use : merge->uses()) {
    if (use == branch || use == cond) continue;
    // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the
    // Merge. Ideally, we would just clone the nodes (and everything that
    // depends on it to some distant join point), but that requires knowledge
    // about dominance/post-dominance.
    if (!NodeProperties::IsPhi(use)) return;
    for (Edge edge : use->use_edges()) {
      // Right now we can only handle Phi/EffectPhi nodes whose uses are
      // directly control-dependend on either the IfTrue or the IfFalse
      // successor, because we know exactly how to update those uses.
      if (edge.from()->op()->ControlInputCount() != 1) return;
      Node* control = NodeProperties::GetControlInput(edge.from());
      if (NodeProperties::IsPhi(edge.from())) {
        control = NodeProperties::GetControlInput(control, edge.index());
      }
      if (control != matcher.IfTrue() && control != matcher.IfFalse()) return;
    }
    phis.push_back(use);
  }
  BranchHint const hint = BranchHintOf(branch->op());
  int const input_count = merge->op()->ControlInputCount();
  DCHECK_LE(1, input_count);
  Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count);
  Node** const merge_true_inputs = &inputs[0];
  Node** const merge_false_inputs = &inputs[input_count];
  for (int index = 0; index < input_count; ++index) {
    Node* cond1 = NodeProperties::GetValueInput(cond, index);
    Node* control1 = NodeProperties::GetControlInput(merge, index);
    Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1);
    merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1);
    merge_false_inputs[index] = graph->NewNode(common->IfFalse(), branch1);
  }
  Node* const merge_true = matcher.IfTrue();
  Node* const merge_false = matcher.IfFalse();
  merge_true->TrimInputCount(0);
  merge_false->TrimInputCount(0);
  for (int i = 0; i < input_count; ++i) {
    merge_true->AppendInput(graph->zone(), merge_true_inputs[i]);
    merge_false->AppendInput(graph->zone(), merge_false_inputs[i]);
  }
262
  DCHECK_EQ(2u, block->SuccessorCount());
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
  NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count));
  NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count));
  int const true_index =
      block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1;
  BlockEffectControlData* true_block_data =
      &block_effects->For(block, block->SuccessorAt(true_index));
  BlockEffectControlData* false_block_data =
      &block_effects->For(block, block->SuccessorAt(true_index ^ 1));
  for (Node* const phi : phis) {
    for (int index = 0; index < input_count; ++index) {
      inputs[index] = phi->InputAt(index);
    }
    inputs[input_count] = merge_true;
    Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs);
    inputs[input_count] = merge_false;
    Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs);
    if (phi->UseCount() == 0) {
      DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi);
    } else {
      for (Edge edge : phi->use_edges()) {
        Node* control = NodeProperties::GetControlInput(edge.from());
        if (NodeProperties::IsPhi(edge.from())) {
          control = NodeProperties::GetControlInput(control, edge.index());
        }
        DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse());
        edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false);
      }
    }
291 292 293 294
    if (phi->opcode() == IrOpcode::kEffectPhi) {
      true_block_data->current_effect = phi_true;
      false_block_data->current_effect = phi_false;
    }
295 296 297 298 299 300 301 302 303 304 305
    phi->Kill();
  }
  // Fix up IfTrue and IfFalse and kill all dead nodes.
  if (branch == block->control_input()) {
    true_block_data->current_control = merge_true;
    false_block_data->current_control = merge_false;
  }
  branch->Kill();
  cond->Kill();
  merge->Kill();
}
306 307 308
}  // namespace

void EffectControlLinearizer::Run() {
309
  BlockEffectControlMap block_effects(temp_zone());
310
  ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone());
311
  ZoneVector<BasicBlock*> pending_block_controls(temp_zone());
312 313 314 315 316 317 318 319
  NodeVector inputs_buffer(temp_zone());

  for (BasicBlock* block : *(schedule()->rpo_order())) {
    size_t instr = 0;

    // The control node should be the first.
    Node* control = block->NodeAt(instr);
    DCHECK(NodeProperties::IsControl(control));
320 321 322 323 324 325 326 327 328 329
    // Update the control inputs.
    if (HasIncomingBackEdges(block)) {
      // If there are back edges, we need to update later because we have not
      // computed the control yet. This should only happen for loops.
      DCHECK_EQ(IrOpcode::kLoop, control->opcode());
      pending_block_controls.push_back(block);
    } else {
      // If there are no back edges, we can update now.
      UpdateBlockControl(block, &block_effects);
    }
330 331 332
    instr++;

    // Iterate over the phis and update the effect phis.
333
    Node* effect = nullptr;
334 335 336 337 338 339
    Node* terminate = nullptr;
    for (; instr < block->NodeCount(); instr++) {
      Node* node = block->NodeAt(instr);
      // Only go through the phis and effect phis.
      if (node->opcode() == IrOpcode::kEffectPhi) {
        // There should be at most one effect phi in a block.
340
        DCHECK_NULL(effect);
341 342
        // IfException blocks should not have effect phis.
        DCHECK_NE(IrOpcode::kIfException, control->opcode());
343 344 345 346 347 348 349 350 351 352
        effect = node;

        // Make sure we update the inputs to the incoming blocks' effects.
        if (HasIncomingBackEdges(block)) {
          // In case of loops, we do not update the effect phi immediately
          // because the back predecessor has not been handled yet. We just
          // record the effect phi for later processing.
          pending_effect_phis.push_back(PendingEffectPhi(node, block));
        } else {
          UpdateEffectPhi(node, block, &block_effects);
353
        }
354 355
      } else if (node->opcode() == IrOpcode::kPhi) {
        // Just skip phis.
356
      } else if (node->opcode() == IrOpcode::kTerminate) {
357
        DCHECK_NULL(terminate);
358 359 360 361 362 363 364 365
        terminate = node;
      } else {
        break;
      }
    }

    if (effect == nullptr) {
      // There was no effect phi.
366
      DCHECK(!HasIncomingBackEdges(block));
367 368 369 370 371 372 373 374 375 376
      if (block == schedule()->start()) {
        // Start block => effect is start.
        DCHECK_EQ(graph()->start(), control);
        effect = graph()->start();
      } else if (control->opcode() == IrOpcode::kEnd) {
        // End block is just a dummy, no effect needed.
        DCHECK_EQ(BasicBlock::kNone, block->control());
        DCHECK_EQ(1u, block->size());
        effect = nullptr;
      } else {
377
        // If all the predecessors have the same effect, we can use it as our
378 379 380 381 382 383
        // current effect.
        effect =
            block_effects.For(block->PredecessorAt(0), block).current_effect;
        for (size_t i = 1; i < block->PredecessorCount(); ++i) {
          if (block_effects.For(block->PredecessorAt(i), block)
                  .current_effect != effect) {
384 385 386 387 388 389 390 391 392
            effect = nullptr;
            break;
          }
        }
        if (effect == nullptr) {
          DCHECK_NE(IrOpcode::kIfException, control->opcode());
          // The input blocks do not have the same effect. We have
          // to create an effect phi node.
          inputs_buffer.clear();
393
          inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead());
394 395 396 397
          inputs_buffer.push_back(control);
          effect = graph()->NewNode(
              common()->EffectPhi(static_cast<int>(block->PredecessorCount())),
              static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front()));
398 399 400 401
          // For loops, we update the effect phi node later to break cycles.
          if (control->opcode() == IrOpcode::kLoop) {
            pending_effect_phis.push_back(PendingEffectPhi(effect, block));
          } else {
402
            UpdateEffectPhi(effect, block, &block_effects);
403
          }
404 405
        } else if (control->opcode() == IrOpcode::kIfException) {
          // The IfException is connected into the effect chain, so we need
406 407 408
          // to update the effect here.
          NodeProperties::ReplaceEffectInput(control, effect);
          effect = control;
409 410 411 412 413 414 415 416 417
        }
      }
    }

    // Fixup the Terminate node.
    if (terminate != nullptr) {
      NodeProperties::ReplaceEffectInput(terminate, effect);
    }

418 419 420 421 422 423 424 425 426
    // The frame state at block entry is determined by the frame states leaving
    // all predecessors. In case there is no frame state dominating this block,
    // we can rely on a checkpoint being present before the next deoptimization.
    // TODO(mstarzinger): Eventually we will need to go hunt for a frame state
    // once deoptimizing nodes roam freely through the schedule.
    Node* frame_state = nullptr;
    if (block != schedule()->start()) {
      // If all the predecessors have the same effect, we can use it
      // as our current effect.
427 428
      frame_state =
          block_effects.For(block->PredecessorAt(0), block).current_frame_state;
429
      for (size_t i = 1; i < block->PredecessorCount(); i++) {
430 431
        if (block_effects.For(block->PredecessorAt(i), block)
                .current_frame_state != frame_state) {
432
          frame_state = nullptr;
433
          frame_state_zapper_ = graph()->end();
434 435 436 437 438
          break;
        }
      }
    }

439 440 441
    // Process the ordinary instructions.
    for (; instr < block->NodeCount(); instr++) {
      Node* node = block->NodeAt(instr);
442
      ProcessNode(node, &frame_state, &effect, &control);
443 444 445 446 447 448 449 450 451 452 453 454 455
    }

    switch (block->control()) {
      case BasicBlock::kGoto:
      case BasicBlock::kNone:
        break;

      case BasicBlock::kCall:
      case BasicBlock::kTailCall:
      case BasicBlock::kSwitch:
      case BasicBlock::kReturn:
      case BasicBlock::kDeoptimize:
      case BasicBlock::kThrow:
456
        ProcessNode(block->control_input(), &frame_state, &effect, &control);
457
        break;
458 459 460

      case BasicBlock::kBranch:
        ProcessNode(block->control_input(), &frame_state, &effect, &control);
461 462
        TryCloneBranch(block->control_input(), block, temp_zone(), graph(),
                       common(), &block_effects, source_positions_);
463
        break;
464 465
    }

466 467 468 469 470 471 472 473 474 475 476
    // Store the effect, control and frame state for later use.
    for (BasicBlock* successor : block->successors()) {
      BlockEffectControlData* data = &block_effects.For(block, successor);
      if (data->current_effect == nullptr) {
        data->current_effect = effect;
      }
      if (data->current_control == nullptr) {
        data->current_control = control;
      }
      data->current_frame_state = frame_state;
    }
477 478 479 480 481
  }

  // Update the incoming edges of the effect phis that could not be processed
  // during the first pass (because they could have incoming back edges).
  for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
482 483 484 485 486
    UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
                    &block_effects);
  }
  for (BasicBlock* pending_block_control : pending_block_controls) {
    UpdateBlockControl(pending_block_control, &block_effects);
487 488 489
  }
}

490 491
void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
                                          Node** effect, Node** control) {
492 493 494
  SourcePositionTable::Scope scope(source_positions_,
                                   source_positions_->GetSourcePosition(node));

495
  // If the node needs to be wired into the effect/control chain, do this
496 497
  // here. Pass current frame state for lowering to eager deoptimization.
  if (TryWireInStateEffect(node, *frame_state, effect, control)) {
498 499 500
    return;
  }

501 502 503
  // If the node has a visible effect, then there must be a checkpoint in the
  // effect chain before we are allowed to place another eager deoptimization
  // point. We zap the frame state to ensure this invariant is maintained.
504 505 506
  if (region_observability_ == RegionObservability::kObservable &&
      !node->op()->HasProperty(Operator::kNoWrite)) {
    *frame_state = nullptr;
507
    frame_state_zapper_ = node;
508
  }
509

510 511
  // Remove the end markers of 'atomic' allocation region because the
  // region should be wired-in now.
512 513 514 515 516 517 518 519 520 521 522 523 524
  if (node->opcode() == IrOpcode::kFinishRegion) {
    // Reset the current region observability.
    region_observability_ = RegionObservability::kObservable;
    // Update the value uses to the value input of the finish node and
    // the effect uses to the effect input.
    return RemoveRegionNode(node);
  }
  if (node->opcode() == IrOpcode::kBeginRegion) {
    // Determine the observability for this region and use that for all
    // nodes inside the region (i.e. ignore the absence of kNoWrite on
    // StoreField and other operators).
    DCHECK_NE(RegionObservability::kNotObservable, region_observability_);
    region_observability_ = RegionObservabilityOf(node->op());
525 526
    // Update the value uses to the value input of the finish node and
    // the effect uses to the effect input.
527
    return RemoveRegionNode(node);
528 529
  }

530 531
  // Special treatment for checkpoint nodes.
  if (node->opcode() == IrOpcode::kCheckpoint) {
532
    // Unlink the check point; effect uses will be updated to the incoming
533
    // effect that is passed. The frame state is preserved for lowering.
534
    DCHECK_EQ(RegionObservability::kObservable, region_observability_);
535
    *frame_state = NodeProperties::GetFrameStateInput(node);
536 537 538
    return;
  }

539 540 541
  // The IfSuccess nodes should always start a basic block (and basic block
  // start nodes are not handled in the ProcessNode method).
  DCHECK_NE(IrOpcode::kIfSuccess, node->opcode());
542

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
  // If the node takes an effect, replace with the current one.
  if (node->op()->EffectInputCount() > 0) {
    DCHECK_EQ(1, node->op()->EffectInputCount());
    Node* input_effect = NodeProperties::GetEffectInput(node);

    if (input_effect != *effect) {
      NodeProperties::ReplaceEffectInput(node, *effect);
    }

    // If the node produces an effect, update our current effect. (However,
    // ignore new effect chains started with ValueEffect.)
    if (node->op()->EffectOutputCount() > 0) {
      DCHECK_EQ(1, node->op()->EffectOutputCount());
      *effect = node;
    }
  } else {
    // New effect chain is only started with a Start or ValueEffect node.
    DCHECK(node->op()->EffectOutputCount() == 0 ||
           node->opcode() == IrOpcode::kStart);
  }
563 564 565 566 567

  // Rewire control inputs.
  for (int i = 0; i < node->op()->ControlInputCount(); i++) {
    NodeProperties::ReplaceControlInput(node, *control, i);
  }
568
  // Update the current control.
569 570 571
  if (node->op()->ControlOutputCount() > 0) {
    *control = node;
  }
572 573
}

574 575 576
bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
                                                   Node* frame_state,
                                                   Node** effect,
577
                                                   Node** control) {
578 579
  gasm()->Reset(*effect, *control);
  Node* result = nullptr;
580
  switch (node->opcode()) {
581
    case IrOpcode::kChangeBitToTagged:
582
      result = LowerChangeBitToTagged(node);
583 584
      break;
    case IrOpcode::kChangeInt31ToTaggedSigned:
585
      result = LowerChangeInt31ToTaggedSigned(node);
586
      break;
587
    case IrOpcode::kChangeInt32ToTagged:
588
      result = LowerChangeInt32ToTagged(node);
589 590
      break;
    case IrOpcode::kChangeUint32ToTagged:
591
      result = LowerChangeUint32ToTagged(node);
592 593
      break;
    case IrOpcode::kChangeFloat64ToTagged:
594
      result = LowerChangeFloat64ToTagged(node);
595
      break;
596
    case IrOpcode::kChangeFloat64ToTaggedPointer:
597
      result = LowerChangeFloat64ToTaggedPointer(node);
598
      break;
599
    case IrOpcode::kChangeTaggedSignedToInt32:
600
      result = LowerChangeTaggedSignedToInt32(node);
601 602
      break;
    case IrOpcode::kChangeTaggedToBit:
603
      result = LowerChangeTaggedToBit(node);
604
      break;
605
    case IrOpcode::kChangeTaggedToInt32:
606
      result = LowerChangeTaggedToInt32(node);
607 608
      break;
    case IrOpcode::kChangeTaggedToUint32:
609
      result = LowerChangeTaggedToUint32(node);
610 611
      break;
    case IrOpcode::kChangeTaggedToFloat64:
612
      result = LowerChangeTaggedToFloat64(node);
613
      break;
614 615 616
    case IrOpcode::kChangeTaggedToTaggedSigned:
      result = LowerChangeTaggedToTaggedSigned(node);
      break;
617
    case IrOpcode::kTruncateTaggedToBit:
618
      result = LowerTruncateTaggedToBit(node);
619
      break;
620 621 622
    case IrOpcode::kTruncateTaggedPointerToBit:
      result = LowerTruncateTaggedPointerToBit(node);
      break;
623
    case IrOpcode::kTruncateTaggedToFloat64:
624
      result = LowerTruncateTaggedToFloat64(node);
625
      break;
626
    case IrOpcode::kCheckBounds:
627
      result = LowerCheckBounds(node, frame_state);
628
      break;
629
    case IrOpcode::kCheckMaps:
630
      LowerCheckMaps(node, frame_state);
631
      break;
632 633 634
    case IrOpcode::kCompareMaps:
      result = LowerCompareMaps(node);
      break;
635
    case IrOpcode::kCheckNumber:
636
      result = LowerCheckNumber(node, frame_state);
637
      break;
638 639 640
    case IrOpcode::kCheckReceiver:
      result = LowerCheckReceiver(node, frame_state);
      break;
641 642 643
    case IrOpcode::kCheckSymbol:
      result = LowerCheckSymbol(node, frame_state);
      break;
644
    case IrOpcode::kCheckString:
645
      result = LowerCheckString(node, frame_state);
646
      break;
647 648 649
    case IrOpcode::kCheckSeqString:
      result = LowerCheckSeqString(node, frame_state);
      break;
650
    case IrOpcode::kCheckInternalizedString:
651
      result = LowerCheckInternalizedString(node, frame_state);
652
      break;
653
    case IrOpcode::kCheckIf:
654
      LowerCheckIf(node, frame_state);
655
      break;
656
    case IrOpcode::kCheckedInt32Add:
657
      result = LowerCheckedInt32Add(node, frame_state);
658 659
      break;
    case IrOpcode::kCheckedInt32Sub:
660
      result = LowerCheckedInt32Sub(node, frame_state);
661
      break;
662
    case IrOpcode::kCheckedInt32Div:
663
      result = LowerCheckedInt32Div(node, frame_state);
664 665
      break;
    case IrOpcode::kCheckedInt32Mod:
666
      result = LowerCheckedInt32Mod(node, frame_state);
667
      break;
668
    case IrOpcode::kCheckedUint32Div:
669
      result = LowerCheckedUint32Div(node, frame_state);
670 671
      break;
    case IrOpcode::kCheckedUint32Mod:
672
      result = LowerCheckedUint32Mod(node, frame_state);
673
      break;
674
    case IrOpcode::kCheckedInt32Mul:
675
      result = LowerCheckedInt32Mul(node, frame_state);
676
      break;
677
    case IrOpcode::kCheckedInt32ToTaggedSigned:
678
      result = LowerCheckedInt32ToTaggedSigned(node, frame_state);
679
      break;
680
    case IrOpcode::kCheckedUint32ToInt32:
681
      result = LowerCheckedUint32ToInt32(node, frame_state);
682
      break;
683
    case IrOpcode::kCheckedUint32ToTaggedSigned:
684
      result = LowerCheckedUint32ToTaggedSigned(node, frame_state);
685
      break;
686
    case IrOpcode::kCheckedFloat64ToInt32:
687
      result = LowerCheckedFloat64ToInt32(node, frame_state);
688
      break;
689
    case IrOpcode::kCheckedTaggedSignedToInt32:
690 691 692 693 694
      if (frame_state == nullptr) {
        V8_Fatal(__FILE__, __LINE__, "No frame state (zapped by #%d: %s)",
                 frame_state_zapper_->id(),
                 frame_state_zapper_->op()->mnemonic());
      }
695
      result = LowerCheckedTaggedSignedToInt32(node, frame_state);
696
      break;
697
    case IrOpcode::kCheckedTaggedToInt32:
698
      result = LowerCheckedTaggedToInt32(node, frame_state);
699 700
      break;
    case IrOpcode::kCheckedTaggedToFloat64:
701
      result = LowerCheckedTaggedToFloat64(node, frame_state);
702
      break;
703
    case IrOpcode::kCheckedTaggedToTaggedSigned:
704
      result = LowerCheckedTaggedToTaggedSigned(node, frame_state);
705
      break;
706
    case IrOpcode::kCheckedTaggedToTaggedPointer:
707
      result = LowerCheckedTaggedToTaggedPointer(node, frame_state);
708
      break;
709
    case IrOpcode::kTruncateTaggedToWord32:
710
      result = LowerTruncateTaggedToWord32(node);
711
      break;
712
    case IrOpcode::kCheckedTruncateTaggedToWord32:
713
      result = LowerCheckedTruncateTaggedToWord32(node, frame_state);
714
      break;
715 716 717
    case IrOpcode::kObjectIsArrayBufferView:
      result = LowerObjectIsArrayBufferView(node);
      break;
718 719 720
    case IrOpcode::kObjectIsCallable:
      result = LowerObjectIsCallable(node);
      break;
721 722 723
    case IrOpcode::kObjectIsConstructor:
      result = LowerObjectIsConstructor(node);
      break;
724 725
    case IrOpcode::kObjectIsDetectableCallable:
      result = LowerObjectIsDetectableCallable(node);
726
      break;
727 728 729
    case IrOpcode::kObjectIsMinusZero:
      result = LowerObjectIsMinusZero(node);
      break;
730 731 732
    case IrOpcode::kObjectIsNaN:
      result = LowerObjectIsNaN(node);
      break;
733 734 735
    case IrOpcode::kObjectIsNonCallable:
      result = LowerObjectIsNonCallable(node);
      break;
736
    case IrOpcode::kObjectIsNumber:
737
      result = LowerObjectIsNumber(node);
738 739
      break;
    case IrOpcode::kObjectIsReceiver:
740
      result = LowerObjectIsReceiver(node);
741
      break;
742
    case IrOpcode::kObjectIsSmi:
743
      result = LowerObjectIsSmi(node);
744
      break;
745
    case IrOpcode::kObjectIsString:
746
      result = LowerObjectIsString(node);
747
      break;
748 749 750
    case IrOpcode::kObjectIsSymbol:
      result = LowerObjectIsSymbol(node);
      break;
751
    case IrOpcode::kObjectIsUndetectable:
752
      result = LowerObjectIsUndetectable(node);
753
      break;
754 755 756 757 758
    case IrOpcode::kArgumentsFrame:
      result = LowerArgumentsFrame(node);
      break;
    case IrOpcode::kArgumentsLength:
      result = LowerArgumentsLength(node);
759
      break;
760 761 762
    case IrOpcode::kToBoolean:
      result = LowerToBoolean(node);
      break;
763 764 765
    case IrOpcode::kTypeOf:
      result = LowerTypeOf(node);
      break;
766 767 768
    case IrOpcode::kClassOf:
      result = LowerClassOf(node);
      break;
769 770
    case IrOpcode::kNewDoubleElements:
      result = LowerNewDoubleElements(node);
771
      break;
772 773
    case IrOpcode::kNewSmiOrObjectElements:
      result = LowerNewSmiOrObjectElements(node);
774
      break;
775 776
    case IrOpcode::kNewArgumentsElements:
      result = LowerNewArgumentsElements(node);
777
      break;
778
    case IrOpcode::kArrayBufferWasNeutered:
779
      result = LowerArrayBufferWasNeutered(node);
780
      break;
781 782 783
    case IrOpcode::kSameValue:
      result = LowerSameValue(node);
      break;
784
    case IrOpcode::kStringFromCharCode:
785
      result = LowerStringFromCharCode(node);
786
      break;
787
    case IrOpcode::kStringFromCodePoint:
788
      result = LowerStringFromCodePoint(node);
789
      break;
790 791 792
    case IrOpcode::kStringIndexOf:
      result = LowerStringIndexOf(node);
      break;
793 794 795
    case IrOpcode::kStringToNumber:
      result = LowerStringToNumber(node);
      break;
796
    case IrOpcode::kStringCharAt:
797
      result = LowerStringCharAt(node);
798
      break;
799
    case IrOpcode::kStringCharCodeAt:
800
      result = LowerStringCharCodeAt(node);
801
      break;
802 803 804
    case IrOpcode::kSeqStringCharCodeAt:
      result = LowerSeqStringCharCodeAt(node);
      break;
805 806 807 808 809 810
    case IrOpcode::kStringToLowerCaseIntl:
      result = LowerStringToLowerCaseIntl(node);
      break;
    case IrOpcode::kStringToUpperCaseIntl:
      result = LowerStringToUpperCaseIntl(node);
      break;
811
    case IrOpcode::kStringEqual:
812
      result = LowerStringEqual(node);
813 814
      break;
    case IrOpcode::kStringLessThan:
815
      result = LowerStringLessThan(node);
816 817
      break;
    case IrOpcode::kStringLessThanOrEqual:
818
      result = LowerStringLessThanOrEqual(node);
819
      break;
820
    case IrOpcode::kCheckFloat64Hole:
821
      result = LowerCheckFloat64Hole(node, frame_state);
822
      break;
823 824 825
    case IrOpcode::kCheckNotTaggedHole:
      result = LowerCheckNotTaggedHole(node, frame_state);
      break;
826
    case IrOpcode::kConvertTaggedHoleToUndefined:
827
      result = LowerConvertTaggedHoleToUndefined(node);
828
      break;
829 830 831 832 833 834
    case IrOpcode::kCheckEqualsInternalizedString:
      LowerCheckEqualsInternalizedString(node, frame_state);
      break;
    case IrOpcode::kCheckEqualsSymbol:
      LowerCheckEqualsSymbol(node, frame_state);
      break;
835
    case IrOpcode::kPlainPrimitiveToNumber:
836
      result = LowerPlainPrimitiveToNumber(node);
837 838
      break;
    case IrOpcode::kPlainPrimitiveToWord32:
839
      result = LowerPlainPrimitiveToWord32(node);
840 841
      break;
    case IrOpcode::kPlainPrimitiveToFloat64:
842
      result = LowerPlainPrimitiveToFloat64(node);
843
      break;
844
    case IrOpcode::kEnsureWritableFastElements:
845
      result = LowerEnsureWritableFastElements(node);
846
      break;
847
    case IrOpcode::kMaybeGrowFastElements:
848
      result = LowerMaybeGrowFastElements(node, frame_state);
849
      break;
850
    case IrOpcode::kTransitionElementsKind:
851
      LowerTransitionElementsKind(node);
852
      break;
853 854 855
    case IrOpcode::kLoadFieldByIndex:
      result = LowerLoadFieldByIndex(node);
      break;
856
    case IrOpcode::kLoadTypedElement:
857
      result = LowerLoadTypedElement(node);
858 859
      break;
    case IrOpcode::kStoreTypedElement:
860
      LowerStoreTypedElement(node);
861
      break;
862 863 864
    case IrOpcode::kStoreSignedSmallElement:
      LowerStoreSignedSmallElement(node);
      break;
865 866
    case IrOpcode::kFindOrderedHashMapEntry:
      result = LowerFindOrderedHashMapEntry(node);
867
      break;
868 869
    case IrOpcode::kFindOrderedHashMapEntryForInt32Key:
      result = LowerFindOrderedHashMapEntryForInt32Key(node);
870
      break;
871 872 873 874 875 876
    case IrOpcode::kTransitionAndStoreNumberElement:
      LowerTransitionAndStoreNumberElement(node);
      break;
    case IrOpcode::kTransitionAndStoreNonNumberElement:
      LowerTransitionAndStoreNonNumberElement(node);
      break;
877 878
    case IrOpcode::kTransitionAndStoreElement:
      LowerTransitionAndStoreElement(node);
879
      break;
880 881 882
    case IrOpcode::kRuntimeAbort:
      LowerRuntimeAbort(node);
      break;
883 884 885
    case IrOpcode::kConvertReceiver:
      result = LowerConvertReceiver(node);
      break;
886
    case IrOpcode::kFloat64RoundUp:
887 888 889
      if (!LowerFloat64RoundUp(node).To(&result)) {
        return false;
      }
890 891
      break;
    case IrOpcode::kFloat64RoundDown:
892 893 894
      if (!LowerFloat64RoundDown(node).To(&result)) {
        return false;
      }
895 896
      break;
    case IrOpcode::kFloat64RoundTruncate:
897 898 899
      if (!LowerFloat64RoundTruncate(node).To(&result)) {
        return false;
      }
900
      break;
901
    case IrOpcode::kFloat64RoundTiesEven:
902 903 904
      if (!LowerFloat64RoundTiesEven(node).To(&result)) {
        return false;
      }
905
      break;
906 907 908
    default:
      return false;
  }
909 910 911 912 913 914 915 916

  if ((result ? 1 : 0) != node->op()->ValueOutputCount()) {
    V8_Fatal(__FILE__, __LINE__,
             "Effect control linearizer lowering of '%s':"
             " value output count does not agree.",
             node->op()->mnemonic());
  }

917 918 919
  *effect = gasm()->ExtractCurrentEffect();
  *control = gasm()->ExtractCurrentControl();
  NodeProperties::ReplaceUses(node, result, *effect, *control);
920 921 922
  return true;
}

923 924 925
#define __ gasm()->

Node* EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node) {
926
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
927
  Node* value = node->InputAt(0);
928

929 930 931
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
  auto if_heapnumber = __ MakeDeferredLabel();
  auto if_int32 = __ MakeLabel();
932 933 934 935 936 937 938 939 940 941

  Node* value32 = __ RoundFloat64ToInt32(value);
  __ GotoIf(__ Float64Equal(value, __ ChangeInt32ToFloat64(value32)),
            &if_int32);
  __ Goto(&if_heapnumber);

  __ Bind(&if_int32);
  {
    if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
      Node* zero = __ Int32Constant(0);
942 943
      auto if_zero = __ MakeDeferredLabel();
      auto if_smi = __ MakeLabel();
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978

      __ GotoIf(__ Word32Equal(value32, zero), &if_zero);
      __ Goto(&if_smi);

      __ Bind(&if_zero);
      {
        // In case of 0, we need to check the high bits for the IEEE -0 pattern.
        __ GotoIf(__ Int32LessThan(__ Float64ExtractHighWord32(value), zero),
                  &if_heapnumber);
        __ Goto(&if_smi);
      }

      __ Bind(&if_smi);
    }

    if (machine()->Is64()) {
      Node* value_smi = ChangeInt32ToSmi(value32);
      __ Goto(&done, value_smi);
    } else {
      Node* add = __ Int32AddWithOverflow(value32, value32);
      Node* ovf = __ Projection(1, add);
      __ GotoIf(ovf, &if_heapnumber);
      Node* value_smi = __ Projection(0, add);
      __ Goto(&done, value_smi);
    }
  }

  __ Bind(&if_heapnumber);
  {
    Node* value_number = AllocateHeapNumberWithValue(value);
    __ Goto(&done, value_number);
  }

  __ Bind(&done);
  return done.PhiAt(0);
979 980
}

981
Node* EffectControlLinearizer::LowerChangeFloat64ToTaggedPointer(Node* node) {
982
  Node* value = node->InputAt(0);
983
  return AllocateHeapNumberWithValue(value);
984 985
}

986
Node* EffectControlLinearizer::LowerChangeBitToTagged(Node* node) {
987 988
  Node* value = node->InputAt(0);

989 990
  auto if_true = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
991

992 993
  __ GotoIf(value, &if_true);
  __ Goto(&done, __ FalseConstant());
994

995 996
  __ Bind(&if_true);
  __ Goto(&done, __ TrueConstant());
997

998 999
  __ Bind(&done);
  return done.PhiAt(0);
1000 1001
}

1002
Node* EffectControlLinearizer::LowerChangeInt31ToTaggedSigned(Node* node) {
1003
  Node* value = node->InputAt(0);
1004
  return ChangeInt32ToSmi(value);
1005 1006
}

1007
Node* EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node) {
1008 1009
  Node* value = node->InputAt(0);

1010
  if (machine()->Is64()) {
1011
    return ChangeInt32ToSmi(value);
1012 1013
  }

1014 1015
  auto if_overflow = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
1016

1017 1018 1019 1020
  Node* add = __ Int32AddWithOverflow(value, value);
  Node* ovf = __ Projection(1, add);
  __ GotoIf(ovf, &if_overflow);
  __ Goto(&done, __ Projection(0, add));
1021

1022 1023 1024
  __ Bind(&if_overflow);
  Node* number = AllocateHeapNumberWithValue(__ ChangeInt32ToFloat64(value));
  __ Goto(&done, number);
1025

1026 1027
  __ Bind(&done);
  return done.PhiAt(0);
1028 1029
}

1030
Node* EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node) {
1031 1032
  Node* value = node->InputAt(0);

1033 1034
  auto if_not_in_smi_range = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
1035

1036
  Node* check = __ Uint32LessThanOrEqual(value, SmiMaxValueConstant());
1037
  __ GotoIfNot(check, &if_not_in_smi_range);
1038
  __ Goto(&done, ChangeUint32ToSmi(value));
1039

1040 1041
  __ Bind(&if_not_in_smi_range);
  Node* number = AllocateHeapNumberWithValue(__ ChangeUint32ToFloat64(value));
1042

1043 1044
  __ Goto(&done, number);
  __ Bind(&done);
1045

1046
  return done.PhiAt(0);
1047 1048
}

1049
Node* EffectControlLinearizer::LowerChangeTaggedSignedToInt32(Node* node) {
1050
  Node* value = node->InputAt(0);
1051
  return ChangeSmiToInt32(value);
1052 1053
}

1054
Node* EffectControlLinearizer::LowerChangeTaggedToBit(Node* node) {
1055
  Node* value = node->InputAt(0);
1056
  return __ WordEqual(value, __ TrueConstant());
1057 1058
}

1059
Node* EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node) {
1060 1061
  Node* value = node->InputAt(0);

1062 1063 1064
  auto if_smi = __ MakeDeferredLabel();
  auto if_heapnumber = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
1065 1066 1067

  Node* zero = __ Int32Constant(0);
  Node* fzero = __ Float64Constant(0.0);
1068

1069 1070 1071
  // Check if {value} is false.
  __ GotoIf(__ WordEqual(value, __ FalseConstant()), &done, zero);

1072 1073
  // Check if {value} is a Smi.
  Node* check_smi = ObjectIsSmi(value);
1074
  __ GotoIf(check_smi, &if_smi);
1075

1076 1077 1078 1079
  // Check if {value} is the empty string.
  __ GotoIf(__ WordEqual(value, __ EmptyStringConstant()), &done, zero);

  // Load the map of {value}.
1080
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
1081 1082

  // Check if the {value} is undetectable and immediately return false.
1083 1084
  Node* value_map_bitfield =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
1085
  __ GotoIfNot(
1086
      __ Word32Equal(__ Word32And(value_map_bitfield,
1087
                                  __ Int32Constant(1 << Map::kIsUndetectable)),
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
                     zero),
      &done, zero);

  // Check if {value} is a HeapNumber.
  __ GotoIf(__ WordEqual(value_map, __ HeapNumberMapConstant()),
            &if_heapnumber);

  // All other values that reach here are true.
  __ Goto(&done, __ Int32Constant(1));

  __ Bind(&if_heapnumber);
  {
    // For HeapNumber {value}, just check that its value is not 0.0, -0.0 or
    // NaN.
    Node* value_value =
        __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
    __ Goto(&done, __ Float64LessThan(fzero, __ Float64Abs(value_value)));
  }
1106

1107
  __ Bind(&if_smi);
1108 1109 1110 1111 1112
  {
    // If {value} is a Smi, then we only need to check that it's not zero.
    __ Goto(&done,
            __ Word32Equal(__ WordEqual(value, __ IntPtrConstant(0)), zero));
  }
1113

1114 1115
  __ Bind(&done);
  return done.PhiAt(0);
1116 1117
}

1118 1119 1120
Node* EffectControlLinearizer::LowerTruncateTaggedPointerToBit(Node* node) {
  Node* value = node->InputAt(0);

1121 1122
  auto if_heapnumber = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

  Node* zero = __ Int32Constant(0);
  Node* fzero = __ Float64Constant(0.0);

  // Check if {value} is false.
  __ GotoIf(__ WordEqual(value, __ FalseConstant()), &done, zero);

  // Check if {value} is the empty string.
  __ GotoIf(__ WordEqual(value, __ EmptyStringConstant()), &done, zero);

  // Load the map of {value}.
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);

  // Check if the {value} is undetectable and immediately return false.
  Node* value_map_bitfield =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
1139
  __ GotoIfNot(
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
      __ Word32Equal(__ Word32And(value_map_bitfield,
                                  __ Int32Constant(1 << Map::kIsUndetectable)),
                     zero),
      &done, zero);

  // Check if {value} is a HeapNumber.
  __ GotoIf(__ WordEqual(value_map, __ HeapNumberMapConstant()),
            &if_heapnumber);

  // All other values that reach here are true.
  __ Goto(&done, __ Int32Constant(1));

  __ Bind(&if_heapnumber);
  {
    // For HeapNumber {value}, just check that its value is not 0.0, -0.0 or
    // NaN.
    Node* value_value =
        __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
    __ Goto(&done, __ Float64LessThan(fzero, __ Float64Abs(value_value)));
  }

  __ Bind(&done);
  return done.PhiAt(0);
}

1165
Node* EffectControlLinearizer::LowerChangeTaggedToInt32(Node* node) {
1166 1167
  Node* value = node->InputAt(0);

1168 1169
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1170

1171
  Node* check = ObjectIsSmi(value);
1172
  __ GotoIfNot(check, &if_not_smi);
1173
  __ Goto(&done, ChangeSmiToInt32(value));
1174

1175 1176 1177 1178 1179
  __ Bind(&if_not_smi);
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  vfalse = __ ChangeFloat64ToInt32(vfalse);
  __ Goto(&done, vfalse);
1180

1181 1182
  __ Bind(&done);
  return done.PhiAt(0);
1183 1184
}

1185
Node* EffectControlLinearizer::LowerChangeTaggedToUint32(Node* node) {
1186 1187
  Node* value = node->InputAt(0);

1188 1189
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1190

1191
  Node* check = ObjectIsSmi(value);
1192
  __ GotoIfNot(check, &if_not_smi);
1193
  __ Goto(&done, ChangeSmiToInt32(value));
1194

1195 1196 1197 1198 1199
  __ Bind(&if_not_smi);
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  vfalse = __ ChangeFloat64ToUint32(vfalse);
  __ Goto(&done, vfalse);
1200

1201 1202
  __ Bind(&done);
  return done.PhiAt(0);
1203 1204
}

1205 1206
Node* EffectControlLinearizer::LowerChangeTaggedToFloat64(Node* node) {
  return LowerTruncateTaggedToFloat64(node);
1207 1208
}

1209 1210 1211
Node* EffectControlLinearizer::LowerChangeTaggedToTaggedSigned(Node* node) {
  Node* value = node->InputAt(0);

1212 1213
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1214 1215

  Node* check = ObjectIsSmi(value);
1216
  __ GotoIfNot(check, &if_not_smi);
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
  __ Goto(&done, value);

  __ Bind(&if_not_smi);
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  vfalse = __ ChangeFloat64ToInt32(vfalse);
  vfalse = ChangeInt32ToSmi(vfalse);
  __ Goto(&done, vfalse);

  __ Bind(&done);
  return done.PhiAt(0);
}

1230
Node* EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node) {
1231 1232
  Node* value = node->InputAt(0);

1233 1234
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
1235

1236
  Node* check = ObjectIsSmi(value);
1237
  __ GotoIfNot(check, &if_not_smi);
1238 1239 1240
  Node* vtrue = ChangeSmiToInt32(value);
  vtrue = __ ChangeInt32ToFloat64(vtrue);
  __ Goto(&done, vtrue);
1241

1242 1243 1244 1245
  __ Bind(&if_not_smi);
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  __ Goto(&done, vfalse);
1246

1247 1248
  __ Bind(&done);
  return done.PhiAt(0);
1249 1250
}

1251
Node* EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state) {
1252 1253 1254
  Node* index = node->InputAt(0);
  Node* limit = node->InputAt(1);

1255
  Node* check = __ Uint32LessThan(index, limit);
1256
  __ DeoptimizeIfNot(DeoptimizeReason::kOutOfBounds, check, frame_state);
1257
  return index;
1258 1259
}

1260
void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
1261
  CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
1262 1263
  Node* value = node->InputAt(0);

1264
  ZoneHandleSet<Map> const& maps = p.maps();
1265 1266 1267
  size_t const map_count = maps.size();

  if (p.flags() & CheckMapsFlag::kTryMigrateInstance) {
1268 1269
    auto done = __ MakeDeferredLabel();
    auto migrate = __ MakeDeferredLabel();
1270 1271 1272 1273 1274 1275 1276 1277 1278

    // Load the current map of the {value}.
    Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);

    // Perform the map checks.
    for (size_t i = 0; i < map_count; ++i) {
      Node* map = __ HeapConstant(maps[i]);
      Node* check = __ WordEqual(value_map, map);
      if (i == map_count - 1) {
1279
        __ GotoIfNot(check, &migrate);
1280 1281 1282 1283 1284
        __ Goto(&done);
      } else {
        __ GotoIf(check, &done);
      }
    }
1285

1286 1287 1288
    // Perform the (deferred) instance migration.
    __ Bind(&migrate);
    {
1289 1290 1291 1292 1293 1294
      // If map is not deprecated the migration attempt does not make sense.
      Node* bitfield3 =
          __ LoadField(AccessBuilder::ForMapBitField3(), value_map);
      Node* if_not_deprecated = __ WordEqual(
          __ Word32And(bitfield3, __ Int32Constant(Map::Deprecated::kMask)),
          __ Int32Constant(0));
1295 1296
      __ DeoptimizeIf(DeoptimizeReason::kWrongMap, if_not_deprecated,
                      frame_state);
1297

1298 1299 1300 1301 1302 1303 1304 1305 1306
      Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
      Runtime::FunctionId id = Runtime::kTryMigrateInstance;
      CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
          graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
      Node* result =
          __ Call(desc, __ CEntryStubConstant(1), value,
                  __ ExternalConstant(ExternalReference(id, isolate())),
                  __ Int32Constant(1), __ NoContextConstant());
      Node* check = ObjectIsSmi(result);
1307 1308
      __ DeoptimizeIf(DeoptimizeReason::kInstanceMigrationFailed, check,
                      frame_state);
1309
    }
1310

1311 1312
    // Reload the current map of the {value}.
    value_map = __ LoadField(AccessBuilder::ForMap(), value);
1313

1314 1315 1316 1317 1318
    // Perform the map checks again.
    for (size_t i = 0; i < map_count; ++i) {
      Node* map = __ HeapConstant(maps[i]);
      Node* check = __ WordEqual(value_map, map);
      if (i == map_count - 1) {
1319
        __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, check, frame_state);
1320 1321 1322
      } else {
        __ GotoIf(check, &done);
      }
1323
    }
1324 1325 1326 1327

    __ Goto(&done);
    __ Bind(&done);
  } else {
1328
    auto done = __ MakeLabel();
1329 1330 1331 1332 1333 1334 1335 1336

    // Load the current map of the {value}.
    Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);

    for (size_t i = 0; i < map_count; ++i) {
      Node* map = __ HeapConstant(maps[i]);
      Node* check = __ WordEqual(value_map, map);
      if (i == map_count - 1) {
1337
        __ DeoptimizeIfNot(DeoptimizeReason::kWrongMap, check, frame_state);
1338 1339 1340 1341 1342 1343
      } else {
        __ GotoIf(check, &done);
      }
    }
    __ Goto(&done);
    __ Bind(&done);
1344 1345 1346
  }
}

1347
Node* EffectControlLinearizer::LowerCompareMaps(Node* node) {
1348
  ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op()).maps();
1349 1350 1351
  size_t const map_count = maps.size();
  Node* value = node->InputAt(0);

1352
  auto done = __ MakeLabel(MachineRepresentation::kBit);
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367

  // Load the current map of the {value}.
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);

  for (size_t i = 0; i < map_count; ++i) {
    Node* map = __ HeapConstant(maps[i]);
    Node* check = __ WordEqual(value_map, map);
    __ GotoIf(check, &done, __ Int32Constant(1));
  }
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

1368
Node* EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state) {
1369 1370
  Node* value = node->InputAt(0);

1371 1372
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel();
1373

1374
  Node* check0 = ObjectIsSmi(value);
1375
  __ GotoIfNot(check0, &if_not_smi);
1376
  __ Goto(&done);
1377

1378 1379 1380
  __ Bind(&if_not_smi);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* check1 = __ WordEqual(value_map, __ HeapNumberMapConstant());
1381
  __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, check1, frame_state);
1382
  __ Goto(&done);
1383

1384 1385
  __ Bind(&done);
  return value;
1386 1387
}

1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
Node* EffectControlLinearizer::LowerCheckReceiver(Node* node,
                                                  Node* frame_state) {
  Node* value = node->InputAt(0);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);

  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
  Node* check = __ Uint32LessThanOrEqual(
      __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
1399 1400
  __ DeoptimizeIfNot(DeoptimizeReason::kNotAJavaScriptObject, check,
                     frame_state);
1401 1402 1403
  return value;
}

1404 1405 1406 1407 1408 1409 1410
Node* EffectControlLinearizer::LowerCheckSymbol(Node* node, Node* frame_state) {
  Node* value = node->InputAt(0);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);

  Node* check =
      __ WordEqual(value_map, __ HeapConstant(factory()->symbol_map()));
1411
  __ DeoptimizeIfNot(DeoptimizeReason::kNotASymbol, check, frame_state);
1412 1413 1414
  return value;
}

1415
Node* EffectControlLinearizer::LowerCheckString(Node* node, Node* frame_state) {
1416 1417
  Node* value = node->InputAt(0);

1418 1419 1420
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1421

1422 1423
  Node* check = __ Uint32LessThan(value_instance_type,
                                  __ Uint32Constant(FIRST_NONSTRING_TYPE));
1424
  __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, check, frame_state);
1425
  return value;
1426 1427
}

1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
Node* EffectControlLinearizer::LowerCheckSeqString(Node* node,
                                                   Node* frame_state) {
  Node* value = node->InputAt(0);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);

  Node* is_string = __ Uint32LessThan(value_instance_type,
                                      __ Uint32Constant(FIRST_NONSTRING_TYPE));
  Node* is_sequential =
      __ Word32Equal(__ Word32And(value_instance_type,
                                  __ Int32Constant(kStringRepresentationMask)),
                     __ Int32Constant(kSeqStringTag));
  Node* is_sequential_string = __ Word32And(is_string, is_sequential);

1444 1445
  __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, is_sequential_string,
                     frame_state);
1446 1447 1448
  return value;
}

1449 1450 1451
Node* EffectControlLinearizer::LowerCheckInternalizedString(Node* node,
                                                            Node* frame_state) {
  Node* value = node->InputAt(0);
1452

1453 1454 1455
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1456

1457
  Node* check = __ Word32Equal(
1458 1459 1460
      __ Word32And(value_instance_type,
                   __ Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)),
      __ Int32Constant(kInternalizedTag));
1461
  __ DeoptimizeIfNot(DeoptimizeReason::kWrongInstanceType, check, frame_state);
1462

1463
  return value;
1464 1465
}

1466
void EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state) {
1467
  Node* value = node->InputAt(0);
1468 1469
  __ DeoptimizeIfNot(DeoptimizeKind::kEager, DeoptimizeReasonOf(node->op()),
                     value, frame_state);
1470 1471 1472 1473
}

Node* EffectControlLinearizer::LowerCheckedInt32Add(Node* node,
                                                    Node* frame_state) {
1474 1475 1476
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1477 1478 1479 1480 1481
  Node* value = __ Int32AddWithOverflow(lhs, rhs);
  Node* check = __ Projection(1, value);
  __ DeoptimizeIf(DeoptimizeReason::kOverflow, check, frame_state);
  return __ Projection(0, value);
}
1482

1483 1484 1485 1486
Node* EffectControlLinearizer::LowerCheckedInt32Sub(Node* node,
                                                    Node* frame_state) {
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);
1487

1488 1489 1490 1491
  Node* value = __ Int32SubWithOverflow(lhs, rhs);
  Node* check = __ Projection(1, value);
  __ DeoptimizeIf(DeoptimizeReason::kOverflow, check, frame_state);
  return __ Projection(0, value);
1492 1493
}

1494 1495
Node* EffectControlLinearizer::LowerCheckedInt32Div(Node* node,
                                                    Node* frame_state) {
1496 1497 1498
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1499 1500 1501 1502
  auto if_not_positive = __ MakeDeferredLabel();
  auto if_is_minint = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
  auto minint_check_done = __ MakeLabel();
1503 1504 1505

  Node* zero = __ Int32Constant(0);

1506
  // Check if {rhs} is positive (and not zero).
1507
  Node* check0 = __ Int32LessThan(zero, rhs);
1508
  __ GotoIfNot(check0, &if_not_positive);
1509

1510 1511
  // Fast case, no additional checking required.
  __ Goto(&done, __ Int32Div(lhs, rhs));
1512 1513

  {
1514 1515
    __ Bind(&if_not_positive);

1516
    // Check if {rhs} is zero.
1517 1518
    Node* check = __ Word32Equal(rhs, zero);
    __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, check, frame_state);
1519 1520

    // Check if {lhs} is zero, as that would produce minus zero.
1521 1522
    check = __ Word32Equal(lhs, zero);
    __ DeoptimizeIf(DeoptimizeReason::kMinusZero, check, frame_state);
1523 1524 1525

    // Check if {lhs} is kMinInt and {rhs} is -1, in which case we'd have
    // to return -kMinInt, which is not representable.
1526
    Node* minint = __ Int32Constant(std::numeric_limits<int32_t>::min());
1527
    Node* check1 = graph()->NewNode(machine()->Word32Equal(), lhs, minint);
1528 1529
    __ GotoIf(check1, &if_is_minint);
    __ Goto(&minint_check_done);
1530

1531 1532 1533 1534 1535 1536
    __ Bind(&if_is_minint);
    // Check if {rhs} is -1.
    Node* minusone = __ Int32Constant(-1);
    Node* is_minus_one = __ Word32Equal(rhs, minusone);
    __ DeoptimizeIf(DeoptimizeReason::kOverflow, is_minus_one, frame_state);
    __ Goto(&minint_check_done);
1537

1538
    __ Bind(&minint_check_done);
1539
    // Perform the actual integer division.
1540
    __ Goto(&done, __ Int32Div(lhs, rhs));
1541 1542
  }

1543 1544
  __ Bind(&done);
  Node* value = done.PhiAt(0);
1545 1546

  // Check if the remainder is non-zero.
1547
  Node* check = __ Word32Equal(lhs, __ Int32Mul(rhs, value));
1548
  __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, check, frame_state);
1549

1550
  return value;
1551 1552
}

1553 1554
Node* EffectControlLinearizer::LowerCheckedInt32Mod(Node* node,
                                                    Node* frame_state) {
1555 1556 1557
  // General case for signed integer modulus, with optimization for (unknown)
  // power of 2 right hand side.
  //
1558 1559 1560 1561 1562 1563 1564 1565 1566
  //   if rhs <= 0 then
  //     rhs = -rhs
  //     deopt if rhs == 0
  //   if lhs < 0 then
  //     let res = lhs % rhs in
  //     deopt if res == 0
  //     res
  //   else
  //     let msk = rhs - 1 in
1567
  //     if rhs & msk == 0 then
1568
  //       lhs & msk
1569 1570 1571
  //     else
  //       lhs % rhs
  //
1572 1573 1574
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1575 1576 1577 1578 1579
  auto if_rhs_not_positive = __ MakeDeferredLabel();
  auto if_lhs_negative = __ MakeDeferredLabel();
  auto if_power_of_two = __ MakeLabel();
  auto rhs_checked = __ MakeLabel(MachineRepresentation::kWord32);
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1580 1581 1582

  Node* zero = __ Int32Constant(0);

1583
  // Check if {rhs} is not strictly positive.
1584 1585 1586
  Node* check0 = __ Int32LessThanOrEqual(rhs, zero);
  __ GotoIf(check0, &if_rhs_not_positive);
  __ Goto(&rhs_checked, rhs);
1587

1588
  __ Bind(&if_rhs_not_positive);
1589
  {
1590 1591
    // Negate {rhs}, might still produce a negative result in case of
    // -2^31, but that is handled safely below.
1592
    Node* vtrue0 = __ Int32Sub(zero, rhs);
1593

1594
    // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
1595 1596 1597
    Node* check = __ Word32Equal(vtrue0, zero);
    __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, check, frame_state);
    __ Goto(&rhs_checked, vtrue0);
1598
  }
1599

1600 1601
  __ Bind(&rhs_checked);
  rhs = rhs_checked.PhiAt(0);
1602 1603

  // Check if {lhs} is negative.
1604 1605
  Node* check1 = __ Int32LessThan(lhs, zero);
  __ GotoIf(check1, &if_lhs_negative);
1606

1607
  // {lhs} non-negative.
1608
  {
1609 1610
    Node* one = __ Int32Constant(1);
    Node* msk = __ Int32Sub(rhs, one);
1611

1612
    // Check if {rhs} minus one is a valid mask.
1613 1614 1615 1616
    Node* check2 = __ Word32Equal(__ Word32And(rhs, msk), zero);
    __ GotoIf(check2, &if_power_of_two);
    // Compute the remainder using the generic {lhs % rhs}.
    __ Goto(&done, __ Int32Mod(lhs, rhs));
1617

1618
    __ Bind(&if_power_of_two);
1619
    // Compute the remainder using {lhs & msk}.
1620 1621
    __ Goto(&done, __ Word32And(lhs, msk));
  }
1622

1623 1624 1625 1626
  __ Bind(&if_lhs_negative);
  {
    // Compute the remainder using {lhs % msk}.
    Node* vtrue1 = __ Int32Mod(lhs, rhs);
1627

1628 1629 1630 1631
    // Check if we would have to return -0.
    Node* check = __ Word32Equal(vtrue1, zero);
    __ DeoptimizeIf(DeoptimizeReason::kMinusZero, check, frame_state);
    __ Goto(&done, vtrue1);
1632 1633
  }

1634 1635
  __ Bind(&done);
  return done.PhiAt(0);
1636 1637
}

1638 1639
Node* EffectControlLinearizer::LowerCheckedUint32Div(Node* node,
                                                     Node* frame_state) {
1640 1641 1642
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1643 1644
  Node* zero = __ Int32Constant(0);

1645
  // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
1646 1647
  Node* check = __ Word32Equal(rhs, zero);
  __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, check, frame_state);
1648 1649

  // Perform the actual unsigned integer division.
1650
  Node* value = __ Uint32Div(lhs, rhs);
1651 1652

  // Check if the remainder is non-zero.
1653
  check = __ Word32Equal(lhs, __ Int32Mul(rhs, value));
1654
  __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, check, frame_state);
1655
  return value;
1656 1657
}

1658 1659
Node* EffectControlLinearizer::LowerCheckedUint32Mod(Node* node,
                                                     Node* frame_state) {
1660 1661 1662
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1663 1664
  Node* zero = __ Int32Constant(0);

1665
  // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
1666 1667
  Node* check = __ Word32Equal(rhs, zero);
  __ DeoptimizeIf(DeoptimizeReason::kDivisionByZero, check, frame_state);
1668 1669

  // Perform the actual unsigned integer modulus.
1670
  return __ Uint32Mod(lhs, rhs);
1671 1672
}

1673 1674
Node* EffectControlLinearizer::LowerCheckedInt32Mul(Node* node,
                                                    Node* frame_state) {
1675
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
1676 1677 1678
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

1679 1680 1681
  Node* projection = __ Int32MulWithOverflow(lhs, rhs);
  Node* check = __ Projection(1, projection);
  __ DeoptimizeIf(DeoptimizeReason::kOverflow, check, frame_state);
1682

1683
  Node* value = __ Projection(0, projection);
1684

1685
  if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
1686 1687
    auto if_zero = __ MakeDeferredLabel();
    auto check_done = __ MakeLabel();
1688 1689 1690 1691
    Node* zero = __ Int32Constant(0);
    Node* check_zero = __ Word32Equal(value, zero);
    __ GotoIf(check_zero, &if_zero);
    __ Goto(&check_done);
1692

1693 1694 1695 1696 1697
    __ Bind(&if_zero);
    // We may need to return negative zero.
    Node* check_or = __ Int32LessThan(__ Word32Or(lhs, rhs), zero);
    __ DeoptimizeIf(DeoptimizeReason::kMinusZero, check_or, frame_state);
    __ Goto(&check_done);
1698

1699
    __ Bind(&check_done);
1700
  }
1701

1702
  return value;
1703 1704
}

1705 1706
Node* EffectControlLinearizer::LowerCheckedInt32ToTaggedSigned(
    Node* node, Node* frame_state) {
1707 1708 1709
  DCHECK(SmiValuesAre31Bits());
  Node* value = node->InputAt(0);

1710 1711 1712 1713
  Node* add = __ Int32AddWithOverflow(value, value);
  Node* check = __ Projection(1, add);
  __ DeoptimizeIf(DeoptimizeReason::kOverflow, check, frame_state);
  return __ Projection(0, add);
1714 1715
}

1716 1717
Node* EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node,
                                                         Node* frame_state) {
1718
  Node* value = node->InputAt(0);
1719 1720
  Node* unsafe = __ Int32LessThan(value, __ Int32Constant(0));
  __ DeoptimizeIf(DeoptimizeReason::kLostPrecision, unsafe, frame_state);
1721
  return value;
1722 1723
}

1724 1725
Node* EffectControlLinearizer::LowerCheckedUint32ToTaggedSigned(
    Node* node, Node* frame_state) {
1726
  Node* value = node->InputAt(0);
1727
  Node* check = __ Uint32LessThanOrEqual(value, SmiMaxValueConstant());
1728
  __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecision, check, frame_state);
1729 1730 1731 1732 1733 1734 1735
  return ChangeUint32ToSmi(value);
}

Node* EffectControlLinearizer::BuildCheckedFloat64ToInt32(
    CheckForMinusZeroMode mode, Node* value, Node* frame_state) {
  Node* value32 = __ RoundFloat64ToInt32(value);
  Node* check_same = __ Float64Equal(value, __ ChangeInt32ToFloat64(value32));
1736 1737
  __ DeoptimizeIfNot(DeoptimizeReason::kLostPrecisionOrNaN, check_same,
                     frame_state);
1738

1739 1740
  if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
    // Check if {value} is -0.
1741 1742
    auto if_zero = __ MakeDeferredLabel();
    auto check_done = __ MakeLabel();
1743

1744 1745 1746
    Node* check_zero = __ Word32Equal(value32, __ Int32Constant(0));
    __ GotoIf(check_zero, &if_zero);
    __ Goto(&check_done);
1747

1748
    __ Bind(&if_zero);
1749
    // In case of 0, we need to check the high bits for the IEEE -0 pattern.
1750 1751 1752 1753
    Node* check_negative = __ Int32LessThan(__ Float64ExtractHighWord32(value),
                                            __ Int32Constant(0));
    __ DeoptimizeIf(DeoptimizeReason::kMinusZero, check_negative, frame_state);
    __ Goto(&check_done);
1754

1755 1756 1757
    __ Bind(&check_done);
  }
  return value32;
1758 1759
}

1760 1761
Node* EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node,
                                                          Node* frame_state) {
1762
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
1763
  Node* value = node->InputAt(0);
1764
  return BuildCheckedFloat64ToInt32(mode, value, frame_state);
1765 1766
}

1767 1768
Node* EffectControlLinearizer::LowerCheckedTaggedSignedToInt32(
    Node* node, Node* frame_state) {
1769 1770
  Node* value = node->InputAt(0);
  Node* check = ObjectIsSmi(value);
1771
  __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, check, frame_state);
1772
  return ChangeSmiToInt32(value);
1773 1774
}

1775 1776
Node* EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
                                                         Node* frame_state) {
1777
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
1778 1779
  Node* value = node->InputAt(0);

1780 1781
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1782

1783
  Node* check = ObjectIsSmi(value);
1784
  __ GotoIfNot(check, &if_not_smi);
1785
  // In the Smi case, just convert to int32.
1786
  __ Goto(&done, ChangeSmiToInt32(value));
1787 1788 1789

  // In the non-Smi case, check the heap numberness, load the number and convert
  // to int32.
1790 1791 1792
  __ Bind(&if_not_smi);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* check_map = __ WordEqual(value_map, __ HeapNumberMapConstant());
1793
  __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, check_map, frame_state);
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  vfalse = BuildCheckedFloat64ToInt32(mode, vfalse, frame_state);
  __ Goto(&done, vfalse);

  __ Bind(&done);
  return done.PhiAt(0);
}

Node* EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
    CheckTaggedInputMode mode, Node* value, Node* frame_state) {
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* check_number = __ WordEqual(value_map, __ HeapNumberMapConstant());
1806 1807
  switch (mode) {
    case CheckTaggedInputMode::kNumber: {
1808 1809
      __ DeoptimizeIfNot(DeoptimizeReason::kNotAHeapNumber, check_number,
                         frame_state);
1810 1811 1812
      break;
    }
    case CheckTaggedInputMode::kNumberOrOddball: {
1813
      auto check_done = __ MakeLabel();
1814

1815
      __ GotoIf(check_number, &check_done);
1816 1817
      // For oddballs also contain the numeric value, let us just check that
      // we have an oddball here.
1818 1819
      Node* instance_type =
          __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
1820
      Node* check_oddball =
1821
          __ Word32Equal(instance_type, __ Int32Constant(ODDBALL_TYPE));
1822 1823
      __ DeoptimizeIfNot(DeoptimizeReason::kNotANumberOrOddball, check_oddball,
                         frame_state);
1824
      STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
1825
      __ Goto(&check_done);
1826

1827
      __ Bind(&check_done);
1828 1829 1830
      break;
    }
  }
1831
  return __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
1832 1833
}

1834 1835
Node* EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
                                                           Node* frame_state) {
1836
  CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op());
1837 1838
  Node* value = node->InputAt(0);

1839 1840
  auto if_smi = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
1841

1842
  Node* check = ObjectIsSmi(value);
1843
  __ GotoIf(check, &if_smi);
1844 1845 1846

  // In the Smi case, just convert to int32 and then float64.
  // Otherwise, check heap numberness and load the number.
1847 1848 1849
  Node* number =
      BuildCheckedHeapNumberOrOddballToFloat64(mode, value, frame_state);
  __ Goto(&done, number);
1850

1851 1852 1853 1854
  __ Bind(&if_smi);
  Node* from_smi = ChangeSmiToInt32(value);
  from_smi = __ ChangeInt32ToFloat64(from_smi);
  __ Goto(&done, from_smi);
1855

1856 1857
  __ Bind(&done);
  return done.PhiAt(0);
1858 1859
}

1860 1861
Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedSigned(
    Node* node, Node* frame_state) {
1862 1863 1864
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
1865
  __ DeoptimizeIfNot(DeoptimizeReason::kNotASmi, check, frame_state);
1866

1867
  return value;
1868 1869
}

1870 1871
Node* EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer(
    Node* node, Node* frame_state) {
1872 1873
  Node* value = node->InputAt(0);

1874
  Node* check = ObjectIsSmi(value);
1875 1876 1877
  __ DeoptimizeIf(DeoptimizeReason::kSmi, check, frame_state);
  return value;
}
1878

1879 1880
Node* EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node) {
  Node* value = node->InputAt(0);
1881

1882 1883
  auto if_not_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1884

1885
  Node* check = ObjectIsSmi(value);
1886
  __ GotoIfNot(check, &if_not_smi);
1887 1888 1889 1890 1891 1892 1893
  __ Goto(&done, ChangeSmiToInt32(value));

  __ Bind(&if_not_smi);
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
  Node* vfalse = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  vfalse = __ TruncateFloat64ToWord32(vfalse);
  __ Goto(&done, vfalse);
1894

1895 1896
  __ Bind(&done);
  return done.PhiAt(0);
1897 1898
}

1899 1900
Node* EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(
    Node* node, Node* frame_state) {
1901
  CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op());
1902 1903
  Node* value = node->InputAt(0);

1904 1905
  auto if_not_smi = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
1906

1907
  Node* check = ObjectIsSmi(value);
1908
  __ GotoIfNot(check, &if_not_smi);
1909
  // In the Smi case, just convert to int32.
1910
  __ Goto(&done, ChangeSmiToInt32(value));
1911 1912 1913

  // Otherwise, check that it's a heap number or oddball and truncate the value
  // to int32.
1914
  __ Bind(&if_not_smi);
1915 1916
  Node* number =
      BuildCheckedHeapNumberOrOddballToFloat64(mode, value, frame_state);
1917 1918 1919 1920 1921 1922 1923
  number = __ TruncateFloat64ToWord32(number);
  __ Goto(&done, number);

  __ Bind(&done);
  return done.PhiAt(0);
}

1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
Node* EffectControlLinearizer::LowerObjectIsArrayBufferView(Node* node) {
  Node* value = node->InputAt(0);

  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);

  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
  STATIC_ASSERT(JS_TYPED_ARRAY_TYPE + 1 == JS_DATA_VIEW_TYPE);
  Node* vfalse = __ Uint32LessThan(
      __ Int32Sub(value_instance_type, __ Int32Constant(JS_TYPED_ARRAY_TYPE)),
      __ Int32Constant(2));
  __ Goto(&done, vfalse);

  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

1949 1950 1951
Node* EffectControlLinearizer::LowerObjectIsCallable(Node* node) {
  Node* value = node->InputAt(0);

1952 1953
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972

  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
  Node* vfalse = __ Word32Equal(
      __ Int32Constant(1 << Map::kIsCallable),
      __ Word32And(value_bit_field, __ Int32Constant(1 << Map::kIsCallable)));
  __ Goto(&done, vfalse);

  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
Node* EffectControlLinearizer::LowerObjectIsConstructor(Node* node) {
  Node* value = node->InputAt(0);

  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);

  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
  Node* vfalse =
      __ Word32Equal(__ Int32Constant(1 << Map::kIsConstructor),
                     __ Word32And(value_bit_field,
                                  __ Int32Constant(1 << Map::kIsConstructor)));
  __ Goto(&done, vfalse);

  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

1998
Node* EffectControlLinearizer::LowerObjectIsDetectableCallable(Node* node) {
1999 2000
  Node* value = node->InputAt(0);

2001 2002
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2003

2004 2005
  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);
2006

2007 2008 2009 2010 2011 2012 2013 2014 2015
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
  Node* vfalse = __ Word32Equal(
      __ Int32Constant(1 << Map::kIsCallable),
      __ Word32And(value_bit_field,
                   __ Int32Constant((1 << Map::kIsCallable) |
                                    (1 << Map::kIsUndetectable))));
  __ Goto(&done, vfalse);
2016

2017 2018
  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));
2019

2020 2021
  __ Bind(&done);
  return done.PhiAt(0);
2022 2023
}

2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048
Node* EffectControlLinearizer::LowerObjectIsMinusZero(Node* node) {
  Node* value = node->InputAt(0);
  Node* zero = __ Int32Constant(0);

  auto done = __ MakeLabel(MachineRepresentation::kBit);

  // Check if {value} is a Smi.
  __ GotoIf(ObjectIsSmi(value), &done, zero);

  // Check if {value} is a HeapNumber.
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
               zero);

  // Check if {value} contains -0.
  Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  __ Goto(&done,
          __ Float64Equal(
              __ Float64Div(__ Float64Constant(1.0), value_value),
              __ Float64Constant(-std::numeric_limits<double>::infinity())));

  __ Bind(&done);
  return done.PhiAt(0);
}

2049 2050 2051 2052
Node* EffectControlLinearizer::LowerObjectIsNaN(Node* node) {
  Node* value = node->InputAt(0);
  Node* zero = __ Int32Constant(0);

2053
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2054 2055 2056 2057 2058 2059

  // Check if {value} is a Smi.
  __ GotoIf(ObjectIsSmi(value), &done, zero);

  // Check if {value} is a HeapNumber.
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
2060 2061
  __ GotoIfNot(__ WordEqual(value_map, __ HeapNumberMapConstant()), &done,
               zero);
2062 2063 2064 2065 2066 2067 2068 2069 2070 2071

  // Check if {value} contains a NaN.
  Node* value_value = __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
  __ Goto(&done,
          __ Word32Equal(__ Float64Equal(value_value, value_value), zero));

  __ Bind(&done);
  return done.PhiAt(0);
}

2072 2073 2074
Node* EffectControlLinearizer::LowerObjectIsNonCallable(Node* node) {
  Node* value = node->InputAt(0);

2075 2076
  auto if_primitive = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2077 2078 2079 2080 2081 2082 2083 2084 2085 2086

  Node* check0 = ObjectIsSmi(value);
  __ GotoIf(check0, &if_primitive);

  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
  Node* check1 = __ Uint32LessThanOrEqual(
      __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
2087
  __ GotoIfNot(check1, &if_primitive);
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102

  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
  Node* check2 = __ Word32Equal(
      __ Int32Constant(0),
      __ Word32And(value_bit_field, __ Int32Constant(1 << Map::kIsCallable)));
  __ Goto(&done, check2);

  __ Bind(&if_primitive);
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

2103
Node* EffectControlLinearizer::LowerObjectIsNumber(Node* node) {
2104 2105
  Node* value = node->InputAt(0);

2106 2107
  auto if_smi = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2108

2109 2110 2111
  __ GotoIf(ObjectIsSmi(value), &if_smi);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  __ Goto(&done, __ WordEqual(value_map, __ HeapNumberMapConstant()));
2112

2113 2114
  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(1));
2115

2116 2117
  __ Bind(&done);
  return done.PhiAt(0);
2118 2119
}

2120
Node* EffectControlLinearizer::LowerObjectIsReceiver(Node* node) {
2121 2122
  Node* value = node->InputAt(0);

2123 2124
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2125

2126
  __ GotoIf(ObjectIsSmi(value), &if_smi);
2127

2128 2129 2130 2131 2132 2133 2134
  STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
  Node* result = __ Uint32LessThanOrEqual(
      __ Uint32Constant(FIRST_JS_RECEIVER_TYPE), value_instance_type);
  __ Goto(&done, result);
2135

2136 2137
  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));
2138

2139 2140
  __ Bind(&done);
  return done.PhiAt(0);
2141 2142
}

2143
Node* EffectControlLinearizer::LowerObjectIsSmi(Node* node) {
2144
  Node* value = node->InputAt(0);
2145
  return ObjectIsSmi(value);
2146 2147
}

2148
Node* EffectControlLinearizer::LowerObjectIsString(Node* node) {
2149 2150
  Node* value = node->InputAt(0);

2151 2152
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2153

2154 2155 2156 2157 2158 2159 2160 2161
  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
  Node* vfalse = __ Uint32LessThan(value_instance_type,
                                   __ Uint32Constant(FIRST_NONSTRING_TYPE));
  __ Goto(&done, vfalse);
2162

2163 2164
  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));
2165

2166 2167
  __ Bind(&done);
  return done.PhiAt(0);
2168 2169
}

2170 2171 2172
Node* EffectControlLinearizer::LowerObjectIsSymbol(Node* node) {
  Node* value = node->InputAt(0);

2173 2174
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191

  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_instance_type =
      __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
  Node* vfalse =
      __ Word32Equal(value_instance_type, __ Uint32Constant(SYMBOL_TYPE));
  __ Goto(&done, vfalse);

  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));

  __ Bind(&done);
  return done.PhiAt(0);
}

2192
Node* EffectControlLinearizer::LowerObjectIsUndetectable(Node* node) {
2193 2194
  Node* value = node->InputAt(0);

2195 2196
  auto if_smi = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kBit);
2197

2198 2199
  Node* check = ObjectIsSmi(value);
  __ GotoIf(check, &if_smi);
2200

2201 2202 2203 2204 2205 2206 2207 2208 2209
  Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForMapBitField(), value_map);
  Node* vfalse = __ Word32Equal(
      __ Word32Equal(__ Int32Constant(0),
                     __ Word32And(value_bit_field,
                                  __ Int32Constant(1 << Map::kIsUndetectable))),
      __ Int32Constant(0));
  __ Goto(&done, vfalse);
2210

2211 2212
  __ Bind(&if_smi);
  __ Goto(&done, __ Int32Constant(0));
2213

2214 2215
  __ Bind(&done);
  return done.PhiAt(0);
2216 2217
}

2218 2219 2220
Node* EffectControlLinearizer::LowerTypeOf(Node* node) {
  Node* obj = node->InputAt(0);
  Callable const callable = Builtins::CallableFor(isolate(), Builtins::kTypeof);
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
  Operator::Properties const properties = Operator::kEliminatable;
  CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), obj,
                 __ NoContextConstant());
}

Node* EffectControlLinearizer::LowerClassOf(Node* node) {
  Node* obj = node->InputAt(0);
  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kClassOf);
2233
  Operator::Properties const properties = Operator::kEliminatable;
2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245
  CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), obj,
                 __ NoContextConstant());
}

Node* EffectControlLinearizer::LowerToBoolean(Node* node) {
  Node* obj = node->InputAt(0);
  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kToBoolean);
  Operator::Properties const properties = Operator::kEliminatable;
2246 2247 2248 2249 2250 2251 2252
  CallDescriptor::Flags const flags = CallDescriptor::kNoAllocate;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), obj,
                 __ NoContextConstant());
}

2253 2254 2255 2256
Node* EffectControlLinearizer::LowerArgumentsLength(Node* node) {
  Node* arguments_frame = NodeProperties::GetValueInput(node, 0);
  int formal_parameter_count = FormalParameterCountOf(node->op());
  bool is_rest_length = IsRestLengthOf(node->op());
2257
  DCHECK_LE(0, formal_parameter_count);
2258 2259 2260 2261 2262 2263

  if (is_rest_length) {
    // The ArgumentsLength node is computing the number of rest parameters,
    // which is max(0, actual_parameter_count - formal_parameter_count).
    // We have to distinguish the case, when there is an arguments adaptor frame
    // (i.e., arguments_frame != LoadFramePointer()).
2264 2265
    auto if_adaptor_frame = __ MakeLabel();
    auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned);
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280

    Node* frame = __ LoadFramePointer();
    __ GotoIf(__ WordEqual(arguments_frame, frame), &done, __ SmiConstant(0));
    __ Goto(&if_adaptor_frame);

    __ Bind(&if_adaptor_frame);
    Node* arguments_length = __ Load(
        MachineType::TaggedSigned(), arguments_frame,
        __ IntPtrConstant(ArgumentsAdaptorFrameConstants::kLengthOffset));

    Node* rest_length =
        __ IntSub(arguments_length, __ SmiConstant(formal_parameter_count));
    __ GotoIf(__ IntLessThan(rest_length, __ SmiConstant(0)), &done,
              __ SmiConstant(0));
    __ Goto(&done, rest_length);
2281

2282 2283 2284 2285 2286 2287
    __ Bind(&done);
    return done.PhiAt(0);
  } else {
    // The ArgumentsLength node is computing the actual number of arguments.
    // We have to distinguish the case when there is an arguments adaptor frame
    // (i.e., arguments_frame != LoadFramePointer()).
2288 2289
    auto if_adaptor_frame = __ MakeLabel();
    auto done = __ MakeLabel(MachineRepresentation::kTaggedSigned);
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307

    Node* frame = __ LoadFramePointer();
    __ GotoIf(__ WordEqual(arguments_frame, frame), &done,
              __ SmiConstant(formal_parameter_count));
    __ Goto(&if_adaptor_frame);

    __ Bind(&if_adaptor_frame);
    Node* arguments_length = __ Load(
        MachineType::TaggedSigned(), arguments_frame,
        __ IntPtrConstant(ArgumentsAdaptorFrameConstants::kLengthOffset));
    __ Goto(&done, arguments_length);

    __ Bind(&done);
    return done.PhiAt(0);
  }
}

Node* EffectControlLinearizer::LowerArgumentsFrame(Node* node) {
2308
  auto done = __ MakeLabel(MachineType::PointerRepresentation());
2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324

  Node* frame = __ LoadFramePointer();
  Node* parent_frame =
      __ Load(MachineType::AnyTagged(), frame,
              __ IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
  Node* parent_frame_type = __ Load(
      MachineType::AnyTagged(), parent_frame,
      __ IntPtrConstant(CommonFrameConstants::kContextOrFrameTypeOffset));
  __ GotoIf(__ WordEqual(parent_frame_type,
                         __ IntPtrConstant(StackFrame::TypeToMarker(
                             StackFrame::ARGUMENTS_ADAPTOR))),
            &done, parent_frame);
  __ Goto(&done, frame);

  __ Bind(&done);
  return done.PhiAt(0);
2325 2326
}

2327
Node* EffectControlLinearizer::LowerNewDoubleElements(Node* node) {
2328 2329 2330
  PretenureFlag const pretenure = PretenureFlagOf(node->op());
  Node* length = node->InputAt(0);

2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344
  // Compute the effective size of the backing store.
  Node* size =
      __ Int32Add(__ Word32Shl(length, __ Int32Constant(kDoubleSizeLog2)),
                  __ Int32Constant(FixedDoubleArray::kHeaderSize));

  // Allocate the result and initialize the header.
  Node* result = __ Allocate(pretenure, size);
  __ StoreField(AccessBuilder::ForMap(), result,
                __ FixedDoubleArrayMapConstant());
  __ StoreField(AccessBuilder::ForFixedArrayLength(), result,
                ChangeInt32ToSmi(length));

  // Initialize the backing store with holes.
  STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
2345
  Node* limit = ChangeUint32ToUintPtr(length);
2346 2347
  Node* the_hole =
      __ LoadField(AccessBuilder::ForHeapNumberValue(), __ TheHoleConstant());
2348
  auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
2349
  auto done_loop = __ MakeLabel();
2350
  __ Goto(&loop, __ IntPtrConstant(0));
2351 2352 2353 2354
  __ Bind(&loop);
  {
    // Check if we've initialized everything.
    Node* index = loop.PhiAt(0);
2355
    Node* check = __ UintLessThan(index, limit);
2356 2357 2358
    __ GotoIfNot(check, &done_loop);

    // Storing "the_hole" doesn't need a write barrier.
2359 2360 2361 2362 2363
    StoreRepresentation rep(MachineRepresentation::kFloat64, kNoWriteBarrier);
    Node* offset = __ IntAdd(
        __ WordShl(index, __ IntPtrConstant(kDoubleSizeLog2)),
        __ IntPtrConstant(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
    __ Store(rep, result, offset, the_hole);
2364 2365

    // Advance the {index}.
2366
    index = __ IntAdd(index, __ IntPtrConstant(1));
2367 2368 2369 2370 2371
    __ Goto(&loop, index);
  }

  __ Bind(&done_loop);
  return result;
2372 2373
}

2374
Node* EffectControlLinearizer::LowerNewSmiOrObjectElements(Node* node) {
2375 2376 2377
  PretenureFlag const pretenure = PretenureFlagOf(node->op());
  Node* length = node->InputAt(0);

2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389
  // Compute the effective size of the backing store.
  Node* size =
      __ Int32Add(__ Word32Shl(length, __ Int32Constant(kPointerSizeLog2)),
                  __ Int32Constant(FixedArray::kHeaderSize));

  // Allocate the result and initialize the header.
  Node* result = __ Allocate(pretenure, size);
  __ StoreField(AccessBuilder::ForMap(), result, __ FixedArrayMapConstant());
  __ StoreField(AccessBuilder::ForFixedArrayLength(), result,
                ChangeInt32ToSmi(length));

  // Initialize the backing store with holes.
2390
  Node* limit = ChangeUint32ToUintPtr(length);
2391
  Node* the_hole = __ TheHoleConstant();
2392
  auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
2393
  auto done_loop = __ MakeLabel();
2394
  __ Goto(&loop, __ IntPtrConstant(0));
2395 2396 2397 2398
  __ Bind(&loop);
  {
    // Check if we've initialized everything.
    Node* index = loop.PhiAt(0);
2399
    Node* check = __ UintLessThan(index, limit);
2400 2401 2402
    __ GotoIfNot(check, &done_loop);

    // Storing "the_hole" doesn't need a write barrier.
2403 2404 2405 2406 2407
    StoreRepresentation rep(MachineRepresentation::kTagged, kNoWriteBarrier);
    Node* offset =
        __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2)),
                  __ IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag));
    __ Store(rep, result, offset, the_hole);
2408 2409

    // Advance the {index}.
2410
    index = __ IntAdd(index, __ IntPtrConstant(1));
2411 2412 2413 2414 2415
    __ Goto(&loop, index);
  }

  __ Bind(&done_loop);
  return result;
2416 2417
}

2418
Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
  Node* frame = NodeProperties::GetValueInput(node, 0);
  Node* length = NodeProperties::GetValueInput(node, 1);
  int mapped_count = OpParameter<int>(node);

  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kNewArgumentsElements);
  Operator::Properties const properties = node->op()->properties();
  CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), frame, length,
                 __ SmiConstant(mapped_count), __ NoContextConstant());
}

2433
Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) {
2434 2435
  Node* value = node->InputAt(0);

2436 2437 2438 2439 2440 2441 2442 2443
  Node* value_bit_field =
      __ LoadField(AccessBuilder::ForJSArrayBufferBitField(), value);
  return __ Word32Equal(
      __ Word32Equal(
          __ Word32And(value_bit_field,
                       __ Int32Constant(JSArrayBuffer::WasNeutered::kMask)),
          __ Int32Constant(0)),
      __ Int32Constant(0));
2444 2445
}

2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
Node* EffectControlLinearizer::LowerSameValue(Node* node) {
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kSameValue);
  Operator::Properties properties = Operator::kEliminatable;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), lhs, rhs,
                 __ NoContextConstant());
}

2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
Node* EffectControlLinearizer::LowerStringToNumber(Node* node) {
  Node* string = node->InputAt(0);

  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kStringToNumber);
  Operator::Properties properties = Operator::kEliminatable;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), string,
                 __ NoContextConstant());
}

2473 2474 2475 2476
Node* EffectControlLinearizer::LowerStringCharAt(Node* node) {
  Node* receiver = node->InputAt(0);
  Node* position = node->InputAt(1);

2477 2478
  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kStringCharAt);
2479 2480 2481 2482
  Operator::Properties properties = Operator::kNoThrow | Operator::kNoWrite;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
2483 2484
  return __ Call(desc, __ HeapConstant(callable.code()), receiver, position,
                 __ NoContextConstant());
2485 2486
}

2487 2488 2489 2490
Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) {
  Node* receiver = node->InputAt(0);
  Node* position = node->InputAt(1);

2491 2492
  Callable const callable =
      Builtins::CallableFor(isolate(), Builtins::kStringCharCodeAt);
2493 2494 2495 2496 2497
  Operator::Properties properties = Operator::kNoThrow | Operator::kNoWrite;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties,
      MachineType::TaggedSigned());
2498 2499
  return __ Call(desc, __ HeapConstant(callable.code()), receiver, position,
                 __ NoContextConstant());
2500 2501
}

2502 2503 2504 2505
Node* EffectControlLinearizer::LowerSeqStringCharCodeAt(Node* node) {
  Node* receiver = node->InputAt(0);
  Node* position = node->InputAt(1);

2506 2507
  auto one_byte_load = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528

  Node* map = __ LoadField(AccessBuilder::ForMap(), receiver);
  Node* instance_type = __ LoadField(AccessBuilder::ForMapInstanceType(), map);
  Node* is_one_byte = __ Word32Equal(
      __ Word32And(instance_type, __ Int32Constant(kStringEncodingMask)),
      __ Int32Constant(kOneByteStringTag));

  __ GotoIf(is_one_byte, &one_byte_load);
  Node* two_byte_result = __ LoadElement(
      AccessBuilder::ForSeqTwoByteStringCharacter(), receiver, position);
  __ Goto(&done, two_byte_result);

  __ Bind(&one_byte_load);
  Node* one_byte_element = __ LoadElement(
      AccessBuilder::ForSeqOneByteStringCharacter(), receiver, position);
  __ Goto(&done, one_byte_element);

  __ Bind(&done);
  return done.PhiAt(0);
}

2529
Node* EffectControlLinearizer::LowerStringFromCharCode(Node* node) {
2530 2531
  Node* value = node->InputAt(0);

2532 2533 2534
  auto runtime_call = __ MakeDeferredLabel();
  auto if_undefined = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
2535

2536
  // Compute the character code.
2537
  Node* code = __ Word32And(value, __ Int32Constant(String::kMaxUtf16CodeUnit));
2538 2539

  // Check if the {code} is a one-byte char code.
2540 2541
  Node* check0 = __ Int32LessThanOrEqual(
      code, __ Int32Constant(String::kMaxOneByteCharCode));
2542
  __ GotoIfNot(check0, &runtime_call);
2543

2544
  // Load the isolate wide single character string cache.
2545
  Node* cache = __ HeapConstant(factory()->single_character_string_cache());
2546

2547
  // Compute the {cache} index for {code}.
2548
  Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code);
2549

2550 2551
  // Check if we have an entry for the {code} in the single character string
  // cache already.
2552 2553
  Node* entry =
      __ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);
2554

2555 2556 2557
  Node* check1 = __ WordEqual(entry, __ UndefinedConstant());
  __ GotoIf(check1, &runtime_call);
  __ Goto(&done, entry);
2558 2559 2560 2561

  // Let %StringFromCharCode handle this case.
  // TODO(turbofan): At some point we may consider adding a stub for this
  // deferred case, so that we don't need to call to C++ here.
2562
  __ Bind(&runtime_call);
2563
  {
2564 2565 2566 2567
    Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
    Runtime::FunctionId id = Runtime::kStringCharFromCode;
    CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
        graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
2568 2569 2570 2571 2572
    Node* vtrue1 =
        __ Call(desc, __ CEntryStubConstant(1), ChangeInt32ToSmi(code),
                __ ExternalConstant(ExternalReference(id, isolate())),
                __ Int32Constant(1), __ NoContextConstant());
    __ Goto(&done, vtrue1);
2573
  }
2574 2575
  __ Bind(&done);
  return done.PhiAt(0);
2576 2577
}

2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617
#ifdef V8_INTL_SUPPORT

Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) {
  Node* receiver = node->InputAt(0);

  Callable callable =
      Builtins::CallableFor(isolate(), Builtins::kStringToLowerCaseIntl);
  Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), receiver,
                 __ NoContextConstant());
}

Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) {
  Node* receiver = node->InputAt(0);
  Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
  Runtime::FunctionId id = Runtime::kStringToUpperCaseIntl;
  CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
      graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
  return __ Call(desc, __ CEntryStubConstant(1), receiver,
                 __ ExternalConstant(ExternalReference(id, isolate())),
                 __ Int32Constant(1), __ NoContextConstant());
}

#else

Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) {
  UNREACHABLE();
  return nullptr;
}

Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) {
  UNREACHABLE();
  return nullptr;
}

#endif  // V8_INTL_SUPPORT

2618
Node* EffectControlLinearizer::LowerStringFromCodePoint(Node* node) {
2619 2620 2621
  Node* value = node->InputAt(0);
  Node* code = value;

2622 2623 2624 2625
  auto if_not_single_code = __ MakeDeferredLabel();
  auto if_not_one_byte = __ MakeDeferredLabel();
  auto cache_miss = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
2626 2627

  // Check if the {code} is a single code unit
2628
  Node* check0 = __ Uint32LessThanOrEqual(code, __ Uint32Constant(0xFFFF));
2629
  __ GotoIfNot(check0, &if_not_single_code);
2630 2631 2632

  {
    // Check if the {code} is a one byte character
2633 2634
    Node* check1 = __ Uint32LessThanOrEqual(
        code, __ Uint32Constant(String::kMaxOneByteCharCode));
2635
    __ GotoIfNot(check1, &if_not_one_byte);
2636 2637
    {
      // Load the isolate wide single character string cache.
2638
      Node* cache = __ HeapConstant(factory()->single_character_string_cache());
2639 2640

      // Compute the {cache} index for {code}.
2641
      Node* index = machine()->Is32() ? code : __ ChangeUint32ToUint64(code);
2642 2643 2644

      // Check if we have an entry for the {code} in the single character string
      // cache already.
2645 2646 2647 2648 2649 2650 2651 2652 2653 2654
      Node* entry =
          __ LoadElement(AccessBuilder::ForFixedArrayElement(), cache, index);

      Node* check2 = __ WordEqual(entry, __ UndefinedConstant());
      __ GotoIf(check2, &cache_miss);

      // Use the {entry} from the {cache}.
      __ Goto(&done, entry);

      __ Bind(&cache_miss);
2655 2656
      {
        // Allocate a new SeqOneByteString for {code}.
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669
        Node* vtrue2 = __ Allocate(
            NOT_TENURED, __ Int32Constant(SeqOneByteString::SizeFor(1)));
        __ StoreField(AccessBuilder::ForMap(), vtrue2,
                      __ HeapConstant(factory()->one_byte_string_map()));
        __ StoreField(AccessBuilder::ForNameHashField(), vtrue2,
                      __ IntPtrConstant(Name::kEmptyHashField));
        __ StoreField(AccessBuilder::ForStringLength(), vtrue2,
                      __ SmiConstant(1));
        __ Store(
            StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
            vtrue2,
            __ IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag),
            code);
2670 2671

        // Remember it in the {cache}.
2672 2673 2674
        __ StoreElement(AccessBuilder::ForFixedArrayElement(), cache, index,
                        vtrue2);
        __ Goto(&done, vtrue2);
2675 2676 2677
      }
    }

2678
    __ Bind(&if_not_one_byte);
2679 2680
    {
      // Allocate a new SeqTwoByteString for {code}.
2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694
      Node* vfalse1 = __ Allocate(
          NOT_TENURED, __ Int32Constant(SeqTwoByteString::SizeFor(1)));
      __ StoreField(AccessBuilder::ForMap(), vfalse1,
                    __ HeapConstant(factory()->string_map()));
      __ StoreField(AccessBuilder::ForNameHashField(), vfalse1,
                    __ IntPtrConstant(Name::kEmptyHashField));
      __ StoreField(AccessBuilder::ForStringLength(), vfalse1,
                    __ SmiConstant(1));
      __ Store(
          StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier),
          vfalse1,
          __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
          code);
      __ Goto(&done, vfalse1);
2695 2696 2697
    }
  }

2698
  __ Bind(&if_not_single_code);
2699 2700 2701 2702 2703 2704 2705 2706
  // Generate surrogate pair string
  {
    switch (UnicodeEncodingOf(node->op())) {
      case UnicodeEncoding::UTF16:
        break;

      case UnicodeEncoding::UTF32: {
        // Convert UTF32 to UTF16 code units, and store as a 32 bit word.
2707
        Node* lead_offset = __ Int32Constant(0xD800 - (0x10000 >> 10));
2708 2709 2710

        // lead = (codepoint >> 10) + LEAD_OFFSET
        Node* lead =
2711
            __ Int32Add(__ Word32Shr(code, __ Int32Constant(10)), lead_offset);
2712 2713

        // trail = (codepoint & 0x3FF) + 0xDC00;
2714 2715
        Node* trail = __ Int32Add(__ Word32And(code, __ Int32Constant(0x3FF)),
                                  __ Int32Constant(0xDC00));
2716 2717

        // codpoint = (trail << 16) | lead;
2718
        code = __ Word32Or(__ Word32Shl(trail, __ Int32Constant(16)), lead);
2719 2720 2721 2722 2723
        break;
      }
    }

    // Allocate a new SeqTwoByteString for {code}.
2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
    Node* vfalse0 = __ Allocate(NOT_TENURED,
                                __ Int32Constant(SeqTwoByteString::SizeFor(2)));
    __ StoreField(AccessBuilder::ForMap(), vfalse0,
                  __ HeapConstant(factory()->string_map()));
    __ StoreField(AccessBuilder::ForNameHashField(), vfalse0,
                  __ IntPtrConstant(Name::kEmptyHashField));
    __ StoreField(AccessBuilder::ForStringLength(), vfalse0, __ SmiConstant(2));
    __ Store(
        StoreRepresentation(MachineRepresentation::kWord32, kNoWriteBarrier),
        vfalse0,
        __ IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
        code);
    __ Goto(&done, vfalse0);
  }

  __ Bind(&done);
  return done.PhiAt(0);
}

2743 2744 2745 2746 2747
Node* EffectControlLinearizer::LowerStringIndexOf(Node* node) {
  Node* subject = node->InputAt(0);
  Node* search_string = node->InputAt(1);
  Node* position = node->InputAt(2);

2748 2749
  Callable callable =
      Builtins::CallableFor(isolate(), Builtins::kStringIndexOf);
2750 2751 2752 2753 2754 2755 2756 2757
  Operator::Properties properties = Operator::kEliminatable;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  return __ Call(desc, __ HeapConstant(callable.code()), subject, search_string,
                 position, __ NoContextConstant());
}

2758 2759 2760 2761
Node* EffectControlLinearizer::LowerStringComparison(Callable const& callable,
                                                     Node* node) {
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);
2762

2763 2764 2765 2766
  Operator::Properties properties = Operator::kEliminatable;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
2767 2768
  return __ Call(desc, __ HeapConstant(callable.code()), lhs, rhs,
                 __ NoContextConstant());
2769 2770
}

2771
Node* EffectControlLinearizer::LowerStringEqual(Node* node) {
2772 2773
  return LowerStringComparison(
      Builtins::CallableFor(isolate(), Builtins::kStringEqual), node);
2774 2775
}

2776
Node* EffectControlLinearizer::LowerStringLessThan(Node* node) {
2777 2778
  return LowerStringComparison(
      Builtins::CallableFor(isolate(), Builtins::kStringLessThan), node);
2779 2780
}

2781
Node* EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node) {
2782 2783
  return LowerStringComparison(
      Builtins::CallableFor(isolate(), Builtins::kStringLessThanOrEqual), node);
2784 2785
}

2786 2787
Node* EffectControlLinearizer::LowerCheckFloat64Hole(Node* node,
                                                     Node* frame_state) {
2788 2789 2790 2791
  // If we reach this point w/o eliminating the {node} that's marked
  // with allow-return-hole, we cannot do anything, so just deoptimize
  // in case of the hole NaN (similar to Crankshaft).
  Node* value = node->InputAt(0);
2792 2793 2794 2795
  Node* check = __ Word32Equal(__ Float64ExtractHighWord32(value),
                               __ Int32Constant(kHoleNanUpper32));
  __ DeoptimizeIf(DeoptimizeReason::kHole, check, frame_state);
  return value;
2796 2797
}

2798 2799 2800 2801 2802

Node* EffectControlLinearizer::LowerCheckNotTaggedHole(Node* node,
                                                       Node* frame_state) {
  Node* value = node->InputAt(0);
  Node* check = __ WordEqual(value, __ TheHoleConstant());
2803 2804
  __ DeoptimizeIf(DeoptimizeReason::kHole, check, frame_state);
  return value;
2805 2806
}

2807
Node* EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node) {
2808 2809
  Node* value = node->InputAt(0);

2810 2811
  auto if_is_hole = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
2812

2813 2814 2815
  Node* check = __ WordEqual(value, __ TheHoleConstant());
  __ GotoIf(check, &if_is_hole);
  __ Goto(&done, value);
2816

2817 2818
  __ Bind(&if_is_hole);
  __ Goto(&done, __ UndefinedConstant());
2819

2820 2821
  __ Bind(&done);
  return done.PhiAt(0);
2822 2823
}

2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
void EffectControlLinearizer::LowerCheckEqualsInternalizedString(
    Node* node, Node* frame_state) {
  Node* exp = node->InputAt(0);
  Node* val = node->InputAt(1);

  auto if_same = __ MakeLabel();
  auto if_notsame = __ MakeDeferredLabel();
  auto if_thinstring = __ MakeLabel();
  auto if_notthinstring = __ MakeLabel();

  // Check if {exp} and {val} are the same, which is the likely case.
  __ Branch(__ WordEqual(exp, val), &if_same, &if_notsame);

  __ Bind(&if_notsame);
  {
    // Now {val} could still be a non-internalized String that matches {exp}.
    __ DeoptimizeIf(DeoptimizeReason::kWrongName, ObjectIsSmi(val),
                    frame_state);
    Node* val_map = __ LoadField(AccessBuilder::ForMap(), val);
    Node* val_instance_type =
        __ LoadField(AccessBuilder::ForMapInstanceType(), val_map);

    // Check for the common case of ThinString first.
    __ GotoIf(__ Word32Equal(val_instance_type,
                             __ Int32Constant(THIN_ONE_BYTE_STRING_TYPE)),
              &if_thinstring);
    __ Branch(
        __ Word32Equal(val_instance_type, __ Int32Constant(THIN_STRING_TYPE)),
        &if_thinstring, &if_notthinstring);

    __ Bind(&if_notthinstring);
    {
      // Check that the {val} is a non-internalized String, if it's anything
      // else it cannot match the recorded feedback {exp} anyways.
      __ DeoptimizeIfNot(
          DeoptimizeReason::kWrongName,
          __ Word32Equal(__ Word32And(val_instance_type,
                                      __ Int32Constant(kIsNotStringMask |
                                                       kIsNotInternalizedMask)),
                         __ Int32Constant(kStringTag | kNotInternalizedTag)),
          frame_state);

      // Try to find the {val} in the string table.
      MachineSignature::Builder builder(graph()->zone(), 1, 1);
      builder.AddReturn(MachineType::AnyTagged());
      builder.AddParam(MachineType::AnyTagged());
      Node* try_internalize_string_function = __ ExternalConstant(
          ExternalReference::try_internalize_string_function(isolate()));
      CallDescriptor const* const desc =
          Linkage::GetSimplifiedCDescriptor(graph()->zone(), builder.Build());
      Node* val_internalized =
          __ Call(common()->Call(desc), try_internalize_string_function, val);

      // Now see if the results match.
      __ DeoptimizeIfNot(DeoptimizeReason::kWrongName,
                         __ WordEqual(exp, val_internalized), frame_state);
      __ Goto(&if_same);
    }

    __ Bind(&if_thinstring);
    {
      // The {val} is a ThinString, let's check the actual value.
      Node* val_actual =
          __ LoadField(AccessBuilder::ForThinStringActual(), val);
      __ DeoptimizeIfNot(DeoptimizeReason::kWrongName,
                         __ WordEqual(exp, val_actual), frame_state);
      __ Goto(&if_same);
    }
  }

  __ Bind(&if_same);
}

void EffectControlLinearizer::LowerCheckEqualsSymbol(Node* node,
                                                     Node* frame_state) {
  Node* exp = node->InputAt(0);
  Node* val = node->InputAt(1);
  Node* check = __ WordEqual(exp, val);
  __ DeoptimizeIfNot(DeoptimizeReason::kWrongName, check, frame_state);
}

2905 2906 2907 2908 2909
Node* EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value) {
  Node* result = __ Allocate(NOT_TENURED, __ Int32Constant(HeapNumber::kSize));
  __ StoreField(AccessBuilder::ForMap(), result, __ HeapNumberMapConstant());
  __ StoreField(AccessBuilder::ForHeapNumberValue(), result, value);
  return result;
2910 2911 2912 2913
}

Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) {
  if (machine()->Is64()) {
2914
    value = __ ChangeInt32ToInt64(value);
2915
  }
2916
  return __ WordShl(value, SmiShiftBitsConstant());
2917 2918
}

2919 2920 2921 2922 2923 2924 2925 2926
Node* EffectControlLinearizer::ChangeIntPtrToInt32(Node* value) {
  if (machine()->Is64()) {
    value = __ TruncateInt64ToInt32(value);
  }
  return value;
}

Node* EffectControlLinearizer::ChangeUint32ToUintPtr(Node* value) {
2927
  if (machine()->Is64()) {
2928
    value = __ ChangeUint32ToUint64(value);
2929
  }
2930 2931 2932 2933 2934
  return value;
}

Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) {
  value = ChangeUint32ToUintPtr(value);
2935
  return __ WordShl(value, SmiShiftBitsConstant());
2936 2937
}

2938 2939 2940 2941
Node* EffectControlLinearizer::ChangeSmiToIntPtr(Node* value) {
  return __ WordSar(value, SmiShiftBitsConstant());
}

2942
Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) {
2943
  value = ChangeSmiToIntPtr(value);
2944
  if (machine()->Is64()) {
2945
    value = __ TruncateInt64ToInt32(value);
2946 2947 2948
  }
  return value;
}
2949

2950
Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
2951 2952
  return __ WordEqual(__ WordAnd(value, __ IntPtrConstant(kSmiTagMask)),
                      __ IntPtrConstant(kSmiTag));
2953 2954
}

2955
Node* EffectControlLinearizer::SmiMaxValueConstant() {
2956
  return __ Int32Constant(Smi::kMaxValue);
2957 2958 2959
}

Node* EffectControlLinearizer::SmiShiftBitsConstant() {
2960
  return __ IntPtrConstant(kSmiShiftSize + kSmiTagSize);
2961 2962
}

2963
Node* EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node) {
2964
  Node* value = node->InputAt(0);
2965
  return __ ToNumber(value);
2966 2967
}

2968
Node* EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node) {
2969 2970
  Node* value = node->InputAt(0);

2971 2972 2973
  auto if_not_smi = __ MakeDeferredLabel();
  auto if_to_number_smi = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
2974

2975
  Node* check0 = ObjectIsSmi(value);
2976
  __ GotoIfNot(check0, &if_not_smi);
2977
  __ Goto(&done, ChangeSmiToInt32(value));
2978

2979 2980
  __ Bind(&if_not_smi);
  Node* to_number = __ ToNumber(value);
2981

2982 2983 2984 2985
  Node* check1 = ObjectIsSmi(to_number);
  __ GotoIf(check1, &if_to_number_smi);
  Node* number = __ LoadField(AccessBuilder::ForHeapNumberValue(), to_number);
  __ Goto(&done, __ TruncateFloat64ToWord32(number));
2986

2987 2988
  __ Bind(&if_to_number_smi);
  __ Goto(&done, ChangeSmiToInt32(to_number));
2989

2990 2991
  __ Bind(&done);
  return done.PhiAt(0);
2992 2993
}

2994
Node* EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node) {
2995 2996
  Node* value = node->InputAt(0);

2997 2998 2999
  auto if_not_smi = __ MakeDeferredLabel();
  auto if_to_number_smi = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
3000

3001
  Node* check0 = ObjectIsSmi(value);
3002
  __ GotoIfNot(check0, &if_not_smi);
3003 3004
  Node* from_smi = ChangeSmiToInt32(value);
  __ Goto(&done, __ ChangeInt32ToFloat64(from_smi));
3005

3006 3007 3008 3009
  __ Bind(&if_not_smi);
  Node* to_number = __ ToNumber(value);
  Node* check1 = ObjectIsSmi(to_number);
  __ GotoIf(check1, &if_to_number_smi);
3010

3011 3012
  Node* number = __ LoadField(AccessBuilder::ForHeapNumberValue(), to_number);
  __ Goto(&done, number);
3013

3014 3015 3016 3017
  __ Bind(&if_to_number_smi);
  Node* number_from_smi = ChangeSmiToInt32(to_number);
  number_from_smi = __ ChangeInt32ToFloat64(number_from_smi);
  __ Goto(&done, number_from_smi);
3018

3019 3020
  __ Bind(&done);
  return done.PhiAt(0);
3021 3022
}

3023
Node* EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node) {
3024 3025 3026
  Node* object = node->InputAt(0);
  Node* elements = node->InputAt(1);

3027 3028
  auto if_not_fixed_array = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
3029

3030
  // Load the current map of {elements}.
3031
  Node* elements_map = __ LoadField(AccessBuilder::ForMap(), elements);
3032 3033

  // Check if {elements} is not a copy-on-write FixedArray.
3034
  Node* check = __ WordEqual(elements_map, __ FixedArrayMapConstant());
3035
  __ GotoIfNot(check, &if_not_fixed_array);
3036
  // Nothing to do if the {elements} are not copy-on-write.
3037
  __ Goto(&done, elements);
3038

3039
  __ Bind(&if_not_fixed_array);
3040
  // We need to take a copy of the {elements} and set them up for {object}.
3041
  Operator::Properties properties = Operator::kEliminatable;
3042 3043
  Callable callable =
      Builtins::CallableFor(isolate(), Builtins::kCopyFastSmiOrObjectElements);
3044 3045 3046 3047 3048 3049
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  Node* result = __ Call(desc, __ HeapConstant(callable.code()), object,
                         __ NoContextConstant());
  __ Goto(&done, result);
3050

3051 3052
  __ Bind(&done);
  return done.PhiAt(0);
3053 3054
}

3055 3056
Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
                                                          Node* frame_state) {
3057
  GrowFastElementsMode mode = GrowFastElementsModeOf(node->op());
3058 3059 3060
  Node* object = node->InputAt(0);
  Node* elements = node->InputAt(1);
  Node* index = node->InputAt(2);
3061
  Node* elements_length = node->InputAt(3);
3062

3063 3064 3065
  auto done = __ MakeLabel(MachineRepresentation::kTagged);
  auto if_grow = __ MakeDeferredLabel();
  auto if_not_grow = __ MakeLabel();
3066

3067 3068 3069 3070
  // Check if we need to grow the {elements} backing store.
  Node* check = __ Uint32LessThan(index, elements_length);
  __ GotoIfNot(check, &if_grow);
  __ Goto(&done, elements);
3071

3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
  __ Bind(&if_grow);
  // We need to grow the {elements} for {object}.
  Operator::Properties properties = Operator::kEliminatable;
  Callable callable =
      (mode == GrowFastElementsMode::kDoubleElements)
          ? Builtins::CallableFor(isolate(), Builtins::kGrowFastDoubleElements)
          : Builtins::CallableFor(isolate(),
                                  Builtins::kGrowFastSmiOrObjectElements);
  CallDescriptor::Flags call_flags = CallDescriptor::kNoFlags;
  CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, call_flags,
      properties);
  Node* new_elements = __ Call(desc, __ HeapConstant(callable.code()), object,
                               ChangeInt32ToSmi(index), __ NoContextConstant());
3086

3087 3088 3089 3090 3091 3092
  // Ensure that we were able to grow the {elements}.
  // TODO(turbofan): We use kSmi as reason here similar to Crankshaft,
  // but maybe we should just introduce a reason that makes sense.
  __ DeoptimizeIf(DeoptimizeReason::kSmi, ObjectIsSmi(new_elements),
                  frame_state);
  __ Goto(&done, new_elements);
3093

3094 3095
  __ Bind(&done);
  return done.PhiAt(0);
3096 3097
}

3098
void EffectControlLinearizer::LowerTransitionElementsKind(Node* node) {
3099 3100
  ElementsTransition const transition = ElementsTransitionOf(node->op());
  Node* object = node->InputAt(0);
3101

3102 3103
  auto if_map_same = __ MakeDeferredLabel();
  auto done = __ MakeLabel();
3104 3105 3106

  Node* source_map = __ HeapConstant(transition.source());
  Node* target_map = __ HeapConstant(transition.target());
3107 3108

  // Load the current map of {object}.
3109
  Node* object_map = __ LoadField(AccessBuilder::ForMap(), object);
3110 3111

  // Check if {object_map} is the same as {source_map}.
3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131
  Node* check = __ WordEqual(object_map, source_map);
  __ GotoIf(check, &if_map_same);
  __ Goto(&done);

  __ Bind(&if_map_same);
  switch (transition.mode()) {
    case ElementsTransition::kFastTransition:
      // In-place migration of {object}, just store the {target_map}.
      __ StoreField(AccessBuilder::ForMap(), object, target_map);
      break;
    case ElementsTransition::kSlowTransition: {
      // Instance migration, call out to the runtime for {object}.
      Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
      Runtime::FunctionId id = Runtime::kTransitionElementsKind;
      CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
          graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
      __ Call(desc, __ CEntryStubConstant(1), object, target_map,
              __ ExternalConstant(ExternalReference(id, isolate())),
              __ Int32Constant(2), __ NoContextConstant());
      break;
3132 3133
    }
  }
3134
  __ Goto(&done);
3135

3136
  __ Bind(&done);
3137 3138
}

3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239
Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) {
  Node* object = node->InputAt(0);
  Node* index = node->InputAt(1);
  Node* zero = __ IntPtrConstant(0);
  Node* one = __ IntPtrConstant(1);

  // Sign-extend the {index} on 64-bit architectures.
  if (machine()->Is64()) {
    index = __ ChangeInt32ToInt64(index);
  }

  auto if_double = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kTagged);

  // Check if field is a mutable double field.
  __ GotoIfNot(__ WordEqual(__ WordAnd(index, one), zero), &if_double);

  // The field is a proper Tagged field on {object}. The {index} is shifted
  // to the left by one in the code below.
  {
    // Check if field is in-object or out-of-object.
    auto if_outofobject = __ MakeLabel();
    __ GotoIf(__ IntLessThan(index, zero), &if_outofobject);

    // The field is located in the {object} itself.
    {
      Node* offset =
          __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2 - 1)),
                    __ IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag));
      Node* result = __ Load(MachineType::AnyTagged(), object, offset);
      __ Goto(&done, result);
    }

    // The field is located in the properties backing store of {object}.
    // The {index} is equal to the negated out of property index plus 1.
    __ Bind(&if_outofobject);
    {
      Node* properties =
          __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object);
      Node* offset =
          __ IntAdd(__ WordShl(__ IntSub(zero, index),
                               __ IntPtrConstant(kPointerSizeLog2 - 1)),
                    __ IntPtrConstant((FixedArray::kHeaderSize - kPointerSize) -
                                      kHeapObjectTag));
      Node* result = __ Load(MachineType::AnyTagged(), properties, offset);
      __ Goto(&done, result);
    }
  }

  // The field is a Double field, either unboxed in the object on 64-bit
  // architectures, or as MutableHeapNumber.
  __ Bind(&if_double);
  {
    auto done_double = __ MakeLabel(MachineRepresentation::kFloat64);

    index = __ WordSar(index, one);

    // Check if field is in-object or out-of-object.
    auto if_outofobject = __ MakeLabel();
    __ GotoIf(__ IntLessThan(index, zero), &if_outofobject);

    // The field is located in the {object} itself.
    {
      Node* offset =
          __ IntAdd(__ WordShl(index, __ IntPtrConstant(kPointerSizeLog2)),
                    __ IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag));
      if (FLAG_unbox_double_fields) {
        Node* result = __ Load(MachineType::Float64(), object, offset);
        __ Goto(&done_double, result);
      } else {
        Node* result = __ Load(MachineType::AnyTagged(), object, offset);
        result = __ LoadField(AccessBuilder::ForHeapNumberValue(), result);
        __ Goto(&done_double, result);
      }
    }

    __ Bind(&if_outofobject);
    {
      Node* properties =
          __ LoadField(AccessBuilder::ForJSObjectPropertiesOrHash(), object);
      Node* offset =
          __ IntAdd(__ WordShl(__ IntSub(zero, index),
                               __ IntPtrConstant(kPointerSizeLog2)),
                    __ IntPtrConstant((FixedArray::kHeaderSize - kPointerSize) -
                                      kHeapObjectTag));
      Node* result = __ Load(MachineType::AnyTagged(), properties, offset);
      result = __ LoadField(AccessBuilder::ForHeapNumberValue(), result);
      __ Goto(&done_double, result);
    }

    __ Bind(&done_double);
    {
      Node* result = AllocateHeapNumberWithValue(done_double.PhiAt(0));
      __ Goto(&done, result);
    }
  }

  __ Bind(&done);
  return done.PhiAt(0);
}

3240
Node* EffectControlLinearizer::LowerLoadTypedElement(Node* node) {
3241 3242 3243 3244 3245 3246 3247 3248
  ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
  Node* buffer = node->InputAt(0);
  Node* base = node->InputAt(1);
  Node* external = node->InputAt(2);
  Node* index = node->InputAt(3);

  // We need to keep the {buffer} alive so that the GC will not release the
  // ArrayBuffer (if there's any) as long as we are still operating on it.
3249
  __ Retain(buffer);
3250

3251 3252 3253
  // Compute the effective storage pointer, handling the case where the
  // {external} pointer is the effective storage pointer (i.e. the {base}
  // is Smi zero).
3254 3255
  Node* storage = NumberMatcher(base).Is(0) ? external : __ UnsafePointerAdd(
                                                             base, external);
3256 3257

  // Perform the actual typed element access.
3258 3259
  return __ LoadElement(AccessBuilder::ForTypedArrayElement(array_type, true),
                        storage, index);
3260 3261
}

3262
void EffectControlLinearizer::LowerStoreTypedElement(Node* node) {
3263 3264 3265 3266 3267 3268 3269 3270 3271
  ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
  Node* buffer = node->InputAt(0);
  Node* base = node->InputAt(1);
  Node* external = node->InputAt(2);
  Node* index = node->InputAt(3);
  Node* value = node->InputAt(4);

  // We need to keep the {buffer} alive so that the GC will not release the
  // ArrayBuffer (if there's any) as long as we are still operating on it.
3272
  __ Retain(buffer);
3273

3274 3275 3276
  // Compute the effective storage pointer, handling the case where the
  // {external} pointer is the effective storage pointer (i.e. the {base}
  // is Smi zero).
3277 3278
  Node* storage = NumberMatcher(base).Is(0) ? external : __ UnsafePointerAdd(
                                                             base, external);
3279 3280

  // Perform the actual typed element access.
3281 3282
  __ StoreElement(AccessBuilder::ForTypedArrayElement(array_type, true),
                  storage, index, value);
3283 3284
}

3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311
void EffectControlLinearizer::TransitionElementsTo(Node* node, Node* array,
                                                   ElementsKind from,
                                                   ElementsKind to) {
  DCHECK(IsMoreGeneralElementsKindTransition(from, to));
  DCHECK(to == HOLEY_ELEMENTS || to == HOLEY_DOUBLE_ELEMENTS);

  Handle<Map> target(to == HOLEY_ELEMENTS ? FastMapParameterOf(node->op())
                                          : DoubleMapParameterOf(node->op()));
  Node* target_map = __ HeapConstant(target);

  if (IsSimpleMapChangeTransition(from, to)) {
    __ StoreField(AccessBuilder::ForMap(), array, target_map);
  } else {
    // Instance migration, call out to the runtime for {array}.
    Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
    Runtime::FunctionId id = Runtime::kTransitionElementsKind;
    CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
        graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
    __ Call(desc, __ CEntryStubConstant(1), array, target_map,
            __ ExternalConstant(ExternalReference(id, isolate())),
            __ Int32Constant(2), __ NoContextConstant());
  }
}

Node* EffectControlLinearizer::IsElementsKindGreaterThan(
    Node* kind, ElementsKind reference_kind) {
  Node* ref_kind = __ Int32Constant(reference_kind);
3312
  Node* ret = __ Int32LessThan(ref_kind, kind);
3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
  return ret;
}

void EffectControlLinearizer::LowerTransitionAndStoreElement(Node* node) {
  Node* array = node->InputAt(0);
  Node* index = node->InputAt(1);
  Node* value = node->InputAt(2);

  // Possibly transition array based on input and store.
  //
  //   -- TRANSITION PHASE -----------------
  //   kind = ElementsKind(array)
  //   if value is not smi {
  //     if kind == HOLEY_SMI_ELEMENTS {
  //       if value is heap number {
  //         Transition array to HOLEY_DOUBLE_ELEMENTS
3329
  //         kind = HOLEY_DOUBLE_ELEMENTS
3330 3331
  //       } else {
  //         Transition array to HOLEY_ELEMENTS
3332
  //         kind = HOLEY_ELEMENTS
3333 3334 3335 3336
  //       }
  //     } else if kind == HOLEY_DOUBLE_ELEMENTS {
  //       if value is not heap number {
  //         Transition array to HOLEY_ELEMENTS
3337
  //         kind = HOLEY_ELEMENTS
3338 3339 3340 3341 3342
  //       }
  //     }
  //   }
  //
  //   -- STORE PHASE ----------------------
3343
  //   [make sure {kind} is up-to-date]
3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366
  //   if kind == HOLEY_DOUBLE_ELEMENTS {
  //     if value is smi {
  //       float_value = convert smi to float
  //       Store array[index] = float_value
  //     } else {
  //       float_value = value
  //       Store array[index] = float_value
  //     }
  //   } else {
  //     // kind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS
  //     Store array[index] = value
  //   }
  //
  Node* map = __ LoadField(AccessBuilder::ForMap(), array);
  Node* kind;
  {
    Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
    Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
    Node* andit = __ Word32And(bit_field2, mask);
    Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
    kind = __ Word32Shr(andit, shift);
  }

3367
  auto do_store = __ MakeLabel(MachineRepresentation::kWord32);
3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389
  // We can store a smi anywhere.
  __ GotoIf(ObjectIsSmi(value), &do_store, kind);

  // {value} is a HeapObject.
  auto transition_smi_array = __ MakeDeferredLabel();
  auto transition_double_to_fast = __ MakeDeferredLabel();
  {
    __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
                 &transition_smi_array);
    __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS), &do_store,
                 kind);

    // We have double elements kind. Only a HeapNumber can be stored
    // without effecting a transition.
    Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
    Node* heap_number_map = __ HeapNumberMapConstant();
    Node* check = __ WordEqual(value_map, heap_number_map);
    __ GotoIfNot(check, &transition_double_to_fast);
    __ Goto(&do_store, kind);
  }

  __ Bind(&transition_smi_array);  // deferred code.
3390
  {
3391 3392 3393 3394 3395 3396 3397
    // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_DOUBLE_ELEMENTS or
    // to HOLEY_ELEMENTS.
    auto if_value_not_heap_number = __ MakeLabel();
    Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
    Node* heap_number_map = __ HeapNumberMapConstant();
    Node* check = __ WordEqual(value_map, heap_number_map);
    __ GotoIfNot(check, &if_value_not_heap_number);
3398
    {
3399 3400 3401 3402
      // {value} is a HeapNumber.
      TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS,
                           HOLEY_DOUBLE_ELEMENTS);
      __ Goto(&do_store, __ Int32Constant(HOLEY_DOUBLE_ELEMENTS));
3403
    }
3404
    __ Bind(&if_value_not_heap_number);
3405
    {
3406
      TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS);
3407
      __ Goto(&do_store, __ Int32Constant(HOLEY_ELEMENTS));
3408 3409 3410
    }
  }

3411 3412 3413 3414 3415 3416
  __ Bind(&transition_double_to_fast);  // deferred code.
  {
    TransitionElementsTo(node, array, HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS);
    __ Goto(&do_store, __ Int32Constant(HOLEY_ELEMENTS));
  }

3417
  // Make sure kind is up-to-date.
3418
  __ Bind(&do_store);
3419 3420
  kind = do_store.PhiAt(0);

3421
  Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
3422 3423
  auto if_kind_is_double = __ MakeLabel();
  auto done = __ MakeLabel();
3424 3425
  __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
            &if_kind_is_double);
3426 3427 3428 3429 3430 3431 3432 3433 3434
  {
    // Our ElementsKind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS.
    __ StoreElement(AccessBuilder::ForFixedArrayElement(HOLEY_ELEMENTS),
                    elements, index, value);
    __ Goto(&done);
  }
  __ Bind(&if_kind_is_double);
  {
    // Our ElementsKind is HOLEY_DOUBLE_ELEMENTS.
3435
    auto do_double_store = __ MakeLabel();
3436
    __ GotoIfNot(ObjectIsSmi(value), &do_double_store);
3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452
    {
      Node* int_value = ChangeSmiToInt32(value);
      Node* float_value = __ ChangeInt32ToFloat64(int_value);
      __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements,
                      index, float_value);
      __ Goto(&done);
    }
    __ Bind(&do_double_store);
    {
      Node* float_value =
          __ LoadField(AccessBuilder::ForHeapNumberValue(), value);
      __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements,
                      index, float_value);
      __ Goto(&done);
    }
  }
3453

3454 3455 3456
  __ Bind(&done);
}

3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519
void EffectControlLinearizer::LowerTransitionAndStoreNumberElement(Node* node) {
  Node* array = node->InputAt(0);
  Node* index = node->InputAt(1);
  Node* value = node->InputAt(2);  // This is a Float64, not tagged.

  // Possibly transition array based on input and store.
  //
  //   -- TRANSITION PHASE -----------------
  //   kind = ElementsKind(array)
  //   if kind == HOLEY_SMI_ELEMENTS {
  //     Transition array to HOLEY_DOUBLE_ELEMENTS
  //   } else if kind != HOLEY_DOUBLE_ELEMENTS {
  //     This is UNREACHABLE, execute a debug break.
  //   }
  //
  //   -- STORE PHASE ----------------------
  //   Store array[index] = value (it's a float)
  //
  Node* map = __ LoadField(AccessBuilder::ForMap(), array);
  Node* kind;
  {
    Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
    Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
    Node* andit = __ Word32And(bit_field2, mask);
    Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
    kind = __ Word32Shr(andit, shift);
  }

  auto do_store = __ MakeLabel();

  // {value} is a float64.
  auto transition_smi_array = __ MakeDeferredLabel();
  {
    __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
                 &transition_smi_array);
    // We expect that our input array started at HOLEY_SMI_ELEMENTS, and
    // climbs the lattice up to HOLEY_DOUBLE_ELEMENTS. Force a debug break
    // if this assumption is broken. It also would be the case that
    // loop peeling can break this assumption.
    __ GotoIf(__ Word32Equal(kind, __ Int32Constant(HOLEY_DOUBLE_ELEMENTS)),
              &do_store);
    // TODO(turbofan): It would be good to have an "Unreachable()" node type.
    __ DebugBreak();
    __ Goto(&do_store);
  }

  __ Bind(&transition_smi_array);  // deferred code.
  {
    // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_DOUBLE_ELEMENTS.
    TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS,
                         HOLEY_DOUBLE_ELEMENTS);
    __ Goto(&do_store);
  }

  __ Bind(&do_store);

  Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
  __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements, index,
                  value);
}

void EffectControlLinearizer::LowerTransitionAndStoreNonNumberElement(
    Node* node) {
3520 3521 3522 3523
  Node* array = node->InputAt(0);
  Node* index = node->InputAt(1);
  Node* value = node->InputAt(2);

3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590
  // Possibly transition array based on input and store.
  //
  //   -- TRANSITION PHASE -----------------
  //   kind = ElementsKind(array)
  //   if kind == HOLEY_SMI_ELEMENTS {
  //     Transition array to HOLEY_ELEMENTS
  //   } else if kind == HOLEY_DOUBLE_ELEMENTS {
  //     Transition array to HOLEY_ELEMENTS
  //   }
  //
  //   -- STORE PHASE ----------------------
  //   // kind is HOLEY_ELEMENTS
  //   Store array[index] = value
  //
  Node* map = __ LoadField(AccessBuilder::ForMap(), array);
  Node* kind;
  {
    Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
    Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
    Node* andit = __ Word32And(bit_field2, mask);
    Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
    kind = __ Word32Shr(andit, shift);
  }

  auto do_store = __ MakeLabel();

  auto transition_smi_array = __ MakeDeferredLabel();
  auto transition_double_to_fast = __ MakeDeferredLabel();
  {
    __ GotoIfNot(IsElementsKindGreaterThan(kind, HOLEY_SMI_ELEMENTS),
                 &transition_smi_array);
    __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
              &transition_double_to_fast);
    __ Goto(&do_store);
  }

  __ Bind(&transition_smi_array);  // deferred code.
  {
    // Transition {array} from HOLEY_SMI_ELEMENTS to HOLEY_ELEMENTS.
    TransitionElementsTo(node, array, HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS);
    __ Goto(&do_store);
  }

  __ Bind(&transition_double_to_fast);  // deferred code.
  {
    TransitionElementsTo(node, array, HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS);
    __ Goto(&do_store);
  }

  __ Bind(&do_store);

  Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
  // Our ElementsKind is HOLEY_ELEMENTS.
  ElementAccess access = AccessBuilder::ForFixedArrayElement(HOLEY_ELEMENTS);
  Type* value_type = ValueTypeParameterOf(node->op());
  if (value_type->Is(Type::BooleanOrNullOrUndefined())) {
    access.type = value_type;
    access.write_barrier_kind = kNoWriteBarrier;
  }
  __ StoreElement(access, elements, index, value);
}

void EffectControlLinearizer::LowerStoreSignedSmallElement(Node* node) {
  Node* array = node->InputAt(0);
  Node* index = node->InputAt(1);
  Node* value = node->InputAt(2);  // int32

3591 3592 3593 3594 3595 3596
  // Store a signed small in an output array.
  //
  //   kind = ElementsKind(array)
  //
  //   -- STORE PHASE ----------------------
  //   if kind == HOLEY_DOUBLE_ELEMENTS {
3597
  //     float_value = convert int32 to float
3598 3599 3600
  //     Store array[index] = float_value
  //   } else {
  //     // kind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS
3601 3602
  //     smi_value = convert int32 to smi
  //     Store array[index] = smi_value
3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627
  //   }
  //
  Node* map = __ LoadField(AccessBuilder::ForMap(), array);
  Node* kind;
  {
    Node* bit_field2 = __ LoadField(AccessBuilder::ForMapBitField2(), map);
    Node* mask = __ Int32Constant(Map::ElementsKindBits::kMask);
    Node* andit = __ Word32And(bit_field2, mask);
    Node* shift = __ Int32Constant(Map::ElementsKindBits::kShift);
    kind = __ Word32Shr(andit, shift);
  }

  Node* elements = __ LoadField(AccessBuilder::ForJSObjectElements(), array);
  auto if_kind_is_double = __ MakeLabel();
  auto done = __ MakeLabel();
  __ GotoIf(IsElementsKindGreaterThan(kind, HOLEY_ELEMENTS),
            &if_kind_is_double);
  {
    // Our ElementsKind is HOLEY_SMI_ELEMENTS or HOLEY_ELEMENTS.
    // In this case, we know our value is a signed small, and we can optimize
    // the ElementAccess information.
    ElementAccess access = AccessBuilder::ForFixedArrayElement();
    access.type = Type::SignedSmall();
    access.machine_type = MachineType::TaggedSigned();
    access.write_barrier_kind = kNoWriteBarrier;
3628 3629
    Node* smi_value = ChangeInt32ToSmi(value);
    __ StoreElement(access, elements, index, smi_value);
3630 3631 3632 3633 3634
    __ Goto(&done);
  }
  __ Bind(&if_kind_is_double);
  {
    // Our ElementsKind is HOLEY_DOUBLE_ELEMENTS.
3635
    Node* float_value = __ ChangeInt32ToFloat64(value);
3636 3637 3638 3639 3640 3641 3642 3643
    __ StoreElement(AccessBuilder::ForFixedDoubleArrayElement(), elements,
                    index, float_value);
    __ Goto(&done);
  }

  __ Bind(&done);
}

3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654
void EffectControlLinearizer::LowerRuntimeAbort(Node* node) {
  BailoutReason reason = BailoutReasonOf(node->op());
  Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
  Runtime::FunctionId id = Runtime::kAbort;
  CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
      graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
  __ Call(desc, __ CEntryStubConstant(1), jsgraph()->SmiConstant(reason),
          __ ExternalConstant(ExternalReference(id, isolate())),
          __ Int32Constant(1), __ NoContextConstant());
}

3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741
Node* EffectControlLinearizer::LowerConvertReceiver(Node* node) {
  ConvertReceiverMode const mode = ConvertReceiverModeOf(node->op());
  Node* value = node->InputAt(0);
  Node* global_proxy = node->InputAt(1);

  switch (mode) {
    case ConvertReceiverMode::kNullOrUndefined: {
      return global_proxy;
    }
    case ConvertReceiverMode::kNotNullOrUndefined: {
      auto convert_to_object = __ MakeDeferredLabel();
      auto done_convert = __ MakeLabel(MachineRepresentation::kTagged);

      // Check if {value} is already a JSReceiver.
      __ GotoIf(ObjectIsSmi(value), &convert_to_object);
      STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
      Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
      Node* value_instance_type =
          __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
      Node* check = __ Uint32LessThan(
          value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE));
      __ GotoIf(check, &convert_to_object);
      __ Goto(&done_convert, value);

      // Wrap the primitive {value} into a JSValue.
      __ Bind(&convert_to_object);
      Operator::Properties properties = Operator::kEliminatable;
      Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
      CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
      CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
          isolate(), graph()->zone(), callable.descriptor(), 0, flags,
          properties);
      Node* native_context = __ LoadField(
          AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy);
      Node* result = __ Call(desc, __ HeapConstant(callable.code()), value,
                             native_context);
      __ Goto(&done_convert, result);

      __ Bind(&done_convert);
      return done_convert.PhiAt(0);
    }
    case ConvertReceiverMode::kAny: {
      auto convert_to_object = __ MakeDeferredLabel();
      auto convert_global_proxy = __ MakeDeferredLabel();
      auto done_convert = __ MakeLabel(MachineRepresentation::kTagged);

      // Check if {value} is already a JSReceiver, or null/undefined.
      __ GotoIf(ObjectIsSmi(value), &convert_to_object);
      STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
      Node* value_map = __ LoadField(AccessBuilder::ForMap(), value);
      Node* value_instance_type =
          __ LoadField(AccessBuilder::ForMapInstanceType(), value_map);
      Node* check = __ Uint32LessThan(
          value_instance_type, __ Uint32Constant(FIRST_JS_RECEIVER_TYPE));
      __ GotoIf(check, &convert_to_object);
      __ Goto(&done_convert, value);

      // Wrap the primitive {value} into a JSValue.
      __ Bind(&convert_to_object);
      __ GotoIf(__ WordEqual(value, __ UndefinedConstant()),
                &convert_global_proxy);
      __ GotoIf(__ WordEqual(value, __ NullConstant()), &convert_global_proxy);
      Operator::Properties properties = Operator::kEliminatable;
      Callable callable = Builtins::CallableFor(isolate(), Builtins::kToObject);
      CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
      CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
          isolate(), graph()->zone(), callable.descriptor(), 0, flags,
          properties);
      Node* native_context = __ LoadField(
          AccessBuilder::ForJSGlobalProxyNativeContext(), global_proxy);
      Node* result = __ Call(desc, __ HeapConstant(callable.code()), value,
                             native_context);
      __ Goto(&done_convert, result);

      // Replace the {value} with the {global_proxy}.
      __ Bind(&convert_global_proxy);
      __ Goto(&done_convert, global_proxy);

      __ Bind(&done_convert);
      return done_convert.PhiAt(0);
    }
  }

  UNREACHABLE();
  return nullptr;
}

3742
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundUp(Node* node) {
3743 3744
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundUp().IsSupported()) {
3745
    return Nothing<Node*>();
3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772
  }

  Node* const input = node->InputAt(0);

  // General case for ceil.
  //
  //   if 0.0 < input then
  //     if 2^52 <= input then
  //       input
  //     else
  //       let temp1 = (2^52 + input) - 2^52 in
  //       if temp1 < input then
  //         temp1 + 1
  //       else
  //         temp1
  //   else
  //     if input == 0 then
  //       input
  //     else
  //       if input <= -2^52 then
  //         input
  //       else
  //         let temp1 = -0 - input in
  //         let temp2 = (2^52 + temp1) - 2^52 in
  //         let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in
  //         -0 - temp3

3773 3774 3775 3776 3777 3778
  auto if_not_positive = __ MakeDeferredLabel();
  auto if_greater_than_two_52 = __ MakeDeferredLabel();
  auto if_less_than_minus_two_52 = __ MakeDeferredLabel();
  auto if_zero = __ MakeDeferredLabel();
  auto done_temp3 = __ MakeLabel(MachineRepresentation::kFloat64);
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
3779

3780 3781 3782
  Node* const zero = __ Float64Constant(0.0);
  Node* const two_52 = __ Float64Constant(4503599627370496.0E0);
  Node* const one = __ Float64Constant(1.0);
3783

3784
  Node* check0 = __ Float64LessThan(zero, input);
3785
  __ GotoIfNot(check0, &if_not_positive);
3786 3787 3788
  {
    Node* check1 = __ Float64LessThanOrEqual(two_52, input);
    __ GotoIf(check1, &if_greater_than_two_52);
3789
    {
3790
      Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52);
3791
      __ GotoIfNot(__ Float64LessThan(temp1, input), &done, temp1);
3792
      __ Goto(&done, __ Float64Add(temp1, one));
3793 3794
    }

3795 3796
    __ Bind(&if_greater_than_two_52);
    __ Goto(&done, input);
3797 3798
  }

3799
  __ Bind(&if_not_positive);
3800
  {
3801 3802
    Node* check1 = __ Float64Equal(input, zero);
    __ GotoIf(check1, &if_zero);
3803

3804 3805 3806
    Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0);
    Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52);
    __ GotoIf(check2, &if_less_than_minus_two_52);
3807 3808

    {
3809 3810 3811 3812
      Node* const minus_zero = __ Float64Constant(-0.0);
      Node* temp1 = __ Float64Sub(minus_zero, input);
      Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52);
      Node* check3 = __ Float64LessThan(temp1, temp2);
3813
      __ GotoIfNot(check3, &done_temp3, temp2);
3814 3815 3816 3817 3818
      __ Goto(&done_temp3, __ Float64Sub(temp2, one));

      __ Bind(&done_temp3);
      Node* temp3 = done_temp3.PhiAt(0);
      __ Goto(&done, __ Float64Sub(minus_zero, temp3));
3819
    }
3820 3821
    __ Bind(&if_less_than_minus_two_52);
    __ Goto(&done, input);
3822

3823 3824
    __ Bind(&if_zero);
    __ Goto(&done, input);
3825
  }
3826 3827
  __ Bind(&done);
  return Just(done.PhiAt(0));
3828 3829
}

3830 3831 3832 3833 3834
Node* EffectControlLinearizer::BuildFloat64RoundDown(Node* value) {
  Node* round_down = __ Float64RoundDown(value);
  if (round_down != nullptr) {
    return round_down;
  }
3835

3836
  Node* const input = value;
3837

3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862
  // General case for floor.
  //
  //   if 0.0 < input then
  //     if 2^52 <= input then
  //       input
  //     else
  //       let temp1 = (2^52 + input) - 2^52 in
  //       if input < temp1 then
  //         temp1 - 1
  //       else
  //         temp1
  //   else
  //     if input == 0 then
  //       input
  //     else
  //       if input <= -2^52 then
  //         input
  //       else
  //         let temp1 = -0 - input in
  //         let temp2 = (2^52 + temp1) - 2^52 in
  //         if temp2 < temp1 then
  //           -1 - temp2
  //         else
  //           -0 - temp2

3863 3864 3865 3866 3867 3868
  auto if_not_positive = __ MakeDeferredLabel();
  auto if_greater_than_two_52 = __ MakeDeferredLabel();
  auto if_less_than_minus_two_52 = __ MakeDeferredLabel();
  auto if_temp2_lt_temp1 = __ MakeLabel();
  auto if_zero = __ MakeDeferredLabel();
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
3869 3870 3871 3872 3873

  Node* const zero = __ Float64Constant(0.0);
  Node* const two_52 = __ Float64Constant(4503599627370496.0E0);

  Node* check0 = __ Float64LessThan(zero, input);
3874
  __ GotoIfNot(check0, &if_not_positive);
3875 3876 3877
  {
    Node* check1 = __ Float64LessThanOrEqual(two_52, input);
    __ GotoIf(check1, &if_greater_than_two_52);
3878
    {
3879 3880
      Node* const one = __ Float64Constant(1.0);
      Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52);
3881
      __ GotoIfNot(__ Float64LessThan(input, temp1), &done, temp1);
3882 3883
      __ Goto(&done, __ Float64Sub(temp1, one));
    }
3884

3885 3886 3887
    __ Bind(&if_greater_than_two_52);
    __ Goto(&done, input);
  }
3888

3889 3890 3891 3892
  __ Bind(&if_not_positive);
  {
    Node* check1 = __ Float64Equal(input, zero);
    __ GotoIf(check1, &if_zero);
3893

3894 3895 3896
    Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0);
    Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52);
    __ GotoIf(check2, &if_less_than_minus_two_52);
3897

3898 3899 3900 3901 3902 3903 3904 3905 3906 3907
    {
      Node* const minus_zero = __ Float64Constant(-0.0);
      Node* temp1 = __ Float64Sub(minus_zero, input);
      Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52);
      Node* check3 = __ Float64LessThan(temp2, temp1);
      __ GotoIf(check3, &if_temp2_lt_temp1);
      __ Goto(&done, __ Float64Sub(minus_zero, temp2));

      __ Bind(&if_temp2_lt_temp1);
      __ Goto(&done, __ Float64Sub(__ Float64Constant(-1.0), temp2));
3908
    }
3909 3910
    __ Bind(&if_less_than_minus_two_52);
    __ Goto(&done, input);
3911

3912 3913
    __ Bind(&if_zero);
    __ Goto(&done, input);
3914
  }
3915 3916
  __ Bind(&done);
  return done.PhiAt(0);
3917 3918
}

3919
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundDown(Node* node) {
3920 3921
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundDown().IsSupported()) {
3922
    return Nothing<Node*>();
3923 3924
  }

3925
  Node* const input = node->InputAt(0);
3926
  return Just(BuildFloat64RoundDown(input));
3927 3928
}

3929
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node) {
3930 3931
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundTiesEven().IsSupported()) {
3932
    return Nothing<Node*>();
3933 3934
  }

3935 3936
  Node* const input = node->InputAt(0);

3937
  // Generate case for round ties to even:
3938
  //
3939 3940 3941 3942 3943 3944
  //   let value = floor(input) in
  //   let temp1 = input - value in
  //   if temp1 < 0.5 then
  //     value
  //   else if 0.5 < temp1 then
  //     value + 1.0
3945
  //   else
3946 3947 3948
  //     let temp2 = value % 2.0 in
  //     if temp2 == 0.0 then
  //       value
3949
  //     else
3950
  //       value + 1.0
3951

3952 3953
  auto if_is_half = __ MakeLabel();
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
3954

3955 3956
  Node* value = BuildFloat64RoundDown(input);
  Node* temp1 = __ Float64Sub(input, value);
3957

3958 3959 3960
  Node* const half = __ Float64Constant(0.5);
  Node* check0 = __ Float64LessThan(temp1, half);
  __ GotoIf(check0, &done, value);
3961

3962 3963
  Node* const one = __ Float64Constant(1.0);
  Node* check1 = __ Float64LessThan(half, temp1);
3964
  __ GotoIfNot(check1, &if_is_half);
3965
  __ Goto(&done, __ Float64Add(value, one));
3966

3967 3968 3969 3970 3971
  __ Bind(&if_is_half);
  Node* temp2 = __ Float64Mod(value, __ Float64Constant(2.0));
  Node* check2 = __ Float64Equal(temp2, __ Float64Constant(0.0));
  __ GotoIf(check2, &done, value);
  __ Goto(&done, __ Float64Add(value, one));
3972

3973 3974
  __ Bind(&done);
  return Just(done.PhiAt(0));
3975 3976
}

3977
Maybe<Node*> EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node) {
3978 3979
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundTruncate().IsSupported()) {
3980
    return Nothing<Node*>();
3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010
  }

  Node* const input = node->InputAt(0);

  // General case for trunc.
  //
  //   if 0.0 < input then
  //     if 2^52 <= input then
  //       input
  //     else
  //       let temp1 = (2^52 + input) - 2^52 in
  //       if input < temp1 then
  //         temp1 - 1
  //       else
  //         temp1
  //   else
  //     if input == 0 then
  //       input
  //     else
  //       if input <= -2^52 then
  //         input
  //       else
  //         let temp1 = -0 - input in
  //         let temp2 = (2^52 + temp1) - 2^52 in
  //         let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in
  //         -0 - temp3
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.

4011 4012 4013 4014 4015 4016
  auto if_not_positive = __ MakeDeferredLabel();
  auto if_greater_than_two_52 = __ MakeDeferredLabel();
  auto if_less_than_minus_two_52 = __ MakeDeferredLabel();
  auto if_zero = __ MakeDeferredLabel();
  auto done_temp3 = __ MakeLabel(MachineRepresentation::kFloat64);
  auto done = __ MakeLabel(MachineRepresentation::kFloat64);
4017

4018 4019 4020
  Node* const zero = __ Float64Constant(0.0);
  Node* const two_52 = __ Float64Constant(4503599627370496.0E0);
  Node* const one = __ Float64Constant(1.0);
4021

4022
  Node* check0 = __ Float64LessThan(zero, input);
4023
  __ GotoIfNot(check0, &if_not_positive);
4024 4025 4026
  {
    Node* check1 = __ Float64LessThanOrEqual(two_52, input);
    __ GotoIf(check1, &if_greater_than_two_52);
4027
    {
4028
      Node* temp1 = __ Float64Sub(__ Float64Add(two_52, input), two_52);
4029
      __ GotoIfNot(__ Float64LessThan(input, temp1), &done, temp1);
4030
      __ Goto(&done, __ Float64Sub(temp1, one));
4031 4032
    }

4033 4034
    __ Bind(&if_greater_than_two_52);
    __ Goto(&done, input);
4035 4036
  }

4037
  __ Bind(&if_not_positive);
4038
  {
4039 4040
    Node* check1 = __ Float64Equal(input, zero);
    __ GotoIf(check1, &if_zero);
4041

4042 4043 4044
    Node* const minus_two_52 = __ Float64Constant(-4503599627370496.0E0);
    Node* check2 = __ Float64LessThanOrEqual(input, minus_two_52);
    __ GotoIf(check2, &if_less_than_minus_two_52);
4045 4046

    {
4047 4048 4049 4050
      Node* const minus_zero = __ Float64Constant(-0.0);
      Node* temp1 = __ Float64Sub(minus_zero, input);
      Node* temp2 = __ Float64Sub(__ Float64Add(two_52, temp1), two_52);
      Node* check3 = __ Float64LessThan(temp1, temp2);
4051
      __ GotoIfNot(check3, &done_temp3, temp2);
4052 4053 4054 4055 4056
      __ Goto(&done_temp3, __ Float64Sub(temp2, one));

      __ Bind(&done_temp3);
      Node* temp3 = done_temp3.PhiAt(0);
      __ Goto(&done, __ Float64Sub(minus_zero, temp3));
4057
    }
4058 4059
    __ Bind(&if_less_than_minus_two_52);
    __ Goto(&done, input);
4060

4061 4062
    __ Bind(&if_zero);
    __ Goto(&done, input);
4063
  }
4064 4065
  __ Bind(&done);
  return Just(done.PhiAt(0));
4066 4067
}

4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105
Node* EffectControlLinearizer::LowerFindOrderedHashMapEntry(Node* node) {
  Node* table = NodeProperties::GetValueInput(node, 0);
  Node* key = NodeProperties::GetValueInput(node, 1);

  {
    Callable const callable =
        Builtins::CallableFor(isolate(), Builtins::kFindOrderedHashMapEntry);
    Operator::Properties const properties = node->op()->properties();
    CallDescriptor::Flags const flags = CallDescriptor::kNoFlags;
    CallDescriptor* desc = Linkage::GetStubCallDescriptor(
        isolate(), graph()->zone(), callable.descriptor(), 0, flags,
        properties);
    return __ Call(desc, __ HeapConstant(callable.code()), table, key,
                   __ NoContextConstant());
  }
}

Node* EffectControlLinearizer::ComputeIntegerHash(Node* value) {
  // See v8::internal::ComputeIntegerHash()
  value = __ Int32Add(__ Word32Xor(value, __ Int32Constant(0xffffffff)),
                      __ Word32Shl(value, __ Int32Constant(15)));
  value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(12)));
  value = __ Int32Add(value, __ Word32Shl(value, __ Int32Constant(2)));
  value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(4)));
  value = __ Int32Mul(value, __ Int32Constant(2057));
  value = __ Word32Xor(value, __ Word32Shr(value, __ Int32Constant(16)));
  value = __ Word32And(value, __ Int32Constant(0x3fffffff));
  return value;
}

Node* EffectControlLinearizer::LowerFindOrderedHashMapEntryForInt32Key(
    Node* node) {
  Node* table = NodeProperties::GetValueInput(node, 0);
  Node* key = NodeProperties::GetValueInput(node, 1);

  // Compute the integer hash code.
  Node* hash = ChangeUint32ToUintPtr(ComputeIntegerHash(key));

4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121
  Node* number_of_buckets = ChangeSmiToIntPtr(__ LoadField(
      AccessBuilder::ForOrderedHashTableBaseNumberOfBuckets(), table));
  hash = __ WordAnd(hash, __ IntSub(number_of_buckets, __ IntPtrConstant(1)));
  Node* first_entry = ChangeSmiToIntPtr(__ Load(
      MachineType::TaggedSigned(), table,
      __ IntAdd(__ WordShl(hash, __ IntPtrConstant(kPointerSizeLog2)),
                __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset -
                                  kHeapObjectTag))));

  auto loop = __ MakeLoopLabel(MachineType::PointerRepresentation());
  auto done = __ MakeLabel(MachineRepresentation::kWord32);
  __ Goto(&loop, first_entry);
  __ Bind(&loop);
  {
    Node* entry = loop.PhiAt(0);
    Node* check =
4122
        __ WordEqual(entry, __ IntPtrConstant(OrderedHashMap::kNotFound));
4123
    __ GotoIf(check, &done, __ Int32Constant(-1));
4124
    entry = __ IntAdd(
4125 4126 4127 4128 4129
        __ IntMul(entry, __ IntPtrConstant(OrderedHashMap::kEntrySize)),
        number_of_buckets);

    Node* candidate_key = __ Load(
        MachineType::AnyTagged(), table,
4130
        __ IntAdd(__ WordShl(entry, __ IntPtrConstant(kPointerSizeLog2)),
4131 4132 4133 4134 4135
                  __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset -
                                    kHeapObjectTag)));

    auto if_match = __ MakeLabel();
    auto if_notmatch = __ MakeLabel();
4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149
    auto if_notsmi = __ MakeDeferredLabel();
    __ GotoIfNot(ObjectIsSmi(candidate_key), &if_notsmi);
    __ Branch(__ Word32Equal(ChangeSmiToInt32(candidate_key), key), &if_match,
              &if_notmatch);

    __ Bind(&if_notsmi);
    __ GotoIfNot(
        __ WordEqual(__ LoadField(AccessBuilder::ForMap(), candidate_key),
                     __ HeapNumberMapConstant()),
        &if_notmatch);
    __ Branch(__ Float64Equal(__ LoadField(AccessBuilder::ForHeapNumberValue(),
                                           candidate_key),
                              __ ChangeInt32ToFloat64(key)),
              &if_match, &if_notmatch);
4150 4151 4152

    __ Bind(&if_match);
    {
4153
      Node* index = ChangeIntPtrToInt32(entry);
4154 4155 4156 4157 4158 4159 4160 4161
      __ Goto(&done, index);
    }

    __ Bind(&if_notmatch);
    {
      Node* next_entry = ChangeSmiToIntPtr(__ Load(
          MachineType::TaggedSigned(), table,
          __ IntAdd(
4162
              __ WordShl(entry, __ IntPtrConstant(kPointerSizeLog2)),
4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173
              __ IntPtrConstant(OrderedHashMap::kHashTableStartOffset +
                                OrderedHashMap::kChainOffset * kPointerSize -
                                kHeapObjectTag))));
      __ Goto(&loop, next_entry);
    }
  }

  __ Bind(&done);
  return done.PhiAt(0);
}

4174 4175
#undef __

4176 4177 4178 4179 4180 4181 4182 4183
Factory* EffectControlLinearizer::factory() const {
  return isolate()->factory();
}

Isolate* EffectControlLinearizer::isolate() const {
  return jsgraph()->isolate();
}

4184 4185 4186
}  // namespace compiler
}  // namespace internal
}  // namespace v8