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