lithium-arm.cc 86.6 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 6
#include <sstream>

7
#include "src/v8.h"
8

9 10
#include "src/arm/lithium-codegen-arm.h"
#include "src/hydrogen-osr.h"
11
#include "src/lithium-inl.h"
12 13 14 15 16 17 18 19 20 21 22

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

23 24
#ifdef DEBUG
void LInstruction::VerifyCall() {
25 26 27 28
  // 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.
29
  DCHECK(Output() == NULL ||
30 31
         LUnallocated::cast(Output())->HasFixedPolicy() ||
         !LUnallocated::cast(Output())->HasRegisterPolicy());
32 33
  for (UseIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
34
    DCHECK(operand->HasFixedPolicy() ||
35
           operand->IsUsedAtStart());
36
  }
37 38
  for (TempIterator it(this); !it.Done(); it.Advance()) {
    LUnallocated* operand = LUnallocated::cast(it.Current());
39
    DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
40 41 42 43 44
  }
}
#endif


45
void LInstruction::PrintTo(StringStream* stream) {
46
  stream->Add("%s ", this->Mnemonic());
47 48

  PrintOutputOperandTo(stream);
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63
  PrintDataTo(stream);

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

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


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


77 78
void LInstruction::PrintOutputOperandTo(StringStream* stream) {
  if (HasResult()) result()->PrintTo(stream);
79 80 81 82
}


void LLabel::PrintDataTo(StringStream* stream) {
fschneider@chromium.org's avatar
fschneider@chromium.org committed
83
  LGap::PrintDataTo(stream);
84 85 86 87 88 89 90 91 92 93 94 95 96
  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
97

98 99 100 101
  return true;
}


102
void LGap::PrintDataTo(StringStream* stream) {
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
  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";
134 135 136
    case Token::BIT_AND: return "bit-and-t";
    case Token::BIT_OR: return "bit-or-t";
    case Token::BIT_XOR: return "bit-xor-t";
137
    case Token::ROR: return "ror-t";
138 139 140
    case Token::SHL: return "shl-t";
    case Token::SAR: return "sar-t";
    case Token::SHR: return "shr-t";
141 142 143 144 145 146 147
    default:
      UNREACHABLE();
      return NULL;
  }
}


148 149 150 151 152
bool LGoto::HasInterestingComment(LCodeGen* gen) const {
  return !gen->IsNextEmittedBlock(block_id());
}


153
void LGoto::PrintDataTo(StringStream* stream) {
154 155 156 157
  stream->Add("B%d", block_id());
}


158
void LBranch::PrintDataTo(StringStream* stream) {
159
  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
160
  value()->PrintTo(stream);
161 162 163
}


164
void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
165
  stream->Add("if ");
166
  left()->PrintTo(stream);
167
  stream->Add(" %s ", Token::String(op()));
168
  right()->PrintTo(stream);
169 170 171 172
  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
}


173
void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
174
  stream->Add("if is_object(");
175
  value()->PrintTo(stream);
176 177 178 179
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


180 181
void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if is_string(");
182
  value()->PrintTo(stream);
183 184 185 186
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


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


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


201 202
void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
  stream->Add("if string_compare(");
203 204
  left()->PrintTo(stream);
  right()->PrintTo(stream);
205 206 207 208
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


209
void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
210
  stream->Add("if has_instance_type(");
211
  value()->PrintTo(stream);
212 213 214 215
  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
}


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


223
void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
224
  stream->Add("if class_of_test(");
225
  value()->PrintTo(stream);
226 227 228 229 230 231 232
  stream->Add(", \"%o\") then B%d else B%d",
              *hydrogen()->class_name(),
              true_block_id(),
              false_block_id());
}


233
void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
234
  stream->Add("if typeof ");
235
  value()->PrintTo(stream);
236
  stream->Add(" == \"%s\" then B%d else B%d",
237
              hydrogen()->type_literal()->ToCString().get(),
238 239 240 241
              true_block_id(), false_block_id());
}


242 243 244 245 246 247 248 249
void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  function()->PrintTo(stream);
  stream->Add(".code_entry = ");
  code_object()->PrintTo(stream);
}


250 251 252
void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
  stream->Add(" = ");
  base_object()->PrintTo(stream);
253 254
  stream->Add(" + ");
  offset()->PrintTo(stream);
255 256 257
}


258 259 260 261 262 263 264 265 266 267 268 269
void LCallJSFunction::PrintDataTo(StringStream* stream) {
  stream->Add("= ");
  function()->PrintTo(stream);
  stream->Add("#%d / ", arity());
}


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


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


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


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


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


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


310
void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
311 312 313 314 315 316 317 318
  arguments()->PrintTo(stream);
  stream->Add(" length ");
  length()->PrintTo(stream);
  stream->Add(" index ");
  index()->PrintTo(stream);
}


319
void LStoreNamedField::PrintDataTo(StringStream* stream) {
320
  object()->PrintTo(stream);
321
  std::ostringstream os;
322
  os << hydrogen()->access() << " <- ";
323
  stream->Add(os.str().c_str());
324 325 326 327
  value()->PrintTo(stream);
}


328 329 330
void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(".");
331
  stream->Add(String::cast(*name())->ToCString().get());
332 333 334 335 336
  stream->Add(" <- ");
  value()->PrintTo(stream);
}


337 338 339 340 341
void LLoadKeyed::PrintDataTo(StringStream* stream) {
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  if (hydrogen()->IsDehoisted()) {
342
    stream->Add(" + %d]", base_offset());
343 344 345 346 347 348
  } else {
    stream->Add("]");
  }
}


349
void LStoreKeyed::PrintDataTo(StringStream* stream) {
350 351 352
  elements()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
353
  if (hydrogen()->IsDehoisted()) {
354
    stream->Add(" + %d] <-", base_offset());
355 356 357
  } else {
    stream->Add("] <- ");
  }
358 359

  if (value() == NULL) {
360
    DCHECK(hydrogen()->IsConstantHoleStore() &&
361 362 363 364 365
           hydrogen()->value()->representation().IsDouble());
    stream->Add("<the hole(nan)>");
  } else {
    value()->PrintTo(stream);
  }
366 367 368
}


369
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
370 371 372 373 374 375 376 377
  object()->PrintTo(stream);
  stream->Add("[");
  key()->PrintTo(stream);
  stream->Add("] <- ");
  value()->PrintTo(stream);
}


378 379 380 381 382 383
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
  object()->PrintTo(stream);
  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
}


384
int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
385
  // Skip a slot if for a double-width slot.
386
  if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
387 388 389 390
  return spill_slot_count_++;
}


391 392 393
LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind)  {
  int index = GetNextSpillIndex(kind);
  if (kind == DOUBLE_REGISTERS) {
394
    return LDoubleStackSlot::Create(index, zone());
395
  } else {
396
    DCHECK(kind == GENERAL_REGISTERS);
397
    return LStackSlot::Create(index, zone());
398 399 400 401
  }
}


402
LPlatformChunk* LChunkBuilder::Build() {
403
  DCHECK(is_unused());
404
  chunk_ = new(zone()) LPlatformChunk(info(), graph());
405
  LPhase phase("L_Building chunk", chunk_);
406
  status_ = BUILDING;
407 408 409 410 411

  // 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--) {
412
      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
413 414 415
    }
  }

416 417 418 419 420 421 422 423 424 425 426 427 428
  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) {
429 430
  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
                                  Register::ToAllocationIndex(reg));
431 432 433 434
}


LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
435 436
  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
                                  DoubleRegister::ToAllocationIndex(reg));
437 438 439 440 441 442 443 444 445 446 447 448 449 450
}


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


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


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


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


LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
463
  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
464 465 466 467
}


LOperand* LChunkBuilder::Use(HValue* value) {
468
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
469 470 471 472
}


LOperand* LChunkBuilder::UseAtStart(HValue* value) {
473 474
  return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
                                             LUnallocated::USED_AT_START));
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
}


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


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


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


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


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


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


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


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


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


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


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


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


563
LInstruction* LChunkBuilder::DefineFixedDouble(
564
    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
565 566 567 568 569 570
  return Define(instr, ToUnallocated(reg));
}


LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
  HEnvironment* hydrogen_env = current_block_->last_environment();
571
  int argument_index_accumulator = 0;
572
  ZoneList<HValue*> objects_to_materialize(0, zone());
