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