lithium-x64.cc 85.9 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/crankshaft/x64/lithium-x64.h"
6

7 8
#include <sstream>

9
#if V8_TARGET_ARCH_X64
10

11 12 13
#include "src/crankshaft/hydrogen-osr.h"
#include "src/crankshaft/lithium-inl.h"
#include "src/crankshaft/x64/lithium-codegen-x64.h"
14 15 16 17

namespace v8 {
namespace internal {

18 19 20 21 22 23 24
#define DEFINE_COMPILE(type)                            \
  void L##type::CompileToNative(LCodeGen* generator) {  \
    generator->Do##type(this);                          \
  }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE

25

26 27
#ifdef DEBUG
void LInstruction::VerifyCall() {
28 29 30 31
  // Call instructions can use only fixed registers as temporaries and
  // outputs because all registers are blocked by the calling convention.
  // Inputs operands must use a fixed register or use-at-start policy or
  // a non-register policy.
32
  DCHECK(Output() == NULL ||
33 34
         LUnallocated::cast(Output())->HasFixedPolicy() ||
         !LUnallocated::cast(Output())->HasRegisterPolicy());
35 36
  for (UseIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
37
    DCHECK(operand->HasFixedPolicy() ||
38
           operand->IsUsedAtStart());
39
  }
40 41
  for (TempIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
42
    DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
43 44 45 46 47
  }
}
#endif


48 49
void LInstruction::PrintTo(StringStream* stream) {
  stream->Add("%s ", this->Mnemonic());
50 51

  PrintOutputOperandTo(stream);
52

53 54 55 56
  PrintDataTo(stream);

  if (HasEnvironment()) {
    stream->Add(" ");
57
    environment()->PrintTo(stream);
58 59 60 61
  }

  if (HasPointerMap()) {
    stream->Add(" ");
62 63 64 65 66
    pointer_map()->PrintTo(stream);
  }
}


67
void LInstruction::PrintDataTo(StringStream* stream) {
68
  stream->Add("= ");
69
  for (int i = 0; i < InputCount(); i++) {
70
    if (i > 0) stream->Add(" ");
71 72 73 74 75
    if (InputAt(i) == NULL) {
      stream->Add("NULL");
    } else {
      InputAt(i)->PrintTo(stream);
    }
76
  }
77 78 79
}


80 81
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
  if (HasResult()) result()->PrintTo(stream);
82 83 84 85
}


void LLabel::PrintDataTo(StringStream* stream) {
fschneider@chromium.org's avatar
fschneider@chromium.org committed
86
  LGap::PrintDataTo(stream);
87 88 89 90 91 92 93
  LLabel* rep = replacement();
  if (rep != NULL) {
    stream->Add(" Dead block replaced with B%d", rep->block_id());
  }
}


94 95 96 97 98 99
bool LGap::IsRedundant() const {
  for (int i = 0; i < 4; i++) {
    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
      return false;
    }
  }
fschneider@chromium.org's avatar
fschneider@chromium.org committed
100

101 102 103 104
  return true;
}


105
void LGap::PrintDataTo(StringStream* stream) {
106 107 108 109 110 111 112 113 114 115
  for (int i = 0; i < 4; i++) {
    stream->Add("(");
    if (parallel_moves_[i] != NULL) {
      parallel_moves_[i]->PrintDataTo(stream);
    }
    stream->Add(") ");
  }
}


116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
const char* LArithmeticD::Mnemonic() const {
  switch (op()) {
    case Token::ADD: return "add-d";
    case Token::SUB: return "sub-d";
    case Token::MUL: return "mul-d";
    case Token::DIV: return "div-d";
    case Token::MOD: return "mod-d";
    default:
      UNREACHABLE();
      return NULL;
  }
}


const char* LArithmeticT::Mnemonic() const {
  switch (op()) {
    case Token::ADD: return "add-t";
    case Token::SUB: return "sub-t";
    case Token::MUL: return "mul-t";
    case Token::MOD: return "mod-t";
    case Token::DIV: return "div-t";
137 138 139
    case Token::BIT_AND: return "bit-and-t";
    case Token::BIT_OR: return "bit-or-t";
    case Token::BIT_XOR: return "bit-xor-t";
140
    case Token::ROR: return "ror-t";
141 142 143
    case Token::SHL: return "sal-t";
    case Token::SAR: return "sar-t";
    case Token::SHR: return "shr-t";
144 145 146 147 148 149 150
    default:
      UNREACHABLE();
      return NULL;
  }
}


151 152 153 154 155
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
  return !gen->IsNextEmittedBlock(block_id());
}


156 157 158 159
template<int R>
bool LTemplateResultInstruction<R>::MustSignExtendResult(
    LPlatformChunk* chunk) const {
  HValue* hvalue = this->hydrogen_value();
160 161 162
  return hvalue != NULL &&
      hvalue->representation().IsInteger32() &&
      chunk->GetDehoistedKeyIds()->Contains(hvalue->id());
163 164 165
}


166 167 168 169 170
void LGoto::PrintDataTo(StringStream* stream) {
  stream->Add("B%d", block_id());
}


171 172
void LBranch::PrintDataTo(StringStream* stream) {
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
173
  value()->PrintTo(stream);
174 175 176
}


177
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
178
  stream->Add("if ");
179
  left()->PrintTo(stream);
180
  stream->Add(" %s ", Token::String(op()));
181
  right()->PrintTo(stream);
182 183 184 185
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}


186 187
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_string(");
188
  value()->PrintTo(stream);
189 190 191 192
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


193 194
void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_smi(");
195
  value()->PrintTo(stream);
196 197 198 199
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


200 201
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_undetectable(");
202
  value()->PrintTo(stream);
203 204 205 206
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


207 208
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if string_compare(");
209 210
  left()->PrintTo(stream);
  right()->PrintTo(stream);
211 212 213 214
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


215 216
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if has_instance_type(");
217
  value()->PrintTo(stream);
218 219 220 221 222 223
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if has_cached_array_index(");
224
  value()->PrintTo(stream);
225 226 227 228 229 230
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if class_of_test(");
231
  value()->PrintTo(stream);
232 233 234 235 236 237 238 239 240
  stream->Add(", \"%o\") then B%d else B%d",
              *hydrogen()->class_name(),
              true_block_id(),
              false_block_id());
}


void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if typeof ");
241
  value()->PrintTo(stream);
242
  stream->Add(" == \"%s\" then B%d else B%d",
243
              hydrogen()->type_literal()->ToCString().get(),
244 245 246 247
              true_block_id(), false_block_id());
}


248 249 250 251 252 253 254 255
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  function()->PrintTo(stream);
  stream->Add(".code_entry = ");
  code_object()->PrintTo(stream);
}


256 257 258
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  base_object()->PrintTo(stream);
259 260
  stream->Add(" + ");
  offset()->PrintTo(stream);
261 262 263
}


264 265 266 267 268
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
  for (int i = 0; i < InputCount(); i++) {
    InputAt(i)->PrintTo(stream);
    stream->Add(" ");
  }
269 270 271 272
  stream->Add("#%d / ", arity());
}


273
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
274
  context()->PrintTo(stream);
275
  stream->Add("[%d]", slot_index());
276 277 278
}


279
void LStoreContextSlot::PrintDataTo(StringStream* stream) {
280
  context()->PrintTo(stream);
whesse@chromium.org's avatar
whesse@chromium.org committed
281
  stream->Add("[%d] <- ", slot_index());
282
  value()->PrintTo(stream);
283 284 285
}


286 287
void LInvokeFunction::PrintDataTo(StringStream* stream) {
  stream->Add("= ");
288
  function()->PrintTo(stream);
289 290 291 292
  stream->Add(" #%d / ", arity());
}


293 294 295 296
void LCallNewArray::PrintDataTo(StringStream* stream) {
  stream->Add("= ");
  constructor()->PrintTo(stream);
  stream->Add(" #%d / ", arity());
297
  ElementsKind kind = hydrogen()->elements_kind();
298 299 300 301
  stream->Add(" (%s) ", ElementsKindToString(kind));
}


302 303 304 305 306 307 308 309 310 311 312
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
  arguments()->PrintTo(stream);

  stream->Add(" length ");
  length()->PrintTo(stream);

  stream->Add(" index ");
  index()->PrintTo(stream);
}


313
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
314 315
  if (kind == DOUBLE_REGISTERS && kDoubleSize == 2 * kPointerSize) {
    // Skip a slot if for a double-width slot for x32 port.
316
    current_frame_slots_++;
317 318 319 320 321
    // The spill slot's address is at rbp - (index + 1) * kPointerSize -
    // StandardFrameConstants::kFixedFrameSizeFromFp. kFixedFrameSizeFromFp is
    // 2 * kPointerSize, if rbp is aligned at 8-byte boundary, the below "|= 1"
    // will make sure the spilled doubles are aligned at 8-byte boundary.
    // TODO(haitao): make sure rbp is aligned at 8-byte boundary for x32 port.
322
    current_frame_slots_ |= 1;
323
  }
324
  return current_frame_slots_++;
325 326 327
}


328
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
329 330 331
  // All stack slots are Double stack slots on x64.
  // Alternatively, at some point, start using half-size
  // stack slots for int32 values.
332 333
  int index = GetNextSpillIndex(kind);
  if (kind == DOUBLE_REGISTERS) {
334
    return LDoubleStackSlot::Create(index, zone());
335
  } else {
336
    DCHECK(kind == GENERAL_REGISTERS);
337
    return LStackSlot::Create(index, zone());
338
  }
339 340 341
}


342
void LStoreNamedField::PrintDataTo(StringStream* stream) {
343
  object()->PrintTo(stream);
344
  std::ostringstream os;
345
  os << hydrogen()->access() << " <- ";
346
  stream->Add(os.str().c_str());
347 348 349 350
  value()->PrintTo(stream);
}


