lithium-ia32.cc 83.7 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/ia32/lithium-ia32.h"
6

7 8
#include <sstream>

9
#if V8_TARGET_ARCH_IA32
10

11 12 13
#include "src/crankshaft/hydrogen-osr.h"
#include "src/crankshaft/ia32/lithium-codegen-ia32.h"
#include "src/crankshaft/lithium-inl.h"
14 15 16 17 18 19 20 21 22 23 24 25

namespace v8 {
namespace internal {

#define DEFINE_COMPILE(type)                            \
  void L##type::CompileToNative(LCodeGen* generator) {  \
    generator->Do##type(this);                          \
  }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
#undef DEFINE_COMPILE


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 50 51 52 53 54 55
bool LInstruction::HasDoubleRegisterResult() {
  return HasResult() && result()->IsDoubleRegister();
}


bool LInstruction::HasDoubleRegisterInput() {
  for (int i = 0; i < InputCount(); i++) {
    LOperand* op = InputAt(i);
56
    if (op != NULL && op->IsDoubleRegister()) {
57 58 59 60 61 62 63
      return true;
    }
  }
  return false;
}


64
void LInstruction::PrintTo(StringStream* stream) {
65
  stream->Add("%s ", this->Mnemonic());
66 67

  PrintOutputOperandTo(stream);
68

69 70 71 72 73 74 75 76 77 78 79 80 81 82
  PrintDataTo(stream);

  if (HasEnvironment()) {
    stream->Add(" ");
    environment()->PrintTo(stream);
  }

  if (HasPointerMap()) {
    stream->Add(" ");
    pointer_map()->PrintTo(stream);
  }
}


83
void LInstruction::PrintDataTo(StringStream* stream) {
84
  stream->Add("= ");
85
  for (int i = 0; i < InputCount(); i++) {
86
    if (i > 0) stream->Add(" ");
87 88 89 90 91
    if (InputAt(i) == NULL) {
      stream->Add("NULL");
    } else {
      InputAt(i)->PrintTo(stream);
    }
92
  }
93 94 95
}


96 97
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
  if (HasResult()) result()->PrintTo(stream);
98 99 100
}


101
void LLabel::PrintDataTo(StringStream* stream) {
fschneider@chromium.org's avatar
fschneider@chromium.org committed
102
  LGap::PrintDataTo(stream);
103 104 105 106 107 108 109 110 111 112 113 114 115
  LLabel* rep = replacement();
  if (rep != NULL) {
    stream->Add(" Dead block replaced with B%d", rep->block_id());
  }
}


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
116

117 118 119 120
  return true;
}


121
void LGap::PrintDataTo(StringStream* stream) {
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  for (int i = 0; i < 4; i++) {
    stream->Add("(");
    if (parallel_moves_[i] != NULL) {
      parallel_moves_[i]->PrintDataTo(stream);
    }
    stream->Add(") ");
  }
}


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";
153 154 155
    case Token::BIT_AND: return "bit-and-t";
    case Token::BIT_OR: return "bit-or-t";
    case Token::BIT_XOR: return "bit-xor-t";
156
    case Token::ROR: return "ror-t";
157 158 159
    case Token::SHL: return "sal-t";
    case Token::SAR: return "sar-t";
    case Token::SHR: return "shr-t";
160 161 162 163 164 165 166
    default:
      UNREACHABLE();
      return NULL;
  }
}


167 168 169 170 171
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
  return !gen->IsNextEmittedBlock(block_id());
}


172
void LGoto::PrintDataTo(StringStream* stream) {
173 174 175 176
  stream->Add("B%d", block_id());
}


177
void LBranch::PrintDataTo(StringStream* stream) {
178
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
179
  value()->PrintTo(stream);
180 181 182
}


183
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
184
  stream->Add("if ");
185
  left()->PrintTo(stream);
186
  stream->Add(" %s ", Token::String(op()));
187
  right()->PrintTo(stream);
188 189 190 191
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}


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


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


206 207
void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_undetectable(");
208
  value()->PrintTo(stream);
209 210 211 212
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


213 214
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if string_compare(");
215 216
  left()->PrintTo(stream);
  right()->PrintTo(stream);
217 218 219 220
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


221
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
222
  stream->Add("if has_instance_type(");
223
  value()->PrintTo(stream);
224 225 226 227
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


228
void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
229
  stream->Add("if has_cached_array_index(");
230
  value()->PrintTo(stream);
231 232 233 234
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


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


245
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
246
  stream->Add("if typeof ");
247
  value()->PrintTo(stream);
248
  stream->Add(" == \"%s\" then B%d else B%d",
249
              hydrogen()->type_literal()->ToCString().get(),
250 251 252 253
              true_block_id(), false_block_id());
}


254 255 256 257 258 259 260 261
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  function()->PrintTo(stream);
  stream->Add(".code_entry = ");
  code_object()->PrintTo(stream);
}


262 263 264
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  base_object()->PrintTo(stream);
265 266
  stream->Add(" + ");
  offset()->PrintTo(stream);
267 268 269
}


270 271 272 273 274
void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
  for (int i = 0; i < InputCount(); i++) {
    InputAt(i)->PrintTo(stream);
    stream->Add(" ");
  }
275 276 277 278
  stream->Add("#%d / ", arity());
}


279
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
280
  context()->PrintTo(stream);
281 282 283 284 285
  stream->Add("[%d]", slot_index());
}


void LStoreContextSlot::PrintDataTo(StringStream* stream) {
286
  context()->PrintTo(stream);
287
  stream->Add("[%d] <- ", slot_index());
288
  value()->PrintTo(stream);
289 290 291
}


292 293
void LInvokeFunction::PrintDataTo(StringStream* stream) {
  stream->Add("= ");
294
  context()->PrintTo(stream);
295
  stream->Add(" ");
296
  function()->PrintTo(stream);
297 298 299 300
  stream->Add(" #%d / ", arity());
}


301 302 303 304 305 306
void LCallNewArray::PrintDataTo(StringStream* stream) {
  stream->Add("= ");
  context()->PrintTo(stream);
  stream->Add(" ");
  constructor()->PrintTo(stream);
  stream->Add(" #%d / ", arity());
307
  ElementsKind kind = hydrogen()->elements_kind();
308 309 310 311
  stream->Add(" (%s) ", ElementsKindToString(kind));
}


312
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
313 314 315 316 317 318 319 320 321 322
  arguments()->PrintTo(stream);

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

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


323
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
324
  // Skip a slot if for a double-width slot.
325
  if (kind == DOUBLE_REGISTERS) {
326 327
    current_frame_slots_++;
    current_frame_slots_ |= 1;
328 329
    num_double_slots_++;
  }
330
  return current_frame_slots_++;
331 332 333
}


334 335 336
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
  int index = GetNextSpillIndex(kind);
  if (kind == DOUBLE_REGISTERS) {
337
    return LDoubleStackSlot::Create(index, zone());
338
  } else {
339
    DCHECK(kind == GENERAL_REGISTERS);
340
    return LStackSlot::Create(index, zone());
341 342 343 344
  }
}


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


