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