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