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