fb13cdadf559c53a926d0fd8309860d95418dde6
[profile/ivi/qtjsbackend.git] / src / 3rdparty / v8 / src / x64 / lithium-x64.cc
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #if defined(V8_TARGET_ARCH_X64)
31
32 #include "lithium-allocator-inl.h"
33 #include "x64/lithium-x64.h"
34 #include "x64/lithium-codegen-x64.h"
35
36 namespace v8 {
37 namespace internal {
38
39 #define DEFINE_COMPILE(type)                            \
40   void L##type::CompileToNative(LCodeGen* generator) {  \
41     generator->Do##type(this);                          \
42   }
43 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
44 #undef DEFINE_COMPILE
45
46 LOsrEntry::LOsrEntry() {
47   for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
48     register_spills_[i] = NULL;
49   }
50   for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
51     double_register_spills_[i] = NULL;
52   }
53 }
54
55
56 void LOsrEntry::MarkSpilledRegister(int allocation_index,
57                                     LOperand* spill_operand) {
58   ASSERT(spill_operand->IsStackSlot());
59   ASSERT(register_spills_[allocation_index] == NULL);
60   register_spills_[allocation_index] = spill_operand;
61 }
62
63
64 void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
65                                           LOperand* spill_operand) {
66   ASSERT(spill_operand->IsDoubleStackSlot());
67   ASSERT(double_register_spills_[allocation_index] == NULL);
68   double_register_spills_[allocation_index] = spill_operand;
69 }
70
71
72 #ifdef DEBUG
73 void LInstruction::VerifyCall() {
74   // Call instructions can use only fixed registers as temporaries and
75   // outputs because all registers are blocked by the calling convention.
76   // Inputs operands must use a fixed register or use-at-start policy or
77   // a non-register policy.
78   ASSERT(Output() == NULL ||
79          LUnallocated::cast(Output())->HasFixedPolicy() ||
80          !LUnallocated::cast(Output())->HasRegisterPolicy());
81   for (UseIterator it(this); !it.Done(); it.Advance()) {
82     LUnallocated* operand = LUnallocated::cast(it.Current());
83     ASSERT(operand->HasFixedPolicy() ||
84            operand->IsUsedAtStart());
85   }
86   for (TempIterator it(this); !it.Done(); it.Advance()) {
87     LUnallocated* operand = LUnallocated::cast(it.Current());
88     ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
89   }
90 }
91 #endif
92
93
94 void LInstruction::PrintTo(StringStream* stream) {
95   stream->Add("%s ", this->Mnemonic());
96
97   PrintOutputOperandTo(stream);
98
99   PrintDataTo(stream);
100
101   if (HasEnvironment()) {
102     stream->Add(" ");
103     environment()->PrintTo(stream);
104   }
105
106   if (HasPointerMap()) {
107     stream->Add(" ");
108     pointer_map()->PrintTo(stream);
109   }
110 }
111
112
113 template<int R, int I, int T>
114 void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
115   stream->Add("= ");
116   for (int i = 0; i < inputs_.length(); i++) {
117     if (i > 0) stream->Add(" ");
118     inputs_[i]->PrintTo(stream);
119   }
120 }
121
122
123 template<int R, int I, int T>
124 void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
125   for (int i = 0; i < results_.length(); i++) {
126     if (i > 0) stream->Add(" ");
127     results_[i]->PrintTo(stream);
128   }
129 }
130
131
132 void LLabel::PrintDataTo(StringStream* stream) {
133   LGap::PrintDataTo(stream);
134   LLabel* rep = replacement();
135   if (rep != NULL) {
136     stream->Add(" Dead block replaced with B%d", rep->block_id());
137   }
138 }
139
140
141 bool LGap::IsRedundant() const {
142   for (int i = 0; i < 4; i++) {
143     if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
144       return false;
145     }
146   }
147
148   return true;
149 }
150
151
152 void LGap::PrintDataTo(StringStream* stream) {
153   for (int i = 0; i < 4; i++) {
154     stream->Add("(");
155     if (parallel_moves_[i] != NULL) {
156       parallel_moves_[i]->PrintDataTo(stream);
157     }
158     stream->Add(") ");
159   }
160 }
161
162
163 const char* LArithmeticD::Mnemonic() const {
164   switch (op()) {
165     case Token::ADD: return "add-d";
166     case Token::SUB: return "sub-d";
167     case Token::MUL: return "mul-d";
168     case Token::DIV: return "div-d";
169     case Token::MOD: return "mod-d";
170     default:
171       UNREACHABLE();
172       return NULL;
173   }
174 }
175
176
177 const char* LArithmeticT::Mnemonic() const {
178   switch (op()) {
179     case Token::ADD: return "add-t";
180     case Token::SUB: return "sub-t";
181     case Token::MUL: return "mul-t";
182     case Token::MOD: return "mod-t";
183     case Token::DIV: return "div-t";
184     case Token::BIT_AND: return "bit-and-t";
185     case Token::BIT_OR: return "bit-or-t";
186     case Token::BIT_XOR: return "bit-xor-t";
187     case Token::SHL: return "sal-t";
188     case Token::SAR: return "sar-t";
189     case Token::SHR: return "shr-t";
190     default:
191       UNREACHABLE();
192       return NULL;
193   }
194 }
195
196
197 void LGoto::PrintDataTo(StringStream* stream) {
198   stream->Add("B%d", block_id());
199 }
200
201
202 void LBranch::PrintDataTo(StringStream* stream) {
203   stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
204   InputAt(0)->PrintTo(stream);
205 }
206
207
208 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
209   stream->Add("if ");
210   InputAt(0)->PrintTo(stream);
211   stream->Add(" %s ", Token::String(op()));
212   InputAt(1)->PrintTo(stream);
213   stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
214 }
215
216
217 void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
218   stream->Add("if ");
219   InputAt(0)->PrintTo(stream);
220   stream->Add(kind() == kStrictEquality ? " === " : " == ");
221   stream->Add(nil() == kNullValue ? "null" : "undefined");
222   stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
223 }
224
225
226 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
227   stream->Add("if is_object(");
228   InputAt(0)->PrintTo(stream);
229   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
230 }
231
232
233 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
234   stream->Add("if is_smi(");
235   InputAt(0)->PrintTo(stream);
236   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
237 }
238
239
240 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
241   stream->Add("if is_undetectable(");
242   InputAt(0)->PrintTo(stream);
243   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
244 }
245
246
247 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
248   stream->Add("if has_instance_type(");
249   InputAt(0)->PrintTo(stream);
250   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
251 }
252
253
254 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
255   stream->Add("if has_cached_array_index(");
256   InputAt(0)->PrintTo(stream);
257   stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
258 }
259
260
261 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
262   stream->Add("if class_of_test(");
263   InputAt(0)->PrintTo(stream);
264   stream->Add(", \"%o\") then B%d else B%d",
265               *hydrogen()->class_name(),
266               true_block_id(),
267               false_block_id());
268 }
269
270
271 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
272   stream->Add("if typeof ");
273   InputAt(0)->PrintTo(stream);
274   stream->Add(" == \"%s\" then B%d else B%d",
275               *hydrogen()->type_literal()->ToCString(),
276               true_block_id(), false_block_id());
277 }
278
279
280 void LCallConstantFunction::PrintDataTo(StringStream* stream) {
281   stream->Add("#%d / ", arity());
282 }
283
284
285 void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
286   stream->Add("/%s ", hydrogen()->OpName());
287   InputAt(0)->PrintTo(stream);
288 }
289
290
291 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
292   InputAt(0)->PrintTo(stream);
293   stream->Add("[%d]", slot_index());
294 }
295
296
297 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
298   InputAt(0)->PrintTo(stream);
299   stream->Add("[%d] <- ", slot_index());
300   InputAt(1)->PrintTo(stream);
301 }
302
303
304 void LInvokeFunction::PrintDataTo(StringStream* stream) {
305   stream->Add("= ");
306   InputAt(0)->PrintTo(stream);
307   stream->Add(" #%d / ", arity());
308 }
309
310
311 void LCallKeyed::PrintDataTo(StringStream* stream) {
312   stream->Add("[rcx] #%d / ", arity());
313 }
314
315
316 void LCallNamed::PrintDataTo(StringStream* stream) {
317   SmartArrayPointer<char> name_string = name()->ToCString();
318   stream->Add("%s #%d / ", *name_string, arity());
319 }
320
321
322 void LCallGlobal::PrintDataTo(StringStream* stream) {
323   SmartArrayPointer<char> name_string = name()->ToCString();
324   stream->Add("%s #%d / ", *name_string, arity());
325 }
326
327
328 void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
329   stream->Add("#%d / ", arity());
330 }
331
332
333 void LCallNew::PrintDataTo(StringStream* stream) {
334   stream->Add("= ");
335   InputAt(0)->PrintTo(stream);
336   stream->Add(" #%d / ", arity());
337 }
338
339
340 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
341   arguments()->PrintTo(stream);
342
343   stream->Add(" length ");
344   length()->PrintTo(stream);
345
346   stream->Add(" index ");
347   index()->PrintTo(stream);
348 }
349
350
351 int LChunk::GetNextSpillIndex(bool is_double) {
352   return spill_slot_count_++;
353 }
354
355
356 LOperand* LChunk::GetNextSpillSlot(bool is_double) {
357   // All stack slots are Double stack slots on x64.
358   // Alternatively, at some point, start using half-size
359   // stack slots for int32 values.
360   int index = GetNextSpillIndex(is_double);
361   if (is_double) {
362     return LDoubleStackSlot::Create(index);
363   } else {
364     return LStackSlot::Create(index);
365   }
366 }
367
368
369 void LChunk::MarkEmptyBlocks() {
370   HPhase phase("Mark empty blocks", this);
371   for (int i = 0; i < graph()->blocks()->length(); ++i) {
372     HBasicBlock* block = graph()->blocks()->at(i);
373     int first = block->first_instruction_index();
374     int last = block->last_instruction_index();
375     LInstruction* first_instr = instructions()->at(first);
376     LInstruction* last_instr = instructions()->at(last);
377
378     LLabel* label = LLabel::cast(first_instr);
379     if (last_instr->IsGoto()) {
380       LGoto* goto_instr = LGoto::cast(last_instr);
381       if (label->IsRedundant() &&
382           !label->is_loop_header()) {
383         bool can_eliminate = true;
384         for (int i = first + 1; i < last && can_eliminate; ++i) {
385           LInstruction* cur = instructions()->at(i);
386           if (cur->IsGap()) {
387             LGap* gap = LGap::cast(cur);
388             if (!gap->IsRedundant()) {
389               can_eliminate = false;
390             }
391           } else {
392             can_eliminate = false;
393           }
394         }
395
396         if (can_eliminate) {
397           label->set_replacement(GetLabel(goto_instr->block_id()));
398         }
399       }
400     }
401   }
402 }
403
404
405 void LStoreNamedField::PrintDataTo(StringStream* stream) {
406   object()->PrintTo(stream);
407   stream->Add(".");
408   stream->Add(*String::cast(*name())->ToCString());
409   stream->Add(" <- ");
410   value()->PrintTo(stream);
411 }
412
413
414 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
415   object()->PrintTo(stream);
416   stream->Add(".");
417   stream->Add(*String::cast(*name())->ToCString());
418   stream->Add(" <- ");
419   value()->PrintTo(stream);
420 }
421
422
423 void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
424   object()->PrintTo(stream);
425   stream->Add("[");
426   key()->PrintTo(stream);
427   stream->Add("] <- ");
428   value()->PrintTo(stream);
429 }
430
431
432 void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
433   elements()->PrintTo(stream);
434   stream->Add("[");
435   key()->PrintTo(stream);
436   stream->Add("] <- ");
437   value()->PrintTo(stream);
438 }
439
440
441 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
442   object()->PrintTo(stream);
443   stream->Add("[");
444   key()->PrintTo(stream);
445   stream->Add("] <- ");
446   value()->PrintTo(stream);
447 }
448
449
450 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
451   object()->PrintTo(stream);
452   stream->Add(" %p -> %p", *original_map(), *transitioned_map());
453 }
454
455
456 void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
457   LInstructionGap* gap = new LInstructionGap(block);
458   int index = -1;
459   if (instr->IsControl()) {
460     instructions_.Add(gap);
461     index = instructions_.length();
462     instructions_.Add(instr);
463   } else {
464     index = instructions_.length();
465     instructions_.Add(instr);
466     instructions_.Add(gap);
467   }
468   if (instr->HasPointerMap()) {
469     pointer_maps_.Add(instr->pointer_map());
470     instr->pointer_map()->set_lithium_position(index);
471   }
472 }
473
474
475 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
476   return LConstantOperand::Create(constant->id());
477 }
478
479
480 int LChunk::GetParameterStackSlot(int index) const {
481   // The receiver is at index 0, the first parameter at index 1, so we
482   // shift all parameter indexes down by the number of parameters, and
483   // make sure they end up negative so they are distinguishable from
484   // spill slots.
485   int result = index - info()->scope()->num_parameters() - 1;
486   ASSERT(result < 0);
487   return result;
488 }
489
490 // A parameter relative to ebp in the arguments stub.
491 int LChunk::ParameterAt(int index) {
492   ASSERT(-1 <= index);  // -1 is the receiver.
493   return (1 + info()->scope()->num_parameters() - index) *
494       kPointerSize;
495 }
496
497
498 LGap* LChunk::GetGapAt(int index) const {
499   return LGap::cast(instructions_[index]);
500 }
501
502
503 bool LChunk::IsGapAt(int index) const {
504   return instructions_[index]->IsGap();
505 }
506
507
508 int LChunk::NearestGapPos(int index) const {
509   while (!IsGapAt(index)) index--;
510   return index;
511 }
512
513
514 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
515   GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
516 }
517
518
519 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
520   return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
521 }
522
523
524 Representation LChunk::LookupLiteralRepresentation(
525     LConstantOperand* operand) const {
526   return graph_->LookupValue(operand->index())->representation();
527 }
528
529
530 LChunk* LChunkBuilder::Build() {
531   ASSERT(is_unused());
532   chunk_ = new LChunk(info(), graph());
533   HPhase phase("Building chunk", chunk_);
534   status_ = BUILDING;
535   const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
536   for (int i = 0; i < blocks->length(); i++) {
537     HBasicBlock* next = NULL;
538     if (i < blocks->length() - 1) next = blocks->at(i + 1);
539     DoBasicBlock(blocks->at(i), next);
540     if (is_aborted()) return NULL;
541   }
542   status_ = DONE;
543   return chunk_;
544 }
545
546
547 void LChunkBuilder::Abort(const char* format, ...) {
548   if (FLAG_trace_bailout) {
549     SmartArrayPointer<char> name(
550         info()->shared_info()->DebugName()->ToCString());
551     PrintF("Aborting LChunk building in @\"%s\": ", *name);
552     va_list arguments;
553     va_start(arguments, format);
554     OS::VPrint(format, arguments);
555     va_end(arguments);
556     PrintF("\n");
557   }
558   status_ = ABORTED;
559 }
560
561
562 LRegister* LChunkBuilder::ToOperand(Register reg) {
563   return LRegister::Create(Register::ToAllocationIndex(reg));
564 }
565
566
567 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
568   return new LUnallocated(LUnallocated::FIXED_REGISTER,
569                           Register::ToAllocationIndex(reg));
570 }
571
572
573 LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
574   return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
575                           XMMRegister::ToAllocationIndex(reg));
576 }
577
578
579 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
580   return Use(value, ToUnallocated(fixed_register));
581 }
582
583
584 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
585   return Use(value, ToUnallocated(reg));
586 }
587
588
589 LOperand* LChunkBuilder::UseRegister(HValue* value) {
590   return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
591 }
592
593
594 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
595   return Use(value,
596              new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
597                               LUnallocated::USED_AT_START));
598 }
599
600
601 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
602   return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
603 }
604
605
606 LOperand* LChunkBuilder::Use(HValue* value) {
607   return Use(value, new LUnallocated(LUnallocated::NONE));
608 }
609
610
611 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
612   return Use(value, new LUnallocated(LUnallocated::NONE,
613                                      LUnallocated::USED_AT_START));
614 }
615
616
617 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
618   return value->IsConstant()
619       ? chunk_->DefineConstantOperand(HConstant::cast(value))
620       : Use(value);
621 }
622
623
624 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
625   return value->IsConstant()
626       ? chunk_->DefineConstantOperand(HConstant::cast(value))
627       : UseAtStart(value);
628 }
629
630
631 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
632   return value->IsConstant()
633       ? chunk_->DefineConstantOperand(HConstant::cast(value))
634       : UseRegister(value);
635 }
636
637
638 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
639   return value->IsConstant()
640       ? chunk_->DefineConstantOperand(HConstant::cast(value))
641       : UseRegisterAtStart(value);
642 }
643
644
645 LOperand* LChunkBuilder::UseAny(HValue* value) {
646   return value->IsConstant()
647       ? chunk_->DefineConstantOperand(HConstant::cast(value))
648       :  Use(value, new LUnallocated(LUnallocated::ANY));
649 }
650
651
652 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
653   if (value->EmitAtUses()) {
654     HInstruction* instr = HInstruction::cast(value);
655     VisitInstruction(instr);
656   }
657   allocator_->RecordUse(value, operand);
658   return operand;
659 }
660
661
662 template<int I, int T>
663 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
664                                     LUnallocated* result) {
665   allocator_->RecordDefinition(current_instruction_, result);
666   instr->set_result(result);
667   return instr;
668 }
669
670
671 template<int I, int T>
672 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
673   return Define(instr, new LUnallocated(LUnallocated::NONE));
674 }
675
676
677 template<int I, int T>
678 LInstruction* LChunkBuilder::DefineAsRegister(
679     LTemplateInstruction<1, I, T>* instr) {
680   return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
681 }
682
683
684 template<int I, int T>
685 LInstruction* LChunkBuilder::DefineAsSpilled(
686     LTemplateInstruction<1, I, T>* instr,
687     int index) {
688   return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
689 }
690
691
692 template<int I, int T>
693 LInstruction* LChunkBuilder::DefineSameAsFirst(
694     LTemplateInstruction<1, I, T>* instr) {
695   return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
696 }
697
698
699 template<int I, int T>
700 LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
701                                          Register reg) {
702   return Define(instr, ToUnallocated(reg));
703 }
704
705
706 template<int I, int T>
707 LInstruction* LChunkBuilder::DefineFixedDouble(
708     LTemplateInstruction<1, I, T>* instr,
709     XMMRegister reg) {
710   return Define(instr, ToUnallocated(reg));
711 }
712
713
714 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
715   HEnvironment* hydrogen_env = current_block_->last_environment();
716   int argument_index_accumulator = 0;
717   instr->set_environment(CreateEnvironment(hydrogen_env,
718                                            &argument_index_accumulator));
719   return instr;
720 }
721
722
723 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
724     LInstruction* instr, int ast_id) {
725   ASSERT(instruction_pending_deoptimization_environment_ == NULL);
726   ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
727   instruction_pending_deoptimization_environment_ = instr;
728   pending_deoptimization_ast_id_ = ast_id;
729   return instr;
730 }
731
732
733 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
734   instruction_pending_deoptimization_environment_ = NULL;
735   pending_deoptimization_ast_id_ = AstNode::kNoNumber;
736 }
737
738
739 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
740                                         HInstruction* hinstr,
741                                         CanDeoptimize can_deoptimize) {
742 #ifdef DEBUG
743   instr->VerifyCall();
744 #endif
745   instr->MarkAsCall();
746   instr = AssignPointerMap(instr);
747
748   if (hinstr->HasObservableSideEffects()) {
749     ASSERT(hinstr->next()->IsSimulate());
750     HSimulate* sim = HSimulate::cast(hinstr->next());
751     instr = SetInstructionPendingDeoptimizationEnvironment(
752         instr, sim->ast_id());
753   }
754
755   // If instruction does not have side-effects lazy deoptimization
756   // after the call will try to deoptimize to the point before the call.
757   // Thus we still need to attach environment to this call even if
758   // call sequence can not deoptimize eagerly.
759   bool needs_environment =
760       (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
761       !hinstr->HasObservableSideEffects();
762   if (needs_environment && !instr->HasEnvironment()) {
763     instr = AssignEnvironment(instr);
764   }
765
766   return instr;
767 }
768
769
770 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
771   instr->MarkAsSaveDoubles();
772   return instr;
773 }
774
775
776 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
777   ASSERT(!instr->HasPointerMap());
778   instr->set_pointer_map(new LPointerMap(position_));
779   return instr;
780 }
781
782
783 LUnallocated* LChunkBuilder::TempRegister() {
784   LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
785   allocator_->RecordTemporary(operand);
786   return operand;
787 }
788
789
790 LOperand* LChunkBuilder::FixedTemp(Register reg) {
791   LUnallocated* operand = ToUnallocated(reg);
792   allocator_->RecordTemporary(operand);
793   return operand;
794 }
795
796
797 LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
798   LUnallocated* operand = ToUnallocated(reg);
799   allocator_->RecordTemporary(operand);
800   return operand;
801 }
802
803
804 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
805   return new LLabel(instr->block());
806 }
807
808
809 LInstruction* LChunkBuilder::DoSoftDeoptimize(HSoftDeoptimize* instr) {
810   return AssignEnvironment(new LDeoptimize);
811 }
812
813
814 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
815   return AssignEnvironment(new LDeoptimize);
816 }
817
818
819 LInstruction* LChunkBuilder::DoShift(Token::Value op,
820                                      HBitwiseBinaryOperation* instr) {
821   if (instr->representation().IsTagged()) {
822     ASSERT(instr->left()->representation().IsTagged());
823     ASSERT(instr->right()->representation().IsTagged());
824
825     LOperand* left = UseFixed(instr->left(), rdx);
826     LOperand* right = UseFixed(instr->right(), rax);
827     LArithmeticT* result = new LArithmeticT(op, left, right);
828     return MarkAsCall(DefineFixed(result, rax), instr);
829   }
830
831   ASSERT(instr->representation().IsInteger32());
832   ASSERT(instr->left()->representation().IsInteger32());
833   ASSERT(instr->right()->representation().IsInteger32());
834   LOperand* left = UseRegisterAtStart(instr->left());
835
836   HValue* right_value = instr->right();
837   LOperand* right = NULL;
838   int constant_value = 0;
839   if (right_value->IsConstant()) {
840     HConstant* constant = HConstant::cast(right_value);
841     right = chunk_->DefineConstantOperand(constant);
842     constant_value = constant->Integer32Value() & 0x1f;
843   } else {
844     right = UseFixed(right_value, rcx);
845   }
846
847   // Shift operations can only deoptimize if we do a logical shift by 0 and
848   // the result cannot be truncated to int32.
849   bool may_deopt = (op == Token::SHR && constant_value == 0);
850   bool does_deopt = false;
851   if (may_deopt) {
852     for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
853       if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
854         does_deopt = true;
855         break;
856       }
857     }
858   }
859
860   LInstruction* result =
861       DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
862   return does_deopt ? AssignEnvironment(result) : result;
863 }
864
865
866 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
867                                            HArithmeticBinaryOperation* instr) {
868   ASSERT(instr->representation().IsDouble());
869   ASSERT(instr->left()->representation().IsDouble());
870   ASSERT(instr->right()->representation().IsDouble());
871   ASSERT(op != Token::MOD);
872   LOperand* left = UseRegisterAtStart(instr->left());
873   LOperand* right = UseRegisterAtStart(instr->right());
874   LArithmeticD* result = new LArithmeticD(op, left, right);
875   return DefineSameAsFirst(result);
876 }
877
878
879 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
880                                            HArithmeticBinaryOperation* instr) {
881   ASSERT(op == Token::ADD ||
882          op == Token::DIV ||
883          op == Token::MOD ||
884          op == Token::MUL ||
885          op == Token::SUB);
886   HValue* left = instr->left();
887   HValue* right = instr->right();
888   ASSERT(left->representation().IsTagged());
889   ASSERT(right->representation().IsTagged());
890   LOperand* left_operand = UseFixed(left, rdx);
891   LOperand* right_operand = UseFixed(right, rax);
892   LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
893   return MarkAsCall(DefineFixed(result, rax), instr);
894 }
895
896
897 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
898   ASSERT(is_building());
899   current_block_ = block;
900   next_block_ = next_block;
901   if (block->IsStartBlock()) {
902     block->UpdateEnvironment(graph_->start_environment());
903     argument_count_ = 0;
904   } else if (block->predecessors()->length() == 1) {
905     // We have a single predecessor => copy environment and outgoing
906     // argument count from the predecessor.
907     ASSERT(block->phis()->length() == 0);
908     HBasicBlock* pred = block->predecessors()->at(0);
909     HEnvironment* last_environment = pred->last_environment();
910     ASSERT(last_environment != NULL);
911     // Only copy the environment, if it is later used again.
912     if (pred->end()->SecondSuccessor() == NULL) {
913       ASSERT(pred->end()->FirstSuccessor() == block);
914     } else {
915       if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
916           pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
917         last_environment = last_environment->Copy();
918       }
919     }
920     block->UpdateEnvironment(last_environment);
921     ASSERT(pred->argument_count() >= 0);
922     argument_count_ = pred->argument_count();
923   } else {
924     // We are at a state join => process phis.
925     HBasicBlock* pred = block->predecessors()->at(0);
926     // No need to copy the environment, it cannot be used later.
927     HEnvironment* last_environment = pred->last_environment();
928     for (int i = 0; i < block->phis()->length(); ++i) {
929       HPhi* phi = block->phis()->at(i);
930       last_environment->SetValueAt(phi->merged_index(), phi);
931     }
932     for (int i = 0; i < block->deleted_phis()->length(); ++i) {
933       last_environment->SetValueAt(block->deleted_phis()->at(i),
934                                    graph_->GetConstantUndefined());
935     }
936     block->UpdateEnvironment(last_environment);
937     // Pick up the outgoing argument count of one of the predecessors.
938     argument_count_ = pred->argument_count();
939   }
940   HInstruction* current = block->first();
941   int start = chunk_->instructions()->length();
942   while (current != NULL && !is_aborted()) {
943     // Code for constants in registers is generated lazily.
944     if (!current->EmitAtUses()) {
945       VisitInstruction(current);
946     }
947     current = current->next();
948   }
949   int end = chunk_->instructions()->length() - 1;
950   if (end >= start) {
951     block->set_first_instruction_index(start);
952     block->set_last_instruction_index(end);
953   }
954   block->set_argument_count(argument_count_);
955   next_block_ = NULL;
956   current_block_ = NULL;
957 }
958
959
960 void LChunkBuilder::VisitInstruction(HInstruction* current) {
961   HInstruction* old_current = current_instruction_;
962   current_instruction_ = current;
963   if (current->has_position()) position_ = current->position();
964   LInstruction* instr = current->CompileToLithium(this);
965
966   if (instr != NULL) {
967     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
968       instr = AssignPointerMap(instr);
969     }
970     if (FLAG_stress_environments && !instr->HasEnvironment()) {
971       instr = AssignEnvironment(instr);
972     }
973     instr->set_hydrogen_value(current);
974     chunk_->AddInstruction(instr, current_block_);
975   }
976   current_instruction_ = old_current;
977 }
978
979
980 LEnvironment* LChunkBuilder::CreateEnvironment(
981     HEnvironment* hydrogen_env,
982     int* argument_index_accumulator) {
983   if (hydrogen_env == NULL) return NULL;
984
985   LEnvironment* outer =
986       CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
987   int ast_id = hydrogen_env->ast_id();
988   ASSERT(ast_id != AstNode::kNoNumber);
989   int value_count = hydrogen_env->length();
990   LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
991                                           ast_id,
992                                           hydrogen_env->parameter_count(),
993                                           argument_count_,
994                                           value_count,
995                                           outer);
996   for (int i = 0; i < value_count; ++i) {
997     if (hydrogen_env->is_special_index(i)) continue;
998
999     HValue* value = hydrogen_env->values()->at(i);
1000     LOperand* op = NULL;
1001     if (value->IsArgumentsObject()) {
1002       op = NULL;
1003     } else if (value->IsPushArgument()) {
1004       op = new LArgument((*argument_index_accumulator)++);
1005     } else {
1006       op = UseAny(value);
1007     }
1008     result->AddValue(op, value->representation());
1009   }
1010
1011   return result;
1012 }
1013
1014
1015 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1016   return new LGoto(instr->FirstSuccessor()->block_id());
1017 }
1018
1019
1020 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1021   HValue* v = instr->value();
1022   if (v->EmitAtUses()) {
1023     ASSERT(v->IsConstant());
1024     ASSERT(!v->representation().IsDouble());
1025     HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
1026         ? instr->FirstSuccessor()
1027         : instr->SecondSuccessor();
1028     return new LGoto(successor->block_id());
1029   }
1030   return AssignEnvironment(new LBranch(UseRegister(v)));
1031 }
1032
1033
1034 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1035   ASSERT(instr->value()->representation().IsTagged());
1036   LOperand* value = UseRegisterAtStart(instr->value());
1037   return new LCmpMapAndBranch(value);
1038 }
1039
1040
1041 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1042   return DefineAsRegister(new LArgumentsLength(Use(length->value())));
1043 }
1044
1045
1046 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1047   return DefineAsRegister(new LArgumentsElements);
1048 }
1049
1050
1051 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1052   LOperand* left = UseFixed(instr->left(), rax);
1053   LOperand* right = UseFixed(instr->right(), rdx);
1054   LInstanceOf* result = new LInstanceOf(left, right);
1055   return MarkAsCall(DefineFixed(result, rax), instr);
1056 }
1057
1058
1059 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1060     HInstanceOfKnownGlobal* instr) {
1061   LInstanceOfKnownGlobal* result =
1062       new LInstanceOfKnownGlobal(UseFixed(instr->left(), rax),
1063                                  FixedTemp(rdi));
1064   return MarkAsCall(DefineFixed(result, rax), instr);
1065 }
1066
1067
1068 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1069   LOperand* function = UseFixed(instr->function(), rdi);
1070   LOperand* receiver = UseFixed(instr->receiver(), rax);
1071   LOperand* length = UseFixed(instr->length(), rbx);
1072   LOperand* elements = UseFixed(instr->elements(), rcx);
1073   LApplyArguments* result = new LApplyArguments(function,
1074                                                 receiver,
1075                                                 length,
1076                                                 elements);
1077   return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
1078 }
1079
1080
1081 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1082   ++argument_count_;
1083   LOperand* argument = UseOrConstant(instr->argument());
1084   return new LPushArgument(argument);
1085 }
1086
1087
1088 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1089   return instr->HasNoUses() ? NULL : DefineAsRegister(new LThisFunction);
1090 }
1091
1092
1093 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1094   return instr->HasNoUses() ? NULL : DefineAsRegister(new LContext);
1095 }
1096
1097
1098 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1099   LOperand* context = UseRegisterAtStart(instr->value());
1100   return DefineAsRegister(new LOuterContext(context));
1101 }
1102
1103
1104 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1105   return DefineAsRegister(new LGlobalObject(instr->qml_global()));
1106 }
1107
1108
1109 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1110   LOperand* global_object = UseRegisterAtStart(instr->value());
1111   return DefineAsRegister(new LGlobalReceiver(global_object));
1112 }
1113
1114
1115 LInstruction* LChunkBuilder::DoCallConstantFunction(
1116     HCallConstantFunction* instr) {
1117   argument_count_ -= instr->argument_count();
1118   return MarkAsCall(DefineFixed(new LCallConstantFunction, rax), instr);
1119 }
1120
1121
1122 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1123   LOperand* function = UseFixed(instr->function(), rdi);
1124   argument_count_ -= instr->argument_count();
1125   LInvokeFunction* result = new LInvokeFunction(function);
1126   return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1127 }
1128
1129
1130 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1131   BuiltinFunctionId op = instr->op();
1132   if (op == kMathLog || op == kMathSin || op == kMathCos) {
1133     LOperand* input = UseFixedDouble(instr->value(), xmm1);
1134     LUnaryMathOperation* result = new LUnaryMathOperation(input);
1135     return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1136   } else {
1137     LOperand* input = UseRegisterAtStart(instr->value());
1138     LUnaryMathOperation* result = new LUnaryMathOperation(input);
1139     switch (op) {
1140       case kMathAbs:
1141         return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1142       case kMathFloor:
1143         return AssignEnvironment(DefineAsRegister(result));
1144       case kMathRound:
1145         return AssignEnvironment(DefineAsRegister(result));
1146       case kMathSqrt:
1147         return DefineSameAsFirst(result);
1148       case kMathPowHalf:
1149         return DefineSameAsFirst(result);
1150       default:
1151         UNREACHABLE();
1152         return NULL;
1153     }
1154   }
1155 }
1156
1157
1158 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1159   ASSERT(instr->key()->representation().IsTagged());
1160   LOperand* key = UseFixed(instr->key(), rcx);
1161   argument_count_ -= instr->argument_count();
1162   LCallKeyed* result = new LCallKeyed(key);
1163   return MarkAsCall(DefineFixed(result, rax), instr);
1164 }
1165
1166
1167 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1168   argument_count_ -= instr->argument_count();
1169   return MarkAsCall(DefineFixed(new LCallNamed, rax), instr);
1170 }
1171
1172
1173 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1174   argument_count_ -= instr->argument_count();
1175   return MarkAsCall(DefineFixed(new LCallGlobal(instr->qml_global()), rax), instr);
1176 }
1177
1178
1179 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1180   argument_count_ -= instr->argument_count();
1181   return MarkAsCall(DefineFixed(new LCallKnownGlobal, rax), instr);
1182 }
1183
1184
1185 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1186   LOperand* constructor = UseFixed(instr->constructor(), rdi);
1187   argument_count_ -= instr->argument_count();
1188   LCallNew* result = new LCallNew(constructor);
1189   return MarkAsCall(DefineFixed(result, rax), instr);
1190 }
1191
1192
1193 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1194   argument_count_ -= instr->argument_count();
1195   LCallFunction* result = new LCallFunction();
1196   return MarkAsCall(DefineFixed(result, rax), instr);
1197 }
1198
1199
1200 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1201   argument_count_ -= instr->argument_count();
1202   return MarkAsCall(DefineFixed(new LCallRuntime, rax), instr);
1203 }
1204
1205
1206 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1207   return DoShift(Token::SHR, instr);
1208 }
1209
1210
1211 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1212   return DoShift(Token::SAR, instr);
1213 }
1214
1215
1216 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1217   return DoShift(Token::SHL, instr);
1218 }
1219
1220
1221 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1222   if (instr->representation().IsInteger32()) {
1223     ASSERT(instr->left()->representation().IsInteger32());
1224     ASSERT(instr->right()->representation().IsInteger32());
1225
1226     LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1227     LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1228     return DefineSameAsFirst(new LBitI(left, right));
1229   } else {
1230     ASSERT(instr->representation().IsTagged());
1231     ASSERT(instr->left()->representation().IsTagged());
1232     ASSERT(instr->right()->representation().IsTagged());
1233
1234     LOperand* left = UseFixed(instr->left(), rdx);
1235     LOperand* right = UseFixed(instr->right(), rax);
1236     LArithmeticT* result = new LArithmeticT(instr->op(), left, right);
1237     return MarkAsCall(DefineFixed(result, rax), instr);
1238   }
1239 }
1240
1241
1242 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1243   ASSERT(instr->value()->representation().IsInteger32());
1244   ASSERT(instr->representation().IsInteger32());
1245   LOperand* input = UseRegisterAtStart(instr->value());
1246   LBitNotI* result = new LBitNotI(input);
1247   return DefineSameAsFirst(result);
1248 }
1249
1250
1251 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1252   if (instr->representation().IsDouble()) {
1253     return DoArithmeticD(Token::DIV, instr);
1254   } else if (instr->representation().IsInteger32()) {
1255     // The temporary operand is necessary to ensure that right is not allocated
1256     // into rdx.
1257     LOperand* temp = FixedTemp(rdx);
1258     LOperand* dividend = UseFixed(instr->left(), rax);
1259     LOperand* divisor = UseRegister(instr->right());
1260     LDivI* result = new LDivI(dividend, divisor, temp);
1261     return AssignEnvironment(DefineFixed(result, rax));
1262   } else {
1263     ASSERT(instr->representation().IsTagged());
1264     return DoArithmeticT(Token::DIV, instr);
1265   }
1266 }
1267
1268
1269 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1270   if (instr->representation().IsInteger32()) {
1271     ASSERT(instr->left()->representation().IsInteger32());
1272     ASSERT(instr->right()->representation().IsInteger32());
1273
1274     LInstruction* result;
1275     if (instr->HasPowerOf2Divisor()) {
1276       ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1277       LOperand* value = UseRegisterAtStart(instr->left());
1278       LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
1279       result = DefineSameAsFirst(mod);
1280     } else {
1281       // The temporary operand is necessary to ensure that right is not
1282       // allocated into edx.
1283       LOperand* temp = FixedTemp(rdx);
1284       LOperand* value = UseFixed(instr->left(), rax);
1285       LOperand* divisor = UseRegister(instr->right());
1286       LModI* mod = new LModI(value, divisor, temp);
1287       result = DefineFixed(mod, rdx);
1288     }
1289
1290     return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1291             instr->CheckFlag(HValue::kCanBeDivByZero))
1292         ? AssignEnvironment(result)
1293         : result;
1294   } else if (instr->representation().IsTagged()) {
1295     return DoArithmeticT(Token::MOD, instr);
1296   } else {
1297     ASSERT(instr->representation().IsDouble());
1298     // We call a C function for double modulo. It can't trigger a GC.
1299     // We need to use fixed result register for the call.
1300     // TODO(fschneider): Allow any register as input registers.
1301     LOperand* left = UseFixedDouble(instr->left(), xmm2);
1302     LOperand* right = UseFixedDouble(instr->right(), xmm1);
1303     LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1304     return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1305   }
1306 }
1307
1308
1309 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1310   if (instr->representation().IsInteger32()) {
1311     ASSERT(instr->left()->representation().IsInteger32());
1312     ASSERT(instr->right()->representation().IsInteger32());
1313     LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1314     LOperand* right = UseOrConstant(instr->MostConstantOperand());
1315     LMulI* mul = new LMulI(left, right);
1316     return AssignEnvironment(DefineSameAsFirst(mul));
1317   } else if (instr->representation().IsDouble()) {
1318     return DoArithmeticD(Token::MUL, instr);
1319   } else {
1320     ASSERT(instr->representation().IsTagged());
1321     return DoArithmeticT(Token::MUL, instr);
1322   }
1323 }
1324
1325
1326 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1327   if (instr->representation().IsInteger32()) {
1328     ASSERT(instr->left()->representation().IsInteger32());
1329     ASSERT(instr->right()->representation().IsInteger32());
1330     LOperand* left = UseRegisterAtStart(instr->left());
1331     LOperand* right = UseOrConstantAtStart(instr->right());
1332     LSubI* sub = new LSubI(left, right);
1333     LInstruction* result = DefineSameAsFirst(sub);
1334     if (instr->CheckFlag(HValue::kCanOverflow)) {
1335       result = AssignEnvironment(result);
1336     }
1337     return result;
1338   } else if (instr->representation().IsDouble()) {
1339     return DoArithmeticD(Token::SUB, instr);
1340   } else {
1341     ASSERT(instr->representation().IsTagged());
1342     return DoArithmeticT(Token::SUB, instr);
1343   }
1344 }
1345
1346
1347 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1348   if (instr->representation().IsInteger32()) {
1349     ASSERT(instr->left()->representation().IsInteger32());
1350     ASSERT(instr->right()->representation().IsInteger32());
1351     LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1352     LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1353     LAddI* add = new LAddI(left, right);
1354     LInstruction* result = DefineSameAsFirst(add);
1355     if (instr->CheckFlag(HValue::kCanOverflow)) {
1356       result = AssignEnvironment(result);
1357     }
1358     return result;
1359   } else if (instr->representation().IsDouble()) {
1360     return DoArithmeticD(Token::ADD, instr);
1361   } else {
1362     ASSERT(instr->representation().IsTagged());
1363     return DoArithmeticT(Token::ADD, instr);
1364   }
1365   return NULL;
1366 }
1367
1368
1369 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1370   ASSERT(instr->representation().IsDouble());
1371   // We call a C function for double power. It can't trigger a GC.
1372   // We need to use fixed result register for the call.
1373   Representation exponent_type = instr->right()->representation();
1374   ASSERT(instr->left()->representation().IsDouble());
1375   LOperand* left = UseFixedDouble(instr->left(), xmm2);
1376   LOperand* right = exponent_type.IsDouble() ?
1377       UseFixedDouble(instr->right(), xmm1) :
1378 #ifdef _WIN64
1379       UseFixed(instr->right(), rdx);
1380 #else
1381       UseFixed(instr->right(), rdi);
1382 #endif
1383   LPower* result = new LPower(left, right);
1384   return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
1385                     CAN_DEOPTIMIZE_EAGERLY);
1386 }
1387
1388
1389 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1390   ASSERT(instr->left()->representation().IsTagged());
1391   ASSERT(instr->right()->representation().IsTagged());
1392   LOperand* left = UseFixed(instr->left(), rdx);
1393   LOperand* right = UseFixed(instr->right(), rax);
1394   LCmpT* result = new LCmpT(left, right);
1395   return MarkAsCall(DefineFixed(result, rax), instr);
1396 }
1397
1398
1399 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
1400     HCompareIDAndBranch* instr) {
1401   Representation r = instr->GetInputRepresentation();
1402   if (r.IsInteger32()) {
1403     ASSERT(instr->left()->representation().IsInteger32());
1404     ASSERT(instr->right()->representation().IsInteger32());
1405     LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1406     LOperand* right = UseOrConstantAtStart(instr->right());
1407     return new LCmpIDAndBranch(left, right);
1408   } else {
1409     ASSERT(r.IsDouble());
1410     ASSERT(instr->left()->representation().IsDouble());
1411     ASSERT(instr->right()->representation().IsDouble());
1412     LOperand* left;
1413     LOperand* right;
1414     if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1415       left = UseRegisterOrConstantAtStart(instr->left());
1416       right = UseRegisterOrConstantAtStart(instr->right());
1417     } else {
1418       left = UseRegisterAtStart(instr->left());
1419       right = UseRegisterAtStart(instr->right());
1420     }
1421     return new LCmpIDAndBranch(left, right);
1422   }
1423 }
1424
1425
1426 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1427     HCompareObjectEqAndBranch* instr) {
1428   LOperand* left = UseRegisterAtStart(instr->left());
1429   LOperand* right = UseRegisterAtStart(instr->right());
1430   return new LCmpObjectEqAndBranch(left, right);
1431 }
1432
1433
1434 LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
1435     HCompareConstantEqAndBranch* instr) {
1436   return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value()));
1437 }
1438
1439
1440 LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
1441   ASSERT(instr->value()->representation().IsTagged());
1442   LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
1443   return new LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
1444 }
1445
1446
1447 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1448   ASSERT(instr->value()->representation().IsTagged());
1449   return new LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
1450 }
1451
1452
1453 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1454   ASSERT(instr->value()->representation().IsTagged());
1455   return new LIsSmiAndBranch(Use(instr->value()));
1456 }
1457
1458
1459 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1460     HIsUndetectableAndBranch* instr) {
1461   ASSERT(instr->value()->representation().IsTagged());
1462   return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()),
1463                                       TempRegister());
1464 }
1465
1466
1467 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1468     HHasInstanceTypeAndBranch* instr) {
1469   ASSERT(instr->value()->representation().IsTagged());
1470   return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value()));
1471 }
1472
1473
1474 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1475     HGetCachedArrayIndex* instr)  {
1476   ASSERT(instr->value()->representation().IsTagged());
1477   LOperand* value = UseRegisterAtStart(instr->value());
1478
1479   return DefineAsRegister(new LGetCachedArrayIndex(value));
1480 }
1481
1482
1483 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1484     HHasCachedArrayIndexAndBranch* instr) {
1485   ASSERT(instr->value()->representation().IsTagged());
1486   return new LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
1487 }
1488
1489
1490 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1491     HClassOfTestAndBranch* instr) {
1492   return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
1493                                    TempRegister(),
1494                                    TempRegister());
1495 }
1496
1497
1498 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1499   LOperand* array = UseRegisterAtStart(instr->value());
1500   return DefineAsRegister(new LJSArrayLength(array));
1501 }
1502
1503
1504 LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
1505     HFixedArrayBaseLength* instr) {
1506   LOperand* array = UseRegisterAtStart(instr->value());
1507   return DefineAsRegister(new LFixedArrayBaseLength(array));
1508 }
1509
1510
1511 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1512   LOperand* object = UseRegisterAtStart(instr->value());
1513   return DefineAsRegister(new LElementsKind(object));
1514 }
1515
1516
1517 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1518   LOperand* object = UseRegister(instr->value());
1519   LValueOf* result = new LValueOf(object);
1520   return AssignEnvironment(DefineSameAsFirst(result));
1521 }
1522
1523
1524 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1525   return AssignEnvironment(new LBoundsCheck(
1526       UseRegisterOrConstantAtStart(instr->index()),
1527       Use(instr->length())));
1528 }
1529
1530
1531 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1532   // The control instruction marking the end of a block that completed
1533   // abruptly (e.g., threw an exception).  There is nothing specific to do.
1534   return NULL;
1535 }
1536
1537
1538 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1539   LOperand* value = UseFixed(instr->value(), rax);
1540   return MarkAsCall(new LThrow(value), instr);
1541 }
1542
1543
1544 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1545   return NULL;
1546 }
1547
1548
1549 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1550   // All HForceRepresentation instructions should be eliminated in the
1551   // representation change phase of Hydrogen.
1552   UNREACHABLE();
1553   return NULL;
1554 }
1555
1556
1557 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1558   Representation from = instr->from();
1559   Representation to = instr->to();
1560   if (from.IsTagged()) {
1561     if (to.IsDouble()) {
1562       LOperand* value = UseRegister(instr->value());
1563       LNumberUntagD* res = new LNumberUntagD(value);
1564       return AssignEnvironment(DefineAsRegister(res));
1565     } else {
1566       ASSERT(to.IsInteger32());
1567       LOperand* value = UseRegister(instr->value());
1568       bool needs_check = !instr->value()->type().IsSmi();
1569       if (needs_check) {
1570         bool truncating = instr->CanTruncateToInt32();
1571         LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1572         LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1573         return AssignEnvironment(DefineSameAsFirst(res));
1574       } else {
1575         return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1576       }
1577     }
1578   } else if (from.IsDouble()) {
1579     if (to.IsTagged()) {
1580       LOperand* value = UseRegister(instr->value());
1581       LOperand* temp = TempRegister();
1582
1583       // Make sure that temp and result_temp are different registers.
1584       LUnallocated* result_temp = TempRegister();
1585       LNumberTagD* result = new LNumberTagD(value, temp);
1586       return AssignPointerMap(Define(result, result_temp));
1587     } else {
1588       ASSERT(to.IsInteger32());
1589       LOperand* value = UseRegister(instr->value());
1590       return AssignEnvironment(DefineAsRegister(new LDoubleToI(value)));
1591     }
1592   } else if (from.IsInteger32()) {
1593     if (to.IsTagged()) {
1594       HValue* val = instr->value();
1595       LOperand* value = UseRegister(val);
1596       if (val->HasRange() && val->range()->IsInSmiRange()) {
1597         return DefineSameAsFirst(new LSmiTag(value));
1598       } else {
1599         LNumberTagI* result = new LNumberTagI(value);
1600         return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1601       }
1602     } else {
1603       ASSERT(to.IsDouble());
1604       return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1605     }
1606   }
1607   UNREACHABLE();
1608   return NULL;
1609 }
1610
1611
1612 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1613   LOperand* value = UseRegisterAtStart(instr->value());
1614   return AssignEnvironment(new LCheckNonSmi(value));
1615 }
1616
1617
1618 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1619   LOperand* value = UseRegisterAtStart(instr->value());
1620   LCheckInstanceType* result = new LCheckInstanceType(value);
1621   return AssignEnvironment(result);
1622 }
1623
1624
1625 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1626   LOperand* temp = TempRegister();
1627   LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp);
1628   return AssignEnvironment(result);
1629 }
1630
1631
1632 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1633   LOperand* value = UseRegisterAtStart(instr->value());
1634   return AssignEnvironment(new LCheckSmi(value));
1635 }
1636
1637
1638 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1639   LOperand* value = UseRegisterAtStart(instr->value());
1640   return AssignEnvironment(new LCheckFunction(value));
1641 }
1642
1643
1644 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1645   LOperand* value = UseRegisterAtStart(instr->value());
1646   LCheckMap* result = new LCheckMap(value);
1647   return AssignEnvironment(result);
1648 }
1649
1650
1651 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1652   HValue* value = instr->value();
1653   Representation input_rep = value->representation();
1654   LOperand* reg = UseRegister(value);
1655   if (input_rep.IsDouble()) {
1656     return DefineAsRegister(new LClampDToUint8(reg,
1657                                                TempRegister()));
1658   } else if (input_rep.IsInteger32()) {
1659     return DefineSameAsFirst(new LClampIToUint8(reg));
1660   } else {
1661     ASSERT(input_rep.IsTagged());
1662     // Register allocator doesn't (yet) support allocation of double
1663     // temps. Reserve xmm1 explicitly.
1664     LClampTToUint8* result = new LClampTToUint8(reg,
1665                                                 TempRegister(),
1666                                                 FixedTemp(xmm1));
1667     return AssignEnvironment(DefineSameAsFirst(result));
1668   }
1669 }
1670
1671
1672 LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) {
1673   HValue* value = instr->value();
1674   Representation input_rep = value->representation();
1675   LOperand* reg = UseRegister(value);
1676   if (input_rep.IsDouble()) {
1677     return AssignEnvironment(DefineAsRegister(new LDoubleToI(reg)));
1678   } else if (input_rep.IsInteger32()) {
1679     // Canonicalization should already have removed the hydrogen instruction in
1680     // this case, since it is a noop.
1681     UNREACHABLE();
1682     return NULL;
1683   } else {
1684     ASSERT(input_rep.IsTagged());
1685     LOperand* reg = UseRegister(value);
1686     // Register allocator doesn't (yet) support allocation of double
1687     // temps. Reserve xmm1 explicitly.
1688     LOperand* xmm_temp =
1689         CpuFeatures::IsSupported(SSE3)
1690         ? NULL
1691         : FixedTemp(xmm1);
1692     return AssignEnvironment(
1693         DefineSameAsFirst(new LTaggedToI(reg, xmm_temp)));
1694   }
1695 }
1696
1697
1698 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1699   return new LReturn(UseFixed(instr->value(), rax));
1700 }
1701
1702
1703 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1704   Representation r = instr->representation();
1705   if (r.IsInteger32()) {
1706     return DefineAsRegister(new LConstantI);
1707   } else if (r.IsDouble()) {
1708     LOperand* temp = TempRegister();
1709     return DefineAsRegister(new LConstantD(temp));
1710   } else if (r.IsTagged()) {
1711     return DefineAsRegister(new LConstantT);
1712   } else {
1713     UNREACHABLE();
1714     return NULL;
1715   }
1716 }
1717
1718
1719 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1720   LLoadGlobalCell* result = new LLoadGlobalCell;
1721   return instr->RequiresHoleCheck()
1722       ? AssignEnvironment(DefineAsRegister(result))
1723       : DefineAsRegister(result);
1724 }
1725
1726
1727 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1728   LOperand* global_object = UseFixed(instr->global_object(), rax);
1729   LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
1730   return MarkAsCall(DefineFixed(result, rax), instr);
1731 }
1732
1733
1734 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
1735   LStoreGlobalCell* result =
1736       new LStoreGlobalCell(UseTempRegister(instr->value()),
1737                            TempRegister(),
1738                            TempRegister());
1739   return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1740 }
1741
1742
1743 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
1744   LOperand* global_object = UseFixed(instr->global_object(), rdx);
1745   LOperand* value = UseFixed(instr->value(), rax);
1746   LStoreGlobalGeneric* result =  new LStoreGlobalGeneric(global_object, value);
1747   return MarkAsCall(result, instr);
1748 }
1749
1750
1751 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1752   LOperand* context = UseRegisterAtStart(instr->value());
1753   return DefineAsRegister(new LLoadContextSlot(context));
1754 }
1755
1756
1757 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1758   LOperand* context;
1759   LOperand* value;
1760   LOperand* temp;
1761   if (instr->NeedsWriteBarrier()) {
1762     context = UseTempRegister(instr->context());
1763     value = UseTempRegister(instr->value());
1764     temp = TempRegister();
1765   } else {
1766     context = UseRegister(instr->context());
1767     value = UseRegister(instr->value());
1768     temp = NULL;
1769   }
1770   return new LStoreContextSlot(context, value, temp);
1771 }
1772
1773
1774 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1775   ASSERT(instr->representation().IsTagged());
1776   LOperand* obj = UseRegisterAtStart(instr->object());
1777   return DefineAsRegister(new LLoadNamedField(obj));
1778 }
1779
1780
1781 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
1782     HLoadNamedFieldPolymorphic* instr) {
1783   ASSERT(instr->representation().IsTagged());
1784   if (instr->need_generic()) {
1785     LOperand* obj = UseFixed(instr->object(), rax);
1786     LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1787     return MarkAsCall(DefineFixed(result, rax), instr);
1788   } else {
1789     LOperand* obj = UseRegisterAtStart(instr->object());
1790     LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1791     return AssignEnvironment(DefineAsRegister(result));
1792   }
1793 }
1794
1795
1796 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1797   LOperand* object = UseFixed(instr->object(), rax);
1798   LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
1799   return MarkAsCall(DefineFixed(result, rax), instr);
1800 }
1801
1802
1803 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1804     HLoadFunctionPrototype* instr) {
1805   return AssignEnvironment(DefineAsRegister(
1806       new LLoadFunctionPrototype(UseRegister(instr->function()))));
1807 }
1808
1809
1810 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1811   LOperand* input = UseRegisterAtStart(instr->value());
1812   return DefineAsRegister(new LLoadElements(input));
1813 }
1814
1815
1816 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
1817     HLoadExternalArrayPointer* instr) {
1818   LOperand* input = UseRegisterAtStart(instr->value());
1819   return DefineAsRegister(new LLoadExternalArrayPointer(input));
1820 }
1821
1822
1823 LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1824     HLoadKeyedFastElement* instr) {
1825   ASSERT(instr->representation().IsTagged());
1826   ASSERT(instr->key()->representation().IsInteger32());
1827   LOperand* obj = UseRegisterAtStart(instr->object());
1828   LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1829   LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
1830   return AssignEnvironment(DefineAsRegister(result));
1831 }
1832
1833
1834 LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
1835     HLoadKeyedFastDoubleElement* instr) {
1836   ASSERT(instr->representation().IsDouble());
1837   ASSERT(instr->key()->representation().IsInteger32());
1838   LOperand* elements = UseRegisterAtStart(instr->elements());
1839   LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1840   LLoadKeyedFastDoubleElement* result =
1841       new LLoadKeyedFastDoubleElement(elements, key);
1842   return AssignEnvironment(DefineAsRegister(result));
1843 }
1844
1845
1846 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
1847     HLoadKeyedSpecializedArrayElement* instr) {
1848   ElementsKind elements_kind = instr->elements_kind();
1849   Representation representation(instr->representation());
1850   ASSERT(
1851       (representation.IsInteger32() &&
1852        (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
1853        (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1854       (representation.IsDouble() &&
1855        ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
1856        (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
1857   ASSERT(instr->key()->representation().IsInteger32());
1858   LOperand* external_pointer = UseRegister(instr->external_pointer());
1859   LOperand* key = UseRegisterOrConstant(instr->key());
1860   LLoadKeyedSpecializedArrayElement* result =
1861       new LLoadKeyedSpecializedArrayElement(external_pointer, key);
1862   LInstruction* load_instr = DefineAsRegister(result);
1863   // An unsigned int array load might overflow and cause a deopt, make sure it
1864   // has an environment.
1865   return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
1866       AssignEnvironment(load_instr) : load_instr;
1867 }
1868
1869
1870 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1871   LOperand* object = UseFixed(instr->object(), rdx);
1872   LOperand* key = UseFixed(instr->key(), rax);
1873
1874   LLoadKeyedGeneric* result = new LLoadKeyedGeneric(object, key);
1875   return MarkAsCall(DefineFixed(result, rax), instr);
1876 }
1877
1878
1879 LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1880     HStoreKeyedFastElement* instr) {
1881   bool needs_write_barrier = instr->NeedsWriteBarrier();
1882   ASSERT(instr->value()->representation().IsTagged());
1883   ASSERT(instr->object()->representation().IsTagged());
1884   ASSERT(instr->key()->representation().IsInteger32());
1885
1886   LOperand* obj = UseTempRegister(instr->object());
1887   LOperand* val = needs_write_barrier
1888       ? UseTempRegister(instr->value())
1889       : UseRegisterAtStart(instr->value());
1890   LOperand* key = needs_write_barrier
1891       ? UseTempRegister(instr->key())
1892       : UseRegisterOrConstantAtStart(instr->key());
1893
1894   return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1895 }
1896
1897
1898 LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
1899     HStoreKeyedFastDoubleElement* instr) {
1900   ASSERT(instr->value()->representation().IsDouble());
1901   ASSERT(instr->elements()->representation().IsTagged());
1902   ASSERT(instr->key()->representation().IsInteger32());
1903
1904   LOperand* elements = UseRegisterAtStart(instr->elements());
1905   LOperand* val = UseTempRegister(instr->value());
1906   LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1907
1908   return new LStoreKeyedFastDoubleElement(elements, key, val);
1909 }
1910
1911
1912 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
1913     HStoreKeyedSpecializedArrayElement* instr) {
1914   Representation representation(instr->value()->representation());
1915   ElementsKind elements_kind = instr->elements_kind();
1916   ASSERT(
1917       (representation.IsInteger32() &&
1918        (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
1919        (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1920       (representation.IsDouble() &&
1921        ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
1922        (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
1923   ASSERT(instr->external_pointer()->representation().IsExternal());
1924   ASSERT(instr->key()->representation().IsInteger32());
1925
1926   LOperand* external_pointer = UseRegister(instr->external_pointer());
1927   bool val_is_temp_register =
1928       elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
1929       elements_kind == EXTERNAL_FLOAT_ELEMENTS;
1930   LOperand* val = val_is_temp_register
1931       ? UseTempRegister(instr->value())
1932       : UseRegister(instr->value());
1933   LOperand* key = UseRegisterOrConstant(instr->key());
1934
1935   return new LStoreKeyedSpecializedArrayElement(external_pointer,
1936                                                 key,
1937                                                 val);
1938 }
1939
1940
1941 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1942   LOperand* object = UseFixed(instr->object(), rdx);
1943   LOperand* key = UseFixed(instr->key(), rcx);
1944   LOperand* value = UseFixed(instr->value(), rax);
1945
1946   ASSERT(instr->object()->representation().IsTagged());
1947   ASSERT(instr->key()->representation().IsTagged());
1948   ASSERT(instr->value()->representation().IsTagged());
1949
1950   LStoreKeyedGeneric* result = new LStoreKeyedGeneric(object, key, value);
1951   return MarkAsCall(result, instr);
1952 }
1953
1954
1955 LInstruction* LChunkBuilder::DoTransitionElementsKind(
1956     HTransitionElementsKind* instr) {
1957   if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
1958       instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
1959     LOperand* object = UseRegister(instr->object());
1960     LOperand* new_map_reg = TempRegister();
1961     LOperand* temp_reg = TempRegister();
1962     LTransitionElementsKind* result =
1963         new LTransitionElementsKind(object, new_map_reg, temp_reg);
1964     return DefineSameAsFirst(result);
1965   } else {
1966     LOperand* object = UseFixed(instr->object(), rax);
1967     LOperand* fixed_object_reg = FixedTemp(rdx);
1968     LOperand* new_map_reg = FixedTemp(rbx);
1969     LTransitionElementsKind* result =
1970         new LTransitionElementsKind(object, new_map_reg, fixed_object_reg);
1971     return MarkAsCall(DefineFixed(result, rax), instr);
1972   }
1973 }
1974
1975
1976 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1977   bool needs_write_barrier = instr->NeedsWriteBarrier();
1978
1979   LOperand* obj = needs_write_barrier
1980       ? UseTempRegister(instr->object())
1981       : UseRegisterAtStart(instr->object());
1982
1983   LOperand* val = needs_write_barrier
1984       ? UseTempRegister(instr->value())
1985       : UseRegister(instr->value());
1986
1987   // We only need a scratch register if we have a write barrier or we
1988   // have a store into the properties array (not in-object-property).
1989   LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1990       ? TempRegister() : NULL;
1991
1992   return new LStoreNamedField(obj, val, temp);
1993 }
1994
1995
1996 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1997   LOperand* object = UseFixed(instr->object(), rdx);
1998   LOperand* value = UseFixed(instr->value(), rax);
1999
2000   LStoreNamedGeneric* result = new LStoreNamedGeneric(object, value);
2001   return MarkAsCall(result, instr);
2002 }
2003
2004
2005 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2006   LOperand* left = UseOrConstantAtStart(instr->left());
2007   LOperand* right = UseOrConstantAtStart(instr->right());
2008   return MarkAsCall(DefineFixed(new LStringAdd(left, right), rax), instr);
2009 }
2010
2011
2012 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2013   LOperand* string = UseTempRegister(instr->string());
2014   LOperand* index = UseTempRegister(instr->index());
2015   LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
2016   return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2017 }
2018
2019
2020 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2021   LOperand* char_code = UseRegister(instr->value());
2022   LStringCharFromCode* result = new LStringCharFromCode(char_code);
2023   return AssignPointerMap(DefineAsRegister(result));
2024 }
2025
2026
2027 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
2028   LOperand* string = UseRegisterAtStart(instr->value());
2029   return DefineAsRegister(new LStringLength(string));
2030 }
2031
2032
2033 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
2034   return MarkAsCall(DefineFixed(new LArrayLiteral, rax), instr);
2035 }
2036
2037
2038 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
2039   return MarkAsCall(DefineFixed(new LObjectLiteral, rax), instr);
2040 }
2041
2042
2043 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2044   return MarkAsCall(DefineFixed(new LRegExpLiteral, rax), instr);
2045 }
2046
2047
2048 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2049   return MarkAsCall(DefineFixed(new LFunctionLiteral, rax), instr);
2050 }
2051
2052
2053 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
2054   LDeleteProperty* result =
2055       new LDeleteProperty(UseAtStart(instr->object()),
2056                           UseOrConstantAtStart(instr->key()));
2057   return MarkAsCall(DefineFixed(result, rax), instr);
2058 }
2059
2060
2061 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2062   allocator_->MarkAsOsrEntry();
2063   current_block_->last_environment()->set_ast_id(instr->ast_id());
2064   return AssignEnvironment(new LOsrEntry);
2065 }
2066
2067
2068 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2069   int spill_index = chunk()->GetParameterStackSlot(instr->index());
2070   return DefineAsSpilled(new LParameter, spill_index);
2071 }
2072
2073
2074 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2075   int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
2076   if (spill_index > LUnallocated::kMaxFixedIndex) {
2077     Abort("Too many spill slots needed for OSR");
2078     spill_index = 0;
2079   }
2080   return DefineAsSpilled(new LUnknownOSRValue, spill_index);
2081 }
2082
2083
2084 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2085   argument_count_ -= instr->argument_count();
2086   return MarkAsCall(DefineFixed(new LCallStub, rax), instr);
2087 }
2088
2089
2090 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2091   // There are no real uses of the arguments object.
2092   // arguments.length and element access are supported directly on
2093   // stack arguments, and any real arguments object use causes a bailout.
2094   // So this value is never used.
2095   return NULL;
2096 }
2097
2098
2099 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2100   LOperand* arguments = UseRegister(instr->arguments());
2101   LOperand* length = UseTempRegister(instr->length());
2102   LOperand* index = Use(instr->index());
2103   LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
2104   return AssignEnvironment(DefineAsRegister(result));
2105 }
2106
2107
2108 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2109   LOperand* object = UseFixed(instr->value(), rax);
2110   LToFastProperties* result = new LToFastProperties(object);
2111   return MarkAsCall(DefineFixed(result, rax), instr);
2112 }
2113
2114
2115 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2116   LTypeof* result = new LTypeof(UseAtStart(instr->value()));
2117   return MarkAsCall(DefineFixed(result, rax), instr);
2118 }
2119
2120
2121 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2122   return new LTypeofIsAndBranch(UseTempRegister(instr->value()));
2123 }
2124
2125
2126 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2127     HIsConstructCallAndBranch* instr) {
2128   return new LIsConstructCallAndBranch(TempRegister());
2129 }
2130
2131
2132 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2133   HEnvironment* env = current_block_->last_environment();
2134   ASSERT(env != NULL);
2135
2136   env->set_ast_id(instr->ast_id());
2137
2138   env->Drop(instr->pop_count());
2139   for (int i = 0; i < instr->values()->length(); ++i) {
2140     HValue* value = instr->values()->at(i);
2141     if (instr->HasAssignedIndexAt(i)) {
2142       env->Bind(instr->GetAssignedIndexAt(i), value);
2143     } else {
2144       env->Push(value);
2145     }
2146   }
2147
2148   // If there is an instruction pending deoptimization environment create a
2149   // lazy bailout instruction to capture the environment.
2150   if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2151     LLazyBailout* lazy_bailout = new LLazyBailout;
2152     LInstruction* result = AssignEnvironment(lazy_bailout);
2153     instruction_pending_deoptimization_environment_->
2154         set_deoptimization_environment(result->environment());
2155     ClearInstructionPendingDeoptimizationEnvironment();
2156     return result;
2157   }
2158
2159   return NULL;
2160 }
2161
2162
2163 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2164   if (instr->is_function_entry()) {
2165     return MarkAsCall(new LStackCheck, instr);
2166   } else {
2167     ASSERT(instr->is_backwards_branch());
2168     return AssignEnvironment(AssignPointerMap(new LStackCheck));
2169   }
2170 }
2171
2172
2173 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2174   HEnvironment* outer = current_block_->last_environment();
2175   HConstant* undefined = graph()->GetConstantUndefined();
2176   HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2177                                                instr->function(),
2178                                                undefined,
2179                                                instr->call_kind());
2180   current_block_->UpdateEnvironment(inner);
2181   chunk_->AddInlinedClosure(instr->closure());
2182   return NULL;
2183 }
2184
2185
2186 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2187   HEnvironment* outer = current_block_->last_environment()->outer();
2188   current_block_->UpdateEnvironment(outer);
2189   return NULL;
2190 }
2191
2192
2193 LInstruction* LChunkBuilder::DoIn(HIn* instr) {
2194   LOperand* key = UseOrConstantAtStart(instr->key());
2195   LOperand* object = UseOrConstantAtStart(instr->object());
2196   LIn* result = new LIn(key, object);
2197   return MarkAsCall(DefineFixed(result, rax), instr);
2198 }
2199
2200
2201 } }  // namespace v8::internal
2202
2203 #endif  // V8_TARGET_ARCH_X64