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