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