351 352 353
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(".");
354
  stream->Add(String::cast(*name())->ToCString().get());
355 356 357 358 359
  stream->Add(" <- ");
  value()->PrintTo(stream);
}


360 361 362 363 364
void LLoadKeyed::PrintDataTo(StringStream* stream) {
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  if (hydrogen()->IsDehoisted()) {
365
    stream->Add(" + %d]", base_offset());
366 367 368 369 370 371
  } else {
    stream->Add("]");
  }
}


372
void LStoreKeyed::PrintDataTo(StringStream* stream) {
373 374 375
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
376
  if (hydrogen()->IsDehoisted()) {
377
    stream->Add(" + %d] <-", base_offset());
378 379 380
  } else {
    stream->Add("] <- ");
  }
381 382

  if (value() == NULL) {
383
    DCHECK(hydrogen()->IsConstantHoleStore() &&
384 385 386 387 388
           hydrogen()->value()->representation().IsDouble());
    stream->Add("<the hole(nan)>");
  } else {
    value()->PrintTo(stream);
  }
389 390 391
}


392
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
393 394 395 396 397 398 399 400
  object()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  stream->Add("] <- ");
  value()->PrintTo(stream);
}


401 402 403 404 405 406
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}


407
LPlatformChunk* LChunkBuilder::Build() {
408
  DCHECK(is_unused());
409
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
410
  LPhase phase("L_Building chunk", chunk_);
411
  status_ = BUILDING;
412 413 414 415 416

  // If compiling for OSR, reserve space for the unoptimized frame,
  // which will be subsumed into this frame.
  if (graph()->has_osr()) {
    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
417
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
418 419 420
    }
  }

421 422 423 424 425 426 427 428 429 430 431 432
  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
  for (int i = 0; i < blocks->length(); i++) {
    HBasicBlock* next = NULL;
    if (i < blocks->length() - 1) next = blocks->at(i + 1);
    DoBasicBlock(blocks->at(i), next);
    if (is_aborted()) return NULL;
  }
  status_ = DONE;
  return chunk_;
}


433
LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
434
  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
435 436 437 438
}


LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
439 440
  return new (zone())
      LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
441 442 443 444 445 446 447 448 449 450 451 452 453 454
}


LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
  return Use(value, ToUnallocated(fixed_register));
}


LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
  return Use(value, ToUnallocated(reg));
}


LOperand* LChunkBuilder::UseRegister(HValue* value) {
455
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
456 457 458 459 460
}


LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
  return Use(value,
461
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
462 463 464 465 466
                              LUnallocated::USED_AT_START));
}


LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
467
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
468 469 470
}


471 472 473 474 475 476 477
LOperand* LChunkBuilder::UseTempRegisterOrConstant(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseTempRegister(value);
}


478
LOperand* LChunkBuilder::Use(HValue* value) {
479
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
480 481 482 483
}


LOperand* LChunkBuilder::UseAtStart(HValue* value) {
484
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
                                     LUnallocated::USED_AT_START));
}


LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : Use(value);
}


LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseAtStart(value);
}


LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegister(value);
}


LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegisterAtStart(value);
}


517 518 519 520 521
LOperand* LChunkBuilder::UseConstant(HValue* value) {
  return chunk_->DefineConstantOperand(HConstant::cast(value));
}


522 523 524
LOperand* LChunkBuilder::UseAny(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
525
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
526 527 528
}


529 530 531 532 533
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
  if (value->EmitAtUses()) {
    HInstruction* instr = HInstruction::cast(value);
    VisitInstruction(instr);
  }
534
  operand->set_virtual_register(value->id());
535 536 537 538
  return operand;
}


539
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
540
                                    LUnallocated* result) {
541
  result->set_virtual_register(current_instruction_->id());
542 543 544 545 546 547
  instr->set_result(result);
  return instr;
}


LInstruction* LChunkBuilder::DefineAsRegister(
548
    LTemplateResultInstruction<1>* instr) {
549 550
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
551 552 553 554
}


LInstruction* LChunkBuilder::DefineAsSpilled(
555
    LTemplateResultInstruction<1>* instr,
556
    int index) {
557 558
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
559 560 561 562
}


LInstruction* LChunkBuilder::DefineSameAsFirst(
563
    LTemplateResultInstruction<1>* instr) {
564 565
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
566 567 568
}


569
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
570 571 572 573 574 575
                                         Register reg) {
  return Define(instr, ToUnallocated(reg));
}


LInstruction* LChunkBuilder::DefineFixedDouble(
576
    LTemplateResultInstruction<1>* instr,
577 578 579 580 581 582 583
    XMMRegister reg) {
  return Define(instr, ToUnallocated(reg));
}


LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
  HEnvironment* hydrogen_env = current_block_->last_environment();
584
  return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
585 586 587 588 589 590
}


LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
                                        HInstruction* hinstr,
                                        CanDeoptimize can_deoptimize) {
591 592
  info()->MarkAsNonDeferredCalling();

593 594 595 596
#ifdef DEBUG
  instr->VerifyCall();
#endif
  instr->MarkAsCall();
597 598 599 600 601 602 603
  instr = AssignPointerMap(instr);

  // If instruction does not have side-effects lazy deoptimization
  // after the call will try to deoptimize to the point before the call.
  // Thus we still need to attach environment to this call even if
  // call sequence can not deoptimize eagerly.
  bool needs_environment =
604 605
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
      !hinstr->HasObservableSideEffects();
606 607
  if (needs_environment && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
608 609
    // We can't really figure out if the environment is needed or not.
    instr->environment()->set_has_been_used();
610 611 612 613 614 615 616
  }

  return instr;
}


LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
617
  DCHECK(!instr->HasPointerMap());
618
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
619 620 621 622 623
  return instr;
}


LUnallocated* LChunkBuilder::TempRegister() {
624 625
  LUnallocated* operand =
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
626 627
  int vreg = allocator_->GetVirtualRegister();
  if (!allocator_->AllocationOk()) {
628
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
629
    vreg = 0;
630 631
  }
  operand->set_virtual_register(vreg);
632 633 634 635 636 637
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(Register reg) {
  LUnallocated* operand = ToUnallocated(reg);
638
  DCHECK(operand->HasFixedPolicy());
639 640 641 642 643 644
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
  LUnallocated* operand = ToUnallocated(reg);
645
  DCHECK(operand->HasFixedPolicy());
646 647 648 649 650
  return operand;
}


LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
651
  return new(zone()) LLabel(instr->block());
652 653 654
}


655 656 657 658 659
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
}


660 661 662 663 664 665
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
  UNREACHABLE();
  return NULL;
}


666
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
667
  return AssignEnvironment(new(zone()) LDeoptimize);
668 669 670
}


671 672
LInstruction* LChunkBuilder::DoShift(Token::Value op,
                                     HBitwiseBinaryOperation* instr) {
673
  if (instr->representation().IsSmiOrInteger32()) {
674 675
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
676
    LOperand* left = UseRegisterAtStart(instr->left());
677

678 679 680
    HValue* right_value = instr->right();
    LOperand* right = NULL;
    int constant_value = 0;
681
    bool does_deopt = false;
682 683 684 685
    if (right_value->IsConstant()) {
      HConstant* constant = HConstant::cast(right_value);
      right = chunk_->DefineConstantOperand(constant);
      constant_value = constant->Integer32Value() & 0x1f;
686 687 688 689 690 691
      if (SmiValuesAre31Bits() && instr->representation().IsSmi() &&
          constant_value > 0) {
        // Left shift can deoptimize if we shift by > 0 and the result
        // cannot be truncated to smi.
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
      }
692
    } else {
693
      right = UseFixed(right_value, rcx);
694 695
    }

696 697 698
    // Shift operations can only deoptimize if we do a logical shift by 0 and
    // the result cannot be truncated to int32.
    if (op == Token::SHR && constant_value == 0) {
699
      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
700 701 702 703 704 705 706 707
    }

    LInstruction* result =
        DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
    return does_deopt ? AssignEnvironment(result) : result;
  } else {
    return DoArithmeticT(op, instr);
  }
708 709 710 711 712
}


LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
                                           HArithmeticBinaryOperation* instr) {
713 714 715
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->left()->representation().IsDouble());
  DCHECK(instr->right()->representation().IsDouble());
716
  if (op == Token::MOD) {
717
    LOperand* left = UseFixedDouble(instr->BetterLeftOperand(), xmm0);
718
    LOperand* right = UseFixedDouble(instr->BetterRightOperand(), xmm1);
719
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
720
    return MarkAsCall(DefineFixedDouble(result, xmm0), instr);
721 722 723 724
  } else {
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
725 726
    return CpuFeatures::IsSupported(AVX) ? DefineAsRegister(result)
                                         : DefineSameAsFirst(result);
727
  }
728 729 730 731
}


LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
732
                                           HBinaryOperation* instr) {
733 734
  HValue* left = instr->left();
  HValue* right = instr->right();
735 736
  DCHECK(left->representation().IsTagged());
  DCHECK(right->representation().IsTagged());
737
  LOperand* context = UseFixed(instr->context(), rsi);
738 739
  LOperand* left_operand = UseFixed(left, rdx);
  LOperand* right_operand = UseFixed(right, rax);
740
  LArithmeticT* result =
741
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
742
  return MarkAsCall(DefineFixed(result, rax), instr);
743 744
}

745

746
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
747
  DCHECK(is_building());
748 749 750 751 752 753 754 755
  current_block_ = block;
  next_block_ = next_block;
  if (block->IsStartBlock()) {
    block->UpdateEnvironment(graph_->start_environment());
    argument_count_ = 0;
  } else if (block->predecessors()->length() == 1) {
    // We have a single predecessor => copy environment and outgoing
    // argument count from the predecessor.
756
    DCHECK(block->phis()->length() == 0);
757 758
    HBasicBlock* pred = block->predecessors()->at(0);
    HEnvironment* last_environment = pred->last_environment();
759
    DCHECK(last_environment != NULL);
760 761
    // Only copy the environment, if it is later used again.
    if (pred->end()->SecondSuccessor() == NULL) {
762
      DCHECK(pred->end()->FirstSuccessor() == block);
763 764 765 766 767 768 769
    } else {
      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
        last_environment = last_environment->Copy();
      }
    }
    block->UpdateEnvironment(last_environment);