354 355 356 357 358
void LLoadKeyed::PrintDataTo(StringStream* stream) {
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  if (hydrogen()->IsDehoisted()) {
359
    stream->Add(" + %d]", base_offset());
360 361 362 363 364 365
  } else {
    stream->Add("]");
  }
}


366
void LStoreKeyed::PrintDataTo(StringStream* stream) {
367 368 369
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
370
  if (hydrogen()->IsDehoisted()) {
371
    stream->Add(" + %d] <-", base_offset());
372 373 374
  } else {
    stream->Add("] <- ");
  }
375 376

  if (value() == NULL) {
377
    DCHECK(hydrogen()->IsConstantHoleStore() &&
378 379 380 381 382
           hydrogen()->value()->representation().IsDouble());
    stream->Add("<the hole(nan)>");
  } else {
    value()->PrintTo(stream);
  }
383 384 385
}


386 387 388 389 390 391
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}


392
LPlatformChunk* LChunkBuilder::Build() {
393
  DCHECK(is_unused());
394
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
395
  LPhase phase("L_Building chunk", chunk_);
396
  status_ = BUILDING;
397

398 399 400 401
  // 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--) {
402
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
403 404 405
    }
  }

406 407 408 409 410 411 412 413 414 415 416 417 418
  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_;
}


LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
419
  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
420 421 422 423
}


LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
424 425
  return new (zone())
      LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
426 427 428 429 430 431 432 433 434 435 436 437 438 439
}


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) {
440
  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
441 442 443 444 445
}


LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
  return Use(value,
446 447
             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
                                      LUnallocated::USED_AT_START));
448 449 450 451
}


LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
452
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
453 454 455 456
}


LOperand* LChunkBuilder::Use(HValue* value) {
457
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
458 459 460 461
}


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


467 468 469 470 471
static inline bool CanBeImmediateConstant(HValue* value) {
  return value->IsConstant() && HConstant::cast(value)->NotInNewSpace();
}


472
LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
473
  return CanBeImmediateConstant(value)
474 475 476 477 478 479
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : Use(value);
}


LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
480
  return CanBeImmediateConstant(value)
481 482 483 484 485
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseAtStart(value);
}


486 487 488 489 490 491 492 493
LOperand* LChunkBuilder::UseFixedOrConstant(HValue* value,
                                            Register fixed_register) {
  return CanBeImmediateConstant(value)
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseFixed(value, fixed_register);
}


494
LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
495
  return CanBeImmediateConstant(value)
496 497 498 499 500 501
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegister(value);
}


LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
502
  return CanBeImmediateConstant(value)
503 504 505 506 507
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
      : UseRegisterAtStart(value);
}


508 509 510 511 512
LOperand* LChunkBuilder::UseConstant(HValue* value) {
  return chunk_->DefineConstantOperand(HConstant::cast(value));
}


513 514 515
LOperand* LChunkBuilder::UseAny(HValue* value) {
  return value->IsConstant()
      ? chunk_->DefineConstantOperand(HConstant::cast(value))
516
      :  Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
517 518 519
}


520 521 522 523 524
LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
  if (value->EmitAtUses()) {
    HInstruction* instr = HInstruction::cast(value);
    VisitInstruction(instr);
  }
525
  operand->set_virtual_register(value->id());
526 527 528 529
  return operand;
}


530
LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
531
                                    LUnallocated* result) {
532
  result->set_virtual_register(current_instruction_->id());
533 534 535 536 537 538
  instr->set_result(result);
  return instr;
}


LInstruction* LChunkBuilder::DefineAsRegister(
539
    LTemplateResultInstruction<1>* instr) {
540 541
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
542 543 544
}


545
LInstruction* LChunkBuilder::DefineAsSpilled(
546
    LTemplateResultInstruction<1>* instr,
547
    int index) {
548 549
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
550 551 552
}


553
LInstruction* LChunkBuilder::DefineSameAsFirst(
554
    LTemplateResultInstruction<1>* instr) {
555 556
  return Define(instr,
                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
557 558 559
}


560
LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
561
                                         Register reg) {
562 563 564 565
  return Define(instr, ToUnallocated(reg));
}


566
LInstruction* LChunkBuilder::DefineFixedDouble(
567
    LTemplateResultInstruction<1>* instr,
568
    XMMRegister reg) {
569 570 571 572 573 574
  return Define(instr, ToUnallocated(reg));
}


LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
  HEnvironment* hydrogen_env = current_block_->last_environment();
575
  return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
576 577 578 579 580 581
}


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

584 585 586 587
#ifdef DEBUG
  instr->VerifyCall();
#endif
  instr->MarkAsCall();
588 589 590 591 592 593 594
  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 =
595 596
      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
      !hinstr->HasObservableSideEffects();
597 598
  if (needs_environment && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
599 600
    // We can't really figure out if the environment is needed or not.
    instr->environment()->set_has_been_used();
601 602 603 604 605 606 607
  }

  return instr;
}


LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
608
  DCHECK(!instr->HasPointerMap());
609
  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
610 611 612 613 614
  return instr;
}


LUnallocated* LChunkBuilder::TempRegister() {
615 616
  LUnallocated* operand =
      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
617
  int vreg = allocator_->GetVirtualRegister();
618
  if (!allocator_->AllocationOk()) {
619
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
620
    vreg = 0;
621
  }
622
  operand->set_virtual_register(vreg);
623 624 625 626 627 628
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(Register reg) {
  LUnallocated* operand = ToUnallocated(reg);
629
  DCHECK(operand->HasFixedPolicy());
630 631 632 633 634 635
  return operand;
}


LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
  LUnallocated* operand = ToUnallocated(reg);
636
  DCHECK(operand->HasFixedPolicy());
637 638 639 640 641
  return operand;
}


LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
642
  return new(zone()) LLabel(instr->block());
643 644 645
}


646 647 648 649 650
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
}


651 652 653 654 655 656
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
  UNREACHABLE();
  return NULL;
}


657
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
658
  return AssignEnvironment(new(zone()) LDeoptimize);
659 660 661 662 663
}


LInstruction* LChunkBuilder::DoShift(Token::Value op,
                                     HBitwiseBinaryOperation* instr) {
664
  if (instr->representation().IsSmiOrInteger32()) {
665 666
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
667
    LOperand* left = UseRegisterAtStart(instr->left());
668

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
    HValue* right_value = instr->right();
    LOperand* right = NULL;
    int constant_value = 0;
    bool does_deopt = false;
    if (right_value->IsConstant()) {
      HConstant* constant = HConstant::cast(right_value);
      right = chunk_->DefineConstantOperand(constant);
      constant_value = constant->Integer32Value() & 0x1f;
      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
      // truncated to smi.
      if (instr->representation().IsSmi() && constant_value > 0) {
        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
      }
    } else {
      right = UseFixed(right_value, ecx);
684
    }
685

686 687 688
    // 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) {
689
      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
690 691
    }

692 693 694 695 696 697
    LInstruction* result =
        DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
    return does_deopt ? AssignEnvironment(result) : result;
  } else {
    return DoArithmeticT(op, instr);
  }
