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