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