698 699 700 701 702
}


LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
                                           HArithmeticBinaryOperation* instr) {
703 704 705
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->left()->representation().IsDouble());
  DCHECK(instr->right()->representation().IsDouble());
706 707 708 709 710 711 712 713 714
  if (op == Token::MOD) {
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
    return MarkAsCall(DefineSameAsFirst(result), instr);
  } else {
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
715 716
    return CpuFeatures::IsSupported(AVX) ? DefineAsRegister(result)
                                         : DefineSameAsFirst(result);
717
  }
718 719 720 721
}


LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
722
                                           HBinaryOperation* instr) {
723 724
  HValue* left = instr->left();
  HValue* right = instr->right();
725 726
  DCHECK(left->representation().IsTagged());
  DCHECK(right->representation().IsTagged());
727
  LOperand* context = UseFixed(instr->context(), esi);
728 729
  LOperand* left_operand = UseFixed(left, edx);
  LOperand* right_operand = UseFixed(right, eax);
730
  LArithmeticT* result =
731
      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
732 733 734
  return MarkAsCall(DefineFixed(result, eax), instr);
}

735

736
void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
737
  DCHECK(is_building());
738 739 740 741 742 743 744 745
  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.
746
    DCHECK(block->phis()->length() == 0);
747 748
    HBasicBlock* pred = block->predecessors()->at(0);
    HEnvironment* last_environment = pred->last_environment();
749
    DCHECK(last_environment != NULL);
750 751
    // Only copy the environment, if it is later used again.
    if (pred->end()->SecondSuccessor() == NULL) {
752
      DCHECK(pred->end()->FirstSuccessor() == block);
753 754 755 756 757 758 759
    } 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);
760
    DCHECK(pred->argument_count() >= 0);
761 762 763 764 765 766 767 768
    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);
769
      if (phi->HasMergedIndex()) {
770 771
        last_environment->SetValueAt(phi->merged_index(), phi);
      }
772 773
    }
    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
774 775 776 777
      if (block->deleted_phis()->at(i) < last_environment->length()) {
        last_environment->SetValueAt(block->deleted_phis()->at(i),
                                     graph_->GetConstantUndefined());
      }
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    }
    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;
}


void LChunkBuilder::VisitInstruction(HInstruction* current) {
  HInstruction* old_current = current_instruction_;
  current_instruction_ = current;
806 807 808

  LInstruction* instr = NULL;
  if (current->CanReplaceWithDummyUses()) {
809 810 811
    if (current->OperandCount() == 0) {
      instr = DefineAsRegister(new(zone()) LDummy());
    } else {
812
      DCHECK(!current->OperandAt(0)->IsControlInstruction());
813 814 815
      instr = DefineAsRegister(new(zone())
          LDummyUse(UseAny(current->OperandAt(0))));
    }
816
    for (int i = 1; i < current->OperandCount(); ++i) {
817
      if (current->OperandAt(i)->IsControlInstruction()) continue;
818 819 820 821 822 823
      LInstruction* dummy =
          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
      dummy->set_hydrogen_value(current);
      chunk_->AddInstruction(dummy, current_block_);
    }
  } else {
824 825 826 827 828 829 830 831
    HBasicBlock* successor;
    if (current->IsControlInstruction() &&
        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
        successor != NULL) {
      instr = new(zone()) LGoto(successor);
    } else {
      instr = current->CompileToLithium(this);
    }
832
  }
833

834
  argument_count_ += current->argument_delta();
835
  DCHECK(argument_count_ >= 0);
836

837
  if (instr != NULL) {
838 839 840 841 842 843 844 845 846 847 848 849
    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);
850

851
#if DEBUG
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
  // 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;
872
    }
873 874 875 876
    for (TempIterator it(instr); !it.Done(); it.Advance()) {
      LUnallocated* operand = LUnallocated::cast(it.Current());
      if (operand->HasFixedPolicy()) ++fixed;
    }
877
    DCHECK(fixed == 0 || used_at_start == 0);
878
  }
879 880
#endif

881 882 883 884 885 886 887 888
  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
    instr = AssignPointerMap(instr);
  }
  if (FLAG_stress_environments && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
  }
  chunk_->AddInstruction(instr, current_block_);

889
  CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
890 891 892
}


893
LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
894
  LInstruction* result = new (zone()) LPrologue();
895
  if (info_->scope()->NeedsContext()) {
896 897 898
    result = MarkAsCall(result, instr);
  }
  return result;
899 900 901
}


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


907
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
908
  HValue* value = instr->value();
909
  Representation r = value->representation();
910
  HType type = value->type();
911 912
  ToBooleanICStub::Types expected = instr->expected_input_types();
  if (expected.IsEmpty()) expected = ToBooleanICStub::Types::Generic();
913

914 915 916 917 918
  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
      type.IsJSArray() || type.IsHeapNumber() || type.IsString();
  LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
  LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
  if (!easy_case &&
919
      ((!expected.Contains(ToBooleanICStub::SMI) && expected.NeedsMap()) ||
920 921
       !expected.IsGeneric())) {
    branch = AssignEnvironment(branch);
922
  }
923
  return branch;
924 925 926
}


927 928 929 930 931
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
  return new(zone()) LDebugBreak();
}


932
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
933
  DCHECK(instr->value()->representation().IsTagged());
934
  LOperand* value = UseRegisterAtStart(instr->value());
935
  return new(zone()) LCmpMapAndBranch(value);
936 937 938 939
}


LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
940
  info()->MarkAsRequiresFrame();
941
  return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
942 943 944 945
}


LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
946
  info()->MarkAsRequiresFrame();
947
  return DefineAsRegister(new(zone()) LArgumentsElements);
948 949 950
}


951 952 953 954 955
LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
    HHasInPrototypeChainAndBranch* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* prototype = UseRegister(instr->prototype());
  LOperand* temp = TempRegister();
956 957 958
  LHasInPrototypeChainAndBranch* result =
      new (zone()) LHasInPrototypeChainAndBranch(object, prototype, temp);
  return AssignEnvironment(result);
959 960 961
}


962 963
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
  LOperand* receiver = UseRegister(instr->receiver());
964
  LOperand* function = UseRegister(instr->function());
965 966 967 968 969 970 971
  LOperand* temp = TempRegister();
  LWrapReceiver* result =
      new(zone()) LWrapReceiver(receiver, function, temp);
  return AssignEnvironment(DefineSameAsFirst(result));
}


972 973 974
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
  LOperand* function = UseFixed(instr->function(), edi);
  LOperand* receiver = UseFixed(instr->receiver(), eax);
975 976
  LOperand* length = UseFixed(instr->length(), ebx);
  LOperand* elements = UseFixed(instr->elements(), ecx);
977 978 979
  LApplyArguments* result = new(zone()) LApplyArguments(function,
                                                        receiver,
                                                        length,
980
                                                        elements);
981 982 983 984
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
}