770
    DCHECK(pred->argument_count() >= 0);
771 772 773 774 775 776 777 778
    argument_count_ = pred->argument_count();
  } else {
    // We are at a state join => process phis.
    HBasicBlock* pred = block->predecessors()->at(0);
    // No need to copy the environment, it cannot be used later.
    HEnvironment* last_environment = pred->last_environment();
    for (int i = 0; i < block->phis()->length(); ++i) {
      HPhi* phi = block->phis()->at(i);
779
      if (phi->HasMergedIndex()) {
780 781
        last_environment->SetValueAt(phi->merged_index(), phi);
      }
782 783
    }
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
784 785 786 787
      if (block->deleted_phis()->at(i) < last_environment->length()) {
        last_environment->SetValueAt(block->deleted_phis()->at(i),
                                     graph_->GetConstantUndefined());
      }
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
    }
    block->UpdateEnvironment(last_environment);
    // Pick up the outgoing argument count of one of the predecessors.
    argument_count_ = pred->argument_count();
  }
  HInstruction* current = block->first();
  int start = chunk_->instructions()->length();
  while (current != NULL && !is_aborted()) {
    // Code for constants in registers is generated lazily.
    if (!current->EmitAtUses()) {
      VisitInstruction(current);
    }
    current = current->next();
  }
  int end = chunk_->instructions()->length() - 1;
  if (end >= start) {
    block->set_first_instruction_index(start);
    block->set_last_instruction_index(end);
  }
  block->set_argument_count(argument_count_);
  next_block_ = NULL;
  current_block_ = NULL;
810 811 812
}


813 814 815
void LChunkBuilder::VisitInstruction(HInstruction* current) {
  HInstruction* old_current = current_instruction_;
  current_instruction_ = current;
816 817 818

  LInstruction* instr = NULL;
  if (current->CanReplaceWithDummyUses()) {
819 820 821
    if (current->OperandCount() == 0) {
      instr = DefineAsRegister(new(zone()) LDummy());
    } else {
822
      DCHECK(!current->OperandAt(0)->IsControlInstruction());
823 824 825
      instr = DefineAsRegister(new(zone())
          LDummyUse(UseAny(current->OperandAt(0))));
    }
826
    for (int i = 1; i < current->OperandCount(); ++i) {
827
      if (current->OperandAt(i)->IsControlInstruction()) continue;
828 829 830 831 832 833
      LInstruction* dummy =
          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
      dummy->set_hydrogen_value(current);
      chunk_->AddInstruction(dummy, current_block_);
    }
  } else {
834 835 836 837 838 839 840 841
    HBasicBlock* successor;
    if (current->IsControlInstruction() &&
        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
        successor != NULL) {
      instr = new(zone()) LGoto(successor);
    } else {
      instr = current->CompileToLithium(this);
    }
842
  }
843

844
  argument_count_ += current->argument_delta();
845
  DCHECK(argument_count_ >= 0);
846

847
  if (instr != NULL) {
848 849 850 851 852 853 854 855 856 857 858 859
    AddInstruction(instr, current);
  }

  current_instruction_ = old_current;
}


void LChunkBuilder::AddInstruction(LInstruction* instr,
                                   HInstruction* hydrogen_val) {
  // Associate the hydrogen instruction first, since we may need it for
  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
  instr->set_hydrogen_value(hydrogen_val);
860

861
#if DEBUG
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
  // Make sure that the lithium instruction has either no fixed register
  // constraints in temps or the result OR no uses that are only used at
  // start. If this invariant doesn't hold, the register allocator can decide
  // to insert a split of a range immediately before the instruction due to an
  // already allocated register needing to be used for the instruction's fixed
  // register constraint. In this case, The register allocator won't see an
  // interference between the split child and the use-at-start (it would if
  // the it was just a plain use), so it is free to move the split child into
  // the same register that is used for the use-at-start.
  // See https://code.google.com/p/chromium/issues/detail?id=201590
  if (!(instr->ClobbersRegisters() &&
        instr->ClobbersDoubleRegisters(isolate()))) {
    int fixed = 0;
    int used_at_start = 0;
    for (UseIterator it(instr); !it.Done(); it.Advance()) {
      LUnallocated* operand = LUnallocated::cast(it.Current());
      if (operand->IsUsedAtStart()) ++used_at_start;
    }
    if (instr->Output() != NULL) {
      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
882
    }
883 884 885 886
    for (TempIterator it(instr); !it.Done(); it.Advance()) {
      LUnallocated* operand = LUnallocated::cast(it.Current());
      if (operand->HasFixedPolicy()) ++fixed;
    }
887
    DCHECK(fixed == 0 || used_at_start == 0);
888
  }
889 890
#endif

891 892 893 894 895 896 897 898
  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
    instr = AssignPointerMap(instr);
  }
  if (FLAG_stress_environments && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
  }
  chunk_->AddInstruction(instr, current_block_);

899
  CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
900 901 902 903
}


LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
904
  return new(zone()) LGoto(instr->FirstSuccessor());
905 906 907
}


908
LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
909
  LInstruction* result = new (zone()) LPrologue();
910
  if (info_->scope()->num_heap_slots() > 0) {
911 912 913
    result = MarkAsCall(result, instr);
  }
  return result;
914 915 916
}


917 918 919 920 921
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
  return new(zone()) LDebugBreak();
}


922
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
923
  HValue* value = instr->value();
924
  Representation r = value->representation();
925
  HType type = value->type();
926 927
  ToBooleanICStub::Types expected = instr->expected_input_types();
  if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
928 929 930 931 932

  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
      type.IsJSArray() || type.IsHeapNumber() || type.IsString();
  LInstruction* branch = new(zone()) LBranch(UseRegister(value));
  if (!easy_case &&
933
      ((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
934 935
       !expected.IsGeneric())) {
    branch = AssignEnvironment(branch);
936
  }
937
  return branch;
938 939 940
}


941
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
942
  DCHECK(instr->value()->representation().IsTagged());
943
  LOperand* value = UseRegisterAtStart(instr->value());
944
  return new(zone()) LCmpMapAndBranch(value);
945 946 947 948
}


LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
949
  info()->MarkAsRequiresFrame();
950
  return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
951 952 953 954
}


LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
955
  info()->MarkAsRequiresFrame();
956
  return DefineAsRegister(new(zone()) LArgumentsElements);
957 958 959
}


960 961 962 963
LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
    HHasInPrototypeChainAndBranch* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* prototype = UseRegister(instr->prototype());
964 965 966
  LHasInPrototypeChainAndBranch* result =
      new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
  return AssignEnvironment(result);
967 968 969
}


970 971 972 973 974 975 976 977
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
  LOperand* receiver = UseRegister(instr->receiver());
  LOperand* function = UseRegisterAtStart(instr->function());
  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
  return AssignEnvironment(DefineSameAsFirst(result));
}


978
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
979 980 981 982
  LOperand* function = UseFixed(instr->function(), rdi);
  LOperand* receiver = UseFixed(instr->receiver(), rax);
  LOperand* length = UseFixed(instr->length(), rbx);
  LOperand* elements = UseFixed(instr->elements(), rcx);
983
  LApplyArguments* result = new(zone()) LApplyArguments(function,
984 985 986 987
                                                receiver,
                                                length,
                                                elements);
  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
988 989 990
}


991 992 993 994 995 996 997
LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
  int argc = instr->OperandCount();
  for (int i = 0; i < argc; ++i) {
    LOperand* argument = UseOrConstant(instr->argument(i));
    AddInstruction(new(zone()) LPushArgument(argument), instr);
  }
  return NULL;
998 999 1000
}


1001 1002 1003 1004 1005 1006 1007 1008
LInstruction* LChunkBuilder::DoStoreCodeEntry(
    HStoreCodeEntry* store_code_entry) {
  LOperand* function = UseRegister(store_code_entry->function());
  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
  return new(zone()) LStoreCodeEntry(function, code_object);
}


1009
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1010 1011 1012 1013 1014
    HInnerAllocatedObject* instr) {
  LOperand* base_object = UseRegisterAtStart(instr->base_object());
  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
  return DefineAsRegister(
      new(zone()) LInnerAllocatedObject(base_object, offset));
1015 1016 1017
}


1018
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1019 1020 1021
  return instr->HasNoUses()
      ? NULL
      : DefineAsRegister(new(zone()) LThisFunction);
1022 1023 1024
}


1025
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1026 1027 1028 1029
  if (instr->HasNoUses()) return NULL;

  if (info()->IsStub()) {
    return DefineFixed(new(zone()) LContext, rsi);
1030 1031
  }

1032
  return DefineAsRegister(new(zone()) LContext);
1033 1034 1035
}


1036
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1037 1038
  LOperand* context = UseFixed(instr->context(), rsi);
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1039 1040 1041
}


1042 1043
LInstruction* LChunkBuilder::DoCallWithDescriptor(
    HCallWithDescriptor* instr) {
1044
  CallInterfaceDescriptor descriptor = instr->descriptor();
1045 1046 1047

  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1048
  // Target
1049
  ops.Add(target, zone());
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
  // Context
  LOperand* op = UseFixed(instr->OperandAt(1), rsi);
  ops.Add(op, zone());
  // Other register parameters
  for (int i = LCallWithDescriptor::kImplicitRegisterParameterCount;
       i < instr->OperandCount(); i++) {
    op =
        UseFixed(instr->OperandAt(i),
                 descriptor.GetRegisterParameter(
                     i - LCallWithDescriptor::kImplicitRegisterParameterCount));
1060 1061 1062 1063 1064
    ops.Add(op, zone());
  }

  LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
      descriptor, ops, zone());