573
  instr->set_environment(CreateEnvironment(hydrogen_env,
574 575
                                           &argument_index_accumulator,
                                           &objects_to_materialize));
576 577 578 579 580 581 582
  return instr;
}


LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
                                        HInstruction* hinstr,
                                        CanDeoptimize can_deoptimize) {
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 618
  int vreg = allocator_->GetVirtualRegister();
  if (!allocator_->AllocationOk()) {
619
    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
620
    vreg = 0;
621 622
  }
  operand->set_virtual_register(vreg);
623 624 625 626
  return operand;
}


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


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


LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
  LUnallocated* operand = ToUnallocated(reg);
649
  DCHECK(operand->HasFixedPolicy());
650 651 652 653 654
  return operand;
}


LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
655
  return new(zone()) LLabel(instr->block());
656 657 658
}


659 660 661 662 663
LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
}


664 665 666 667 668 669
LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
  UNREACHABLE();
  return NULL;
}


670
LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
671
  return AssignEnvironment(new(zone()) LDeoptimize);
672 673 674 675 676
}


LInstruction* LChunkBuilder::DoShift(Token::Value op,
                                     HBitwiseBinaryOperation* instr) {
677
  if (instr->representation().IsSmiOrInteger32()) {
678 679
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
680
    LOperand* left = UseRegisterAtStart(instr->left());
681

682 683 684 685 686 687 688
    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);
689
      constant_value = constant->Integer32Value() & 0x1f;
690 691 692 693 694 695 696
      // 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 = UseRegisterAtStart(right_value);
697
    }
698

699 700 701
    // 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) {
702
      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
703 704
    }

705 706 707 708 709 710
    LInstruction* result =
        DefineAsRegister(new(zone()) LShiftI(op, left, right, does_deopt));
    return does_deopt ? AssignEnvironment(result) : result;
  } else {
    return DoArithmeticT(op, instr);
  }
711 712 713 714 715
}


LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
                                           HArithmeticBinaryOperation* instr) {
716 717 718
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->left()->representation().IsDouble());
  DCHECK(instr->right()->representation().IsDouble());
719
  if (op == Token::MOD) {
720 721
    LOperand* left = UseFixedDouble(instr->left(), d0);
    LOperand* right = UseFixedDouble(instr->right(), d1);
722
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
723
    return MarkAsCall(DefineFixedDouble(result, d0), instr);
724 725 726 727 728
  } else {
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseRegisterAtStart(instr->right());
    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
    return DefineAsRegister(result);
729
  }
730 731 732 733
}


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

747

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

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

846
  argument_count_ += current->argument_delta();
847
  DCHECK(argument_count_ >= 0);
848

849
  if (instr != NULL) {
850 851 852 853 854 855 856 857 858 859 860 861
    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);
862

863
#if DEBUG
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
  // 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;
884
    }
885 886 887 888
    for (TempIterator it(instr); !it.Done(); it.Advance()) {
      LUnallocated* operand = LUnallocated::cast(it.Current());
      if (operand->HasFixedPolicy()) ++fixed;
    }
889
    DCHECK(fixed == 0 || used_at_start == 0);
890
  }
891 892
#endif

893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
    instr = AssignPointerMap(instr);
  }
  if (FLAG_stress_environments && !instr->HasEnvironment()) {
    instr = AssignEnvironment(instr);
  }
  chunk_->AddInstruction(instr, current_block_);

  if (instr->IsCall()) {
    HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
    LInstruction* instruction_needing_environment = NULL;
    if (hydrogen_val->HasObservableSideEffects()) {
      HSimulate* sim = HSimulate::cast(hydrogen_val->next());
      instruction_needing_environment = instr;
      sim->ReplayEnvironment(current_block_->last_environment());
      hydrogen_value_for_lazy_bailout = sim;
909
    }
910 911 912 913 914 915 916 917
    LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
    bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
    chunk_->AddInstruction(bailout, current_block_);
    if (instruction_needing_environment != NULL) {
      // Store the lazy deopt environment with the instruction if needed.
      // Right now it is only used for LInstanceOfKnownGlobal.
      instruction_needing_environment->
          SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
918
    }
919 920 921 922 923
  }
}


LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
924
  return new(zone()) LGoto(instr->FirstSuccessor());
925 926 927
}


928
LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
929
  HValue* value = instr->value();
930
  Representation r = value->representation();
931
  HType type = value->type();
932
  ToBooleanStub::Types expected = instr->expected_input_types();
933 934 935 936 937 938 939 940 941
  if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();

  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
      type.IsJSArray() || type.IsHeapNumber() || type.IsString();
  LInstruction* branch = new(zone()) LBranch(UseRegister(value));
  if (!easy_case &&
      ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
       !expected.IsGeneric())) {
    branch = AssignEnvironment(branch);
942
  }
943
  return branch;
944 945 946
}


947 948 949 950
LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
  return new(zone()) LDebugBreak();
}

951

952
LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
953
  DCHECK(instr->value()->representation().IsTagged());
954
  LOperand* value = UseRegisterAtStart(instr->value());
955
  LOperand* temp = TempRegister();
956
  return new(zone()) LCmpMapAndBranch(value, temp);
957 958 959
}


960
LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
961
  info()->MarkAsRequiresFrame();
962 963
  LOperand* value = UseRegister(instr->value());
  return DefineAsRegister(new(zone()) LArgumentsLength(value));
964 965 966 967
}


LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
968
  info()->MarkAsRequiresFrame();
969
  return DefineAsRegister(new(zone()) LArgumentsElements);
970 971 972 973
}


LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
974
  LOperand* context = UseFixed(instr->context(), cp);
975
  LInstanceOf* result =
976 977
      new(zone()) LInstanceOf(context, UseFixed(instr->left(), r0),
                              UseFixed(instr->right(), r1));
978 979 980 981
  return MarkAsCall(DefineFixed(result, r0), instr);
}


982 983
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
    HInstanceOfKnownGlobal* instr) {
984
  LInstanceOfKnownGlobal* result =
985 986 987 988
      new(zone()) LInstanceOfKnownGlobal(
          UseFixed(instr->context(), cp),
          UseFixed(instr->left(), r0),
          FixedTemp(r4));
989
  return MarkAsCall(DefineFixed(result, r0), instr);
990 991 992
}


993 994 995 996
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
  LOperand* receiver = UseRegisterAtStart(instr->receiver());
  LOperand* function = UseRegisterAtStart(instr->function());
  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
997
  return AssignEnvironment(DefineAsRegister(result));
998 999 1000
}


1001 1002 1003
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
  LOperand* function = UseFixed(instr->function(), r1);
  LOperand* receiver = UseFixed(instr->receiver(), r0);
1004 1005
  LOperand* length = UseFixed(instr->length(), r2);
  LOperand* elements = UseFixed(instr->elements(), r3);
1006
  LApplyArguments* result = new(zone()) LApplyArguments(function,
1007 1008 1009
                                                receiver,
                                                length,
                                                elements);
1010 1011 1012 1013
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
}


1014 1015 1016 1017 1018 1019 1020
LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
  int argc = instr->OperandCount();
  for (int i = 0; i < argc; ++i) {
    LOperand* argument = Use(instr->argument(i));
    AddInstruction(new(zone()) LPushArgument(argument), instr);
  }
  return NULL;
1021 1022 1023
}


1024 1025 1026 1027 1028 1029 1030 1031
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);
}


1032
LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1033 1034 1035 1036 1037
    HInnerAllocatedObject* instr) {
  LOperand* base_object = UseRegisterAtStart(instr->base_object());
  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
  return DefineAsRegister(
      new(zone()) LInnerAllocatedObject(base_object, offset));
1038 1039 1040
}


1041
LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1042 1043 1044
  return instr->HasNoUses()
      ? NULL
      : DefineAsRegister(new(zone()) LThisFunction);
1045 1046 1047
}


1048
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1049 1050 1051 1052
  if (instr->HasNoUses()) return NULL;

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

1055
  return DefineAsRegister(new(zone()) LContext);
1056 1057 1058
}


1059
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1060 1061
  LOperand* context = UseFixed(instr->context(), cp);
  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1062 1063 1064
}


1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
LInstruction* LChunkBuilder::DoCallJSFunction(
    HCallJSFunction* instr) {
  LOperand* function = UseFixed(instr->function(), r1);

  LCallJSFunction* result = new(zone()) LCallJSFunction(function);

  return MarkAsCall(DefineFixed(result, r0), instr);
}