985 986 987 988 989 990 991
LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
  int argc = instr->OperandCount();
  for (int i = 0; i < argc; ++i) {
    LOperand* argument = UseAny(instr->argument(i));
    AddInstruction(new(zone()) LPushArgument(argument), instr);
  }
  return NULL;
992 993 994
}


995 996 997 998 999 1000 1001 1002
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);
}


1003
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1004 1005 1006 1007 1008
    HInnerAllocatedObject* instr) {
  LOperand* base_object = UseRegisterAtStart(instr->base_object());
  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
  return DefineAsRegister(
      new(zone()) LInnerAllocatedObject(base_object, offset));
1009 1010 1011
}


1012
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1013 1014 1015
  return instr->HasNoUses()
      ? NULL
      : DefineAsRegister(new(zone()) LThisFunction);
1016 1017 1018
}


1019
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1020 1021 1022 1023 1024 1025 1026
  if (instr->HasNoUses()) return NULL;

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

  return DefineAsRegister(new(zone()) LContext);
1027 1028 1029
}


1030 1031 1032 1033 1034 1035
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
}


1036 1037
LInstruction* LChunkBuilder::DoCallWithDescriptor(
    HCallWithDescriptor* instr) {
1038
  CallInterfaceDescriptor descriptor = instr->descriptor();
1039 1040 1041 1042
  DCHECK_EQ(descriptor.GetParameterCount() +
                LCallWithDescriptor::kImplicitRegisterParameterCount,
            instr->OperandCount());

1043 1044
  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1045
  // Target
1046
  ops.Add(target, zone());
1047 1048 1049
  // Context
  LOperand* op = UseFixed(instr->OperandAt(1), esi);
  ops.Add(op, zone());
1050 1051 1052 1053 1054 1055
  // Load register parameters.
  int i = 0;
  for (; i < descriptor.GetRegisterParameterCount(); i++) {
    op = UseFixed(instr->OperandAt(
                      i + LCallWithDescriptor::kImplicitRegisterParameterCount),
                  descriptor.GetRegisterParameter(i));
1056 1057
    ops.Add(op, zone());
  }
1058 1059 1060 1061 1062 1063
  // Push stack parameters.
  for (; i < descriptor.GetParameterCount(); i++) {
    op = UseAny(instr->OperandAt(
        i + LCallWithDescriptor::kImplicitRegisterParameterCount));
    AddInstruction(new (zone()) LPushArgument(op), instr);
  }
1064 1065 1066

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


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


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

1115
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1116
  DCHECK(instr->value()->representation().IsDouble());
1117
  LOperand* input = UseRegisterAtStart(instr->value());
1118 1119 1120 1121 1122 1123 1124 1125
  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);
  }
1126 1127 1128
}

LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1129
  DCHECK(instr->value()->representation().IsDouble());
1130
  LOperand* input = UseRegister(instr->value());
1131 1132 1133 1134 1135 1136 1137 1138 1139
  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);
  }
1140 1141
}

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


1149 1150 1151
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
  LOperand* context = UseAny(instr->context());  // Deferred use.
  LOperand* input = UseRegisterAtStart(instr->value());
1152 1153 1154 1155 1156 1157
  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;
1158 1159 1160 1161
}


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


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

1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
  LOperand* input = UseRegisterAtStart(instr->value());
  return MarkAsCall(DefineSameAsFirst(new (zone()) LMathCos(input)), instr);
}

LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
  LOperand* input = UseRegisterAtStart(instr->value());
  return MarkAsCall(DefineSameAsFirst(new (zone()) LMathSin(input)), instr);
}
1188

1189
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1190 1191
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
1192 1193
  LOperand* input = UseRegisterAtStart(instr->value());
  return MarkAsCall(DefineSameAsFirst(new (zone()) LMathExp(input)), instr);
1194 1195 1196 1197
}


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


LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
  LOperand* input = UseRegisterAtStart(instr->value());
  LOperand* temp = TempRegister();
1206
  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
1207 1208 1209 1210
  return DefineSameAsFirst(result);
}


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


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


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


1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
LInstruction* LChunkBuilder::DoShr(HShr* instr) {
  return DoShift(Token::SHR, instr);
}


LInstruction* LChunkBuilder::DoSar(HSar* instr) {
  return DoShift(Token::SAR, instr);
}


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


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

1251 1252
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1253
    return DefineSameAsFirst(new(zone()) LBitI(left, right));
1254
  } else {
1255
    return DoArithmeticT(instr->op(), instr);
1256
  }
1257 1258 1259
}


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


1278
LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1279 1280 1281
  DCHECK(instr->representation().IsInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1282 1283 1284 1285
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
  LOperand* temp1 = FixedTemp(eax);
  LOperand* temp2 = FixedTemp(edx);
1286 1287 1288 1289 1290 1291 1292 1293
  LInstruction* result = DefineFixed(new(zone()) LDivByConstI(
          dividend, divisor, temp1, temp2), edx);
  if (divisor == 0 ||
      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
    result = AssignEnvironment(result);
  }
  return result;
1294 1295 1296
}


1297
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1298 1299 1300
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1301 1302 1303
  LOperand* dividend = UseFixed(instr->left(), eax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(edx);
1304 1305 1306 1307 1308
  LInstruction* result = DefineFixed(new(zone()) LDivI(
          dividend, divisor, temp), eax);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
      instr->CheckFlag(HValue::kCanOverflow) ||
1309
      !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1310 1311 1312
    result = AssignEnvironment(result);
  }
  return result;
1313 1314 1315
}


1316
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1317
  if (instr->representation().IsSmiOrInteger32()) {
1318 1319 1320 1321 1322 1323 1324
    if (instr->RightIsPowerOf2()) {
      return DoDivByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoDivByConstI(instr);
    } else {
      return DoDivI(instr);
    }
1325 1326
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::DIV, instr);
1327 1328 1329 1330 1331 1332
  } else {
    return DoArithmeticT(Token::DIV, instr);
  }
}


1333 1334 1335
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1336 1337 1338 1339 1340 1341 1342
  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;
1343 1344 1345 1346
}


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

1372

1373
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1374 1375 1376
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
  LOperand* dividend = UseFixed(instr->left(), eax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(edx);
  LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
          dividend, divisor, temp), eax);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
      instr->CheckFlag(HValue::kCanOverflow)) {
    result = AssignEnvironment(result);
  }
  return result;
}


1391 1392 1393
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
  if (instr->RightIsPowerOf2()) {
    return DoFlooringDivByPowerOf2I(instr);
1394 1395
  } else if (instr->right()->IsConstant()) {
    return DoFlooringDivByConstI(instr);
1396
  } else {
1397
    return DoFlooringDivI(instr);
1398 1399 1400 1401
  }
}


1402
LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1403 1404 1405
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1406 1407
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1408 1409
  LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
          dividend, divisor));
1410 1411
  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1412 1413 1414
    result = AssignEnvironment(result);
  }
  return result;
1415 1416 1417
}


1418
LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1419 1420 1421
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1422 1423 1424 1425
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
  LOperand* temp1 = FixedTemp(eax);
  LOperand* temp2 = FixedTemp(edx);
