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