LInstruction* LChunkBuilder::DoCallWithDescriptor(
    HCallWithDescriptor* instr) {
1077
  CallInterfaceDescriptor descriptor = instr->descriptor();
1078 1079 1080 1081 1082

  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
  ops.Add(target, zone());
  for (int i = 1; i < instr->OperandCount(); i++) {
1083 1084
    LOperand* op =
        UseFixed(instr->OperandAt(i), descriptor.GetParameterRegister(i - 1));
1085 1086 1087 1088 1089 1090
    ops.Add(op, zone());
  }

  LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
      descriptor, ops, zone());
  return MarkAsCall(DefineFixed(result, r0), instr);
1091 1092 1093
}


1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
    HTailCallThroughMegamorphicCache* instr) {
  LOperand* context = UseFixed(instr->context(), cp);
  LOperand* receiver_register =
      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
  LOperand* name_register =
      UseFixed(instr->name(), LoadDescriptor::NameRegister());
  // Not marked as call. It can't deoptimize, and it never returns.
  return new (zone()) LTailCallThroughMegamorphicCache(
      context, receiver_register, name_register);
}


1107
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1108
  LOperand* context = UseFixed(instr->context(), cp);
1109
  LOperand* function = UseFixed(instr->function(), r1);
1110
  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1111 1112 1113 1114
  return MarkAsCall(DefineFixed(result, r0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}


1115
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1116
  switch (instr->op()) {
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
    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);
1135 1136 1137
    default:
      UNREACHABLE();
      return NULL;
1138 1139 1140 1141
  }
}


1142 1143 1144 1145 1146 1147 1148 1149 1150
LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
  LOperand* input = UseRegister(instr->value());
  LMathFloor* result = new(zone()) LMathFloor(input);
  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}


LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
  LOperand* input = UseRegister(instr->value());
1151
  LOperand* temp = TempDoubleRegister();
1152 1153 1154 1155 1156
  LMathRound* result = new(zone()) LMathRound(input, temp);
  return AssignEnvironment(DefineAsRegister(result));
}


1157 1158 1159 1160 1161 1162 1163
LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
  LOperand* input = UseRegister(instr->value());
  LMathFround* result = new (zone()) LMathFround(input);
  return DefineAsRegister(result);
}


1164
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1165 1166 1167 1168
  Representation r = instr->value()->representation();
  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
      ? NULL
      : UseFixed(instr->context(), cp);
1169
  LOperand* input = UseRegister(instr->value());
1170 1171 1172 1173 1174
  LInstruction* result =
      DefineAsRegister(new(zone()) LMathAbs(context, input));
  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
  if (!r.IsDouble()) result = AssignEnvironment(result);
  return result;
1175 1176 1177 1178
}


LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1179 1180
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
1181 1182
  LOperand* input = UseFixedDouble(instr->value(), d0);
  return MarkAsCall(DefineFixedDouble(new(zone()) LMathLog(input), d0), instr);
1183 1184 1185
}


1186 1187 1188 1189 1190 1191 1192
LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
  LOperand* input = UseRegisterAtStart(instr->value());
  LMathClz32* result = new(zone()) LMathClz32(input);
  return DefineAsRegister(result);
}


1193
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1194 1195
  DCHECK(instr->representation().IsDouble());
  DCHECK(instr->value()->representation().IsDouble());
1196
  LOperand* input = UseRegister(instr->value());
1197 1198
  LOperand* temp1 = TempRegister();
  LOperand* temp2 = TempRegister();
1199
  LOperand* double_temp = TempDoubleRegister();
1200 1201 1202 1203 1204 1205
  LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
  return DefineAsRegister(result);
}


LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1206
  LOperand* input = UseRegisterAtStart(instr->value());
1207 1208 1209 1210 1211 1212
  LMathSqrt* result = new(zone()) LMathSqrt(input);
  return DefineAsRegister(result);
}


LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1213 1214 1215
  LOperand* input = UseRegisterAtStart(instr->value());
  LMathPowHalf* result = new(zone()) LMathPowHalf(input);
  return DefineAsRegister(result);
1216 1217 1218
}


1219
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1220
  LOperand* context = UseFixed(instr->context(), cp);
1221
  LOperand* constructor = UseFixed(instr->constructor(), r1);
1222
  LCallNew* result = new(zone()) LCallNew(context, constructor);
1223 1224 1225 1226
  return MarkAsCall(DefineFixed(result, r0), instr);
}


1227
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1228
  LOperand* context = UseFixed(instr->context(), cp);
1229
  LOperand* constructor = UseFixed(instr->constructor(), r1);
1230
  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1231 1232 1233 1234
  return MarkAsCall(DefineFixed(result, r0), instr);
}


1235
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1236
  LOperand* context = UseFixed(instr->context(), cp);
1237
  LOperand* function = UseFixed(instr->function(), r1);
1238
  LCallFunction* call = new(zone()) LCallFunction(context, function);
verwaest@chromium.org's avatar
verwaest@chromium.org committed
1239
  return MarkAsCall(DefineFixed(call, r0), instr);
1240 1241 1242 1243
}


LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1244 1245
  LOperand* context = UseFixed(instr->context(), cp);
  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), r0), instr);
1246 1247 1248
}


1249 1250 1251 1252 1253
LInstruction* LChunkBuilder::DoRor(HRor* instr) {
  return DoShift(Token::ROR, instr);
}


1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
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);
}


1269
LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1270
  if (instr->representation().IsSmiOrInteger32()) {
1271 1272 1273
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1274

1275 1276
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1277
    return DefineAsRegister(new(zone()) LBitI(left, right));
1278
  } else {
1279
    return DoArithmeticT(instr->op(), instr);
1280
  }
1281 1282 1283
}


1284
LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1285 1286 1287
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1288 1289
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1290 1291 1292 1293
  LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
          dividend, divisor));
  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1294
      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1295 1296 1297 1298
       divisor != 1 && divisor != -1)) {
    result = AssignEnvironment(result);
  }
  return result;
1299 1300 1301
}


1302
LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1303 1304 1305
  DCHECK(instr->representation().IsInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1306 1307
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1308 1309 1310 1311 1312 1313 1314 1315
  LInstruction* result = DefineAsRegister(new(zone()) LDivByConstI(
          dividend, divisor));
  if (divisor == 0 ||
      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
    result = AssignEnvironment(result);
  }
  return result;
1316 1317 1318
}


1319
LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1320 1321 1322
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1323 1324
  LOperand* dividend = UseRegister(instr->left());
  LOperand* divisor = UseRegister(instr->right());
1325 1326
  LOperand* temp =
      CpuFeatures::IsSupported(SUDIV) ? NULL : TempDoubleRegister();
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
  LInstruction* result =
      DefineAsRegister(new(zone()) LDivI(dividend, divisor, temp));
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
      (instr->CheckFlag(HValue::kCanOverflow) &&
       (!CpuFeatures::IsSupported(SUDIV) ||
        !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) ||
      (!instr->IsMathFloorOfDiv() &&
       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
    result = AssignEnvironment(result);
  }
  return result;
1339 1340 1341
}


1342
LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1343
  if (instr->representation().IsSmiOrInteger32()) {
1344 1345 1346 1347 1348 1349 1350
    if (instr->RightIsPowerOf2()) {
      return DoDivByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoDivByConstI(instr);
    } else {
      return DoDivI(instr);
    }
1351 1352
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::DIV, instr);
1353 1354 1355 1356 1357 1358
  } else {
    return DoArithmeticT(Token::DIV, instr);
  }
}


1359 1360 1361
LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1362 1363 1364 1365 1366 1367 1368
  LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
          dividend, divisor));
  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
    result = AssignEnvironment(result);
  }
  return result;
1369 1370
}

1371