1426 1427 1428 1429 1430 1431
  LInstruction* result = DefineFixed(new(zone()) LModByConstI(
          dividend, divisor, temp1, temp2), eax);
  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
  }
  return result;
1432 1433 1434
}


1435
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1436 1437 1438
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1439 1440 1441
  LOperand* dividend = UseFixed(instr->left(), eax);
  LOperand* divisor = UseRegister(instr->right());
  LOperand* temp = FixedTemp(edx);
1442 1443 1444 1445 1446 1447 1448
  LInstruction* result = DefineFixed(new(zone()) LModI(
          dividend, divisor, temp), edx);
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
  }
  return result;
1449 1450 1451
}


1452
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1453
  if (instr->representation().IsSmiOrInteger32()) {
1454 1455 1456 1457 1458 1459 1460
    if (instr->RightIsPowerOf2()) {
      return DoModByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoModByConstI(instr);
    } else {
      return DoModI(instr);
    }
1461 1462
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::MOD, instr);
1463
  } else {
1464
    return DoArithmeticT(Token::MOD, instr);
1465 1466 1467 1468 1469
  }
}


LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1470
  if (instr->representation().IsSmiOrInteger32()) {
1471 1472
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1473
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1474 1475
    HValue* h_right = instr->BetterRightOperand();
    LOperand* right = UseOrConstant(h_right);
1476 1477 1478 1479
    LOperand* temp = NULL;
    if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
      temp = TempRegister();
    }
1480
    LMulI* mul = new(zone()) LMulI(left, right, temp);
1481 1482 1483 1484 1485 1486 1487 1488 1489
    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) {
1490 1491 1492
      AssignEnvironment(mul);
    }
    return DefineSameAsFirst(mul);
1493
  } else if (instr->representation().IsDouble()) {
1494
    return DoArithmeticD(Token::MUL, instr);
1495 1496 1497 1498 1499 1500 1501
  } else {
    return DoArithmeticT(Token::MUL, instr);
  }
}


LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1502
  if (instr->representation().IsSmiOrInteger32()) {
1503 1504
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1505 1506
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseOrConstantAtStart(instr->right());
1507
    LSubI* sub = new(zone()) LSubI(left, right);
1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
    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);
  }
}


LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1522
  if (instr->representation().IsSmiOrInteger32()) {
1523 1524
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
    // 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);
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    HValue* right_candidate = instr->BetterRightOperand();
    LOperand* right = use_lea
        ? UseRegisterOrConstantAtStart(right_candidate)
        : UseOrConstantAtStart(right_candidate);
1535
    LAddI* add = new(zone()) LAddI(left, right);
1536 1537 1538 1539 1540
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
    LInstruction* result = use_lea
        ? DefineAsRegister(add)
        : DefineSameAsFirst(add);
    if (can_overflow) {
1541 1542 1543 1544 1545
      result = AssignEnvironment(result);
    }
    return result;
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::ADD, instr);
1546
  } else if (instr->representation().IsExternal()) {
1547
    DCHECK(instr->IsConsistentExternalRepresentation());
1548
    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
    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;
1560 1561 1562 1563 1564 1565
  } else {
    return DoArithmeticT(Token::ADD, instr);
  }
}


1566 1567 1568
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
  LOperand* left = NULL;
  LOperand* right = NULL;
1569
  if (instr->representation().IsSmiOrInteger32()) {
1570 1571
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1572 1573
    left = UseRegisterAtStart(instr->BetterLeftOperand());
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1574
  } else {
1575 1576 1577
    DCHECK(instr->representation().IsDouble());
    DCHECK(instr->left()->representation().IsDouble());
    DCHECK(instr->right()->representation().IsDouble());
1578 1579 1580 1581 1582 1583 1584 1585
    left = UseRegisterAtStart(instr->left());
    right = UseRegisterAtStart(instr->right());
  }
  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
  return DefineSameAsFirst(minmax);
}


1586
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1587
  DCHECK(instr->representation().IsDouble());
1588 1589 1590
  // 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();
1591
  DCHECK(instr->left()->representation().IsDouble());
1592
  LOperand* left = UseFixedDouble(instr->left(), xmm2);
1593 1594 1595 1596
  LOperand* right =
      exponent_type.IsDouble()
          ? UseFixedDouble(instr->right(), xmm1)
          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1597
  LPower* result = new(zone()) LPower(left, right);
1598
  return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1599 1600 1601 1602
                    CAN_DEOPTIMIZE_EAGERLY);
}


1603
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1604 1605
  DCHECK(instr->left()->representation().IsSmiOrTagged());
  DCHECK(instr->right()->representation().IsSmiOrTagged());
1606
  LOperand* context = UseFixed(instr->context(), esi);
1607 1608
  LOperand* left = UseFixed(instr->left(), edx);
  LOperand* right = UseFixed(instr->right(), eax);
1609 1610
  LCmpT* result = new(zone()) LCmpT(context, left, right);
  return MarkAsCall(DefineFixed(result, eax), instr);
1611 1612 1613
}


1614 1615
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
    HCompareNumericAndBranch* instr) {
1616
  Representation r = instr->representation();
1617
  if (r.IsSmiOrInteger32()) {
1618 1619
    DCHECK(instr->left()->representation().Equals(r));
    DCHECK(instr->right()->representation().Equals(r));
1620
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1621
    LOperand* right = UseOrConstantAtStart(instr->right());
1622
    return new(zone()) LCompareNumericAndBranch(left, right);
1623
  } else {
1624 1625 1626
    DCHECK(r.IsDouble());
    DCHECK(instr->left()->representation().IsDouble());
    DCHECK(instr->right()->representation().IsDouble());
1627 1628
    LOperand* left;
    LOperand* right;
1629 1630 1631 1632 1633 1634
    if (CanBeImmediateConstant(instr->left()) &&
        CanBeImmediateConstant(instr->right())) {
      // The code generator requires either both inputs to be constant
      // operands, or neither.
      left = UseConstant(instr->left());
      right = UseConstant(instr->right());
1635 1636 1637 1638
    } else {
      left = UseRegisterAtStart(instr->left());
      right = UseRegisterAtStart(instr->right());
    }
1639
    return new(zone()) LCompareNumericAndBranch(left, right);
1640 1641 1642 1643
  }
}


1644 1645
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
    HCompareObjectEqAndBranch* instr) {
1646
  LOperand* left = UseRegisterAtStart(instr->left());
1647
  LOperand* right = UseOrConstantAtStart(instr->right());
1648
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1649 1650 1651
}


1652 1653
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
    HCompareHoleAndBranch* instr) {
1654 1655
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LCmpHoleAndBranch(value);
1656 1657 1658
}


1659
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1660
  DCHECK(instr->value()->representation().IsTagged());
1661
  LOperand* temp = TempRegister();
1662
  return new(zone()) LIsStringAndBranch(UseRegister(instr->value()), temp);
1663 1664 1665
}


1666
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1667
  DCHECK(instr->value()->representation().IsTagged());
