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