1372
LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1373 1374 1375
  DCHECK(instr->representation().IsInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1376
  LOperand* dividend = UseRegister(instr->left());
1377
  int32_t divisor = instr->right()->GetInteger32Constant();
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
  LOperand* temp =
      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
      NULL : TempRegister();
  LInstruction* result = DefineAsRegister(
      new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
  if (divisor == 0 ||
      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
    result = AssignEnvironment(result);
  }
  return result;
1389 1390 1391
}


1392
LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1393 1394 1395
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1396 1397
  LOperand* dividend = UseRegister(instr->left());
  LOperand* divisor = UseRegister(instr->right());
1398 1399
  LOperand* temp =
      CpuFeatures::IsSupported(SUDIV) ? NULL : TempDoubleRegister();
1400 1401 1402 1403 1404
  LFlooringDivI* div = new(zone()) LFlooringDivI(dividend, divisor, temp);
  return AssignEnvironment(DefineAsRegister(div));
}


1405 1406 1407
LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
  if (instr->RightIsPowerOf2()) {
    return DoFlooringDivByPowerOf2I(instr);
1408 1409
  } else if (instr->right()->IsConstant()) {
    return DoFlooringDivByConstI(instr);
1410
  } else {
1411
    return DoFlooringDivI(instr);
1412 1413 1414 1415 1416
  }
}


LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1417 1418 1419
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1420 1421
  LOperand* dividend = UseRegisterAtStart(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1422 1423
  LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
          dividend, divisor));
1424 1425
  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1426 1427 1428
    result = AssignEnvironment(result);
  }
  return result;
1429 1430 1431
}


1432
LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1433 1434 1435
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1436 1437
  LOperand* dividend = UseRegister(instr->left());
  int32_t divisor = instr->right()->GetInteger32Constant();
1438 1439 1440 1441 1442 1443
  LInstruction* result = DefineAsRegister(new(zone()) LModByConstI(
          dividend, divisor));
  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
  }
  return result;
1444 1445 1446
}


1447
LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1448 1449 1450
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1451 1452
  LOperand* dividend = UseRegister(instr->left());
  LOperand* divisor = UseRegister(instr->right());
1453 1454 1455 1456
  LOperand* temp =
      CpuFeatures::IsSupported(SUDIV) ? NULL : TempDoubleRegister();
  LOperand* temp2 =
      CpuFeatures::IsSupported(SUDIV) ? NULL : TempDoubleRegister();
1457 1458 1459 1460 1461
  LInstruction* result = DefineAsRegister(new(zone()) LModI(
          dividend, divisor, temp, temp2));
  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
    result = AssignEnvironment(result);
1462
  }
1463
  return result;
1464 1465 1466
}


1467
LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1468
  if (instr->representation().IsSmiOrInteger32()) {
1469 1470 1471 1472 1473 1474 1475
    if (instr->RightIsPowerOf2()) {
      return DoModByPowerOf2I(instr);
    } else if (instr->right()->IsConstant()) {
      return DoModByConstI(instr);
    } else {
      return DoModI(instr);
    }
1476 1477
  } else if (instr->representation().IsDouble()) {
    return DoArithmeticD(Token::MOD, instr);
1478
  } else {
1479
    return DoArithmeticT(Token::MOD, instr);
1480 1481 1482 1483 1484
  }
}


LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1485
  if (instr->representation().IsSmiOrInteger32()) {
1486 1487
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
    HValue* left = instr->BetterLeftOperand();
    HValue* right = instr->BetterRightOperand();
    LOperand* left_op;
    LOperand* right_op;
    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);

    if (right->IsConstant()) {
      HConstant* constant = HConstant::cast(right);
      int32_t constant_value = constant->Integer32Value();
      // Constants -1, 0 and 1 can be optimized if the result can overflow.
      // For other constants, it can be optimized only without overflow.
      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
        left_op = UseRegisterAtStart(left);
        right_op = UseConstant(right);
      } else {
        if (bailout_on_minus_zero) {
          left_op = UseRegister(left);
        } else {
          left_op = UseRegisterAtStart(left);
        }
        right_op = UseRegister(right);
      }
1511
    } else {
1512 1513 1514 1515 1516 1517
      if (bailout_on_minus_zero) {
        left_op = UseRegister(left);
      } else {
        left_op = UseRegisterAtStart(left);
      }
      right_op = UseRegister(right);
1518
    }
1519 1520
    LMulI* mul = new(zone()) LMulI(left_op, right_op);
    if (can_overflow || bailout_on_minus_zero) {
1521 1522 1523
      AssignEnvironment(mul);
    }
    return DefineAsRegister(mul);
1524

1525
  } else if (instr->representation().IsDouble()) {
1526 1527
    if (instr->HasOneUse() && (instr->uses().value()->IsAdd() ||
                               instr->uses().value()->IsSub())) {
1528 1529 1530 1531 1532
      HBinaryOperation* use = HBinaryOperation::cast(instr->uses().value());

      if (use->IsAdd() && instr == use->left()) {
        // This mul is the lhs of an add. The add and mul will be folded into a
        // multiply-add in DoAdd.
1533 1534
        return NULL;
      }
1535
      if (instr == use->right() && use->IsAdd() && !use->left()->IsMul()) {
1536
        // This mul is the rhs of an add, where the lhs is not another mul.
1537 1538 1539 1540 1541 1542
        // The add and mul will be folded into a multiply-add in DoAdd.
        return NULL;
      }
      if (instr == use->right() && use->IsSub()) {
        // This mul is the rhs of a sub. The sub and mul will be folded into a
        // multiply-sub in DoSub.
1543 1544 1545
        return NULL;
      }
    }
1546

1547
    return DoArithmeticD(Token::MUL, instr);
1548 1549 1550 1551 1552 1553 1554
  } else {
    return DoArithmeticT(Token::MUL, instr);
  }
}


LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1555
  if (instr->representation().IsSmiOrInteger32()) {
1556 1557
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1558 1559 1560 1561 1562 1563

    if (instr->left()->IsConstant()) {
      // If lhs is constant, do reverse subtraction instead.
      return DoRSub(instr);
    }

1564 1565
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseOrConstantAtStart(instr->right());
1566
    LSubI* sub = new(zone()) LSubI(left, right);
1567
    LInstruction* result = DefineAsRegister(sub);
1568 1569 1570 1571 1572
    if (instr->CheckFlag(HValue::kCanOverflow)) {
      result = AssignEnvironment(result);
    }
    return result;
  } else if (instr->representation().IsDouble()) {
1573
    if (instr->right()->IsMul() && instr->right()->HasOneUse()) {
1574 1575 1576
      return DoMultiplySub(instr->left(), HMul::cast(instr->right()));
    }

1577 1578 1579 1580 1581 1582
    return DoArithmeticD(Token::SUB, instr);
  } else {
    return DoArithmeticT(Token::SUB, instr);
  }
}

1583 1584

LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1585 1586 1587
  DCHECK(instr->representation().IsSmiOrInteger32());
  DCHECK(instr->left()->representation().Equals(instr->representation()));
  DCHECK(instr->right()->representation().Equals(instr->representation()));
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601

  // Note: The lhs of the subtraction becomes the rhs of the
  // reverse-subtraction.
  LOperand* left = UseRegisterAtStart(instr->right());
  LOperand* right = UseOrConstantAtStart(instr->left());
  LRSubI* rsb = new(zone()) LRSubI(left, right);
  LInstruction* result = DefineAsRegister(rsb);
  if (instr->CheckFlag(HValue::kCanOverflow)) {
    result = AssignEnvironment(result);
  }
  return result;
}


1602 1603 1604 1605 1606 1607 1608
LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());
  LOperand* addend_op = UseRegisterAtStart(addend);
  return DefineSameAsFirst(new(zone()) LMultiplyAddD(addend_op, multiplier_op,
                                                     multiplicand_op));
}
1609

1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621

LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
  LOperand* minuend_op = UseRegisterAtStart(minuend);
  LOperand* multiplier_op = UseRegisterAtStart(mul->left());
  LOperand* multiplicand_op = UseRegisterAtStart(mul->right());

  return DefineSameAsFirst(new(zone()) LMultiplySubD(minuend_op,
                                                     multiplier_op,
                                                     multiplicand_op));
}


