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