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