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