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