1668
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1669 1670 1671
}


1672 1673
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
    HIsUndetectableAndBranch* instr) {
1674
  DCHECK(instr->value()->representation().IsTagged());
1675 1676
  return new(zone()) LIsUndetectableAndBranch(
      UseRegisterAtStart(instr->value()), TempRegister());
1677 1678 1679
}


1680 1681
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
    HStringCompareAndBranch* instr) {
1682 1683
  DCHECK(instr->left()->representation().IsTagged());
  DCHECK(instr->right()->representation().IsTagged());
1684 1685 1686 1687
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* left = UseFixed(instr->left(), edx);
  LOperand* right = UseFixed(instr->right(), eax);

1688
  LStringCompareAndBranch* result = new(zone())
1689 1690 1691 1692 1693 1694
      LStringCompareAndBranch(context, left, right);

  return MarkAsCall(result, instr);
}


1695 1696
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
    HHasInstanceTypeAndBranch* instr) {
1697
  DCHECK(instr->value()->representation().IsTagged());
1698 1699 1700
  return new(zone()) LHasInstanceTypeAndBranch(
      UseRegisterAtStart(instr->value()),
      TempRegister());
1701 1702 1703
}


1704 1705
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
    HGetCachedArrayIndex* instr)  {
1706
  DCHECK(instr->value()->representation().IsTagged());
1707 1708
  LOperand* value = UseRegisterAtStart(instr->value());

1709
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1710 1711 1712
}


1713 1714
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
    HHasCachedArrayIndexAndBranch* instr) {
1715
  DCHECK(instr->value()->representation().IsTagged());
1716
  return new(zone()) LHasCachedArrayIndexAndBranch(
1717
      UseRegisterAtStart(instr->value()));
1718 1719 1720
}


1721 1722
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
    HClassOfTestAndBranch* instr) {
1723
  DCHECK(instr->value()->representation().IsTagged());
1724 1725 1726
  return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
                                           TempRegister(),
                                           TempRegister());
1727 1728 1729
}


1730 1731 1732 1733 1734 1735 1736
LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
  LOperand* string = UseRegisterAtStart(instr->string());
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
  return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
}


1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
LOperand* LChunkBuilder::GetSeqStringSetCharOperand(HSeqStringSetChar* instr) {
  if (instr->encoding() == String::ONE_BYTE_ENCODING) {
    if (FLAG_debug_code) {
      return UseFixed(instr->value(), eax);
    } else {
      return UseFixedOrConstant(instr->value(), eax);
    }
  } else {
    if (FLAG_debug_code) {
      return UseRegisterAtStart(instr->value());
    } else {
      return UseRegisterOrConstantAtStart(instr->value());
    }
  }
}


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


1770
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
  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;
1781 1782 1783
}


1784 1785 1786 1787 1788 1789 1790
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;
}


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


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


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


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


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


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


1929 1930 1931
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* temp = TempRegister();
1932
  LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp);
1933 1934 1935 1936
  return AssignEnvironment(result);
}


1937 1938 1939
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
  // If the object is in new space, we'll emit a global cell compare and so
  // want the value in a register.  If the object gets promoted before we
1940 1941
  // emit code, we will still get the register but will do an immediate
  // compare instead of the cell compare.  This is safe.
1942
  LOperand* value = instr->object_in_new_space()
1943
      ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value());
1944
  return AssignEnvironment(new(zone()) LCheckValue(value));
1945 1946 1947
}


1948
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1949 1950 1951 1952 1953 1954
  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);
1955 1956
  }
  return result;
1957 1958 1959
}


1960 1961 1962 1963 1964
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
  HValue* value = instr->value();
  Representation input_rep = value->representation();
  if (input_rep.IsDouble()) {
    LOperand* reg = UseRegister(value);
1965
    return DefineFixed(new(zone()) LClampDToUint8(reg), eax);
1966 1967
  } else if (input_rep.IsInteger32()) {
    LOperand* reg = UseFixed(value, eax);
1968
    return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
1969
  } else {
1970
    DCHECK(input_rep.IsSmiOrTagged());
1971 1972 1973 1974 1975 1976
    LOperand* reg = UseFixed(value, eax);
    // Register allocator doesn't (yet) support allocation of double
    // temps. Reserve xmm1 explicitly.
    LOperand* temp = FixedTemp(xmm1);
    LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
    return AssignEnvironment(DefineFixed(result, eax));
1977 1978 1979 1980
  }
}


1981
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1982
  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), esi) : NULL;
1983
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1984 1985
  return new(zone()) LReturn(
      UseFixed(instr->value(), eax), context, parameter_count);
1986 1987 1988 1989 1990
}


LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
  Representation r = instr->representation();
1991 1992 1993
  if (r.IsSmi()) {
    return DefineAsRegister(new(zone()) LConstantS);
  } else if (r.IsInteger32()) {
1994
    return DefineAsRegister(new(zone()) LConstantI);
1995
  } else if (r.IsDouble()) {
1996 1997
    uint64_t const bits = instr->DoubleValueAsBits();
    LOperand* temp = bits ? TempRegister() : nullptr;
1998
    return DefineAsRegister(new(zone()) LConstantD(temp));
1999 2000
  } else if (r.IsExternal()) {
    return DefineAsRegister(new(zone()) LConstantE);
2001
  } else if (r.IsTagged()) {
2002
    return DefineAsRegister(new(zone()) LConstantT);
2003
  } else {
2004
    UNREACHABLE();
2005 2006 2007 2008 2009
    return NULL;
  }
}


2010 2011
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
2012
  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2013

2014
  LLoadGlobalGeneric* result = new (zone()) LLoadGlobalGeneric(context, vector);
2015 2016 2017 2018
  return MarkAsCall(DefineFixed(result, eax), instr);
}


2019
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2020
  LOperand* context = UseRegisterAtStart(instr->value());
2021 2022
  LInstruction* result =
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2023 2024 2025 2026
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2027 2028 2029 2030 2031 2032
}


LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
  LOperand* value;
  LOperand* temp;
2033
  LOperand* context = UseRegister(instr->context());
2034 2035 2036 2037 2038 2039 2040
  if (instr->NeedsWriteBarrier()) {
    value = UseTempRegister(instr->value());
    temp = TempRegister();
  } else {
    value = UseRegister(instr->value());
    temp = NULL;
  }
2041
  LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2042 2043 2044 2045
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2046 2047 2048
}


2049
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2050 2051 2052 2053
  LOperand* obj = (instr->access().IsExternalMemory() &&
                   instr->access().offset() == 0)
      ? UseRegisterOrConstantAtStart(instr->object())
      : UseRegisterAtStart(instr->object());
2054
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2055 2056 2057 2058
}


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


2069 2070 2071
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
    HLoadFunctionPrototype* instr) {
  return AssignEnvironment(DefineAsRegister(
2072 2073
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()),
                                         TempRegister())));
2074 2075 2076
}


2077 2078 2079 2080 2081
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
  return DefineAsRegister(new(zone()) LLoadRoot);
}


