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