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