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