2082
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2083
  DCHECK(instr->key()->representation().IsSmiOrInteger32());
2084
  ElementsKind elements_kind = instr->elements_kind();
2085 2086 2087
  bool clobbers_key = ExternalArrayOpRequiresTemp(
      instr->key()->representation(), elements_kind);
  LOperand* key = clobbers_key
2088
      ? UseTempRegister(instr->key())
2089
      : UseRegisterOrConstantAtStart(instr->key());
2090
  LInstruction* result = NULL;
2091

2092
  if (!instr->is_fixed_typed_array()) {
2093
    LOperand* obj = UseRegisterAtStart(instr->elements());
2094
    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
2095
  } else {
2096
    DCHECK(
2097
        (instr->representation().IsInteger32() &&
2098
         !(IsDoubleOrFloatElementsKind(instr->elements_kind()))) ||
2099
        (instr->representation().IsDouble() &&
2100 2101
         (IsDoubleOrFloatElementsKind(instr->elements_kind()))));
    LOperand* backing_store = UseRegister(instr->elements());
2102 2103 2104
    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
    result = DefineAsRegister(
        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
2105
  }
2106

2107
  bool needs_environment;
2108
  if (instr->is_fixed_typed_array()) {
2109
    // see LCodeGen::DoLoadKeyedExternalArray
2110
    needs_environment = elements_kind == UINT32_ELEMENTS &&
2111 2112 2113 2114 2115 2116 2117 2118 2119 2120
                        !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) {
2121 2122 2123
    result = AssignEnvironment(result);
  }
  return result;
2124 2125 2126
}


2127
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2128
  LOperand* context = UseFixed(instr->context(), esi);
2129
  LOperand* object =
2130 2131
      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
2132
  LOperand* vector = FixedTemp(LoadWithVectorDescriptor::VectorRegister());
2133
  LLoadKeyedGeneric* result =
2134
      new(zone()) LLoadKeyedGeneric(context, object, key, vector);
2135
  return MarkAsCall(DefineFixed(result, eax), instr);
2136 2137 2138
}


2139 2140 2141 2142 2143
LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
  ElementsKind elements_kind = instr->elements_kind();

  // Determine if we need a byte register in this case for the value.
  bool val_is_fixed_register =
2144 2145 2146
      elements_kind == UINT8_ELEMENTS ||
      elements_kind == INT8_ELEMENTS ||
      elements_kind == UINT8_CLAMPED_ELEMENTS;
2147 2148 2149 2150 2151 2152 2153 2154
  if (val_is_fixed_register) {
    return UseFixed(instr->value(), eax);
  }

  return UseRegister(instr->value());
}


2155
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2156
  if (!instr->is_fixed_typed_array()) {
2157 2158
    DCHECK(instr->elements()->representation().IsTagged());
    DCHECK(instr->key()->representation().IsInteger32() ||
2159
           instr->key()->representation().IsSmi());
2160

2161 2162
    if (instr->value()->representation().IsDouble()) {
      LOperand* object = UseRegisterAtStart(instr->elements());
2163
      LOperand* val = NULL;
2164
      val = UseRegisterAtStart(instr->value());
2165
      LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2166
      return new (zone()) LStoreKeyed(object, key, val, nullptr);
2167
    } else {
2168
      DCHECK(instr->value()->representation().IsSmiOrTagged());
2169 2170 2171
      bool needs_write_barrier = instr->NeedsWriteBarrier();

      LOperand* obj = UseRegister(instr->elements());
2172 2173 2174 2175 2176 2177
      LOperand* val;
      LOperand* key;
      if (needs_write_barrier) {
        val = UseTempRegister(instr->value());
        key = UseTempRegister(instr->key());
      } else {
2178 2179
        val = UseRegisterOrConstantAtStart(instr->value());
        key = UseRegisterOrConstantAtStart(instr->key());
2180
      }
2181
      return new (zone()) LStoreKeyed(obj, key, val, nullptr);
2182
    }
2183
  }
2184

2185
  ElementsKind elements_kind = instr->elements_kind();
2186
  DCHECK(
2187
      (instr->value()->representation().IsInteger32() &&
2188
       !IsDoubleOrFloatElementsKind(elements_kind)) ||
2189
      (instr->value()->representation().IsDouble() &&
2190
       IsDoubleOrFloatElementsKind(elements_kind)));
2191
  DCHECK(instr->elements()->representation().IsExternal());
2192

2193
  LOperand* backing_store = UseRegister(instr->elements());
2194
  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2195
  LOperand* val = GetStoreKeyedValueOperand(instr);
2196 2197 2198 2199 2200
  bool clobbers_key = ExternalArrayOpRequiresTemp(
      instr->key()->representation(), elements_kind);
  LOperand* key = clobbers_key
      ? UseTempRegister(instr->key())
      : UseRegisterOrConstantAtStart(instr->key());
2201
  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2202 2203 2204
}


2205 2206
LInstruction* LChunkBuilder::DoTransitionElementsKind(
    HTransitionElementsKind* instr) {
2207
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2208 2209 2210 2211
    LOperand* object = UseRegister(instr->object());
    LOperand* new_map_reg = TempRegister();
    LOperand* temp_reg = TempRegister();
    LTransitionElementsKind* result =
2212 2213 2214
        new(zone()) LTransitionElementsKind(object, NULL,
                                            new_map_reg, temp_reg);
    return result;
2215
  } else {
2216
    LOperand* object = UseFixed(instr->object(), eax);
2217
    LOperand* context = UseFixed(instr->context(), esi);
2218 2219
    LTransitionElementsKind* result =
        new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2220
    return MarkAsCall(result, instr);
2221 2222 2223 2224
  }
}


2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
    HTrapAllocationMemento* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* temp = TempRegister();
  LTrapAllocationMemento* result =
      new(zone()) LTrapAllocationMemento(object, temp);
  return AssignEnvironment(result);
}


2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
  info()->MarkAsDeferredCalling();
  LOperand* context = UseFixed(instr->context(), esi);
  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, eax);
  return AssignPointerMap(AssignEnvironment(result));
}


2250
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2251
  bool is_in_object = instr->access().IsInobject();
2252 2253
  bool is_external_location = instr->access().IsExternalMemory() &&
      instr->access().offset() == 0;
2254
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2255 2256
  bool needs_write_barrier_for_map = instr->has_transition() &&
      instr->NeedsWriteBarrierForMap();
2257

2258 2259
  LOperand* obj;
  if (needs_write_barrier) {
2260
    obj = is_in_object
2261 2262
        ? UseRegister(instr->object())
        : UseTempRegister(instr->object());
2263
  } else if (is_external_location) {
2264 2265 2266
    DCHECK(!is_in_object);
    DCHECK(!needs_write_barrier);
    DCHECK(!needs_write_barrier_for_map);
2267
    obj = UseRegisterOrConstant(instr->object());
2268
  } else {
2269 2270 2271
    obj = needs_write_barrier_for_map
        ? UseRegister(instr->object())
        : UseRegisterAtStart(instr->object());
2272
  }
2273