1622
LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1623
  if (instr->representation().IsSmiOrInteger32()) {
1624 1625
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1626 1627
    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1628
    LAddI* add = new(zone()) LAddI(left, right);
1629
    LInstruction* result = DefineAsRegister(add);
1630 1631 1632 1633
    if (instr->CheckFlag(HValue::kCanOverflow)) {
      result = AssignEnvironment(result);
    }
    return result;
1634
  } else if (instr->representation().IsExternal()) {
1635 1636 1637
    DCHECK(instr->left()->representation().IsExternal());
    DCHECK(instr->right()->representation().IsInteger32());
    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1638 1639 1640 1641 1642
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseOrConstantAtStart(instr->right());
    LAddI* add = new(zone()) LAddI(left, right);
    LInstruction* result = DefineAsRegister(add);
    return result;
1643
  } else if (instr->representation().IsDouble()) {
1644
    if (instr->left()->IsMul() && instr->left()->HasOneUse()) {
1645
      return DoMultiplyAdd(HMul::cast(instr->left()), instr->right());
1646
    }
1647

1648
    if (instr->right()->IsMul() && instr->right()->HasOneUse()) {
1649
      DCHECK(!instr->left()->IsMul() || !instr->left()->HasOneUse());
1650 1651 1652
      return DoMultiplyAdd(HMul::cast(instr->right()), instr->left());
    }

1653 1654 1655 1656 1657 1658 1659
    return DoArithmeticD(Token::ADD, instr);
  } else {
    return DoArithmeticT(Token::ADD, instr);
  }
}


1660 1661 1662
LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
  LOperand* left = NULL;
  LOperand* right = NULL;
1663
  if (instr->representation().IsSmiOrInteger32()) {
1664 1665
    DCHECK(instr->left()->representation().Equals(instr->representation()));
    DCHECK(instr->right()->representation().Equals(instr->representation()));
1666 1667
    left = UseRegisterAtStart(instr->BetterLeftOperand());
    right = UseOrConstantAtStart(instr->BetterRightOperand());
1668
  } else {
1669 1670 1671
    DCHECK(instr->representation().IsDouble());
    DCHECK(instr->left()->representation().IsDouble());
    DCHECK(instr->right()->representation().IsDouble());
1672 1673 1674 1675 1676 1677 1678
    left = UseRegisterAtStart(instr->left());
    right = UseRegisterAtStart(instr->right());
  }
  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
}


1679
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1680
  DCHECK(instr->representation().IsDouble());
1681 1682 1683
  // 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();
1684
  DCHECK(instr->left()->representation().IsDouble());
1685
  LOperand* left = UseFixedDouble(instr->left(), d0);
1686 1687 1688 1689
  LOperand* right =
      exponent_type.IsDouble()
          ? UseFixedDouble(instr->right(), d1)
          : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1690
  LPower* result = new(zone()) LPower(left, right);
1691
  return MarkAsCall(DefineFixedDouble(result, d2),
1692 1693
                    instr,
                    CAN_DEOPTIMIZE_EAGERLY);
1694 1695 1696
}


1697
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1698 1699
  DCHECK(instr->left()->representation().IsTagged());
  DCHECK(instr->right()->representation().IsTagged());
1700
  LOperand* context = UseFixed(instr->context(), cp);
1701 1702
  LOperand* left = UseFixed(instr->left(), r1);
  LOperand* right = UseFixed(instr->right(), r0);
1703
  LCmpT* result = new(zone()) LCmpT(context, left, right);
1704
  return MarkAsCall(DefineFixed(result, r0), instr);
1705 1706 1707
}


1708 1709
LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
    HCompareNumericAndBranch* instr) {
1710
  Representation r = instr->representation();
1711
  if (r.IsSmiOrInteger32()) {
1712 1713
    DCHECK(instr->left()->representation().Equals(r));
    DCHECK(instr->right()->representation().Equals(r));
1714 1715
    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1716
    return new(zone()) LCompareNumericAndBranch(left, right);
1717
  } else {
1718 1719 1720
    DCHECK(r.IsDouble());
    DCHECK(instr->left()->representation().IsDouble());
    DCHECK(instr->right()->representation().IsDouble());
1721 1722
    LOperand* left = UseRegisterAtStart(instr->left());
    LOperand* right = UseRegisterAtStart(instr->right());
1723
    return new(zone()) LCompareNumericAndBranch(left, right);
1724 1725 1726 1727
  }
}


1728 1729
LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
    HCompareObjectEqAndBranch* instr) {
1730 1731
  LOperand* left = UseRegisterAtStart(instr->left());
  LOperand* right = UseRegisterAtStart(instr->right());
1732
  return new(zone()) LCmpObjectEqAndBranch(left, right);
1733 1734 1735
}


1736 1737
LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
    HCompareHoleAndBranch* instr) {
1738 1739
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LCmpHoleAndBranch(value);
1740 1741 1742
}


1743 1744 1745 1746 1747 1748 1749 1750
LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
    HCompareMinusZeroAndBranch* instr) {
  LOperand* value = UseRegister(instr->value());
  LOperand* scratch = TempRegister();
  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
}


1751
LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1752
  DCHECK(instr->value()->representation().IsTagged());
1753
  LOperand* value = UseRegisterAtStart(instr->value());
1754
  LOperand* temp = TempRegister();
1755
  return new(zone()) LIsObjectAndBranch(value, temp);
1756 1757 1758
}


1759
LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1760
  DCHECK(instr->value()->representation().IsTagged());
1761
  LOperand* value = UseRegisterAtStart(instr->value());
1762
  LOperand* temp = TempRegister();
1763
  return new(zone()) LIsStringAndBranch(value, temp);
1764 1765 1766
}


1767
LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1768
  DCHECK(instr->value()->representation().IsTagged());
1769
  return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1770 1771 1772
}


1773 1774
LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
    HIsUndetectableAndBranch* instr) {
1775
  DCHECK(instr->value()->representation().IsTagged());
1776 1777
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
1778 1779 1780
}


1781 1782
LInstruction* LChunkBuilder::DoStringCompareAndBranch(
    HStringCompareAndBranch* instr) {
1783 1784
  DCHECK(instr->left()->representation().IsTagged());
  DCHECK(instr->right()->representation().IsTagged());
1785
  LOperand* context = UseFixed(instr->context(), cp);
1786 1787
  LOperand* left = UseFixed(instr->left(), r1);
  LOperand* right = UseFixed(instr->right(), r0);
1788
  LStringCompareAndBranch* result =
1789
      new(zone()) LStringCompareAndBranch(context, left, right);
1790 1791 1792 1793
  return MarkAsCall(result, instr);
}


1794 1795
LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
    HHasInstanceTypeAndBranch* instr) {
1796
  DCHECK(instr->value()->representation().IsTagged());
1797 1798
  LOperand* value = UseRegisterAtStart(instr->value());
  return new(zone()) LHasInstanceTypeAndBranch(value);
1799 1800 1801
}


1802 1803
LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
    HGetCachedArrayIndex* instr)  {
1804
  DCHECK(instr->value()->representation().IsTagged());
1805
  LOperand* value = UseRegisterAtStart(instr->value());
1806

1807
  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1808 1809 1810
}


1811 1812
LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
    HHasCachedArrayIndexAndBranch* instr) {
1813
  DCHECK(instr->value()->representation().IsTagged());
1814
  return new(zone()) LHasCachedArrayIndexAndBranch(
1815
      UseRegisterAtStart(instr->value()));
1816 1817 1818
}


1819 1820
LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
    HClassOfTestAndBranch* instr) {
1821
  DCHECK(instr->value()->representation().IsTagged());
1822 1823
  LOperand* value = UseRegister(instr->value());
  return new(zone()) LClassOfTestAndBranch(value, TempRegister());
1824 1825 1826
}


1827 1828 1829 1830 1831 1832
LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
  LOperand* map = UseRegisterAtStart(instr->value());
  return DefineAsRegister(new(zone()) LMapEnumLength(map));
}


1833
LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1834
  LOperand* object = UseFixed(instr->value(), r0);
1835 1836
  LDateField* result =
      new(zone()) LDateField(object, FixedTemp(r1), instr->index());
1837
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
1838 1839 1840
}


1841 1842 1843 1844 1845 1846 1847
LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
  LOperand* string = UseRegisterAtStart(instr->string());
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
  return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
}


1848
LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1849 1850 1851 1852 1853 1854 1855
  LOperand* string = UseRegisterAtStart(instr->string());
  LOperand* index = FLAG_debug_code
      ? UseRegisterAtStart(instr->index())
      : UseRegisterOrConstantAtStart(instr->index());
  LOperand* value = UseRegisterAtStart(instr->value());
  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
  return new(zone()) LSeqStringSetChar(context, string, index, value);
1856 1857 1858
}


