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