1065 1066 1067
  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
    result->MarkAsSyntacticTailCall();
  }
1068
  return MarkAsCall(DefineFixed(result, rax), instr);
1069 1070 1071
}


1072
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1073
  LOperand* context = UseFixed(instr->context(), rsi);
1074
  LOperand* function = UseFixed(instr->function(), rdi);
1075
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1076 1077 1078
  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
    result->MarkAsSyntacticTailCall();
  }
1079 1080 1081 1082
  return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}


1083
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1084
  switch (instr->op()) {
1085 1086 1087 1088 1089 1090 1091 1092
    case kMathFloor:
      return DoMathFloor(instr);
    case kMathRound:
      return DoMathRound(instr);
    case kMathFround:
      return DoMathFround(instr);
    case kMathAbs:
      return DoMathAbs(instr);
1093 1094
    case kMathCos:
      return DoMathCos(instr);
1095 1096 1097 1098
    case kMathLog:
      return DoMathLog(instr);
    case kMathExp:
      return DoMathExp(instr);
1099 1100
    case kMathSin:
      return DoMathSin(instr);
1101 1102 1103 1104 1105 1106
    case kMathSqrt:
      return DoMathSqrt(instr);
    case kMathPowHalf:
      return DoMathPowHalf(instr);
    case kMathClz32:
      return DoMathClz32(instr);
1107 1108 1109
    default:
      UNREACHABLE();
      return NULL;
1110
  }
1111 1112
}

1113
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1114
  DCHECK(instr->value()->representation().IsDouble());
1115
  LOperand* input = UseRegisterAtStart(instr->value());
1116 1117 1118 1119 1120 1121 1122 1123
  if (instr->representation().IsInteger32()) {
    LMathFloorI* result = new (zone()) LMathFloorI(input);
    return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
  } else {
    DCHECK(instr->representation().IsDouble());
    LMathFloorD* result = new (zone()) LMathFloorD(input);
    return DefineAsRegister(result);
  }
1124 1125 1126
}

LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1127
  DCHECK(instr->value()->representation().IsDouble());
1128
  LOperand* input = UseRegister(instr->value());
1129 1130 1131 1132 1133 1134 1135 1136 1137
  if (instr->representation().IsInteger32()) {
    LOperand* temp = FixedTemp(xmm4);
    LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
    return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
  } else {
    DCHECK(instr->representation().IsDouble());
    LMathRoundD* result = new (zone()) LMathRoundD(input);
    return DefineAsRegister(result);
  }
1138 1139
}

1140 1141 1142 1143 1144 1145 1146
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
  LOperand* input = UseRegister(instr->value());
  LMathFround* result = new (zone()) LMathFround(input);
  return DefineAsRegister(result);
}


1147
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1148
  LOperand* context = UseAny(instr->context());
1149
  LOperand* input = UseRegisterAtStart(instr->value());
1150 1151 1152 1153 1154 1155
  LInstruction* result =
      DefineSameAsFirst(new(zone()) LMathAbs(context, input));
  Representation r = instr->value()->representation();
  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
  if (!r.IsDouble()) result = AssignEnvironment(result);
  return result;
1156 1157 1158 1159
}


LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1160 1161
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
1162 1163 1164
  LOperand* input = UseFixedDouble(instr->value(), xmm0);
  return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), xmm0),
                    instr);
1165 1166 1167
}


1168 1169 1170 1171 1172 1173
LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
  LOperand* input = UseRegisterAtStart(instr->value());
  LMathClz32* result = new(zone()) LMathClz32(input);
  return DefineAsRegister(result);
}

1174 1175 1176 1177 1178 1179 1180
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
  LOperand* input = UseFixedDouble(instr->value(), xmm0);
  return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), xmm0),
                    instr);
}
1181

1182
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1183 1184
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
1185 1186 1187
  LOperand* input = UseFixedDouble(instr->value(), xmm0);
  return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), xmm0),
                    instr);
1188 1189
}

1190 1191 1192 1193 1194 1195 1196
LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
  LOperand* input = UseFixedDouble(instr->value(), xmm0);
  return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), xmm0),
                    instr);
}
1197 1198

LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1199 1200
  LOperand* input = UseAtStart(instr->value());
  return DefineAsRegister(new(zone()) LMathSqrt(input));
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
}


LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
  LOperand* input = UseRegisterAtStart(instr->value());
  LMathPowHalf* result = new(zone()) LMathPowHalf(input);
  return DefineSameAsFirst(result);
}


1211
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1212
  LOperand* context = UseFixed(instr->context(), rsi);
1213
  LOperand* constructor = UseFixed(instr->constructor(), rdi);
1214
  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1215 1216 1217 1218
  return MarkAsCall(DefineFixed(result, rax), instr);
}


1219
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1220 1221 1222
  LOperand* context = UseFixed(instr->context(), rsi);
  LCallRuntime* result = new(zone()) LCallRuntime(context);
  return MarkAsCall(DefineFixed(result, rax), instr);
1223 1224 1225
}


1226 1227 1228 1229 1230
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
  return DoShift(Token::ROR, instr);
}


1231
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1232
  return DoShift(Token::SHR, instr);
1233 1234 1235 1236
}


LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1237
  return DoShift(Token::SAR, instr);
1238 1239 1240 1241
}


LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1242
  return DoShift(Token::SHL, instr);
1243 1244 1245
}


1246
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1247
  if (instr->representation().IsSmiOrInteger32()) {
1248 1249 1250
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1251

1252
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1253 1254 1255 1256 1257 1258 1259
    LOperand* right;
    if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
      // We don't support tagged immediates, so we request it in a register.
      right = UseRegisterAtStart(instr->BetterRightOperand());
    } else {
      right = UseOrConstantAtStart(instr->BetterRightOperand());
    }
1260
    return DefineSameAsFirst(new(zone()) LBitI(left, right));
1261
  } else {
1262
    return DoArithmeticT(instr->op(), instr);
1263
  }
1264 1265 1266
}


1267
LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1268 1269 1270
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1271 1272
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1273 1274 1275 1276
  LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
          dividend, divisor));
  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1277
      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1278 1279 1280 1281
       divisor != 1 && divisor != -1)) {
    result = AssignEnvironment(result);
  }
  return result;
1282 1283 1284
}


1285
LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1286 1287 1288
  DCHECK(instr->representation().IsInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1289 1290 1291 1292
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
  LOperand* temp1 = FixedTemp(rax);
  LOperand* temp2 = FixedTemp(rdx);
1293 1294 1295 1296 1297 1298 1299 1300
  LInstruction* result = DefineFixed(new(zone()) LDivByConstI(
          dividend, divisor, temp1, temp2), rdx);
  if (divisor == 0 ||
      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
    result = AssignEnvironment(result);
  }
  return result;
1301 1302 1303
}


1304
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1305 1306 1307
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1308 1309 1310
  LOperand* dividend = UseFixed(instr->left(), rax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(rdx);
1311 1312 1313 1314 1315
  LInstruction* result = DefineFixed(new(zone()) LDivI(
          dividend, divisor, temp), rax);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
      instr->CheckFlag(HValue::kCanOverflow) ||
1316
      !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1317 1318 1319
    result = AssignEnvironment(result);
  }
  return result;
1320 1321 1322
}


1323
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1324
  if (instr->representation().IsSmiOrInteger32()) {
1325 1326 1327 1328 1329 1330 1331
    if (instr->RightIsPowerOf2()) {
      return DoDivByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoDivByConstI(instr);
    } else {
      return DoDivI(instr);
    }
1332 1333
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::DIV, instr);
1334 1335 1336
  } else {
    return DoArithmeticT(Token::DIV, instr);
  }
1337 1338 1339
}


1340 1341 1342
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1343 1344 1345 1346 1347 1348 1349
  LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
          dividend, divisor));
  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
    result = AssignEnvironment(result);
  }
  return result;
1350 1351 1352 1353
}


LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1354 1355 1356
  DCHECK(instr->representation().IsInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1357
  LOperand* dividend = UseRegister(instr->left());
1358
  int32_t divisor = instr->right()->GetInteger32Constant();
1359 1360
  LOperand* temp1 = FixedTemp(rax);
  LOperand* temp2 = FixedTemp(rdx);
1361 1362 1363 1364
  LOperand* temp3 =
      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
      NULL : TempRegister();
1365
  LInstruction* result =
1366 1367 1368
      DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
                                                   divisor,
                                                   temp1,
1369 1370
                                                   temp2,
                                                   temp3),
1371
                  rdx);
1372 1373 1374 1375 1376
  if (divisor == 0 ||
      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
    result = AssignEnvironment(result);
  }
  return result;
1377
}
1378

1379

1380
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1381 1382 1383
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
  LOperand* dividend = UseFixed(instr->left(), rax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(rdx);
  LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
          dividend, divisor, temp), rax);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
      instr->CheckFlag(HValue::kCanOverflow)) {
    result = AssignEnvironment(result);
  }
  return result;
}


1398 1399 1400
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
  if (instr->RightIsPowerOf2()) {
    return DoFlooringDivByPowerOf2I(instr);
1401 1402
  } else if (instr->right()->IsConstant()) {
    return DoFlooringDivByConstI(instr);
1403
  } else {
1404
    return DoFlooringDivI(instr);
1405 1406 1407 1408
  }
}


1409
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1410 1411 1412
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1413 1414
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1415 1416
  LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
          dividend, divisor));
1417 1418
  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1419 1420 1421
    result = AssignEnvironment(result);
  }
  return result;
1422 1423 1424
}


1425
LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1426 1427 1428
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1429 1430 1431 1432
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
  LOperand* temp1 = FixedTemp(rax);
  LOperand* temp2 = FixedTemp(rdx);
