1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/crankshaft/s390/lithium-s390.h"
6
7#include <sstream>
8
9#include "src/crankshaft/hydrogen-osr.h"
10#include "src/crankshaft/lithium-inl.h"
11#include "src/crankshaft/s390/lithium-codegen-s390.h"
12
13namespace v8 {
14namespace internal {
15
16#define DEFINE_COMPILE(type)                           \
17  void L##type::CompileToNative(LCodeGen* generator) { \
18    generator->Do##type(this);                         \
19  }
20LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
21#undef DEFINE_COMPILE
22
23#ifdef DEBUG
24void LInstruction::VerifyCall() {
25  // Call instructions can use only fixed registers as temporaries and
26  // outputs because all registers are blocked by the calling convention.
27  // Inputs operands must use a fixed register or use-at-start policy or
28  // a non-register policy.
29  DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
30         !LUnallocated::cast(Output())->HasRegisterPolicy());
31  for (UseIterator it(this); !it.Done(); it.Advance()) {
32    LUnallocated* operand = LUnallocated::cast(it.Current());
33    DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
34  }
35  for (TempIterator it(this); !it.Done(); it.Advance()) {
36    LUnallocated* operand = LUnallocated::cast(it.Current());
37    DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
38  }
39}
40#endif
41
42void LInstruction::PrintTo(StringStream* stream) {
43  stream->Add("%s ", this->Mnemonic());
44
45  PrintOutputOperandTo(stream);
46
47  PrintDataTo(stream);
48
49  if (HasEnvironment()) {
50    stream->Add(" ");
51    environment()->PrintTo(stream);
52  }
53
54  if (HasPointerMap()) {
55    stream->Add(" ");
56    pointer_map()->PrintTo(stream);
57  }
58}
59
60void LInstruction::PrintDataTo(StringStream* stream) {
61  stream->Add("= ");
62  for (int i = 0; i < InputCount(); i++) {
63    if (i > 0) stream->Add(" ");
64    if (InputAt(i) == NULL) {
65      stream->Add("NULL");
66    } else {
67      InputAt(i)->PrintTo(stream);
68    }
69  }
70}
71
72void LInstruction::PrintOutputOperandTo(StringStream* stream) {
73  if (HasResult()) result()->PrintTo(stream);
74}
75
76void LLabel::PrintDataTo(StringStream* stream) {
77  LGap::PrintDataTo(stream);
78  LLabel* rep = replacement();
79  if (rep != NULL) {
80    stream->Add(" Dead block replaced with B%d", rep->block_id());
81  }
82}
83
84bool LGap::IsRedundant() const {
85  for (int i = 0; i < 4; i++) {
86    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
87      return false;
88    }
89  }
90
91  return true;
92}
93
94void LGap::PrintDataTo(StringStream* stream) {
95  for (int i = 0; i < 4; i++) {
96    stream->Add("(");
97    if (parallel_moves_[i] != NULL) {
98      parallel_moves_[i]->PrintDataTo(stream);
99    }
100    stream->Add(") ");
101  }
102}
103
104const char* LArithmeticD::Mnemonic() const {
105  switch (op()) {
106    case Token::ADD:
107      return "add-d";
108    case Token::SUB:
109      return "sub-d";
110    case Token::MUL:
111      return "mul-d";
112    case Token::DIV:
113      return "div-d";
114    case Token::MOD:
115      return "mod-d";
116    default:
117      UNREACHABLE();
118      return NULL;
119  }
120}
121
122const char* LArithmeticT::Mnemonic() const {
123  switch (op()) {
124    case Token::ADD:
125      return "add-t";
126    case Token::SUB:
127      return "sub-t";
128    case Token::MUL:
129      return "mul-t";
130    case Token::MOD:
131      return "mod-t";
132    case Token::DIV:
133      return "div-t";
134    case Token::BIT_AND:
135      return "bit-and-t";
136    case Token::BIT_OR:
137      return "bit-or-t";
138    case Token::BIT_XOR:
139      return "bit-xor-t";
140    case Token::ROR:
141      return "ror-t";
142    case Token::SHL:
143      return "shl-t";
144    case Token::SAR:
145      return "sar-t";
146    case Token::SHR:
147      return "shr-t";
148    default:
149      UNREACHABLE();
150      return NULL;
151  }
152}
153
154bool LGoto::HasInterestingComment(LCodeGen* gen) const {
155  return !gen->IsNextEmittedBlock(block_id());
156}
157
158void LGoto::PrintDataTo(StringStream* stream) {
159  stream->Add("B%d", block_id());
160}
161
162void LBranch::PrintDataTo(StringStream* stream) {
163  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
164  value()->PrintTo(stream);
165}
166
167void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
168  stream->Add("if ");
169  left()->PrintTo(stream);
170  stream->Add(" %s ", Token::String(op()));
171  right()->PrintTo(stream);
172  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
173}
174
175void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
176  stream->Add("if is_string(");
177  value()->PrintTo(stream);
178  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
179}
180
181void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
182  stream->Add("if is_smi(");
183  value()->PrintTo(stream);
184  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
185}
186
187void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
188  stream->Add("if is_undetectable(");
189  value()->PrintTo(stream);
190  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
191}
192
193void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
194  stream->Add("if string_compare(");
195  left()->PrintTo(stream);
196  right()->PrintTo(stream);
197  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
198}
199
200void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
201  stream->Add("if has_instance_type(");
202  value()->PrintTo(stream);
203  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
204}
205
206void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
207  stream->Add("if class_of_test(");
208  value()->PrintTo(stream);
209  stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
210              true_block_id(), false_block_id());
211}
212
213void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
214  stream->Add("if typeof ");
215  value()->PrintTo(stream);
216  stream->Add(" == \"%s\" then B%d else B%d",
217              hydrogen()->type_literal()->ToCString().get(), true_block_id(),
218              false_block_id());
219}
220
221void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
222  stream->Add(" = ");
223  function()->PrintTo(stream);
224  stream->Add(".code_entry = ");
225  code_object()->PrintTo(stream);
226}
227
228void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
229  stream->Add(" = ");
230  base_object()->PrintTo(stream);
231  stream->Add(" + ");
232  offset()->PrintTo(stream);
233}
234
235void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
236  for (int i = 0; i < InputCount(); i++) {
237    InputAt(i)->PrintTo(stream);
238    stream->Add(" ");
239  }
240  stream->Add("#%d / ", arity());
241}
242
243void LLoadContextSlot::PrintDataTo(StringStream* stream) {
244  context()->PrintTo(stream);
245  stream->Add("[%d]", slot_index());
246}
247
248void LStoreContextSlot::PrintDataTo(StringStream* stream) {
249  context()->PrintTo(stream);
250  stream->Add("[%d] <- ", slot_index());
251  value()->PrintTo(stream);
252}
253
254void LInvokeFunction::PrintDataTo(StringStream* stream) {
255  stream->Add("= ");
256  function()->PrintTo(stream);
257  stream->Add(" #%d / ", arity());
258}
259
260void LCallNewArray::PrintDataTo(StringStream* stream) {
261  stream->Add("= ");
262  constructor()->PrintTo(stream);
263  stream->Add(" #%d / ", arity());
264  ElementsKind kind = hydrogen()->elements_kind();
265  stream->Add(" (%s) ", ElementsKindToString(kind));
266}
267
268void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
269  arguments()->PrintTo(stream);
270  stream->Add(" length ");
271  length()->PrintTo(stream);
272  stream->Add(" index ");
273  index()->PrintTo(stream);
274}
275
276void LStoreNamedField::PrintDataTo(StringStream* stream) {
277  object()->PrintTo(stream);
278  std::ostringstream os;
279  os << hydrogen()->access() << " <- ";
280  stream->Add(os.str().c_str());
281  value()->PrintTo(stream);
282}
283
284void LLoadKeyed::PrintDataTo(StringStream* stream) {
285  elements()->PrintTo(stream);
286  stream->Add("[");
287  key()->PrintTo(stream);
288  if (hydrogen()->IsDehoisted()) {
289    stream->Add(" + %d]", base_offset());
290  } else {
291    stream->Add("]");
292  }
293}
294
295void LStoreKeyed::PrintDataTo(StringStream* stream) {
296  elements()->PrintTo(stream);
297  stream->Add("[");
298  key()->PrintTo(stream);
299  if (hydrogen()->IsDehoisted()) {
300    stream->Add(" + %d] <-", base_offset());
301  } else {
302    stream->Add("] <- ");
303  }
304
305  if (value() == NULL) {
306    DCHECK(hydrogen()->IsConstantHoleStore() &&
307           hydrogen()->value()->representation().IsDouble());
308    stream->Add("<the hole(nan)>");
309  } else {
310    value()->PrintTo(stream);
311  }
312}
313
314void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
315  object()->PrintTo(stream);
316  stream->Add(" %p -> %p", *original_map(), *transitioned_map());
317}
318
319int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
320  // Skip a slot if for a double-width slot.
321  if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
322  return current_frame_slots_++;
323}
324
325LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
326  int index = GetNextSpillIndex(kind);
327  if (kind == DOUBLE_REGISTERS) {
328    return LDoubleStackSlot::Create(index, zone());
329  } else {
330    DCHECK(kind == GENERAL_REGISTERS);
331    return LStackSlot::Create(index, zone());
332  }
333}
334
335LPlatformChunk* LChunkBuilder::Build() {
336  DCHECK(is_unused());
337  chunk_ = new (zone()) LPlatformChunk(info(), graph());
338  LPhase phase("L_Building chunk", chunk_);
339  status_ = BUILDING;
340
341  // If compiling for OSR, reserve space for the unoptimized frame,
342  // which will be subsumed into this frame.
343  if (graph()->has_osr()) {
344    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
345      chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
346    }
347  }
348
349  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
350  for (int i = 0; i < blocks->length(); i++) {
351    HBasicBlock* next = NULL;
352    if (i < blocks->length() - 1) next = blocks->at(i + 1);
353    DoBasicBlock(blocks->at(i), next);
354    if (is_aborted()) return NULL;
355  }
356  status_ = DONE;
357  return chunk_;
358}
359
360LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
361  return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
362}
363
364LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
365  return new (zone())
366      LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
367}
368
369LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
370  return Use(value, ToUnallocated(fixed_register));
371}
372
373LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
374  return Use(value, ToUnallocated(reg));
375}
376
377LOperand* LChunkBuilder::UseRegister(HValue* value) {
378  return Use(value,
379             new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
380}
381
382LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
383  return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
384                                              LUnallocated::USED_AT_START));
385}
386
387LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
388  return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
389}
390
391LOperand* LChunkBuilder::Use(HValue* value) {
392  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
393}
394
395LOperand* LChunkBuilder::UseAtStart(HValue* value) {
396  return Use(value, new (zone()) LUnallocated(LUnallocated::NONE,
397                                              LUnallocated::USED_AT_START));
398}
399
400LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
401  return value->IsConstant()
402             ? chunk_->DefineConstantOperand(HConstant::cast(value))
403             : Use(value);
404}
405
406LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
407  return value->IsConstant()
408             ? chunk_->DefineConstantOperand(HConstant::cast(value))
409             : UseAtStart(value);
410}
411
412LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
413  return value->IsConstant()
414             ? chunk_->DefineConstantOperand(HConstant::cast(value))
415             : UseRegister(value);
416}
417
418LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
419  return value->IsConstant()
420             ? chunk_->DefineConstantOperand(HConstant::cast(value))
421             : UseRegisterAtStart(value);
422}
423
424LOperand* LChunkBuilder::UseConstant(HValue* value) {
425  return chunk_->DefineConstantOperand(HConstant::cast(value));
426}
427
428LOperand* LChunkBuilder::UseAny(HValue* value) {
429  return value->IsConstant()
430             ? chunk_->DefineConstantOperand(HConstant::cast(value))
431             : Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
432}
433
434LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
435  if (value->EmitAtUses()) {
436    HInstruction* instr = HInstruction::cast(value);
437    VisitInstruction(instr);
438  }
439  operand->set_virtual_register(value->id());
440  return operand;
441}
442
443LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
444                                    LUnallocated* result) {
445  result->set_virtual_register(current_instruction_->id());
446  instr->set_result(result);
447  return instr;
448}
449
450LInstruction* LChunkBuilder::DefineAsRegister(
451    LTemplateResultInstruction<1>* instr) {
452  return Define(instr,
453                new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
454}
455
456LInstruction* LChunkBuilder::DefineAsSpilled(
457    LTemplateResultInstruction<1>* instr, int index) {
458  return Define(instr,
459                new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
460}
461
462LInstruction* LChunkBuilder::DefineSameAsFirst(
463    LTemplateResultInstruction<1>* instr) {
464  return Define(instr,
465                new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
466}
467
468LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
469                                         Register reg) {
470  return Define(instr, ToUnallocated(reg));
471}
472
473LInstruction* LChunkBuilder::DefineFixedDouble(
474    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
475  return Define(instr, ToUnallocated(reg));
476}
477
478LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
479  HEnvironment* hydrogen_env = current_block_->last_environment();
480  return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
481}
482
483LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
484                                        HInstruction* hinstr,
485                                        CanDeoptimize can_deoptimize) {
486  info()->MarkAsNonDeferredCalling();
487#ifdef DEBUG
488  instr->VerifyCall();
489#endif
490  instr->MarkAsCall();
491  instr = AssignPointerMap(instr);
492
493  // If instruction does not have side-effects lazy deoptimization
494  // after the call will try to deoptimize to the point before the call.
495  // Thus we still need to attach environment to this call even if
496  // call sequence can not deoptimize eagerly.
497  bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
498                           !hinstr->HasObservableSideEffects();
499  if (needs_environment && !instr->HasEnvironment()) {
500    instr = AssignEnvironment(instr);
501    // We can't really figure out if the environment is needed or not.
502    instr->environment()->set_has_been_used();
503  }
504
505  return instr;
506}
507
508LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
509  DCHECK(!instr->HasPointerMap());
510  instr->set_pointer_map(new (zone()) LPointerMap(zone()));
511  return instr;
512}
513
514LUnallocated* LChunkBuilder::TempRegister() {
515  LUnallocated* operand =
516      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
517  int vreg = allocator_->GetVirtualRegister();
518  if (!allocator_->AllocationOk()) {
519    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
520    vreg = 0;
521  }
522  operand->set_virtual_register(vreg);
523  return operand;
524}
525
526LUnallocated* LChunkBuilder::TempDoubleRegister() {
527  LUnallocated* operand =
528      new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
529  int vreg = allocator_->GetVirtualRegister();
530  if (!allocator_->AllocationOk()) {
531    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
532    vreg = 0;
533  }
534  operand->set_virtual_register(vreg);
535  return operand;
536}
537
538LOperand* LChunkBuilder::FixedTemp(Register reg) {
539  LUnallocated* operand = ToUnallocated(reg);
540  DCHECK(operand->HasFixedPolicy());
541  return operand;
542}
543
544LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
545  LUnallocated* operand = ToUnallocated(reg);
546  DCHECK(operand->HasFixedPolicy());
547  return operand;
548}
549
550LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
551  return new (zone()) LLabel(instr->block());
552}
553
554LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
555  return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
556}
557
558LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
559  UNREACHABLE();
560  return NULL;
561}
562
563LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
564  return AssignEnvironment(new (zone()) LDeoptimize);
565}
566
567LInstruction* LChunkBuilder::DoShift(Token::Value op,
568                                     HBitwiseBinaryOperation* instr) {
569  if (instr->representation().IsSmiOrInteger32()) {
570    DCHECK(instr->left()->representation().Equals(instr->representation()));
571    DCHECK(instr->right()->representation().Equals(instr->representation()));
572    LOperand* left = UseRegisterAtStart(instr->left());
573
574    HValue* right_value = instr->right();
575    LOperand* right = NULL;
576    int constant_value = 0;
577    bool does_deopt = false;
578    if (right_value->IsConstant()) {
579      HConstant* constant = HConstant::cast(right_value);
580      right = chunk_->DefineConstantOperand(constant);
581      constant_value = constant->Integer32Value() & 0x1f;
582      // Left shifts can deoptimize if we shift by > 0 and the result cannot be
583      // truncated to smi.
584      if (instr->representation().IsSmi() && constant_value > 0) {
585        does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
586      }
587    } else {
588      right = UseRegisterAtStart(right_value);
589    }
590
591    // Shift operations can only deoptimize if we do a logical shift
592    // by 0 and the result cannot be truncated to int32.
593    if (op == Token::SHR && constant_value == 0) {
594      does_deopt = !instr->CheckFlag(HInstruction::kUint32);
595    }
596
597    LInstruction* result =
598        DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
599    return does_deopt ? AssignEnvironment(result) : result;
600  } else {
601    return DoArithmeticT(op, instr);
602  }
603}
604
605LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
606                                           HArithmeticBinaryOperation* instr) {
607  DCHECK(instr->representation().IsDouble());
608  DCHECK(instr->left()->representation().IsDouble());
609  DCHECK(instr->right()->representation().IsDouble());
610  if (op == Token::MOD) {
611    LOperand* left = UseFixedDouble(instr->left(), d1);
612    LOperand* right = UseFixedDouble(instr->right(), d2);
613    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
614    // We call a C function for double modulo. It can't trigger a GC. We need
615    // to use fixed result register for the call.
616    // TODO(fschneider): Allow any register as input registers.
617    return MarkAsCall(DefineFixedDouble(result, d1), instr);
618  } else {
619    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
620    LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
621    LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
622    return CpuFeatures::IsSupported(VECTOR_FACILITY)
623               ? DefineAsRegister(result)
624               : DefineSameAsFirst(result);
625  }
626}
627
628LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
629                                           HBinaryOperation* instr) {
630  HValue* left = instr->left();
631  HValue* right = instr->right();
632  DCHECK(left->representation().IsTagged());
633  DCHECK(right->representation().IsTagged());
634  LOperand* context = UseFixed(instr->context(), cp);
635  LOperand* left_operand = UseFixed(left, r3);
636  LOperand* right_operand = UseFixed(right, r2);
637  LArithmeticT* result =
638      new (zone()) LArithmeticT(op, context, left_operand, right_operand);
639  return MarkAsCall(DefineFixed(result, r2), instr);
640}
641
642void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
643  DCHECK(is_building());
644  current_block_ = block;
645  next_block_ = next_block;
646  if (block->IsStartBlock()) {
647    block->UpdateEnvironment(graph_->start_environment());
648    argument_count_ = 0;
649  } else if (block->predecessors()->length() == 1) {
650    // We have a single predecessor => copy environment and outgoing
651    // argument count from the predecessor.
652    DCHECK(block->phis()->length() == 0);
653    HBasicBlock* pred = block->predecessors()->at(0);
654    HEnvironment* last_environment = pred->last_environment();
655    DCHECK(last_environment != NULL);
656    // Only copy the environment, if it is later used again.
657    if (pred->end()->SecondSuccessor() == NULL) {
658      DCHECK(pred->end()->FirstSuccessor() == block);
659    } else {
660      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
661          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
662        last_environment = last_environment->Copy();
663      }
664    }
665    block->UpdateEnvironment(last_environment);
666    DCHECK(pred->argument_count() >= 0);
667    argument_count_ = pred->argument_count();
668  } else {
669    // We are at a state join => process phis.
670    HBasicBlock* pred = block->predecessors()->at(0);
671    // No need to copy the environment, it cannot be used later.
672    HEnvironment* last_environment = pred->last_environment();
673    for (int i = 0; i < block->phis()->length(); ++i) {
674      HPhi* phi = block->phis()->at(i);
675      if (phi->HasMergedIndex()) {
676        last_environment->SetValueAt(phi->merged_index(), phi);
677      }
678    }
679    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
680      if (block->deleted_phis()->at(i) < last_environment->length()) {
681        last_environment->SetValueAt(block->deleted_phis()->at(i),
682                                     graph_->GetConstantUndefined());
683      }
684    }
685    block->UpdateEnvironment(last_environment);
686    // Pick up the outgoing argument count of one of the predecessors.
687    argument_count_ = pred->argument_count();
688  }
689  HInstruction* current = block->first();
690  int start = chunk_->instructions()->length();
691  while (current != NULL && !is_aborted()) {
692    // Code for constants in registers is generated lazily.
693    if (!current->EmitAtUses()) {
694      VisitInstruction(current);
695    }
696    current = current->next();
697  }
698  int end = chunk_->instructions()->length() - 1;
699  if (end >= start) {
700    block->set_first_instruction_index(start);
701    block->set_last_instruction_index(end);
702  }
703  block->set_argument_count(argument_count_);
704  next_block_ = NULL;
705  current_block_ = NULL;
706}
707
708void LChunkBuilder::VisitInstruction(HInstruction* current) {
709  HInstruction* old_current = current_instruction_;
710  current_instruction_ = current;
711
712  LInstruction* instr = NULL;
713  if (current->CanReplaceWithDummyUses()) {
714    if (current->OperandCount() == 0) {
715      instr = DefineAsRegister(new (zone()) LDummy());
716    } else {
717      DCHECK(!current->OperandAt(0)->IsControlInstruction());
718      instr = DefineAsRegister(new (zone())
719                                   LDummyUse(UseAny(current->OperandAt(0))));
720    }
721    for (int i = 1; i < current->OperandCount(); ++i) {
722      if (current->OperandAt(i)->IsControlInstruction()) continue;
723      LInstruction* dummy =
724          new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
725      dummy->set_hydrogen_value(current);
726      chunk_->AddInstruction(dummy, current_block_);
727    }
728  } else {
729    HBasicBlock* successor;
730    if (current->IsControlInstruction() &&
731        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
732        successor != NULL) {
733      instr = new (zone()) LGoto(successor);
734    } else {
735      instr = current->CompileToLithium(this);
736    }
737  }
738
739  argument_count_ += current->argument_delta();
740  DCHECK(argument_count_ >= 0);
741
742  if (instr != NULL) {
743    AddInstruction(instr, current);
744  }
745
746  current_instruction_ = old_current;
747}
748
749void LChunkBuilder::AddInstruction(LInstruction* instr,
750                                   HInstruction* hydrogen_val) {
751  // Associate the hydrogen instruction first, since we may need it for
752  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
753  instr->set_hydrogen_value(hydrogen_val);
754
755#if DEBUG
756  // Make sure that the lithium instruction has either no fixed register
757  // constraints in temps or the result OR no uses that are only used at
758  // start. If this invariant doesn't hold, the register allocator can decide
759  // to insert a split of a range immediately before the instruction due to an
760  // already allocated register needing to be used for the instruction's fixed
761  // register constraint. In this case, The register allocator won't see an
762  // interference between the split child and the use-at-start (it would if
763  // the it was just a plain use), so it is free to move the split child into
764  // the same register that is used for the use-at-start.
765  // See https://code.google.com/p/chromium/issues/detail?id=201590
766  if (!(instr->ClobbersRegisters() &&
767        instr->ClobbersDoubleRegisters(isolate()))) {
768    int fixed = 0;
769    int used_at_start = 0;
770    for (UseIterator it(instr); !it.Done(); it.Advance()) {
771      LUnallocated* operand = LUnallocated::cast(it.Current());
772      if (operand->IsUsedAtStart()) ++used_at_start;
773    }
774    if (instr->Output() != NULL) {
775      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
776    }
777    for (TempIterator it(instr); !it.Done(); it.Advance()) {
778      LUnallocated* operand = LUnallocated::cast(it.Current());
779      if (operand->HasFixedPolicy()) ++fixed;
780    }
781    DCHECK(fixed == 0 || used_at_start == 0);
782  }
783#endif
784
785  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
786    instr = AssignPointerMap(instr);
787  }
788  if (FLAG_stress_environments && !instr->HasEnvironment()) {
789    instr = AssignEnvironment(instr);
790  }
791  chunk_->AddInstruction(instr, current_block_);
792
793  CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
794}
795
796LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
797  LInstruction* result = new (zone()) LPrologue();
798  if (info_->scope()->NeedsContext()) {
799    result = MarkAsCall(result, instr);
800  }
801  return result;
802}
803
804LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
805  return new (zone()) LGoto(instr->FirstSuccessor());
806}
807
808LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
809  HValue* value = instr->value();
810  Representation r = value->representation();
811  HType type = value->type();
812  ToBooleanHints expected = instr->expected_input_types();
813  if (expected == ToBooleanHint::kNone) expected = ToBooleanHint::kAny;
814
815  bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
816                   type.IsJSArray() || type.IsHeapNumber() || type.IsString();
817  LInstruction* branch = new (zone()) LBranch(UseRegister(value));
818  if (!easy_case && ((!(expected & ToBooleanHint::kSmallInteger) &&
819                      (expected & ToBooleanHint::kNeedsMap)) ||
820                     expected != ToBooleanHint::kAny)) {
821    branch = AssignEnvironment(branch);
822  }
823  return branch;
824}
825
826LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
827  return new (zone()) LDebugBreak();
828}
829
830LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
831  DCHECK(instr->value()->representation().IsTagged());
832  LOperand* value = UseRegister(instr->value());
833  LOperand* temp = TempRegister();
834  return new (zone()) LCmpMapAndBranch(value, temp);
835}
836
837LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
838  info()->MarkAsRequiresFrame();
839  LOperand* value = UseRegister(instr->value());
840  return DefineAsRegister(new (zone()) LArgumentsLength(value));
841}
842
843LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
844  info()->MarkAsRequiresFrame();
845  return DefineAsRegister(new (zone()) LArgumentsElements);
846}
847
848LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
849    HHasInPrototypeChainAndBranch* instr) {
850  LOperand* object = UseRegister(instr->object());
851  LOperand* prototype = UseRegister(instr->prototype());
852  LHasInPrototypeChainAndBranch* result =
853      new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
854  return AssignEnvironment(result);
855}
856
857LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
858  LOperand* receiver = UseRegisterAtStart(instr->receiver());
859  LOperand* function = UseRegisterAtStart(instr->function());
860  LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
861  return AssignEnvironment(DefineAsRegister(result));
862}
863
864LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
865  LOperand* function = UseFixed(instr->function(), r3);
866  LOperand* receiver = UseFixed(instr->receiver(), r2);
867  LOperand* length = UseFixed(instr->length(), r4);
868  LOperand* elements = UseFixed(instr->elements(), r5);
869  LApplyArguments* result =
870      new (zone()) LApplyArguments(function, receiver, length, elements);
871  return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
872}
873
874LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
875  int argc = instr->OperandCount();
876  for (int i = 0; i < argc; ++i) {
877    LOperand* argument = Use(instr->argument(i));
878    AddInstruction(new (zone()) LPushArgument(argument), instr);
879  }
880  return NULL;
881}
882
883LInstruction* LChunkBuilder::DoStoreCodeEntry(
884    HStoreCodeEntry* store_code_entry) {
885  LOperand* function = UseRegister(store_code_entry->function());
886  LOperand* code_object = UseTempRegister(store_code_entry->code_object());
887  return new (zone()) LStoreCodeEntry(function, code_object);
888}
889
890LInstruction* LChunkBuilder::DoInnerAllocatedObject(
891    HInnerAllocatedObject* instr) {
892  LOperand* base_object = UseRegisterAtStart(instr->base_object());
893  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
894  return DefineAsRegister(new (zone())
895                              LInnerAllocatedObject(base_object, offset));
896}
897
898LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
899  return instr->HasNoUses() ? NULL
900                            : DefineAsRegister(new (zone()) LThisFunction);
901}
902
903LInstruction* LChunkBuilder::DoContext(HContext* instr) {
904  if (instr->HasNoUses()) return NULL;
905
906  if (info()->IsStub()) {
907    return DefineFixed(new (zone()) LContext, cp);
908  }
909
910  return DefineAsRegister(new (zone()) LContext);
911}
912
913LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
914  LOperand* context = UseFixed(instr->context(), cp);
915  return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
916}
917
918LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
919  CallInterfaceDescriptor descriptor = instr->descriptor();
920  DCHECK_EQ(descriptor.GetParameterCount() +
921                LCallWithDescriptor::kImplicitRegisterParameterCount,
922            instr->OperandCount());
923
924  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
925  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
926  // Target
927  ops.Add(target, zone());
928  // Context
929  LOperand* op = UseFixed(instr->OperandAt(1), cp);
930  ops.Add(op, zone());
931  // Load register parameters.
932  int i = 0;
933  for (; i < descriptor.GetRegisterParameterCount(); i++) {
934    op = UseFixed(instr->OperandAt(
935                      i + LCallWithDescriptor::kImplicitRegisterParameterCount),
936                  descriptor.GetRegisterParameter(i));
937    ops.Add(op, zone());
938  }
939  // Push stack parameters.
940  for (; i < descriptor.GetParameterCount(); i++) {
941    op = UseAny(instr->OperandAt(
942        i + LCallWithDescriptor::kImplicitRegisterParameterCount));
943    AddInstruction(new (zone()) LPushArgument(op), instr);
944  }
945
946  LCallWithDescriptor* result =
947      new (zone()) LCallWithDescriptor(descriptor, ops, zone());
948  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
949    result->MarkAsSyntacticTailCall();
950  }
951  return MarkAsCall(DefineFixed(result, r2), instr);
952}
953
954LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
955  LOperand* context = UseFixed(instr->context(), cp);
956  LOperand* function = UseFixed(instr->function(), r3);
957  LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
958  if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
959    result->MarkAsSyntacticTailCall();
960  }
961  return MarkAsCall(DefineFixed(result, r2), instr, CANNOT_DEOPTIMIZE_EAGERLY);
962}
963
964LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
965  switch (instr->op()) {
966    case kMathFloor:
967      return DoMathFloor(instr);
968    case kMathRound:
969      return DoMathRound(instr);
970    case kMathFround:
971      return DoMathFround(instr);
972    case kMathAbs:
973      return DoMathAbs(instr);
974    case kMathLog:
975      return DoMathLog(instr);
976    case kMathCos:
977      return DoMathCos(instr);
978    case kMathSin:
979      return DoMathSin(instr);
980    case kMathExp:
981      return DoMathExp(instr);
982    case kMathSqrt:
983      return DoMathSqrt(instr);
984    case kMathPowHalf:
985      return DoMathPowHalf(instr);
986    case kMathClz32:
987      return DoMathClz32(instr);
988    default:
989      UNREACHABLE();
990      return NULL;
991  }
992}
993
994LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
995  LOperand* input = UseRegister(instr->value());
996  LMathFloor* result = new (zone()) LMathFloor(input);
997  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
998}
999
1000LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1001  LOperand* input = UseRegister(instr->value());
1002  LOperand* temp = TempDoubleRegister();
1003  LMathRound* result = new (zone()) LMathRound(input, temp);
1004  return AssignEnvironment(DefineAsRegister(result));
1005}
1006
1007LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1008  LOperand* input = UseRegister(instr->value());
1009  LMathFround* result = new (zone()) LMathFround(input);
1010  return DefineAsRegister(result);
1011}
1012
1013LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1014  Representation r = instr->value()->representation();
1015  LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1016                          ? NULL
1017                          : UseFixed(instr->context(), cp);
1018  LOperand* input = UseRegister(instr->value());
1019  LInstruction* result =
1020      DefineAsRegister(new (zone()) LMathAbs(context, input));
1021  if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1022  if (!r.IsDouble()) result = AssignEnvironment(result);
1023  return result;
1024}
1025
1026LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1027  DCHECK(instr->representation().IsDouble());
1028  DCHECK(instr->value()->representation().IsDouble());
1029  LOperand* input = UseFixedDouble(instr->value(), d0);
1030  return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d0), instr);
1031}
1032
1033LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1034  LOperand* input = UseRegisterAtStart(instr->value());
1035  LMathClz32* result = new (zone()) LMathClz32(input);
1036  return DefineAsRegister(result);
1037}
1038
1039LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1040  DCHECK(instr->representation().IsDouble());
1041  DCHECK(instr->value()->representation().IsDouble());
1042  LOperand* input = UseFixedDouble(instr->value(), d0);
1043  return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), d0), instr);
1044}
1045
1046LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1047  DCHECK(instr->representation().IsDouble());
1048  DCHECK(instr->value()->representation().IsDouble());
1049  LOperand* input = UseFixedDouble(instr->value(), d0);
1050  return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), d0), instr);
1051}
1052
1053LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1054  DCHECK(instr->representation().IsDouble());
1055  DCHECK(instr->value()->representation().IsDouble());
1056  LOperand* input = UseFixedDouble(instr->value(), d0);
1057  return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
1058}
1059
1060LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1061  LOperand* input = UseAtStart(instr->value());
1062  LMathSqrt* result = new (zone()) LMathSqrt(input);
1063  return DefineAsRegister(result);
1064}
1065
1066LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1067  LOperand* input = UseRegisterAtStart(instr->value());
1068  LMathPowHalf* result = new (zone()) LMathPowHalf(input);
1069  return DefineAsRegister(result);
1070}
1071
1072LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1073  LOperand* context = UseFixed(instr->context(), cp);
1074  LOperand* constructor = UseFixed(instr->constructor(), r3);
1075  LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
1076  return MarkAsCall(DefineFixed(result, r2), instr);
1077}
1078
1079LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1080  LOperand* context = UseFixed(instr->context(), cp);
1081  return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r2), instr);
1082}
1083
1084LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1085  return DoShift(Token::ROR, instr);
1086}
1087
1088LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1089  return DoShift(Token::SHR, instr);
1090}
1091
1092LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1093  return DoShift(Token::SAR, instr);
1094}
1095
1096LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1097  return DoShift(Token::SHL, instr);
1098}
1099
1100LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1101  if (instr->representation().IsSmiOrInteger32()) {
1102    DCHECK(instr->left()->representation().Equals(instr->representation()));
1103    DCHECK(instr->right()->representation().Equals(instr->representation()));
1104    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1105
1106    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1107    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1108    return DefineAsRegister(new (zone()) LBitI(left, right));
1109  } else {
1110    return DoArithmeticT(instr->op(), instr);
1111  }
1112}
1113
1114LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1115  DCHECK(instr->representation().IsSmiOrInteger32());
1116  DCHECK(instr->left()->representation().Equals(instr->representation()));
1117  DCHECK(instr->right()->representation().Equals(instr->representation()));
1118  LOperand* dividend = UseRegister(instr->left());
1119  int32_t divisor = instr->right()->GetInteger32Constant();
1120  LInstruction* result =
1121      DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
1122  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1123      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1124      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1125       divisor != 1 && divisor != -1)) {
1126    result = AssignEnvironment(result);
1127  }
1128  return result;
1129}
1130
1131LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1132  DCHECK(instr->representation().IsInteger32());
1133  DCHECK(instr->left()->representation().Equals(instr->representation()));
1134  DCHECK(instr->right()->representation().Equals(instr->representation()));
1135  LOperand* dividend = UseRegister(instr->left());
1136  int32_t divisor = instr->right()->GetInteger32Constant();
1137  LInstruction* result =
1138      DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
1139  if (divisor == 0 ||
1140      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1141      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1142    result = AssignEnvironment(result);
1143  }
1144  return result;
1145}
1146
1147LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1148  DCHECK(instr->representation().IsSmiOrInteger32());
1149  DCHECK(instr->left()->representation().Equals(instr->representation()));
1150  DCHECK(instr->right()->representation().Equals(instr->representation()));
1151  LOperand* dividend = UseRegister(instr->left());
1152  LOperand* divisor = UseRegister(instr->right());
1153  LInstruction* result =
1154      DefineAsRegister(new (zone()) LDivI(dividend, divisor));
1155  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1156      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1157      (instr->CheckFlag(HValue::kCanOverflow) &&
1158       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
1159      (!instr->IsMathFloorOfDiv() &&
1160       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1161    result = AssignEnvironment(result);
1162  }
1163  return result;
1164}
1165
1166LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1167  if (instr->representation().IsSmiOrInteger32()) {
1168    if (instr->RightIsPowerOf2()) {
1169      return DoDivByPowerOf2I(instr);
1170    } else if (instr->right()->IsConstant()) {
1171      return DoDivByConstI(instr);
1172    } else {
1173      return DoDivI(instr);
1174    }
1175  } else if (instr->representation().IsDouble()) {
1176    return DoArithmeticD(Token::DIV, instr);
1177  } else {
1178    return DoArithmeticT(Token::DIV, instr);
1179  }
1180}
1181
1182LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1183  LOperand* dividend = UseRegisterAtStart(instr->left());
1184  int32_t divisor = instr->right()->GetInteger32Constant();
1185  LInstruction* result =
1186      DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
1187  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1188      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1189    result = AssignEnvironment(result);
1190  }
1191  return result;
1192}
1193
1194LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1195  DCHECK(instr->representation().IsInteger32());
1196  DCHECK(instr->left()->representation().Equals(instr->representation()));
1197  DCHECK(instr->right()->representation().Equals(instr->representation()));
1198  LOperand* dividend = UseRegister(instr->left());
1199  int32_t divisor = instr->right()->GetInteger32Constant();
1200  LOperand* temp =
1201      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1202       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
1203          ? NULL
1204          : TempRegister();
1205  LInstruction* result = DefineAsRegister(
1206      new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
1207  if (divisor == 0 ||
1208      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1209    result = AssignEnvironment(result);
1210  }
1211  return result;
1212}
1213
1214LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1215  DCHECK(instr->representation().IsSmiOrInteger32());
1216  DCHECK(instr->left()->representation().Equals(instr->representation()));
1217  DCHECK(instr->right()->representation().Equals(instr->representation()));
1218  LOperand* dividend = UseRegister(instr->left());
1219  LOperand* divisor = UseRegister(instr->right());
1220  LInstruction* result =
1221      DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
1222  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1223      instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1224      (instr->CheckFlag(HValue::kCanOverflow) &&
1225       !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1226    result = AssignEnvironment(result);
1227  }
1228  return result;
1229}
1230
1231LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1232  if (instr->RightIsPowerOf2()) {
1233    return DoFlooringDivByPowerOf2I(instr);
1234  } else if (instr->right()->IsConstant()) {
1235    return DoFlooringDivByConstI(instr);
1236  } else {
1237    return DoFlooringDivI(instr);
1238  }
1239}
1240
1241LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1242  DCHECK(instr->representation().IsSmiOrInteger32());
1243  DCHECK(instr->left()->representation().Equals(instr->representation()));
1244  DCHECK(instr->right()->representation().Equals(instr->representation()));
1245  LOperand* dividend = UseRegisterAtStart(instr->left());
1246  int32_t divisor = instr->right()->GetInteger32Constant();
1247  LInstruction* result =
1248      DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
1249  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1250      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1251    result = AssignEnvironment(result);
1252  }
1253  return result;
1254}
1255
1256LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1257  DCHECK(instr->representation().IsSmiOrInteger32());
1258  DCHECK(instr->left()->representation().Equals(instr->representation()));
1259  DCHECK(instr->right()->representation().Equals(instr->representation()));
1260  LOperand* dividend = UseRegister(instr->left());
1261  int32_t divisor = instr->right()->GetInteger32Constant();
1262  LInstruction* result =
1263      DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
1264  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1265    result = AssignEnvironment(result);
1266  }
1267  return result;
1268}
1269
1270LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1271  DCHECK(instr->representation().IsSmiOrInteger32());
1272  DCHECK(instr->left()->representation().Equals(instr->representation()));
1273  DCHECK(instr->right()->representation().Equals(instr->representation()));
1274  LOperand* dividend = UseRegister(instr->left());
1275  LOperand* divisor = UseRegister(instr->right());
1276  LInstruction* result =
1277      DefineAsRegister(new (zone()) LModI(dividend, divisor));
1278  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1279      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1280    result = AssignEnvironment(result);
1281  }
1282  return result;
1283}
1284
1285LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1286  if (instr->representation().IsSmiOrInteger32()) {
1287    if (instr->RightIsPowerOf2()) {
1288      return DoModByPowerOf2I(instr);
1289    } else if (instr->right()->IsConstant()) {
1290      return DoModByConstI(instr);
1291    } else {
1292      return DoModI(instr);
1293    }
1294  } else if (instr->representation().IsDouble()) {
1295    return DoArithmeticD(Token::MOD, instr);
1296  } else {
1297    return DoArithmeticT(Token::MOD, instr);
1298  }
1299}
1300
1301LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1302  if (instr->representation().IsSmiOrInteger32()) {
1303    DCHECK(instr->left()->representation().Equals(instr->representation()));
1304    DCHECK(instr->right()->representation().Equals(instr->representation()));
1305    HValue* left = instr->BetterLeftOperand();
1306    HValue* right = instr->BetterRightOperand();
1307    LOperand* left_op;
1308    LOperand* right_op;
1309    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1310    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1311
1312    int32_t constant_value = 0;
1313    if (right->IsConstant()) {
1314      HConstant* constant = HConstant::cast(right);
1315      constant_value = constant->Integer32Value();
1316      // Constants -1, 0 and 1 can be optimized if the result can overflow.
1317      // For other constants, it can be optimized only without overflow.
1318      if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1319        left_op = UseRegisterAtStart(left);
1320        right_op = UseConstant(right);
1321      } else {
1322        if (bailout_on_minus_zero) {
1323          left_op = UseRegister(left);
1324        } else {
1325          left_op = UseRegisterAtStart(left);
1326        }
1327        right_op = UseRegister(right);
1328      }
1329    } else {
1330      if (bailout_on_minus_zero) {
1331        left_op = UseRegister(left);
1332      } else {
1333        left_op = UseRegisterAtStart(left);
1334      }
1335      right_op = UseRegister(right);
1336    }
1337    LMulI* mul = new (zone()) LMulI(left_op, right_op);
1338    if (right_op->IsConstantOperand()
1339            ? ((can_overflow && constant_value == -1) ||
1340               (bailout_on_minus_zero && constant_value <= 0))
1341            : (can_overflow || bailout_on_minus_zero)) {
1342      AssignEnvironment(mul);
1343    }
1344    return DefineAsRegister(mul);
1345
1346  } else if (instr->representation().IsDouble()) {
1347    return DoArithmeticD(Token::MUL, instr);
1348  } else {
1349    return DoArithmeticT(Token::MUL, instr);
1350  }
1351}
1352
1353LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1354  if (instr->representation().IsSmiOrInteger32()) {
1355    DCHECK(instr->left()->representation().Equals(instr->representation()));
1356    DCHECK(instr->right()->representation().Equals(instr->representation()));
1357
1358    LOperand* left = UseRegisterAtStart(instr->left());
1359    LOperand* right = UseOrConstantAtStart(instr->right());
1360    LSubI* sub = new (zone()) LSubI(left, right);
1361    LInstruction* result = DefineAsRegister(sub);
1362    if (instr->CheckFlag(HValue::kCanOverflow)) {
1363      result = AssignEnvironment(result);
1364    }
1365    return result;
1366  } else if (instr->representation().IsDouble()) {
1367    return DoArithmeticD(Token::SUB, instr);
1368  } else {
1369    return DoArithmeticT(Token::SUB, instr);
1370  }
1371}
1372
1373LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1374  LOperand* multiplier_op = UseRegister(mul->left());
1375  LOperand* multiplicand_op = UseRegister(mul->right());
1376  LOperand* addend_op = UseRegister(addend);
1377  return DefineAsRegister(
1378      new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
1379}
1380
1381LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1382  LOperand* minuend_op = UseRegister(minuend);
1383  LOperand* multiplier_op = UseRegister(mul->left());
1384  LOperand* multiplicand_op = UseRegister(mul->right());
1385
1386  return DefineAsRegister(
1387      new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
1388}
1389
1390LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1391  if (instr->representation().IsSmiOrInteger32()) {
1392    DCHECK(instr->left()->representation().Equals(instr->representation()));
1393    DCHECK(instr->right()->representation().Equals(instr->representation()));
1394    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1395    LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1396    LAddI* add = new (zone()) LAddI(left, right);
1397    LInstruction* result = DefineAsRegister(add);
1398    if (instr->CheckFlag(HValue::kCanOverflow)) {
1399      result = AssignEnvironment(result);
1400    }
1401    return result;
1402  } else if (instr->representation().IsExternal()) {
1403    DCHECK(instr->IsConsistentExternalRepresentation());
1404    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1405    LOperand* left = UseRegisterAtStart(instr->left());
1406    LOperand* right = UseOrConstantAtStart(instr->right());
1407    LAddI* add = new (zone()) LAddI(left, right);
1408    LInstruction* result = DefineAsRegister(add);
1409    return result;
1410  } else if (instr->representation().IsDouble()) {
1411    return DoArithmeticD(Token::ADD, instr);
1412  } else {
1413    return DoArithmeticT(Token::ADD, instr);
1414  }
1415}
1416
1417LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1418  LOperand* left = NULL;
1419  LOperand* right = NULL;
1420  if (instr->representation().IsSmiOrInteger32()) {
1421    DCHECK(instr->left()->representation().Equals(instr->representation()));
1422    DCHECK(instr->right()->representation().Equals(instr->representation()));
1423    left = UseRegisterAtStart(instr->BetterLeftOperand());
1424    right = UseOrConstantAtStart(instr->BetterRightOperand());
1425  } else {
1426    DCHECK(instr->representation().IsDouble());
1427    DCHECK(instr->left()->representation().IsDouble());
1428    DCHECK(instr->right()->representation().IsDouble());
1429    left = UseRegister(instr->left());
1430    right = UseRegister(instr->right());
1431  }
1432  return DefineAsRegister(new (zone()) LMathMinMax(left, right));
1433}
1434
1435LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1436  DCHECK(instr->representation().IsDouble());
1437  // We call a C function for double power. It can't trigger a GC.
1438  // We need to use fixed result register for the call.
1439  Representation exponent_type = instr->right()->representation();
1440  DCHECK(instr->left()->representation().IsDouble());
1441  LOperand* left = UseFixedDouble(instr->left(), d1);
1442  LOperand* right = exponent_type.IsDouble()
1443                        ? UseFixedDouble(instr->right(), d2)
1444                        : UseFixed(instr->right(), r4);
1445  LPower* result = new (zone()) LPower(left, right);
1446  return MarkAsCall(DefineFixedDouble(result, d3), instr,
1447                    CAN_DEOPTIMIZE_EAGERLY);
1448}
1449
1450LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1451  DCHECK(instr->left()->representation().IsTagged());
1452  DCHECK(instr->right()->representation().IsTagged());
1453  LOperand* context = UseFixed(instr->context(), cp);
1454  LOperand* left = UseFixed(instr->left(), r3);
1455  LOperand* right = UseFixed(instr->right(), r2);
1456  LCmpT* result = new (zone()) LCmpT(context, left, right);
1457  return MarkAsCall(DefineFixed(result, r2), instr);
1458}
1459
1460LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1461    HCompareNumericAndBranch* instr) {
1462  Representation r = instr->representation();
1463  if (r.IsSmiOrInteger32()) {
1464    DCHECK(instr->left()->representation().Equals(r));
1465    DCHECK(instr->right()->representation().Equals(r));
1466    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1467    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1468    return new (zone()) LCompareNumericAndBranch(left, right);
1469  } else {
1470    DCHECK(r.IsDouble());
1471    DCHECK(instr->left()->representation().IsDouble());
1472    DCHECK(instr->right()->representation().IsDouble());
1473    LOperand* left = UseRegisterAtStart(instr->left());
1474    LOperand* right = UseRegisterAtStart(instr->right());
1475    return new (zone()) LCompareNumericAndBranch(left, right);
1476  }
1477}
1478
1479LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1480    HCompareObjectEqAndBranch* instr) {
1481  LOperand* left = UseRegisterAtStart(instr->left());
1482  LOperand* right = UseRegisterAtStart(instr->right());
1483  return new (zone()) LCmpObjectEqAndBranch(left, right);
1484}
1485
1486LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1487    HCompareHoleAndBranch* instr) {
1488  LOperand* value = UseRegisterAtStart(instr->value());
1489  return new (zone()) LCmpHoleAndBranch(value);
1490}
1491
1492LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1493  DCHECK(instr->value()->representation().IsTagged());
1494  LOperand* value = UseRegisterAtStart(instr->value());
1495  LOperand* temp = TempRegister();
1496  return new (zone()) LIsStringAndBranch(value, temp);
1497}
1498
1499LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1500  DCHECK(instr->value()->representation().IsTagged());
1501  return new (zone()) LIsSmiAndBranch(Use(instr->value()));
1502}
1503
1504LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1505    HIsUndetectableAndBranch* instr) {
1506  DCHECK(instr->value()->representation().IsTagged());
1507  LOperand* value = UseRegisterAtStart(instr->value());
1508  return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
1509}
1510
1511LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1512    HStringCompareAndBranch* instr) {
1513  DCHECK(instr->left()->representation().IsTagged());
1514  DCHECK(instr->right()->representation().IsTagged());
1515  LOperand* context = UseFixed(instr->context(), cp);
1516  LOperand* left = UseFixed(instr->left(), r3);
1517  LOperand* right = UseFixed(instr->right(), r2);
1518  LStringCompareAndBranch* result =
1519      new (zone()) LStringCompareAndBranch(context, left, right);
1520  return MarkAsCall(result, instr);
1521}
1522
1523LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1524    HHasInstanceTypeAndBranch* instr) {
1525  DCHECK(instr->value()->representation().IsTagged());
1526  LOperand* value = UseRegisterAtStart(instr->value());
1527  return new (zone()) LHasInstanceTypeAndBranch(value);
1528}
1529
1530LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1531    HClassOfTestAndBranch* instr) {
1532  DCHECK(instr->value()->representation().IsTagged());
1533  LOperand* value = UseRegister(instr->value());
1534  return new (zone()) LClassOfTestAndBranch(value, TempRegister());
1535}
1536
1537LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1538  LOperand* string = UseRegisterAtStart(instr->string());
1539  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1540  return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
1541}
1542
1543LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1544  LOperand* string = UseRegisterAtStart(instr->string());
1545  LOperand* index = FLAG_debug_code
1546                        ? UseRegisterAtStart(instr->index())
1547                        : UseRegisterOrConstantAtStart(instr->index());
1548  LOperand* value = UseRegisterAtStart(instr->value());
1549  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1550  return new (zone()) LSeqStringSetChar(context, string, index, value);
1551}
1552
1553LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1554  if (!FLAG_debug_code && instr->skip_check()) return NULL;
1555  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1556  LOperand* length = !index->IsConstantOperand()
1557                         ? UseRegisterOrConstantAtStart(instr->length())
1558                         : UseRegisterAtStart(instr->length());
1559  LInstruction* result = new (zone()) LBoundsCheck(index, length);
1560  if (!FLAG_debug_code || !instr->skip_check()) {
1561    result = AssignEnvironment(result);
1562  }
1563  return result;
1564}
1565
1566LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1567  // The control instruction marking the end of a block that completed
1568  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1569  return NULL;
1570}
1571
1572LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
1573
1574LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1575  // All HForceRepresentation instructions should be eliminated in the
1576  // representation change phase of Hydrogen.
1577  UNREACHABLE();
1578  return NULL;
1579}
1580
1581LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1582  Representation from = instr->from();
1583  Representation to = instr->to();
1584  HValue* val = instr->value();
1585  if (from.IsSmi()) {
1586    if (to.IsTagged()) {
1587      LOperand* value = UseRegister(val);
1588      return DefineSameAsFirst(new (zone()) LDummyUse(value));
1589    }
1590    from = Representation::Tagged();
1591  }
1592  if (from.IsTagged()) {
1593    if (to.IsDouble()) {
1594      LOperand* value = UseRegister(val);
1595      LInstruction* result =
1596          DefineAsRegister(new (zone()) LNumberUntagD(value));
1597      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1598      return result;
1599    } else if (to.IsSmi()) {
1600      LOperand* value = UseRegister(val);
1601      if (val->type().IsSmi()) {
1602        return DefineSameAsFirst(new (zone()) LDummyUse(value));
1603      }
1604      return AssignEnvironment(
1605          DefineSameAsFirst(new (zone()) LCheckSmi(value)));
1606    } else {
1607      DCHECK(to.IsInteger32());
1608      if (val->type().IsSmi() || val->representation().IsSmi()) {
1609        LOperand* value = UseRegisterAtStart(val);
1610        return DefineAsRegister(new (zone()) LSmiUntag(value, false));
1611      } else {
1612        LOperand* value = UseRegister(val);
1613        LOperand* temp1 = TempRegister();
1614        LOperand* temp2 = TempDoubleRegister();
1615        LInstruction* result =
1616            DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
1617        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1618        return result;
1619      }
1620    }
1621  } else if (from.IsDouble()) {
1622    if (to.IsTagged()) {
1623      info()->MarkAsDeferredCalling();
1624      LOperand* value = UseRegister(val);
1625      LOperand* temp1 = TempRegister();
1626      LOperand* temp2 = TempRegister();
1627      LUnallocated* result_temp = TempRegister();
1628      LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
1629      return AssignPointerMap(Define(result, result_temp));
1630    } else if (to.IsSmi()) {
1631      LOperand* value = UseRegister(val);
1632      return AssignEnvironment(
1633          DefineAsRegister(new (zone()) LDoubleToSmi(value)));
1634    } else {
1635      DCHECK(to.IsInteger32());
1636      LOperand* value = UseRegister(val);
1637      LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
1638      if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1639      return result;
1640    }
1641  } else if (from.IsInteger32()) {
1642    info()->MarkAsDeferredCalling();
1643    if (to.IsTagged()) {
1644      if (!instr->CheckFlag(HValue::kCanOverflow)) {
1645        LOperand* value = UseRegisterAtStart(val);
1646        return DefineAsRegister(new (zone()) LSmiTag(value));
1647      } else if (val->CheckFlag(HInstruction::kUint32)) {
1648        LOperand* value = UseRegisterAtStart(val);
1649        LOperand* temp1 = TempRegister();
1650        LOperand* temp2 = TempRegister();
1651        LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
1652        return AssignPointerMap(DefineAsRegister(result));
1653      } else {
1654        LOperand* value = UseRegisterAtStart(val);
1655        LOperand* temp1 = TempRegister();
1656        LOperand* temp2 = TempRegister();
1657        LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
1658        return AssignPointerMap(DefineAsRegister(result));
1659      }
1660    } else if (to.IsSmi()) {
1661      LOperand* value = UseRegister(val);
1662      LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
1663      if (instr->CheckFlag(HValue::kCanOverflow)) {
1664        result = AssignEnvironment(result);
1665      }
1666      return result;
1667    } else {
1668      DCHECK(to.IsDouble());
1669      if (val->CheckFlag(HInstruction::kUint32)) {
1670        return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
1671      } else {
1672        return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
1673      }
1674    }
1675  }
1676  UNREACHABLE();
1677  return NULL;
1678}
1679
1680LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1681  LOperand* value = UseAtStart(instr->value());
1682  LInstruction* result = new (zone()) LCheckNonSmi(value);
1683  if (!instr->value()->type().IsHeapObject()) {
1684    result = AssignEnvironment(result);
1685  }
1686  return result;
1687}
1688
1689LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1690  LOperand* value = UseAtStart(instr->value());
1691  return AssignEnvironment(new (zone()) LCheckSmi(value));
1692}
1693
1694LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1695    HCheckArrayBufferNotNeutered* instr) {
1696  LOperand* view = UseRegisterAtStart(instr->value());
1697  LCheckArrayBufferNotNeutered* result =
1698      new (zone()) LCheckArrayBufferNotNeutered(view);
1699  return AssignEnvironment(result);
1700}
1701
1702LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1703  LOperand* value = UseRegisterAtStart(instr->value());
1704  LInstruction* result = new (zone()) LCheckInstanceType(value);
1705  return AssignEnvironment(result);
1706}
1707
1708LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1709  LOperand* value = UseRegisterAtStart(instr->value());
1710  return AssignEnvironment(new (zone()) LCheckValue(value));
1711}
1712
1713LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1714  if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
1715  LOperand* value = UseRegisterAtStart(instr->value());
1716  LOperand* temp = TempRegister();
1717  LInstruction* result =
1718      AssignEnvironment(new (zone()) LCheckMaps(value, temp));
1719  if (instr->HasMigrationTarget()) {
1720    info()->MarkAsDeferredCalling();
1721    result = AssignPointerMap(result);
1722  }
1723  return result;
1724}
1725
1726LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1727  HValue* value = instr->value();
1728  Representation input_rep = value->representation();
1729  LOperand* reg = UseRegister(value);
1730  if (input_rep.IsDouble()) {
1731    return DefineAsRegister(new (zone()) LClampDToUint8(reg));
1732  } else if (input_rep.IsInteger32()) {
1733    return DefineAsRegister(new (zone()) LClampIToUint8(reg));
1734  } else {
1735    DCHECK(input_rep.IsSmiOrTagged());
1736    LClampTToUint8* result =
1737        new (zone()) LClampTToUint8(reg, TempDoubleRegister());
1738    return AssignEnvironment(DefineAsRegister(result));
1739  }
1740}
1741
1742LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1743  LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
1744  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1745  return new (zone())
1746      LReturn(UseFixed(instr->value(), r2), context, parameter_count);
1747}
1748
1749LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1750  Representation r = instr->representation();
1751  if (r.IsSmi()) {
1752    return DefineAsRegister(new (zone()) LConstantS);
1753  } else if (r.IsInteger32()) {
1754    return DefineAsRegister(new (zone()) LConstantI);
1755  } else if (r.IsDouble()) {
1756    return DefineAsRegister(new (zone()) LConstantD);
1757  } else if (r.IsExternal()) {
1758    return DefineAsRegister(new (zone()) LConstantE);
1759  } else if (r.IsTagged()) {
1760    return DefineAsRegister(new (zone()) LConstantT);
1761  } else {
1762    UNREACHABLE();
1763    return NULL;
1764  }
1765}
1766
1767LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1768  LOperand* context = UseRegisterAtStart(instr->value());
1769  LInstruction* result =
1770      DefineAsRegister(new (zone()) LLoadContextSlot(context));
1771  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1772    result = AssignEnvironment(result);
1773  }
1774  return result;
1775}
1776
1777LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1778  LOperand* context;
1779  LOperand* value;
1780  if (instr->NeedsWriteBarrier()) {
1781    context = UseTempRegister(instr->context());
1782    value = UseTempRegister(instr->value());
1783  } else {
1784    context = UseRegister(instr->context());
1785    value = UseRegister(instr->value());
1786  }
1787  LInstruction* result = new (zone()) LStoreContextSlot(context, value);
1788  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1789    result = AssignEnvironment(result);
1790  }
1791  return result;
1792}
1793
1794LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1795  LOperand* obj = UseRegisterAtStart(instr->object());
1796  return DefineAsRegister(new (zone()) LLoadNamedField(obj));
1797}
1798
1799LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1800    HLoadFunctionPrototype* instr) {
1801  return AssignEnvironment(DefineAsRegister(
1802      new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
1803}
1804
1805LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1806  return DefineAsRegister(new (zone()) LLoadRoot);
1807}
1808
1809LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1810  DCHECK(instr->key()->representation().IsSmiOrInteger32());
1811  ElementsKind elements_kind = instr->elements_kind();
1812  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1813  LInstruction* result = NULL;
1814
1815  if (!instr->is_fixed_typed_array()) {
1816    LOperand* obj = NULL;
1817    if (instr->representation().IsDouble()) {
1818      obj = UseRegister(instr->elements());
1819    } else {
1820      obj = UseRegisterAtStart(instr->elements());
1821    }
1822    result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
1823  } else {
1824    DCHECK((instr->representation().IsInteger32() &&
1825            !IsDoubleOrFloatElementsKind(elements_kind)) ||
1826           (instr->representation().IsDouble() &&
1827            IsDoubleOrFloatElementsKind(elements_kind)));
1828    LOperand* backing_store = UseRegister(instr->elements());
1829    LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1830    result = DefineAsRegister(
1831        new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
1832  }
1833
1834  bool needs_environment;
1835  if (instr->is_fixed_typed_array()) {
1836    // see LCodeGen::DoLoadKeyedExternalArray
1837    needs_environment = elements_kind == UINT32_ELEMENTS &&
1838                        !instr->CheckFlag(HInstruction::kUint32);
1839  } else {
1840    // see LCodeGen::DoLoadKeyedFixedDoubleArray and
1841    // LCodeGen::DoLoadKeyedFixedArray
1842    needs_environment =
1843        instr->RequiresHoleCheck() ||
1844        (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
1845  }
1846
1847  if (needs_environment) {
1848    result = AssignEnvironment(result);
1849  }
1850  return result;
1851}
1852
1853LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
1854  if (!instr->is_fixed_typed_array()) {
1855    DCHECK(instr->elements()->representation().IsTagged());
1856    bool needs_write_barrier = instr->NeedsWriteBarrier();
1857    LOperand* object = NULL;
1858    LOperand* key = NULL;
1859    LOperand* val = NULL;
1860
1861    if (instr->value()->representation().IsDouble()) {
1862      object = UseRegisterAtStart(instr->elements());
1863      val = UseRegister(instr->value());
1864      key = UseRegisterOrConstantAtStart(instr->key());
1865    } else {
1866      if (needs_write_barrier) {
1867        object = UseTempRegister(instr->elements());
1868        val = UseTempRegister(instr->value());
1869        key = UseTempRegister(instr->key());
1870      } else {
1871        object = UseRegisterAtStart(instr->elements());
1872        val = UseRegisterAtStart(instr->value());
1873        key = UseRegisterOrConstantAtStart(instr->key());
1874      }
1875    }
1876
1877    return new (zone()) LStoreKeyed(object, key, val, nullptr);
1878  }
1879
1880  DCHECK((instr->value()->representation().IsInteger32() &&
1881          !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
1882         (instr->value()->representation().IsDouble() &&
1883          IsDoubleOrFloatElementsKind(instr->elements_kind())));
1884  DCHECK(instr->elements()->representation().IsExternal());
1885  LOperand* val = UseRegister(instr->value());
1886  LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1887  LOperand* backing_store = UseRegister(instr->elements());
1888  LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1889  return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
1890}
1891
1892LInstruction* LChunkBuilder::DoTransitionElementsKind(
1893    HTransitionElementsKind* instr) {
1894  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
1895    LOperand* object = UseRegister(instr->object());
1896    LOperand* new_map_reg = TempRegister();
1897    LTransitionElementsKind* result =
1898        new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
1899    return result;
1900  } else {
1901    LOperand* object = UseFixed(instr->object(), r2);
1902    LOperand* context = UseFixed(instr->context(), cp);
1903    LTransitionElementsKind* result =
1904        new (zone()) LTransitionElementsKind(object, context, NULL);
1905    return MarkAsCall(result, instr);
1906  }
1907}
1908
1909LInstruction* LChunkBuilder::DoTrapAllocationMemento(
1910    HTrapAllocationMemento* instr) {
1911  LOperand* object = UseRegister(instr->object());
1912  LOperand* temp1 = TempRegister();
1913  LOperand* temp2 = TempRegister();
1914  LTrapAllocationMemento* result =
1915      new (zone()) LTrapAllocationMemento(object, temp1, temp2);
1916  return AssignEnvironment(result);
1917}
1918
1919LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
1920  info()->MarkAsDeferredCalling();
1921  LOperand* context = UseFixed(instr->context(), cp);
1922  LOperand* object = Use(instr->object());
1923  LOperand* elements = Use(instr->elements());
1924  LOperand* key = UseRegisterOrConstant(instr->key());
1925  LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
1926
1927  LMaybeGrowElements* result = new (zone())
1928      LMaybeGrowElements(context, object, elements, key, current_capacity);
1929  DefineFixed(result, r2);
1930  return AssignPointerMap(AssignEnvironment(result));
1931}
1932
1933LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1934  bool is_in_object = instr->access().IsInobject();
1935  bool needs_write_barrier = instr->NeedsWriteBarrier();
1936  bool needs_write_barrier_for_map =
1937      instr->has_transition() && instr->NeedsWriteBarrierForMap();
1938
1939  LOperand* obj;
1940  if (needs_write_barrier) {
1941    obj = is_in_object ? UseRegister(instr->object())
1942                       : UseTempRegister(instr->object());
1943  } else {
1944    obj = needs_write_barrier_for_map ? UseRegister(instr->object())
1945                                      : UseRegisterAtStart(instr->object());
1946  }
1947
1948  LOperand* val;
1949  if (needs_write_barrier) {
1950    val = UseTempRegister(instr->value());
1951  } else if (instr->field_representation().IsDouble()) {
1952    val = UseRegisterAtStart(instr->value());
1953  } else {
1954    val = UseRegister(instr->value());
1955  }
1956
1957  // We need a temporary register for write barrier of the map field.
1958  LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
1959
1960  return new (zone()) LStoreNamedField(obj, val, temp);
1961}
1962
1963LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
1964  LOperand* context = UseFixed(instr->context(), cp);
1965  LOperand* left = UseFixed(instr->left(), r3);
1966  LOperand* right = UseFixed(instr->right(), r2);
1967  return MarkAsCall(
1968      DefineFixed(new (zone()) LStringAdd(context, left, right), r2), instr);
1969}
1970
1971LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1972  LOperand* string = UseTempRegister(instr->string());
1973  LOperand* index = UseTempRegister(instr->index());
1974  LOperand* context = UseAny(instr->context());
1975  LStringCharCodeAt* result =
1976      new (zone()) LStringCharCodeAt(context, string, index);
1977  return AssignPointerMap(DefineAsRegister(result));
1978}
1979
1980LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
1981  LOperand* char_code = UseRegister(instr->value());
1982  LOperand* context = UseAny(instr->context());
1983  LStringCharFromCode* result =
1984      new (zone()) LStringCharFromCode(context, char_code);
1985  return AssignPointerMap(DefineAsRegister(result));
1986}
1987
1988LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
1989  LOperand* size = UseRegisterOrConstant(instr->size());
1990  LOperand* temp1 = TempRegister();
1991  LOperand* temp2 = TempRegister();
1992  if (instr->IsAllocationFolded()) {
1993    LFastAllocate* result = new (zone()) LFastAllocate(size, temp1, temp2);
1994    return DefineAsRegister(result);
1995  } else {
1996    info()->MarkAsDeferredCalling();
1997    LOperand* context = UseAny(instr->context());
1998    LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
1999    return AssignPointerMap(DefineAsRegister(result));
2000  }
2001}
2002
2003LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2004  DCHECK(argument_count_ == 0);
2005  allocator_->MarkAsOsrEntry();
2006  current_block_->last_environment()->set_ast_id(instr->ast_id());
2007  return AssignEnvironment(new (zone()) LOsrEntry);
2008}
2009
2010LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2011  LParameter* result = new (zone()) LParameter;
2012  if (instr->kind() == HParameter::STACK_PARAMETER) {
2013    int spill_index = chunk()->GetParameterStackSlot(instr->index());
2014    return DefineAsSpilled(result, spill_index);
2015  } else {
2016    DCHECK(info()->IsStub());
2017    CallInterfaceDescriptor descriptor = graph()->descriptor();
2018    int index = static_cast<int>(instr->index());
2019    Register reg = descriptor.GetRegisterParameter(index);
2020    return DefineFixed(result, reg);
2021  }
2022}
2023
2024LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2025  // Use an index that corresponds to the location in the unoptimized frame,
2026  // which the optimized frame will subsume.
2027  int env_index = instr->index();
2028  int spill_index = 0;
2029  if (instr->environment()->is_parameter_index(env_index)) {
2030    spill_index = chunk()->GetParameterStackSlot(env_index);
2031  } else {
2032    spill_index = env_index - instr->environment()->first_local_index();
2033    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2034      Retry(kTooManySpillSlotsNeededForOSR);
2035      spill_index = 0;
2036    }
2037    spill_index += StandardFrameConstants::kFixedSlotCount;
2038  }
2039  return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
2040}
2041
2042LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2043  // There are no real uses of the arguments object.
2044  // arguments.length and element access are supported directly on
2045  // stack arguments, and any real arguments object use causes a bailout.
2046  // So this value is never used.
2047  return NULL;
2048}
2049
2050LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2051  instr->ReplayEnvironment(current_block_->last_environment());
2052
2053  // There are no real uses of a captured object.
2054  return NULL;
2055}
2056
2057LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2058  info()->MarkAsRequiresFrame();
2059  LOperand* args = UseRegister(instr->arguments());
2060  LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2061  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2062  return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
2063}
2064
2065LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2066  LOperand* context = UseFixed(instr->context(), cp);
2067  LOperand* value = UseFixed(instr->value(), r5);
2068  LTypeof* result = new (zone()) LTypeof(context, value);
2069  return MarkAsCall(DefineFixed(result, r2), instr);
2070}
2071
2072LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2073  return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2074}
2075
2076LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2077  instr->ReplayEnvironment(current_block_->last_environment());
2078  return NULL;
2079}
2080
2081LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2082  if (instr->is_function_entry()) {
2083    LOperand* context = UseFixed(instr->context(), cp);
2084    return MarkAsCall(new (zone()) LStackCheck(context), instr);
2085  } else {
2086    DCHECK(instr->is_backwards_branch());
2087    LOperand* context = UseAny(instr->context());
2088    return AssignEnvironment(
2089        AssignPointerMap(new (zone()) LStackCheck(context)));
2090  }
2091}
2092
2093LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2094  HEnvironment* outer = current_block_->last_environment();
2095  outer->set_ast_id(instr->ReturnId());
2096  HConstant* undefined = graph()->GetConstantUndefined();
2097  HEnvironment* inner = outer->CopyForInlining(
2098      instr->closure(), instr->arguments_count(), instr->function(), undefined,
2099      instr->inlining_kind(), instr->syntactic_tail_call_mode());
2100  // Only replay binding of arguments object if it wasn't removed from graph.
2101  if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2102    inner->Bind(instr->arguments_var(), instr->arguments_object());
2103  }
2104  inner->BindContext(instr->closure_context());
2105  inner->set_entry(instr);
2106  current_block_->UpdateEnvironment(inner);
2107  return NULL;
2108}
2109
2110LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2111  LInstruction* pop = NULL;
2112
2113  HEnvironment* env = current_block_->last_environment();
2114
2115  if (env->entry()->arguments_pushed()) {
2116    int argument_count = env->arguments_environment()->parameter_count();
2117    pop = new (zone()) LDrop(argument_count);
2118    DCHECK(instr->argument_delta() == -argument_count);
2119  }
2120
2121  HEnvironment* outer =
2122      current_block_->last_environment()->DiscardInlined(false);
2123  current_block_->UpdateEnvironment(outer);
2124
2125  return pop;
2126}
2127
2128LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2129  LOperand* context = UseFixed(instr->context(), cp);
2130  LOperand* object = UseFixed(instr->enumerable(), r2);
2131  LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
2132  return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
2133}
2134
2135LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2136  LOperand* map = UseRegister(instr->map());
2137  return AssignEnvironment(
2138      DefineAsRegister(new (zone()) LForInCacheArray(map)));
2139}
2140
2141LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2142  LOperand* value = UseRegisterAtStart(instr->value());
2143  LOperand* map = UseRegisterAtStart(instr->map());
2144  return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
2145}
2146
2147LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2148  LOperand* object = UseRegister(instr->object());
2149  LOperand* index = UseTempRegister(instr->index());
2150  LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
2151  LInstruction* result = DefineSameAsFirst(load);
2152  return AssignPointerMap(result);
2153}
2154
2155}  // namespace internal
2156}  // namespace v8
2157