2274
  bool can_be_constant = instr->value()->IsConstant() &&
2275
      HConstant::cast(instr->value())->NotInNewSpace() &&
2276
      !instr->field_representation().IsDouble();
2277

2278
  LOperand* val;
2279 2280
  if (instr->field_representation().IsInteger8() ||
      instr->field_representation().IsUInteger8()) {
2281 2282 2283 2284
    // mov_b requires a byte register (i.e. any of eax, ebx, ecx, edx).
    // Just force the value to be in eax and we're safe here.
    val = UseFixed(instr->value(), eax);
  } else if (needs_write_barrier) {
2285
    val = UseTempRegister(instr->value());
2286
  } else if (can_be_constant) {
2287
    val = UseRegisterOrConstant(instr->value());
2288
  } else if (instr->field_representation().IsDouble()) {
2289
    val = UseRegisterAtStart(instr->value());
2290 2291 2292
  } else {
    val = UseRegister(instr->value());
  }
2293 2294 2295

  // 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).
2296 2297 2298 2299 2300
  LOperand* temp = (!is_in_object || needs_write_barrier ||
                    needs_write_barrier_for_map) ? TempRegister() : NULL;

  // We need a temporary register for write barrier of the map field.
  LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
2301

2302
  return new(zone()) LStoreNamedField(obj, val, temp, temp_map);
2303 2304 2305
}


2306
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2307
  LOperand* context = UseFixed(instr->context(), esi);
2308 2309
  LOperand* left = UseFixed(instr->left(), edx);
  LOperand* right = UseFixed(instr->right(), eax);
2310
  LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
2311
  return MarkAsCall(DefineFixed(string_add, eax), instr);
2312 2313 2314
}


2315
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2316 2317
  LOperand* string = UseTempRegister(instr->string());
  LOperand* index = UseTempRegister(instr->index());
2318
  LOperand* context = UseAny(instr->context());
2319 2320
  LStringCharCodeAt* result =
      new(zone()) LStringCharCodeAt(context, string, index);
2321
  return AssignPointerMap(DefineAsRegister(result));
2322 2323 2324
}


2325 2326
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
  LOperand* char_code = UseRegister(instr->value());
2327
  LOperand* context = UseAny(instr->context());
2328 2329
  LStringCharFromCode* result =
      new(zone()) LStringCharFromCode(context, char_code);
2330 2331 2332 2333
  return AssignPointerMap(DefineAsRegister(result));
}


2334
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
  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));
  }
2348 2349 2350
}


2351
LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2352
  DCHECK(argument_count_ == 0);
2353 2354
  allocator_->MarkAsOsrEntry();
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2355
  return AssignEnvironment(new(zone()) LOsrEntry);
2356 2357 2358 2359
}


LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2360
  LParameter* result = new(zone()) LParameter;
2361
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2362 2363 2364
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
    return DefineAsSpilled(result, spill_index);
  } else {
2365
    DCHECK(info()->IsStub());
2366
    CallInterfaceDescriptor descriptor = graph()->descriptor();
2367
    int index = static_cast<int>(instr->index());
2368
    Register reg = descriptor.GetRegisterParameter(index);
2369 2370
    return DefineFixed(result, reg);
  }
2371 2372 2373 2374
}


LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2375 2376 2377 2378 2379 2380 2381 2382 2383
  // 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) {
2384
      Retry(kNotEnoughSpillSlotsForOsr);
2385 2386
      spill_index = 0;
    }
2387
    spill_index += StandardFrameConstants::kFixedSlotCount;
2388
  }
2389
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2390 2391 2392 2393
}


LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2394 2395 2396 2397
  // 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.
2398 2399 2400 2401
  return NULL;
}


2402
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2403
  instr->ReplayEnvironment(current_block_->last_environment());
2404

2405 2406 2407 2408 2409
  // There are no real uses of a captured object.
  return NULL;
}


2410
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2411
  info()->MarkAsRequiresFrame();
2412
  LOperand* args = UseRegister(instr->arguments());
2413 2414 2415 2416 2417 2418 2419 2420 2421
  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());
  }
2422
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2423 2424 2425 2426
}


LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2427
  LOperand* context = UseFixed(instr->context(), esi);
2428
  LOperand* value = UseFixed(instr->value(), ebx);
2429
  LTypeof* result = new(zone()) LTypeof(context, value);
2430 2431 2432 2433
  return MarkAsCall(DefineFixed(result, eax), instr);
}


2434
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2435
  return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2436 2437
}

2438

2439
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2440
  instr->ReplayEnvironment(current_block_->last_environment());
2441 2442 2443 2444 2445
  return NULL;
}


LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2446
  info()->MarkAsDeferredCalling();
2447 2448 2449 2450
  if (instr->is_function_entry()) {
    LOperand* context = UseFixed(instr->context(), esi);
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
  } else {
2451
    DCHECK(instr->is_backwards_branch());
2452 2453 2454 2455
    LOperand* context = UseAny(instr->context());
    return AssignEnvironment(
        AssignPointerMap(new(zone()) LStackCheck(context)));
  }
2456 2457 2458 2459 2460
}


LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
  HEnvironment* outer = current_block_->last_environment();
2461
  outer->set_ast_id(instr->ReturnId());
2462
  HConstant* undefined = graph()->GetConstantUndefined();
2463 2464 2465
  HEnvironment* inner = outer->CopyForInlining(
      instr->closure(), instr->arguments_count(), instr->function(), undefined,
      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2466 2467 2468
  // 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());
2469
  }
2470
  inner->BindContext(instr->closure_context());
2471
  inner->set_entry(instr);
2472
  current_block_->UpdateEnvironment(inner);
2473
  chunk_->AddInlinedFunction(instr->shared());
2474 2475 2476 2477 2478
  return NULL;
}


LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2479 2480 2481 2482
  LInstruction* pop = NULL;

  HEnvironment* env = current_block_->last_environment();

2483
  if (env->entry()->arguments_pushed()) {
2484 2485
    int argument_count = env->arguments_environment()->parameter_count();
    pop = new(zone()) LDrop(argument_count);
2486
    DCHECK(instr->argument_delta() == -argument_count);
2487 2488
  }

2489 2490
  HEnvironment* outer = current_block_->last_environment()->
      DiscardInlined(false);
2491
  current_block_->UpdateEnvironment(outer);
2492
  return pop;
2493 2494 2495
}


2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
  LOperand* context = UseFixed(instr->context(), esi);
  LOperand* object = UseFixed(instr->enumerable(), eax);
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
  return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
}


LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
  LOperand* map = UseRegister(instr->map());
  return AssignEnvironment(DefineAsRegister(
      new(zone()) LForInCacheArray(map)));
}


LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* map = UseRegisterAtStart(instr->map());
  return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
}


LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* index = UseTempRegister(instr->index());
2521 2522 2523
  LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
  LInstruction* result = DefineSameAsFirst(load);
  return AssignPointerMap(result);
2524 2525
}

2526 2527
}  // namespace internal
}  // namespace v8
2528 2529

#endif  // V8_TARGET_ARCH_IA32