1433 1434 1435 1436 1437 1438
  LInstruction* result = DefineFixed(new(zone()) LModByConstI(
          dividend, divisor, temp1, temp2), rax);
  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
  }
  return result;
1439 1440 1441
}


1442
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1443 1444 1445
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1446 1447 1448
  LOperand* dividend = UseFixed(instr->left(), rax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(rdx);
1449 1450 1451 1452 1453 1454 1455
  LInstruction* result = DefineFixed(new(zone()) LModI(
          dividend, divisor, temp), rdx);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
  }
  return result;
1456 1457 1458
}


1459
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1460
  if (instr->representation().IsSmiOrInteger32()) {
1461 1462 1463 1464 1465 1466 1467
    if (instr->RightIsPowerOf2()) {
      return DoModByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoModByConstI(instr);
    } else {
      return DoModI(instr);
    }
1468 1469
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::MOD, instr);
1470
  } else {
1471
    return DoArithmeticT(Token::MOD, instr);
1472
  }
1473 1474 1475 1476
}


LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1477
  if (instr->representation().IsSmiOrInteger32()) {
1478 1479
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1480
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1481 1482
    HValue* h_right = instr->BetterRightOperand();
    LOperand* right = UseOrConstant(h_right);
1483
    LMulI* mul = new(zone()) LMulI(left, right);
1484 1485 1486 1487 1488 1489 1490 1491 1492
    int constant_value =
        h_right->IsConstant() ? HConstant::cast(h_right)->Integer32Value() : 0;
    // |needs_environment| must mirror the cases where LCodeGen::DoMulI calls
    // |DeoptimizeIf|.
    bool needs_environment =
        instr->CheckFlag(HValue::kCanOverflow) ||
        (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
         (!right->IsConstantOperand() || constant_value <= 0));
    if (needs_environment) {
1493 1494 1495
      AssignEnvironment(mul);
    }
    return DefineSameAsFirst(mul);
1496 1497 1498 1499 1500
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::MUL, instr);
  } else {
    return DoArithmeticT(Token::MUL, instr);
  }
1501 1502 1503 1504
}


LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1505
  if (instr->representation().IsSmiOrInteger32()) {
1506 1507
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1508
    LOperand* left = UseRegisterAtStart(instr->left());
1509 1510 1511 1512 1513 1514 1515
    LOperand* right;
    if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
      // We don't support tagged immediates, so we request it in a register.
      right = UseRegisterAtStart(instr->right());
    } else {
      right = UseOrConstantAtStart(instr->right());
    }
1516
    LSubI* sub = new(zone()) LSubI(left, right);
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
    LInstruction* result = DefineSameAsFirst(sub);
    if (instr->CheckFlag(HValue::kCanOverflow)) {
      result = AssignEnvironment(result);
    }
    return result;
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::SUB, instr);
  } else {
    return DoArithmeticT(Token::SUB, instr);
  }
1527 1528 1529 1530
}


LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1531
  if (instr->representation().IsSmiOrInteger32()) {
1532 1533 1534 1535 1536
    // Check to see if it would be advantageous to use an lea instruction rather
    // than an add. This is the case when no overflow check is needed and there
    // are multiple uses of the add's inputs, so using a 3-register add will
    // preserve all input values for later uses.
    bool use_lea = LAddI::UseLea(instr);
1537 1538
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1539 1540
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    HValue* right_candidate = instr->BetterRightOperand();
1541
    LOperand* right;
1542
    if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
1543 1544 1545 1546 1547 1548 1549
      // We cannot add a tagged immediate to a tagged value,
      // so we request it in a register.
      right = UseRegisterAtStart(right_candidate);
    } else {
      right = use_lea ? UseRegisterOrConstantAtStart(right_candidate)
                      : UseOrConstantAtStart(right_candidate);
    }
1550
    LAddI* add = new(zone()) LAddI(left, right);
1551
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1552 1553
    LInstruction* result = use_lea ? DefineAsRegister(add)
                                   : DefineSameAsFirst(add);
1554
    if (can_overflow) {
1555 1556 1557
      result = AssignEnvironment(result);
    }
    return result;
1558
  } else if (instr->representation().IsExternal()) {
1559
    DCHECK(instr->IsConsistentExternalRepresentation());
1560
    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
    bool use_lea = LAddI::UseLea(instr);
    LOperand* left = UseRegisterAtStart(instr->left());
    HValue* right_candidate = instr->right();
    LOperand* right = use_lea
        ? UseRegisterOrConstantAtStart(right_candidate)
        : UseOrConstantAtStart(right_candidate);
    LAddI* add = new(zone()) LAddI(left, right);
    LInstruction* result = use_lea
        ? DefineAsRegister(add)
        : DefineSameAsFirst(add);
    return result;
1572
  } else if (instr->representation().IsDouble()) {
ager@chromium.org's avatar
ager@chromium.org committed
1573
    return DoArithmeticD(Token::ADD, instr);
1574 1575 1576
  } else {
    return DoArithmeticT(Token::ADD, instr);
  }
1577 1578 1579 1580
  return NULL;
}


1581 1582 1583
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
  LOperand* left = NULL;
  LOperand* right = NULL;
1584 1585
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1586 1587 1588 1589
  if (instr->representation().IsSmi()) {
    left = UseRegisterAtStart(instr->BetterLeftOperand());
    right = UseAtStart(instr->BetterRightOperand());
  } else if (instr->representation().IsInteger32()) {
1590 1591
    left = UseRegisterAtStart(instr->BetterLeftOperand());
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1592
  } else {
1593
    DCHECK(instr->representation().IsDouble());
1594 1595 1596 1597 1598 1599 1600 1601
    left = UseRegisterAtStart(instr->left());
    right = UseRegisterAtStart(instr->right());
  }
  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
  return DefineSameAsFirst(minmax);
}


1602
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1603
  DCHECK(instr->representation().IsDouble());
1604 1605 1606
  // We call a C function for double power. It can't trigger a GC.
  // We need to use fixed result register for the call.
  Representation exponent_type = instr->right()->representation();
1607
  DCHECK(instr->left()->representation().IsDouble());
1608
  LOperand* left = UseFixedDouble(instr->left(), xmm2);
1609 1610 1611 1612
  LOperand* right =
      exponent_type.IsDouble()
          ? UseFixedDouble(instr->right(), xmm1)
          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1613
  LPower* result = new(zone()) LPower(left, right);
1614
  return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1615
                    CAN_DEOPTIMIZE_EAGERLY);
1616 1617 1618
}


1619
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1620 1621
  DCHECK(instr->left()->representation().IsTagged());
  DCHECK(instr->right()->representation().IsTagged());
1622
  LOperand* context = UseFixed(instr->context(), rsi);
1623 1624
  LOperand* left = UseFixed(instr->left(), rdx);
  LOperand* right = UseFixed(instr->right(), rax);
1625
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1626
  return MarkAsCall(DefineFixed(result, rax), instr);
1627 1628 1629
}


1630 1631
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
    HCompareNumericAndBranch* instr) {
1632
  Representation r = instr->representation();
1633
  if (r.IsSmiOrInteger32()) {
1634 1635
    DCHECK(instr->left()->representation().Equals(r));
    DCHECK(instr->right()->representation().Equals(r));
1636
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1637
    LOperand* right = UseOrConstantAtStart(instr->right());
1638
    return new(zone()) LCompareNumericAndBranch(left, right);
1639
  } else {
1640 1641 1642
    DCHECK(r.IsDouble());
    DCHECK(instr->left()->representation().IsDouble());
    DCHECK(instr->right()->representation().IsDouble());
1643 1644 1645 1646 1647 1648 1649 1650 1651
    LOperand* left;
    LOperand* right;
    if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
      left = UseRegisterOrConstantAtStart(instr->left());
      right = UseRegisterOrConstantAtStart(instr->right());
    } else {
      left = UseRegisterAtStart(instr->left());
      right = UseRegisterAtStart(instr->right());
    }
1652
    return new(zone()) LCompareNumericAndBranch(left, right);
1653
  }
1654 1655 1656
}


1657 1658
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
    HCompareObjectEqAndBranch* instr) {
1659
  LOperand* left = UseRegisterAtStart(instr->left());
1660
  LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1661
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1662 1663 1664
}


1665 1666
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
    HCompareHoleAndBranch* instr) {
1667 1668
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LCmpHoleAndBranch(value);
1669 1670 1671
}


1672
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1673
  DCHECK(instr->value()->representation().IsTagged());
1674
  LOperand* value = UseRegisterAtStart(instr->value());
1675
  LOperand* temp = TempRegister();
1676
  return new(zone()) LIsStringAndBranch(value, temp);
1677 1678 1679
}


1680
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1681
  DCHECK(instr->value()->representation().IsTagged());
1682
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1683 1684 1685
}


1686 1687
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
    HIsUndetectableAndBranch* instr) {
1688
  DCHECK(instr->value()->representation().IsTagged());
1689 1690 1691
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* temp = TempRegister();
  return new(zone()) LIsUndetectableAndBranch(value, temp);
1692 1693 1694
}


1695 1696 1697
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
    HStringCompareAndBranch* instr) {

1698 1699
  DCHECK(instr->left()->representation().IsTagged());
  DCHECK(instr->right()->representation().IsTagged());
1700
  LOperand* context = UseFixed(instr->context(), rsi);
1701 1702
  LOperand* left = UseFixed(instr->left(), rdx);
  LOperand* right = UseFixed(instr->right(), rax);
1703
  LStringCompareAndBranch* result =
1704
      new(zone()) LStringCompareAndBranch(context, left, right);
1705 1706 1707 1708 1709

  return MarkAsCall(result, instr);
}


1710 1711
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
    HHasInstanceTypeAndBranch* instr) {
1712
  DCHECK(instr->value()->representation().IsTagged());
1713 1714
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LHasInstanceTypeAndBranch(value);
1715 1716 1717
}


