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