1859
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
  if (!FLAG_debug_code && instr->skip_check()) return NULL;
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
  LOperand* length = !index->IsConstantOperand()
      ? UseRegisterOrConstantAtStart(instr->length())
      : UseRegisterAtStart(instr->length());
  LInstruction* result = new(zone()) LBoundsCheck(index, length);
  if (!FLAG_debug_code || !instr->skip_check()) {
    result = AssignEnvironment(result);
  }
  return result;
1870 1871 1872
}


1873 1874 1875 1876 1877 1878 1879
LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
    HBoundsCheckBaseIndexInformation* instr) {
  UNREACHABLE();
  return NULL;
}


1880 1881 1882 1883 1884 1885 1886
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;
}


1887 1888 1889
LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
  return NULL;
}
1890 1891


1892 1893 1894 1895 1896 1897 1898 1899
LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
  // All HForceRepresentation instructions should be eliminated in the
  // representation change phase of Hydrogen.
  UNREACHABLE();
  return NULL;
}


1900 1901 1902
LInstruction* LChunkBuilder::DoChange(HChange* instr) {
  Representation from = instr->from();
  Representation to = instr->to();
1903
  HValue* val = instr->value();
1904 1905
  if (from.IsSmi()) {
    if (to.IsTagged()) {
1906
      LOperand* value = UseRegister(val);
1907 1908 1909 1910
      return DefineSameAsFirst(new(zone()) LDummyUse(value));
    }
    from = Representation::Tagged();
  }
1911 1912
  if (from.IsTagged()) {
    if (to.IsDouble()) {
1913 1914 1915 1916
      LOperand* value = UseRegister(val);
      LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
      return result;
1917
    } else if (to.IsSmi()) {
1918
      LOperand* value = UseRegister(val);
1919 1920 1921
      if (val->type().IsSmi()) {
        return DefineSameAsFirst(new(zone()) LDummyUse(value));
      }
1922
      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1923
    } else {
1924
      DCHECK(to.IsInteger32());
1925
      if (val->type().IsSmi() || val->representation().IsSmi()) {
1926 1927
        LOperand* value = UseRegisterAtStart(val);
        return DefineAsRegister(new(zone()) LSmiUntag(value, false));
1928
      } else {
1929
        LOperand* value = UseRegister(val);
1930
        LOperand* temp1 = TempRegister();
1931
        LOperand* temp2 = TempDoubleRegister();
1932 1933
        LInstruction* result =
            DefineSameAsFirst(new(zone()) LTaggedToI(value, temp1, temp2));
1934
        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1935
        return result;
1936 1937 1938 1939
      }
    }
  } else if (from.IsDouble()) {
    if (to.IsTagged()) {
1940
      info()->MarkAsDeferredCalling();
1941
      LOperand* value = UseRegister(val);
1942 1943
      LOperand* temp1 = TempRegister();
      LOperand* temp2 = TempRegister();
1944
      LUnallocated* result_temp = TempRegister();
1945
      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
1946
      return AssignPointerMap(Define(result, result_temp));
1947
    } else if (to.IsSmi()) {
1948
      LOperand* value = UseRegister(val);
1949 1950
      return AssignEnvironment(
          DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1951
    } else {
1952
      DCHECK(to.IsInteger32());
1953 1954 1955 1956
      LOperand* value = UseRegister(val);
      LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
      return result;
1957 1958
    }
  } else if (from.IsInteger32()) {
1959
    info()->MarkAsDeferredCalling();
1960
    if (to.IsTagged()) {
1961
      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1962
        LOperand* value = UseRegisterAtStart(val);
1963 1964
        return DefineAsRegister(new(zone()) LSmiTag(value));
      } else if (val->CheckFlag(HInstruction::kUint32)) {
1965
        LOperand* value = UseRegisterAtStart(val);
1966 1967 1968
        LOperand* temp1 = TempRegister();
        LOperand* temp2 = TempRegister();
        LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1969
        return AssignPointerMap(DefineAsRegister(result));
1970
      } else {
1971
        LOperand* value = UseRegisterAtStart(val);
1972 1973 1974
        LOperand* temp1 = TempRegister();
        LOperand* temp2 = TempRegister();
        LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
1975
        return AssignPointerMap(DefineAsRegister(result));
1976
      }
1977 1978
    } else if (to.IsSmi()) {
      LOperand* value = UseRegister(val);
1979 1980 1981
      LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
      if (instr->CheckFlag(HValue::kCanOverflow)) {
        result = AssignEnvironment(result);
1982
      }
1983
      return result;
1984
    } else {
1985
      DCHECK(to.IsDouble());
1986 1987
      if (val->CheckFlag(HInstruction::kUint32)) {
        return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1988
      } else {
1989
        return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
1990
      }
1991 1992 1993 1994 1995 1996 1997
    }
  }
  UNREACHABLE();
  return NULL;
}


1998
LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1999
  LOperand* value = UseRegisterAtStart(instr->value());
2000
  LInstruction* result = new(zone()) LCheckNonSmi(value);
2001 2002 2003
  if (!instr->value()->type().IsHeapObject()) {
    result = AssignEnvironment(result);
  }
2004
  return result;
2005 2006 2007
}


2008 2009 2010 2011 2012 2013
LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
  return AssignEnvironment(new(zone()) LCheckSmi(value));
}


2014 2015
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
  LOperand* value = UseRegisterAtStart(instr->value());
2016
  LInstruction* result = new(zone()) LCheckInstanceType(value);
2017 2018 2019 2020
  return AssignEnvironment(result);
}


2021
LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2022
  LOperand* value = UseRegisterAtStart(instr->value());
2023
  return AssignEnvironment(new(zone()) LCheckValue(value));
2024 2025 2026
}


2027
LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
2028 2029 2030 2031 2032 2033
  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);
2034 2035
  }
  return result;
2036 2037 2038
}


2039 2040 2041 2042 2043
LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
  HValue* value = instr->value();
  Representation input_rep = value->representation();
  LOperand* reg = UseRegister(value);
  if (input_rep.IsDouble()) {
2044
    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
2045
  } else if (input_rep.IsInteger32()) {
2046
    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
2047
  } else {
2048
    DCHECK(input_rep.IsSmiOrTagged());
2049 2050
    // Register allocator doesn't (yet) support allocation of double
    // temps. Reserve d1 explicitly.
2051 2052
    LClampTToUint8* result =
        new(zone()) LClampTToUint8(reg, TempDoubleRegister());
2053 2054 2055 2056 2057
    return AssignEnvironment(DefineAsRegister(result));
  }
}


2058 2059
LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
  HValue* value = instr->value();
2060
  DCHECK(value->representation().IsDouble());
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
  return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value)));
}


LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
  LOperand* lo = UseRegister(instr->lo());
  LOperand* hi = UseRegister(instr->hi());
  return DefineAsRegister(new(zone()) LConstructDouble(hi, lo));
}


2072
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2073 2074 2075
  LOperand* context = info()->IsStub()
      ? UseFixed(instr->context(), cp)
      : NULL;
2076
  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2077
  return new(zone()) LReturn(UseFixed(instr->value(), r0), context,
2078
                             parameter_count);
2079 2080 2081 2082 2083
}


LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
  Representation r = instr->representation();
2084 2085 2086
  if (r.IsSmi()) {
    return DefineAsRegister(new(zone()) LConstantS);
  } else if (r.IsInteger32()) {
2087
    return DefineAsRegister(new(zone()) LConstantI);
2088
  } else if (r.IsDouble()) {
2089
    return DefineAsRegister(new(zone()) LConstantD);
2090 2091
  } else if (r.IsExternal()) {
    return DefineAsRegister(new(zone()) LConstantE);
2092
  } else if (r.IsTagged()) {
2093
    return DefineAsRegister(new(zone()) LConstantT);
2094
  } else {
2095
    UNREACHABLE();
2096 2097 2098 2099 2100
    return NULL;
  }
}


2101
LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2102
  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2103
  return instr->RequiresHoleCheck()
2104 2105 2106 2107 2108
      ? AssignEnvironment(DefineAsRegister(result))
      : DefineAsRegister(result);
}


2109
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2110
  LOperand* context = UseFixed(instr->context(), cp);
2111
  LOperand* global_object =
2112
      UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
2113 2114
  LOperand* vector = NULL;
  if (FLAG_vector_ics) {
2115
    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
2116
  }