1718 1719
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
    HGetCachedArrayIndex* instr)  {
1720
  DCHECK(instr->value()->representation().IsTagged());
1721 1722
  LOperand* value = UseRegisterAtStart(instr->value());

1723
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1724 1725 1726
}


1727 1728
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
    HHasCachedArrayIndexAndBranch* instr) {
1729
  DCHECK(instr->value()->representation().IsTagged());
1730 1731
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LHasCachedArrayIndexAndBranch(value);
1732 1733 1734
}


1735 1736
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
    HClassOfTestAndBranch* instr) {
1737 1738 1739 1740
  LOperand* value = UseRegister(instr->value());
  return new(zone()) LClassOfTestAndBranch(value,
                                           TempRegister(),
                                           TempRegister());
1741 1742 1743
}


1744 1745 1746 1747 1748 1749 1750
LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
  LOperand* string = UseRegisterAtStart(instr->string());
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
  return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
}


1751
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1752
  LOperand* string = UseRegisterAtStart(instr->string());
1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
  LOperand* index = FLAG_debug_code
      ? UseRegisterAtStart(instr->index())
      : UseRegisterOrConstantAtStart(instr->index());
  LOperand* value = FLAG_debug_code
      ? UseRegisterAtStart(instr->value())
      : UseRegisterOrConstantAtStart(instr->value());
  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), rsi) : NULL;
  LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
                                                       index, value);
  if (FLAG_debug_code) {
    result = MarkAsCall(result, instr);
  }
  return result;
1766 1767 1768
}


1769
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779
  if (!FLAG_debug_code && instr->skip_check()) return NULL;
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
  LOperand* length = !index->IsConstantOperand()
      ? UseOrConstantAtStart(instr->length())
      : UseAtStart(instr->length());
  LInstruction* result = new(zone()) LBoundsCheck(index, length);
  if (!FLAG_debug_code || !instr->skip_check()) {
    result = AssignEnvironment(result);
  }
  return result;
1780 1781 1782
}


1783 1784 1785 1786 1787 1788 1789
LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
  // The control instruction marking the end of a block that completed
  // abruptly (e.g., threw an exception).  There is nothing specific to do.
  return NULL;
}


1790 1791 1792 1793 1794
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
  return NULL;
}


1795 1796 1797 1798 1799 1800 1801 1802
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
  // All HForceRepresentation instructions should be eliminated in the
  // representation change phase of Hydrogen.
  UNREACHABLE();
  return NULL;
}


1803
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1804 1805
  Representation from = instr->from();
  Representation to = instr->to();
1806
  HValue* val = instr->value();
1807 1808
  if (from.IsSmi()) {
    if (to.IsTagged()) {
1809
      LOperand* value = UseRegister(val);
1810 1811 1812 1813
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
    }
    from = Representation::Tagged();
  }
1814 1815
  if (from.IsTagged()) {
    if (to.IsDouble()) {
1816 1817 1818 1819
      LOperand* value = UseRegister(val);
      LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
      return result;
1820
    } else if (to.IsSmi()) {
1821
      LOperand* value = UseRegister(val);
1822 1823 1824
      if (val->type().IsSmi()) {
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
      }
1825
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1826
    } else {
1827
      DCHECK(to.IsInteger32());
1828
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1829
        LOperand* value = UseRegister(val);
1830
        return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1831
      } else {
1832
        LOperand* value = UseRegister(val);
1833 1834
        bool truncating = instr->CanTruncateToInt32();
        LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1835
        LInstruction* result =
1836
            DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
1837
        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1838
        return result;
1839 1840 1841 1842
      }
    }
  } else if (from.IsDouble()) {
    if (to.IsTagged()) {
1843
      info()->MarkAsDeferredCalling();
1844
      LOperand* value = UseRegister(val);
1845 1846
      LOperand* temp = TempRegister();
      LUnallocated* result_temp = TempRegister();
1847
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1848
      return AssignPointerMap(Define(result, result_temp));
1849
    } else if (to.IsSmi()) {
1850
      LOperand* value = UseRegister(val);
1851 1852
      return AssignEnvironment(
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1853
    } else {
1854
      DCHECK(to.IsInteger32());
1855
      LOperand* value = UseRegister(val);
1856
      LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
1857
      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1858
      return result;
1859 1860
    }
  } else if (from.IsInteger32()) {
1861
    info()->MarkAsDeferredCalling();
1862
    if (to.IsTagged()) {
1863
      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1864
        LOperand* value = UseRegister(val);
1865 1866
        return DefineAsRegister(new(zone()) LSmiTag(value));
      } else if (val->CheckFlag(HInstruction::kUint32)) {
1867
        LOperand* value = UseRegister(val);
1868 1869 1870
        LOperand* temp1 = TempRegister();
        LOperand* temp2 = FixedTemp(xmm1);
        LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1871
        return AssignPointerMap(DefineSameAsFirst(result));
1872
      } else {
1873
        LOperand* value = UseRegister(val);
1874 1875 1876
        LOperand* temp1 = SmiValuesAre32Bits() ? NULL : TempRegister();
        LOperand* temp2 = SmiValuesAre32Bits() ? NULL : FixedTemp(xmm1);
        LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
1877
        return AssignPointerMap(DefineSameAsFirst(result));
1878
      }
1879 1880
    } else if (to.IsSmi()) {
      LOperand* value = UseRegister(val);
1881 1882 1883
      LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
      if (instr->CheckFlag(HValue::kCanOverflow)) {
        result = AssignEnvironment(result);
1884
      }
1885
      return result;
1886
    } else {
1887
      DCHECK(to.IsDouble());
1888
      if (val->CheckFlag(HInstruction::kUint32)) {
1889
        return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1890
      } else {
1891
        LOperand* value = Use(val);
1892 1893
        return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
      }
1894 1895 1896
    }
  }
  UNREACHABLE();
1897 1898 1899 1900
  return NULL;
}


1901
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1902
  LOperand* value = UseRegisterAtStart(instr->value());
1903
  LInstruction* result = new(zone()) LCheckNonSmi(value);
1904 1905 1906
  if (!instr->value()->type().IsHeapObject()) {
    result = AssignEnvironment(result);
  }
1907
  return result;
1908 1909 1910
}


1911 1912 1913 1914 1915 1916
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  return AssignEnvironment(new(zone()) LCheckSmi(value));
}


1917 1918 1919 1920 1921 1922 1923 1924 1925
LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
    HCheckArrayBufferNotNeutered* instr) {
  LOperand* view = UseRegisterAtStart(instr->value());
  LCheckArrayBufferNotNeutered* result =
      new (zone()) LCheckArrayBufferNotNeutered(view);
  return AssignEnvironment(result);
}


1926
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1927
  LOperand* value = UseRegisterAtStart(instr->value());
1928
  LCheckInstanceType* result = new(zone()) LCheckInstanceType(value);
1929
  return AssignEnvironment(result);
1930 1931 1932
}


1933
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1934
  LOperand* value = UseRegisterAtStart(instr->value());
1935
  return AssignEnvironment(new(zone()) LCheckValue(value));
1936 1937 1938
}


1939
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1940 1941 1942 1943 1944 1945
  if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
  LOperand* value = UseRegisterAtStart(instr->value());
  LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
  if (instr->HasMigrationTarget()) {
    info()->MarkAsDeferredCalling();
    result = AssignPointerMap(result);
1946 1947
  }
  return result;
1948 1949 1950
}


1951 1952 1953 1954 1955
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
  HValue* value = instr->value();
  Representation input_rep = value->representation();
  LOperand* reg = UseRegister(value);
  if (input_rep.IsDouble()) {
1956
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1957
  } else if (input_rep.IsInteger32()) {
1958
    return DefineSameAsFirst(new(zone()) LClampIToUint8(reg));
1959
  } else {
1960
    DCHECK(input_rep.IsSmiOrTagged());
1961 1962
    // Register allocator doesn't (yet) support allocation of double
    // temps. Reserve xmm1 explicitly.
1963 1964
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg,
                                                        FixedTemp(xmm1));
1965 1966 1967 1968 1969
    return AssignEnvironment(DefineSameAsFirst(result));
  }
}


1970
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1971
  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), rsi) : NULL;
1972
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1973 1974
  return new(zone()) LReturn(
      UseFixed(instr->value(), rax), context, parameter_count);
1975 1976 1977 1978
}


LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1979
  Representation r = instr->representation();
1980 1981 1982
  if (r.IsSmi()) {
    return DefineAsRegister(new(zone()) LConstantS);
  } else if (r.IsInteger32()) {
1983
    return DefineAsRegister(new(zone()) LConstantI);
1984
  } else if (r.IsDouble()) {
1985
    return DefineAsRegister(new (zone()) LConstantD);
1986 1987
  } else if (r.IsExternal()) {
    return DefineAsRegister(new(zone()) LConstantE);
1988
  } else if (r.IsTagged()) {
1989
    return DefineAsRegister(new(zone()) LConstantT);
1990 1991 1992 1993
  } else {
    UNREACHABLE();
    return NULL;
  }
1994 1995 1996
}


1997
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1998
  LOperand* context = UseFixed(instr->context(), rsi);
1999
  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2000

2001
  LLoadGlobalGeneric* result = new (zone()) LLoadGlobalGeneric(context, vector);
2002 2003 2004 2005
  return MarkAsCall(DefineFixed(result, rax), instr);
}


2006
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
whesse@chromium.org's avatar
whesse@chromium.org committed
2007
  LOperand* context = UseRegisterAtStart(instr->value());
2008 2009
  LInstruction* result =
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2010 2011 2012 2013
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2014 2015 2016
}


2017
LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
whesse@chromium.org's avatar
whesse@chromium.org committed
2018
  LOperand* context;
2019
  LOperand* value;
2020
  LOperand* temp;
