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