2117
  LLoadGlobalGeneric* result =
2118
      new(zone()) LLoadGlobalGeneric(context, global_object, vector);
2119 2120 2121 2122
  return MarkAsCall(DefineFixed(result, r0), instr);
}


2123
LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2124 2125 2126 2127
  LOperand* value = UseRegister(instr->value());
  // Use a temp to check the value in the cell in the case where we perform
  // a hole check.
  return instr->RequiresHoleCheck()
2128 2129
      ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister()))
      : new(zone()) LStoreGlobalCell(value, NULL);
2130 2131 2132
}


2133
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2134
  LOperand* context = UseRegisterAtStart(instr->value());
2135 2136
  LInstruction* result =
      DefineAsRegister(new(zone()) LLoadContextSlot(context));
2137 2138 2139 2140
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2141 2142 2143 2144
}


LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2145
  LOperand* context;
2146 2147
  LOperand* value;
  if (instr->NeedsWriteBarrier()) {
2148
    context = UseTempRegister(instr->context());
2149 2150
    value = UseTempRegister(instr->value());
  } else {
2151
    context = UseRegister(instr->context());
2152 2153
    value = UseRegister(instr->value());
  }
2154
  LInstruction* result = new(zone()) LStoreContextSlot(context, value);
2155 2156 2157 2158
  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
    result = AssignEnvironment(result);
  }
  return result;
2159 2160 2161
}


2162
LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2163
  LOperand* obj = UseRegisterAtStart(instr->object());
2164
  return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2165 2166 2167 2168
}


LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2169
  LOperand* context = UseFixed(instr->context(), cp);
2170
  LOperand* object =
2171
      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
2172 2173
  LOperand* vector = NULL;
  if (FLAG_vector_ics) {
2174
    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
2175 2176
  }

2177
  LInstruction* result =
2178
      DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), r0);
2179 2180 2181 2182
  return MarkAsCall(result, instr);
}


2183 2184 2185
LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
    HLoadFunctionPrototype* instr) {
  return AssignEnvironment(DefineAsRegister(
2186
      new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2187 2188 2189
}


2190 2191 2192 2193 2194
LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
  return DefineAsRegister(new(zone()) LLoadRoot);
}


2195
LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2196
  DCHECK(instr->key()->representation().IsSmiOrInteger32());
2197
  ElementsKind elements_kind = instr->elements_kind();
2198
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2199
  LInstruction* result = NULL;
2200

2201
  if (!instr->is_typed_elements()) {
2202 2203
    LOperand* obj = NULL;
    if (instr->representation().IsDouble()) {
2204
      obj = UseRegister(instr->elements());
2205
    } else {
2206
      DCHECK(instr->representation().IsSmiOrTagged());
2207 2208
      obj = UseRegisterAtStart(instr->elements());
    }
2209
    result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
2210
  } else {
2211
    DCHECK(
2212
        (instr->representation().IsInteger32() &&
2213
         !IsDoubleOrFloatElementsKind(elements_kind)) ||
2214
        (instr->representation().IsDouble() &&
2215
         IsDoubleOrFloatElementsKind(elements_kind)));
2216
    LOperand* backing_store = UseRegister(instr->elements());
2217
    result = DefineAsRegister(new(zone()) LLoadKeyed(backing_store, key));
2218
  }
2219

2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230
  if ((instr->is_external() || instr->is_fixed_typed_array()) ?
      // see LCodeGen::DoLoadKeyedExternalArray
      ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
        elements_kind == UINT32_ELEMENTS) &&
       !instr->CheckFlag(HInstruction::kUint32)) :
      // see LCodeGen::DoLoadKeyedFixedDoubleArray and
      // LCodeGen::DoLoadKeyedFixedArray
      instr->RequiresHoleCheck()) {
    result = AssignEnvironment(result);
  }
  return result;
2231 2232 2233
}


2234
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2235
  LOperand* context = UseFixed(instr->context(), cp);
2236
  LOperand* object =
2237 2238
      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
2239 2240
  LOperand* vector = NULL;
  if (FLAG_vector_ics) {
2241
    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
2242
  }
2243 2244

  LInstruction* result =
2245 2246
      DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector),
                  r0);
2247 2248 2249 2250
  return MarkAsCall(result, instr);
}


2251
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2252
  if (!instr->is_typed_elements()) {
2253
    DCHECK(instr->elements()->representation().IsTagged());
2254
    bool needs_write_barrier = instr->NeedsWriteBarrier();
2255
    LOperand* object = NULL;
2256 2257 2258
    LOperand* key = NULL;
    LOperand* val = NULL;

2259 2260
    if (instr->value()->representation().IsDouble()) {
      object = UseRegisterAtStart(instr->elements());
2261
      val = UseRegister(instr->value());
2262
      key = UseRegisterOrConstantAtStart(instr->key());
2263
    } else {
2264
      DCHECK(instr->value()->representation().IsSmiOrTagged());
2265 2266 2267 2268 2269 2270 2271 2272 2273
      if (needs_write_barrier) {
        object = UseTempRegister(instr->elements());
        val = UseTempRegister(instr->value());
        key = UseTempRegister(instr->key());
      } else {
        object = UseRegisterAtStart(instr->elements());
        val = UseRegisterAtStart(instr->value());
        key = UseRegisterOrConstantAtStart(instr->key());
      }
2274 2275
    }

2276
    return new(zone()) LStoreKeyed(object, key, val);
2277 2278
  }

2279
  DCHECK(
2280
      (instr->value()->representation().IsInteger32() &&
2281
       !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
2282
      (instr->value()->representation().IsDouble() &&
2283
       IsDoubleOrFloatElementsKind(instr->elements_kind())));
2284
  DCHECK((instr->is_fixed_typed_array() &&
2285 2286 2287
          instr->elements()->representation().IsTagged()) ||
         (instr->is_external() &&
          instr->elements()->representation().IsExternal()));
2288
  LOperand* val = UseRegister(instr->value());
2289
  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2290 2291
  LOperand* backing_store = UseRegister(instr->elements());
  return new(zone()) LStoreKeyed(backing_store, key, val);
2292 2293 2294
}


2295
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2296
  LOperand* context = UseFixed(instr->context(), cp);
2297
  LOperand* obj =
2298 2299 2300
      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
  LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
  LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2301

2302 2303 2304
  DCHECK(instr->object()->representation().IsTagged());
  DCHECK(instr->key()->representation().IsTagged());
  DCHECK(instr->value()->representation().IsTagged());
2305

2306 2307
  return MarkAsCall(
      new(zone()) LStoreKeyedGeneric(context, obj, key, val), instr);
2308 2309 2310
}


2311 2312
LInstruction* LChunkBuilder::DoTransitionElementsKind(
    HTransitionElementsKind* instr) {
2313
  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2314
    LOperand* object = UseRegister(instr->object());
2315 2316
    LOperand* new_map_reg = TempRegister();
    LTransitionElementsKind* result =
2317
        new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
danno@chromium.org's avatar
danno@chromium.org committed
2318
    return result;
2319
  } else {
2320
    LOperand* object = UseFixed(instr->object(), r0);
2321
    LOperand* context = UseFixed(instr->context(), cp);
2322
    LTransitionElementsKind* result =
2323
        new(zone()) LTransitionElementsKind(object, context, NULL);
2324
    return MarkAsCall(result, instr);
2325 2326 2327 2328
  }
}


2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
LInstruction* LChunkBuilder::DoTrapAllocationMemento(
    HTrapAllocationMemento* instr) {
  LOperand* object = UseRegister(instr->object());
  LOperand* temp = TempRegister();
  LTrapAllocationMemento* result =
      new(zone()) LTrapAllocationMemento(object, temp);
  return AssignEnvironment(result);
}


2339
LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2340
  bool is_in_object = instr->access().IsInobject();
2341
  bool needs_write_barrier = instr->NeedsWriteBarrier();
2342 2343
  bool needs_write_barrier_for_map = instr->has_transition() &&
      instr->NeedsWriteBarrierForMap();
2344 2345 2346

  LOperand* obj;
  if (needs_write_barrier) {
2347
    obj = is_in_object
2348 2349 2350
        ? UseRegister(instr->object())
        : UseTempRegister(instr->object());
  } else {
2351 2352 2353
    obj = needs_write_barrier_for_map
        ? UseRegister(instr->object())
        : UseRegisterAtStart(instr->object());
2354
  }