2021
  context = UseRegister(instr->context());
2022 2023
  if (instr->NeedsWriteBarrier()) {
    value = UseTempRegister(instr->value());
2024
    temp = TempRegister();
2025 2026
  } else {
    value = UseRegister(instr->value());
2027
    temp = NULL;
2028
  }
2029
  LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2030 2031 2032 2033
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2034 2035 2036
}


2037
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2038 2039 2040 2041 2042 2043 2044 2045
  // Use the special mov rax, moffs64 encoding for external
  // memory accesses with 64-bit word-sized values.
  if (instr->access().IsExternalMemory() &&
      instr->access().offset() == 0 &&
      (instr->access().representation().IsSmi() ||
       instr->access().representation().IsTagged() ||
       instr->access().representation().IsHeapObject() ||
       instr->access().representation().IsExternal())) {
2046 2047 2048
    LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
    return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
  }
2049
  LOperand* obj = UseRegisterAtStart(instr->object());
2050
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2051 2052 2053 2054
}


LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2055
  LOperand* context = UseFixed(instr->context(), rsi);
2056
  LOperand* object =
2057
      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
2058
  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2059 2060
  LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(
      context, object, vector);
2061
  return MarkAsCall(DefineFixed(result, rax), instr);
2062 2063 2064 2065 2066
}


LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
    HLoadFunctionPrototype* instr) {
2067
  return AssignEnvironment(DefineAsRegister(
2068
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2069 2070 2071
}


2072 2073 2074 2075 2076
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
  return DefineAsRegister(new(zone()) LLoadRoot);
}


2077
void LChunkBuilder::FindDehoistedKeyDefinitions(HValue* candidate) {
2078 2079 2080 2081
  // We sign extend the dehoisted key at the definition point when the pointer
  // size is 64-bit. For x32 port, we sign extend the dehoisted key at the use
  // points and should not invoke this function. We can't use STATIC_ASSERT
  // here as the pointer size is 32-bit for x32.
2082
  DCHECK(kPointerSize == kInt64Size);
2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
  BitVector* dehoisted_key_ids = chunk_->GetDehoistedKeyIds();
  if (dehoisted_key_ids->Contains(candidate->id())) return;
  dehoisted_key_ids->Add(candidate->id());
  if (!candidate->IsPhi()) return;
  for (int i = 0; i < candidate->OperandCount(); ++i) {
    FindDehoistedKeyDefinitions(candidate->OperandAt(i));
  }
}


2093
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2094
  DCHECK((kPointerSize == kInt64Size &&
2095 2096 2097
          instr->key()->representation().IsInteger32()) ||
         (kPointerSize == kInt32Size &&
          instr->key()->representation().IsSmiOrInteger32()));
2098
  ElementsKind elements_kind = instr->elements_kind();
2099
  LOperand* key = NULL;
2100
  LInstruction* result = NULL;
2101

2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
  if (kPointerSize == kInt64Size) {
    key = UseRegisterOrConstantAtStart(instr->key());
  } else {
    bool clobbers_key = ExternalArrayOpRequiresTemp(
        instr->key()->representation(), elements_kind);
    key = clobbers_key
        ? UseTempRegister(instr->key())
        : UseRegisterOrConstantAtStart(instr->key());
  }

2112
  if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2113 2114 2115
    FindDehoistedKeyDefinitions(instr->key());
  }

2116
  if (!instr->is_fixed_typed_array()) {
2117
    LOperand* obj = UseRegisterAtStart(instr->elements());
2118
    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
2119
  } else {
2120
    DCHECK(
2121
        (instr->representation().IsInteger32() &&
2122
         !(IsDoubleOrFloatElementsKind(elements_kind))) ||
2123
        (instr->representation().IsDouble() &&
2124
         (IsDoubleOrFloatElementsKind(elements_kind))));
2125
    LOperand* backing_store = UseRegister(instr->elements());
2126 2127 2128
    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
    result = DefineAsRegister(
        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
2129
  }
2130

2131
  bool needs_environment;
2132
  if (instr->is_fixed_typed_array()) {
2133
    // see LCodeGen::DoLoadKeyedExternalArray
2134
    needs_environment = elements_kind == UINT32_ELEMENTS &&
2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
                        !instr->CheckFlag(HInstruction::kUint32);
  } else {
    // see LCodeGen::DoLoadKeyedFixedDoubleArray and
    // LCodeGen::DoLoadKeyedFixedArray
    needs_environment =
        instr->RequiresHoleCheck() ||
        (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
  }

  if (needs_environment) {
2145 2146 2147
    result = AssignEnvironment(result);
  }
  return result;
2148 2149 2150
}


2151
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2152
  LOperand* context = UseFixed(instr->context(), rsi);
2153
  LOperand* object =
2154 2155
      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
2156
  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2157

2158
  LLoadKeyedGeneric* result =
2159
      new(zone()) LLoadKeyedGeneric(context, object, key, vector);
2160
  return MarkAsCall(DefineFixed(result, rax), instr);
2161 2162 2163
}


2164
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2165
  ElementsKind elements_kind = instr->elements_kind();
2166

2167
  if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2168 2169 2170
    FindDehoistedKeyDefinitions(instr->key());
  }

2171
  if (!instr->is_fixed_typed_array()) {
2172
    DCHECK(instr->elements()->representation().IsTagged());
2173
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2174
    LOperand* object = NULL;
2175 2176 2177
    LOperand* key = NULL;
    LOperand* val = NULL;

2178 2179
    Representation value_representation = instr->value()->representation();
    if (value_representation.IsDouble()) {
2180
      object = UseRegisterAtStart(instr->elements());
2181
      val = UseRegisterAtStart(instr->value());
2182
      key = UseRegisterOrConstantAtStart(instr->key());
2183
    } else {
2184
      DCHECK(value_representation.IsSmiOrTagged() ||
2185
             value_representation.IsInteger32());
2186
      if (needs_write_barrier) {
2187
        object = UseTempRegister(instr->elements());
2188 2189 2190
        val = UseTempRegister(instr->value());
        key = UseTempRegister(instr->key());
      } else {
2191
        object = UseRegisterAtStart(instr->elements());
2192
        val = UseRegisterOrConstantAtStart(instr->value());
2193
        key = UseRegisterOrConstantAtStart(instr->key());
2194
      }
2195 2196
    }

2197
    return new (zone()) LStoreKeyed(object, key, val, nullptr);
2198 2199
  }

2200
  DCHECK(
2201 2202 2203 2204
       (instr->value()->representation().IsInteger32() &&
       !IsDoubleOrFloatElementsKind(elements_kind)) ||
       (instr->value()->representation().IsDouble() &&
       IsDoubleOrFloatElementsKind(elements_kind)));
2205
  DCHECK(instr->elements()->representation().IsExternal());
2206 2207
  bool val_is_temp_register = elements_kind == UINT8_CLAMPED_ELEMENTS ||
                              elements_kind == FLOAT32_ELEMENTS;
2208 2209
  LOperand* val = val_is_temp_register ? UseTempRegister(instr->value())
      : UseRegister(instr->value());
2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
  LOperand* key = NULL;
  if (kPointerSize == kInt64Size) {
    key = UseRegisterOrConstantAtStart(instr->key());
  } else {
    bool clobbers_key = ExternalArrayOpRequiresTemp(
        instr->key()->representation(), elements_kind);
    key = clobbers_key
        ? UseTempRegister(instr->key())
        : UseRegisterOrConstantAtStart(instr->key());
  }
2220
  LOperand* backing_store = UseRegister(instr->elements());
2221 2222
  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2223 2224 2225
}


2226
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2227
  LOperand* context = UseFixed(instr->context(), rsi);
2228
  LOperand* object =
2229 2230 2231
      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
  LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
  LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2232

2233 2234 2235
  DCHECK(instr->object()->representation().IsTagged());
  DCHECK(instr->key()->representation().IsTagged());
  DCHECK(instr->value()->representation().IsTagged());
2236

2237 2238
  LOperand* slot = FixedTemp(StoreWithVectorDescriptor::SlotRegister());
  LOperand* vector = FixedTemp(StoreWithVectorDescriptor::VectorRegister());
2239 2240 2241

  LStoreKeyedGeneric* result = new (zone())
      LStoreKeyedGeneric(context, object, key, value, slot, vector);
2242
  return MarkAsCall(result, instr);
2243 2244 2245
}


2246 2247
LInstruction* LChunkBuilder::DoTransitionElementsKind(
    HTransitionElementsKind* instr) {
2248
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2249 2250 2251
    LOperand* object = UseRegister(instr->object());
    LOperand* new_map_reg = TempRegister();
    LOperand* temp_reg = TempRegister();
2252 2253
    LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(
        object, NULL, new_map_reg, temp_reg);
2254
    return result;
2255
  } else {
2256
    LOperand* object = UseFixed(instr->object(), rax);
2257
    LOperand* context = UseFixed(instr->context(), rsi);
2258
    LTransitionElementsKind* result =
2259
        new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2260
    return MarkAsCall(result, instr);
2261 2262 2263 2264
  }
}


2265 2266 2267 2268 2269 2270 2271 2272 2273 2274
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
    HTrapAllocationMemento* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* temp = TempRegister();
  LTrapAllocationMemento* result =
      new(zone()) LTrapAllocationMemento(object, temp);
  return AssignEnvironment(result);
}


2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
  info()->MarkAsDeferredCalling();
  LOperand* context = UseFixed(instr->context(), rsi);
  LOperand* object = Use(instr->object());
  LOperand* elements = Use(instr->elements());
  LOperand* key = UseRegisterOrConstant(instr->key());
  LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());

  LMaybeGrowElements* result = new (zone())
      LMaybeGrowElements(context, object, elements, key, current_capacity);
  DefineFixed(result, rax);
  return AssignPointerMap(AssignEnvironment(result));
}