2355

2356
  LOperand* val;
2357
  if (needs_write_barrier) {
2358
    val = UseTempRegister(instr->value());
2359
  } else if (instr->field_representation().IsDouble()) {
2360 2361 2362 2363
    val = UseRegisterAtStart(instr->value());
  } else {
    val = UseRegister(instr->value());
  }
2364

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

2368
  return new(zone()) LStoreNamedField(obj, val, temp);
2369 2370 2371 2372
}


LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2373
  LOperand* context = UseFixed(instr->context(), cp);
2374
  LOperand* obj =
2375 2376
      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
  LOperand* val = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
2377

2378
  LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
2379 2380 2381 2382
  return MarkAsCall(result, instr);
}


2383
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2384
  LOperand* context = UseFixed(instr->context(), cp);
2385 2386
  LOperand* left = UseFixed(instr->left(), r1);
  LOperand* right = UseFixed(instr->right(), r0);
2387 2388 2389
  return MarkAsCall(
      DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
      instr);
2390 2391 2392
}


2393
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2394 2395
  LOperand* string = UseTempRegister(instr->string());
  LOperand* index = UseTempRegister(instr->index());
2396 2397 2398
  LOperand* context = UseAny(instr->context());
  LStringCharCodeAt* result =
      new(zone()) LStringCharCodeAt(context, string, index);
2399
  return AssignPointerMap(DefineAsRegister(result));
2400 2401 2402
}


2403 2404
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
  LOperand* char_code = UseRegister(instr->value());
2405 2406 2407
  LOperand* context = UseAny(instr->context());
  LStringCharFromCode* result =
      new(zone()) LStringCharFromCode(context, char_code);
2408 2409 2410 2411
  return AssignPointerMap(DefineAsRegister(result));
}


2412 2413
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
  info()->MarkAsDeferredCalling();
2414
  LOperand* context = UseAny(instr->context());
2415
  LOperand* size = UseRegisterOrConstant(instr->size());
2416 2417
  LOperand* temp1 = TempRegister();
  LOperand* temp2 = TempRegister();
2418
  LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
2419 2420 2421 2422
  return AssignPointerMap(DefineAsRegister(result));
}


2423
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2424 2425 2426
  LOperand* context = UseFixed(instr->context(), cp);
  return MarkAsCall(
      DefineFixed(new(zone()) LRegExpLiteral(context), r0), instr);
2427 2428 2429 2430
}


LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2431 2432 2433
  LOperand* context = UseFixed(instr->context(), cp);
  return MarkAsCall(
      DefineFixed(new(zone()) LFunctionLiteral(context), r0), instr);
2434 2435 2436 2437
}


LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2438
  DCHECK(argument_count_ == 0);
2439 2440
  allocator_->MarkAsOsrEntry();
  current_block_->last_environment()->set_ast_id(instr->ast_id());
2441
  return AssignEnvironment(new(zone()) LOsrEntry);
2442 2443 2444 2445
}


LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2446
  LParameter* result = new(zone()) LParameter;
2447
  if (instr->kind() == HParameter::STACK_PARAMETER) {
2448 2449 2450
    int spill_index = chunk()->GetParameterStackSlot(instr->index());
    return DefineAsSpilled(result, spill_index);
  } else {
2451
    DCHECK(info()->IsStub());
2452 2453
    CallInterfaceDescriptor descriptor =
        info()->code_stub()->GetCallInterfaceDescriptor();
2454
    int index = static_cast<int>(instr->index());
2455
    Register reg = descriptor.GetEnvironmentParameterRegister(index);
2456 2457
    return DefineFixed(result, reg);
  }
2458 2459 2460 2461
}


LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2462 2463 2464 2465 2466 2467 2468 2469 2470
  // 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) {
2471
      Retry(kTooManySpillSlotsNeededForOSR);
2472 2473
      spill_index = 0;
    }
2474
  }
2475
  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2476 2477 2478 2479
}


LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2480 2481
  LOperand* context = UseFixed(instr->context(), cp);
  return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), r0), instr);
2482 2483 2484 2485
}


LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2486 2487 2488 2489
  // 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.
2490 2491 2492 2493
  return NULL;
}


2494
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2495
  instr->ReplayEnvironment(current_block_->last_environment());
2496

2497 2498 2499 2500 2501
  // There are no real uses of a captured object.
  return NULL;
}


2502
LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2503
  info()->MarkAsRequiresFrame();
2504
  LOperand* args = UseRegister(instr->arguments());
2505 2506
  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2507
  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2508 2509 2510
}


2511 2512
LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
  LOperand* object = UseFixed(instr->value(), r0);
2513
  LToFastProperties* result = new(zone()) LToFastProperties(object);
2514 2515 2516 2517
  return MarkAsCall(DefineFixed(result, r0), instr);
}


2518
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2519 2520
  LOperand* context = UseFixed(instr->context(), cp);
  LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), r0));
2521 2522 2523 2524
  return MarkAsCall(DefineFixed(result, r0), instr);
}


2525
LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2526
  return new(zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2527 2528
}

2529

2530 2531
LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
    HIsConstructCallAndBranch* instr) {
2532
  return new(zone()) LIsConstructCallAndBranch(TempRegister());
2533 2534 2535
}


2536
LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2537
  instr->ReplayEnvironment(current_block_->last_environment());
2538 2539 2540 2541 2542
  return NULL;
}


LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2543
  if (instr->is_function_entry()) {
2544 2545
    LOperand* context = UseFixed(instr->context(), cp);
    return MarkAsCall(new(zone()) LStackCheck(context), instr);
2546
  } else {
2547
    DCHECK(instr->is_backwards_branch());
2548 2549 2550
    LOperand* context = UseAny(instr->context());
    return AssignEnvironment(
        AssignPointerMap(new(zone()) LStackCheck(context)));
2551
  }
2552 2553 2554 2555 2556
}


LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
  HEnvironment* outer = current_block_->last_environment();
2557
  outer->set_ast_id(instr->ReturnId());
2558 2559
  HConstant* undefined = graph()->GetConstantUndefined();
  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2560
                                               instr->arguments_count(),
2561
                                               instr->function(),
2562
                                               undefined,
2563
                                               instr->inlining_kind());
2564 2565 2566
  // 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());
2567
  }
2568
  inner->BindContext(instr->closure_context());
2569
  inner->set_entry(instr);
2570 2571 2572 2573 2574 2575 2576
  current_block_->UpdateEnvironment(inner);
  chunk_->AddInlinedClosure(instr->closure());
  return NULL;
}


LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2577 2578 2579 2580
  LInstruction* pop = NULL;

  HEnvironment* env = current_block_->last_environment();

2581
  if (env->entry()->arguments_pushed()) {
2582 2583
    int argument_count = env->arguments_environment()->parameter_count();
    pop = new(zone()) LDrop(argument_count);
2584
    DCHECK(instr->argument_delta() == -argument_count);
2585 2586
  }

2587 2588
  HEnvironment* outer = current_block_->last_environment()->
      DiscardInlined(false);
2589
  current_block_->UpdateEnvironment(outer);
2590 2591

  return pop;
2592 2593 2594
}


2595
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2596
  LOperand* context = UseFixed(instr->context(), cp);
2597
  LOperand* object = UseFixed(instr->enumerable(), r0);
2598
  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2599 2600 2601 2602 2603 2604
  return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
}


LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
  LOperand* map = UseRegister(instr->map());
2605
  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
2606 2607 2608 2609 2610 2611
}


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


LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
  LOperand* object = UseRegister(instr->object());
2618
  LOperand* index = UseTempRegister(instr->index());
2619 2620 2621
  LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
  LInstruction* result = DefineSameAsFirst(load);
  return AssignPointerMap(result);
2622 2623
}

2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639

LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
  LOperand* context = UseRegisterAtStart(instr->context());
  return new(zone()) LStoreFrameContext(context);
}


LInstruction* LChunkBuilder::DoAllocateBlockContext(
    HAllocateBlockContext* instr) {
  LOperand* context = UseFixed(instr->context(), cp);
  LOperand* function = UseRegisterAtStart(instr->function());
  LAllocateBlockContext* result =
      new(zone()) LAllocateBlockContext(context, function);
  return MarkAsCall(DefineFixed(result, cp), instr);
}

2640
} }  // namespace v8::internal