2290
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2291
  bool is_in_object = instr->access().IsInobject();
2292 2293
  bool is_external_location = instr->access().IsExternalMemory() &&
      instr->access().offset() == 0;
2294
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2295 2296
  bool needs_write_barrier_for_map = instr->has_transition() &&
      instr->NeedsWriteBarrierForMap();
2297 2298 2299

  LOperand* obj;
  if (needs_write_barrier) {
2300
    obj = is_in_object
2301 2302
        ? UseRegister(instr->object())
        : UseTempRegister(instr->object());
2303
  } else if (is_external_location) {
2304 2305 2306
    DCHECK(!is_in_object);
    DCHECK(!needs_write_barrier);
    DCHECK(!needs_write_barrier_for_map);
2307
    obj = UseRegisterOrConstant(instr->object());
2308
  } else {
2309 2310 2311
    obj = needs_write_barrier_for_map
        ? UseRegister(instr->object())
        : UseRegisterAtStart(instr->object());
2312
  }
2313

2314
  bool can_be_constant = instr->value()->IsConstant() &&
2315
      HConstant::cast(instr->value())->NotInNewSpace() &&
2316
      !instr->field_representation().IsDouble();
2317

2318 2319 2320
  LOperand* val;
  if (needs_write_barrier) {
    val = UseTempRegister(instr->value());
2321 2322
  } else if (is_external_location) {
    val = UseFixed(instr->value(), rax);
2323
  } else if (can_be_constant) {
2324
    val = UseRegisterOrConstant(instr->value());
2325
  } else if (instr->field_representation().IsDouble()) {
2326
    val = UseRegisterAtStart(instr->value());
2327 2328 2329
  } else {
    val = UseRegister(instr->value());
  }
2330 2331 2332

  // We only need a scratch register if we have a write barrier or we
  // have a store into the properties array (not in-object-property).
2333 2334
  LOperand* temp = (!is_in_object || needs_write_barrier ||
      needs_write_barrier_for_map) ? TempRegister() : NULL;
2335

2336
  return new(zone()) LStoreNamedField(obj, val, temp);
2337 2338 2339 2340
}


LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2341
  LOperand* context = UseFixed(instr->context(), rsi);
2342
  LOperand* object =
2343 2344
      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
  LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2345 2346
  LOperand* slot = FixedTemp(StoreWithVectorDescriptor::SlotRegister());
  LOperand* vector = FixedTemp(StoreWithVectorDescriptor::VectorRegister());
2347

2348
  LStoreNamedGeneric* result =
2349
      new (zone()) LStoreNamedGeneric(context, object, value, slot, vector);
2350
  return MarkAsCall(result, instr);
2351 2352 2353
}


2354
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2355
  LOperand* context = UseFixed(instr->context(), rsi);
2356 2357
  LOperand* left = UseFixed(instr->left(), rdx);
  LOperand* right = UseFixed(instr->right(), rax);
2358 2359
  return MarkAsCall(
      DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr);
2360 2361 2362
}


2363
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2364 2365
  LOperand* string = UseTempRegister(instr->string());
  LOperand* index = UseTempRegister(instr->index());
2366 2367 2368
  LOperand* context = UseAny(instr->context());
  LStringCharCodeAt* result =
      new(zone()) LStringCharCodeAt(context, string, index);
2369
  return AssignPointerMap(DefineAsRegister(result));
2370 2371 2372
}


2373 2374
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
  LOperand* char_code = UseRegister(instr->value());
2375 2376 2377
  LOperand* context = UseAny(instr->context());
  LStringCharFromCode* result =
      new(zone()) LStringCharFromCode(context, char_code);
2378 2379 2380 2381
  return AssignPointerMap(DefineAsRegister(result));
}


2382
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395
  LOperand* size = instr->size()->IsConstant() ? UseConstant(instr->size())
                                               : UseRegister(instr->size());
  if (instr->IsAllocationFolded()) {
    LOperand* temp = TempRegister();
    LFastAllocate* result = new (zone()) LFastAllocate(size, temp);
    return DefineAsRegister(result);
  } else {
    info()->MarkAsDeferredCalling();
    LOperand* context = UseAny(instr->context());
    LOperand* temp = TempRegister();
    LAllocate* result = new (zone()) LAllocate(context, size, temp);
    return AssignPointerMap(DefineAsRegister(result));
  }
2396 2397 2398
}


2399
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2400
  DCHECK(argument_count_ == 0);
2401 2402
  allocator_->MarkAsOsrEntry();
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2403
  return AssignEnvironment(new(zone()) LOsrEntry);
2404 2405 2406 2407
}


LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2408
  LParameter* result = new(zone()) LParameter;
2409
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2410 2411 2412
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
    return DefineAsSpilled(result, spill_index);
  } else {
2413
    DCHECK(info()->IsStub());
2414
    CallInterfaceDescriptor descriptor = graph()->descriptor();
2415
    int index = static_cast<int>(instr->index());
2416
    Register reg = descriptor.GetRegisterParameter(index);
2417 2418
    return DefineFixed(result, reg);
  }
2419 2420 2421 2422
}


LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2423 2424 2425 2426 2427 2428 2429 2430 2431
  // Use an index that corresponds to the location in the unoptimized frame,
  // which the optimized frame will subsume.
  int env_index = instr->index();
  int spill_index = 0;
  if (instr->environment()->is_parameter_index(env_index)) {
    spill_index = chunk()->GetParameterStackSlot(env_index);
  } else {
    spill_index = env_index - instr->environment()->first_local_index();
    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2432
      Retry(kTooManySpillSlotsNeededForOSR);
2433 2434
      spill_index = 0;
    }
2435
    spill_index += StandardFrameConstants::kFixedSlotCount;
2436
  }
2437
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2438 2439 2440 2441
}


LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2442 2443 2444 2445
  // There are no real uses of the arguments object.
  // arguments.length and element access are supported directly on
  // stack arguments, and any real arguments object use causes a bailout.
  // So this value is never used.
2446 2447 2448 2449
  return NULL;
}


2450
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2451
  instr->ReplayEnvironment(current_block_->last_environment());
2452

2453 2454 2455 2456 2457
  // There are no real uses of a captured object.
  return NULL;
}


2458
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2459
  info()->MarkAsRequiresFrame();
2460
  LOperand* args = UseRegister(instr->arguments());
2461 2462 2463 2464 2465 2466 2467 2468 2469
  LOperand* length;
  LOperand* index;
  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
    length = UseRegisterOrConstant(instr->length());
    index = UseOrConstant(instr->index());
  } else {
    length = UseTempRegister(instr->length());
    index = Use(instr->index());
  }
2470
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2471 2472 2473 2474
}


LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2475
  LOperand* context = UseFixed(instr->context(), rsi);
2476
  LOperand* value = UseFixed(instr->value(), rbx);
2477
  LTypeof* result = new(zone()) LTypeof(context, value);
2478
  return MarkAsCall(DefineFixed(result, rax), instr);
2479 2480 2481
}


2482
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2483
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2484 2485
}

2486

2487
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2488
  instr->ReplayEnvironment(current_block_->last_environment());
2489 2490 2491 2492 2493
  return NULL;
}


LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2494
  info()->MarkAsDeferredCalling();
2495
  if (instr->is_function_entry()) {
2496 2497
    LOperand* context = UseFixed(instr->context(), rsi);
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2498
  } else {
2499
    DCHECK(instr->is_backwards_branch());
2500 2501 2502
    LOperand* context = UseAny(instr->context());
    return AssignEnvironment(
        AssignPointerMap(new(zone()) LStackCheck(context)));
2503
  }
2504 2505 2506 2507
}


LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2508
  HEnvironment* outer = current_block_->last_environment();
2509
  outer->set_ast_id(instr->ReturnId());
2510
  HConstant* undefined = graph()->GetConstantUndefined();
2511 2512 2513
  HEnvironment* inner = outer->CopyForInlining(
      instr->closure(), instr->arguments_count(), instr->function(), undefined,
      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2514 2515 2516
  // Only replay binding of arguments object if it wasn't removed from graph.
  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
    inner->Bind(instr->arguments_var(), instr->arguments_object());
2517
  }
2518
  inner->BindContext(instr->closure_context());
2519
  inner->set_entry(instr);
2520
  current_block_->UpdateEnvironment(inner);
2521
  chunk_->AddInlinedFunction(instr->shared());
2522 2523 2524 2525 2526
  return NULL;
}


LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2527 2528 2529 2530
  LInstruction* pop = NULL;

  HEnvironment* env = current_block_->last_environment();

2531
  if (env->entry()->arguments_pushed()) {
2532 2533
    int argument_count = env->arguments_environment()->parameter_count();
    pop = new(zone()) LDrop(argument_count);
2534
    DCHECK(instr->argument_delta() == -argument_count);
2535 2536
  }

2537 2538
  HEnvironment* outer = current_block_->last_environment()->
      DiscardInlined(false);
2539
  current_block_->UpdateEnvironment(outer);
2540 2541

  return pop;
2542 2543
}

2544

2545
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2546
  LOperand* context = UseFixed(instr->context(), rsi);
2547
  LOperand* object = UseFixed(instr->enumerable(), rax);
2548
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2549 2550 2551 2552 2553 2554 2555
  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
}


LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
  LOperand* map = UseRegister(instr->map());
  return AssignEnvironment(DefineAsRegister(
2556
      new(zone()) LForInCacheArray(map)));
2557 2558 2559 2560 2561 2562
}


LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* map = UseRegisterAtStart(instr->map());
2563
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2564 2565 2566 2567 2568 2569
}


LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* index = UseTempRegister(instr->index());
2570 2571 2572
  LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
  LInstruction* result = DefineSameAsFirst(load);
  return AssignPointerMap(result);
2573 2574
}

2575 2576
}  // namespace internal
}  // namespace v8
2577 2578

#endif  // V8_TARGET_ARCH_X64