lithium-x64.cc revision 7d3e7fc4b65010eabe860313ee0c64f50843f6e3
1// Copyright 2011 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 defined(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
46LOsrEntry::LOsrEntry() {
47  for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
48    register_spills_[i] = NULL;
49  }
50  for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
51    double_register_spills_[i] = NULL;
52  }
53}
54
55
56void LOsrEntry::MarkSpilledRegister(int allocation_index,
57                                    LOperand* spill_operand) {
58  ASSERT(spill_operand->IsStackSlot());
59  ASSERT(register_spills_[allocation_index] == NULL);
60  register_spills_[allocation_index] = spill_operand;
61}
62
63
64void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
65                                          LOperand* spill_operand) {
66  ASSERT(spill_operand->IsDoubleStackSlot());
67  ASSERT(double_register_spills_[allocation_index] == NULL);
68  double_register_spills_[allocation_index] = spill_operand;
69}
70
71
72#ifdef DEBUG
73void LInstruction::VerifyCall() {
74  // Call instructions can use only fixed registers as
75  // temporaries and outputs because all registers
76  // are blocked by the calling convention.
77  // Inputs must use a fixed register.
78  ASSERT(Output() == NULL ||
79         LUnallocated::cast(Output())->HasFixedPolicy() ||
80         !LUnallocated::cast(Output())->HasRegisterPolicy());
81  for (UseIterator it(this); it.HasNext(); it.Advance()) {
82    LOperand* operand = it.Next();
83    ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
84           !LUnallocated::cast(operand)->HasRegisterPolicy());
85  }
86  for (TempIterator it(this); it.HasNext(); it.Advance()) {
87    LOperand* operand = it.Next();
88    ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
89           !LUnallocated::cast(operand)->HasRegisterPolicy());
90  }
91}
92#endif
93
94
95void LInstruction::PrintTo(StringStream* stream) {
96  stream->Add("%s ", this->Mnemonic());
97
98  PrintOutputOperandTo(stream);
99
100  PrintDataTo(stream);
101
102  if (HasEnvironment()) {
103    stream->Add(" ");
104    environment()->PrintTo(stream);
105  }
106
107  if (HasPointerMap()) {
108    stream->Add(" ");
109    pointer_map()->PrintTo(stream);
110  }
111}
112
113
114template<int R, int I, int T>
115void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
116  stream->Add("= ");
117  inputs_.PrintOperandsTo(stream);
118}
119
120
121template<int R, int I, int T>
122void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
123  results_.PrintOperandsTo(stream);
124}
125
126
127template<typename T, int N>
128void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
129  for (int i = 0; i < N; i++) {
130    if (i > 0) stream->Add(" ");
131    elems_[i]->PrintTo(stream);
132  }
133}
134
135
136void LLabel::PrintDataTo(StringStream* stream) {
137  LGap::PrintDataTo(stream);
138  LLabel* rep = replacement();
139  if (rep != NULL) {
140    stream->Add(" Dead block replaced with B%d", rep->block_id());
141  }
142}
143
144
145bool LGap::IsRedundant() const {
146  for (int i = 0; i < 4; i++) {
147    if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
148      return false;
149    }
150  }
151
152  return true;
153}
154
155
156void LGap::PrintDataTo(StringStream* stream) {
157  for (int i = 0; i < 4; i++) {
158    stream->Add("(");
159    if (parallel_moves_[i] != NULL) {
160      parallel_moves_[i]->PrintDataTo(stream);
161    }
162    stream->Add(") ");
163  }
164}
165
166
167const char* LArithmeticD::Mnemonic() const {
168  switch (op()) {
169    case Token::ADD: return "add-d";
170    case Token::SUB: return "sub-d";
171    case Token::MUL: return "mul-d";
172    case Token::DIV: return "div-d";
173    case Token::MOD: return "mod-d";
174    default:
175      UNREACHABLE();
176      return NULL;
177  }
178}
179
180
181const char* LArithmeticT::Mnemonic() const {
182  switch (op()) {
183    case Token::ADD: return "add-t";
184    case Token::SUB: return "sub-t";
185    case Token::MUL: return "mul-t";
186    case Token::MOD: return "mod-t";
187    case Token::DIV: return "div-t";
188    case Token::BIT_AND: return "bit-and-t";
189    case Token::BIT_OR: return "bit-or-t";
190    case Token::BIT_XOR: return "bit-xor-t";
191    case Token::SHL: return "sal-t";
192    case Token::SAR: return "sar-t";
193    case Token::SHR: return "shr-t";
194    default:
195      UNREACHABLE();
196      return NULL;
197  }
198}
199
200
201void LGoto::PrintDataTo(StringStream* stream) {
202  stream->Add("B%d", block_id());
203}
204
205
206void LBranch::PrintDataTo(StringStream* stream) {
207  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
208  InputAt(0)->PrintTo(stream);
209}
210
211
212void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
213  stream->Add("if ");
214  InputAt(0)->PrintTo(stream);
215  stream->Add(" %s ", Token::String(op()));
216  InputAt(1)->PrintTo(stream);
217  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
218}
219
220
221void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
222  stream->Add("if ");
223  InputAt(0)->PrintTo(stream);
224  stream->Add(is_strict() ? " === null" : " == null");
225  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
226}
227
228
229void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
230  stream->Add("if is_object(");
231  InputAt(0)->PrintTo(stream);
232  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
233}
234
235
236void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
237  stream->Add("if is_smi(");
238  InputAt(0)->PrintTo(stream);
239  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
240}
241
242
243void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
244  stream->Add("if has_instance_type(");
245  InputAt(0)->PrintTo(stream);
246  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
247}
248
249
250void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
251  stream->Add("if has_cached_array_index(");
252  InputAt(0)->PrintTo(stream);
253  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
254}
255
256
257void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
258  stream->Add("if class_of_test(");
259  InputAt(0)->PrintTo(stream);
260  stream->Add(", \"%o\") then B%d else B%d",
261              *hydrogen()->class_name(),
262              true_block_id(),
263              false_block_id());
264}
265
266
267void LTypeofIs::PrintDataTo(StringStream* stream) {
268  InputAt(0)->PrintTo(stream);
269  stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
270}
271
272
273void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
274  stream->Add("if typeof ");
275  InputAt(0)->PrintTo(stream);
276  stream->Add(" == \"%s\" then B%d else B%d",
277              *hydrogen()->type_literal()->ToCString(),
278              true_block_id(), false_block_id());
279}
280
281
282void LCallConstantFunction::PrintDataTo(StringStream* stream) {
283  stream->Add("#%d / ", arity());
284}
285
286
287void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
288  stream->Add("/%s ", hydrogen()->OpName());
289  InputAt(0)->PrintTo(stream);
290}
291
292
293void LLoadContextSlot::PrintDataTo(StringStream* stream) {
294  InputAt(0)->PrintTo(stream);
295  stream->Add("[%d]", slot_index());
296}
297
298
299void LStoreContextSlot::PrintDataTo(StringStream* stream) {
300  InputAt(0)->PrintTo(stream);
301  stream->Add("[%d] <- ", slot_index());
302  InputAt(1)->PrintTo(stream);
303}
304
305
306void LCallKeyed::PrintDataTo(StringStream* stream) {
307  stream->Add("[rcx] #%d / ", arity());
308}
309
310
311void LCallNamed::PrintDataTo(StringStream* stream) {
312  SmartPointer<char> name_string = name()->ToCString();
313  stream->Add("%s #%d / ", *name_string, arity());
314}
315
316
317void LCallGlobal::PrintDataTo(StringStream* stream) {
318  SmartPointer<char> name_string = name()->ToCString();
319  stream->Add("%s #%d / ", *name_string, arity());
320}
321
322
323void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
324  stream->Add("#%d / ", arity());
325}
326
327
328void LCallNew::PrintDataTo(StringStream* stream) {
329  stream->Add("= ");
330  InputAt(0)->PrintTo(stream);
331  stream->Add(" #%d / ", arity());
332}
333
334
335void LClassOfTest::PrintDataTo(StringStream* stream) {
336  stream->Add("= class_of_test(");
337  InputAt(0)->PrintTo(stream);
338  stream->Add(", \"%o\")", *hydrogen()->class_name());
339}
340
341
342void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
343  arguments()->PrintTo(stream);
344
345  stream->Add(" length ");
346  length()->PrintTo(stream);
347
348  stream->Add(" index ");
349  index()->PrintTo(stream);
350}
351
352
353int LChunk::GetNextSpillIndex(bool is_double) {
354  return spill_slot_count_++;
355}
356
357
358LOperand* LChunk::GetNextSpillSlot(bool is_double) {
359  // All stack slots are Double stack slots on x64.
360  // Alternatively, at some point, start using half-size
361  // stack slots for int32 values.
362  int index = GetNextSpillIndex(is_double);
363  if (is_double) {
364    return LDoubleStackSlot::Create(index);
365  } else {
366    return LStackSlot::Create(index);
367  }
368}
369
370
371void LChunk::MarkEmptyBlocks() {
372  HPhase phase("Mark empty blocks", this);
373  for (int i = 0; i < graph()->blocks()->length(); ++i) {
374    HBasicBlock* block = graph()->blocks()->at(i);
375    int first = block->first_instruction_index();
376    int last = block->last_instruction_index();
377    LInstruction* first_instr = instructions()->at(first);
378    LInstruction* last_instr = instructions()->at(last);
379
380    LLabel* label = LLabel::cast(first_instr);
381    if (last_instr->IsGoto()) {
382      LGoto* goto_instr = LGoto::cast(last_instr);
383      if (!goto_instr->include_stack_check() &&
384          label->IsRedundant() &&
385          !label->is_loop_header()) {
386        bool can_eliminate = true;
387        for (int i = first + 1; i < last && can_eliminate; ++i) {
388          LInstruction* cur = instructions()->at(i);
389          if (cur->IsGap()) {
390            LGap* gap = LGap::cast(cur);
391            if (!gap->IsRedundant()) {
392              can_eliminate = false;
393            }
394          } else {
395            can_eliminate = false;
396          }
397        }
398
399        if (can_eliminate) {
400          label->set_replacement(GetLabel(goto_instr->block_id()));
401        }
402      }
403    }
404  }
405}
406
407
408void LStoreNamedField::PrintDataTo(StringStream* stream) {
409  object()->PrintTo(stream);
410  stream->Add(".");
411  stream->Add(*String::cast(*name())->ToCString());
412  stream->Add(" <- ");
413  value()->PrintTo(stream);
414}
415
416
417void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
418  object()->PrintTo(stream);
419  stream->Add(".");
420  stream->Add(*String::cast(*name())->ToCString());
421  stream->Add(" <- ");
422  value()->PrintTo(stream);
423}
424
425
426void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
427  object()->PrintTo(stream);
428  stream->Add("[");
429  key()->PrintTo(stream);
430  stream->Add("] <- ");
431  value()->PrintTo(stream);
432}
433
434
435void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
436  object()->PrintTo(stream);
437  stream->Add("[");
438  key()->PrintTo(stream);
439  stream->Add("] <- ");
440  value()->PrintTo(stream);
441}
442
443
444void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
445  LGap* gap = new LGap(block);
446  int index = -1;
447  if (instr->IsControl()) {
448    instructions_.Add(gap);
449    index = instructions_.length();
450    instructions_.Add(instr);
451  } else {
452    index = instructions_.length();
453    instructions_.Add(instr);
454    instructions_.Add(gap);
455  }
456  if (instr->HasPointerMap()) {
457    pointer_maps_.Add(instr->pointer_map());
458    instr->pointer_map()->set_lithium_position(index);
459  }
460}
461
462
463LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
464  return LConstantOperand::Create(constant->id());
465}
466
467
468int LChunk::GetParameterStackSlot(int index) const {
469  // The receiver is at index 0, the first parameter at index 1, so we
470  // shift all parameter indexes down by the number of parameters, and
471  // make sure they end up negative so they are distinguishable from
472  // spill slots.
473  int result = index - info()->scope()->num_parameters() - 1;
474  ASSERT(result < 0);
475  return result;
476}
477
478// A parameter relative to ebp in the arguments stub.
479int LChunk::ParameterAt(int index) {
480  ASSERT(-1 <= index);  // -1 is the receiver.
481  return (1 + info()->scope()->num_parameters() - index) *
482      kPointerSize;
483}
484
485
486LGap* LChunk::GetGapAt(int index) const {
487  return LGap::cast(instructions_[index]);
488}
489
490
491bool LChunk::IsGapAt(int index) const {
492  return instructions_[index]->IsGap();
493}
494
495
496int LChunk::NearestGapPos(int index) const {
497  while (!IsGapAt(index)) index--;
498  return index;
499}
500
501
502void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
503  GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
504}
505
506
507Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
508  return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
509}
510
511
512Representation LChunk::LookupLiteralRepresentation(
513    LConstantOperand* operand) const {
514  return graph_->LookupValue(operand->index())->representation();
515}
516
517
518LChunk* LChunkBuilder::Build() {
519  ASSERT(is_unused());
520  chunk_ = new LChunk(info(), graph());
521  HPhase phase("Building chunk", chunk_);
522  status_ = BUILDING;
523  const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
524  for (int i = 0; i < blocks->length(); i++) {
525    HBasicBlock* next = NULL;
526    if (i < blocks->length() - 1) next = blocks->at(i + 1);
527    DoBasicBlock(blocks->at(i), next);
528    if (is_aborted()) return NULL;
529  }
530  status_ = DONE;
531  return chunk_;
532}
533
534
535void LChunkBuilder::Abort(const char* format, ...) {
536  if (FLAG_trace_bailout) {
537    SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
538    PrintF("Aborting LChunk building in @\"%s\": ", *name);
539    va_list arguments;
540    va_start(arguments, format);
541    OS::VPrint(format, arguments);
542    va_end(arguments);
543    PrintF("\n");
544  }
545  status_ = ABORTED;
546}
547
548
549LRegister* LChunkBuilder::ToOperand(Register reg) {
550  return LRegister::Create(Register::ToAllocationIndex(reg));
551}
552
553
554LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
555  return new LUnallocated(LUnallocated::FIXED_REGISTER,
556                          Register::ToAllocationIndex(reg));
557}
558
559
560LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
561  return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
562                          XMMRegister::ToAllocationIndex(reg));
563}
564
565
566LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
567  return Use(value, ToUnallocated(fixed_register));
568}
569
570
571LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
572  return Use(value, ToUnallocated(reg));
573}
574
575
576LOperand* LChunkBuilder::UseRegister(HValue* value) {
577  return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
578}
579
580
581LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
582  return Use(value,
583             new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
584                              LUnallocated::USED_AT_START));
585}
586
587
588LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
589  return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
590}
591
592
593LOperand* LChunkBuilder::Use(HValue* value) {
594  return Use(value, new LUnallocated(LUnallocated::NONE));
595}
596
597
598LOperand* LChunkBuilder::UseAtStart(HValue* value) {
599  return Use(value, new LUnallocated(LUnallocated::NONE,
600                                     LUnallocated::USED_AT_START));
601}
602
603
604LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
605  return value->IsConstant()
606      ? chunk_->DefineConstantOperand(HConstant::cast(value))
607      : Use(value);
608}
609
610
611LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
612  return value->IsConstant()
613      ? chunk_->DefineConstantOperand(HConstant::cast(value))
614      : UseAtStart(value);
615}
616
617
618LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
619  return value->IsConstant()
620      ? chunk_->DefineConstantOperand(HConstant::cast(value))
621      : UseRegister(value);
622}
623
624
625LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
626  return value->IsConstant()
627      ? chunk_->DefineConstantOperand(HConstant::cast(value))
628      : UseRegisterAtStart(value);
629}
630
631
632LOperand* LChunkBuilder::UseAny(HValue* value) {
633  return value->IsConstant()
634      ? chunk_->DefineConstantOperand(HConstant::cast(value))
635      :  Use(value, new LUnallocated(LUnallocated::ANY));
636}
637
638
639LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
640  if (value->EmitAtUses()) {
641    HInstruction* instr = HInstruction::cast(value);
642    VisitInstruction(instr);
643  }
644  allocator_->RecordUse(value, operand);
645  return operand;
646}
647
648
649template<int I, int T>
650LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
651                                    LUnallocated* result) {
652  allocator_->RecordDefinition(current_instruction_, result);
653  instr->set_result(result);
654  return instr;
655}
656
657
658template<int I, int T>
659LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
660  return Define(instr, new LUnallocated(LUnallocated::NONE));
661}
662
663
664template<int I, int T>
665LInstruction* LChunkBuilder::DefineAsRegister(
666    LTemplateInstruction<1, I, T>* instr) {
667  return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
668}
669
670
671template<int I, int T>
672LInstruction* LChunkBuilder::DefineAsSpilled(
673    LTemplateInstruction<1, I, T>* instr,
674    int index) {
675  return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
676}
677
678
679template<int I, int T>
680LInstruction* LChunkBuilder::DefineSameAsFirst(
681    LTemplateInstruction<1, I, T>* instr) {
682  return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
683}
684
685
686template<int I, int T>
687LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
688                                         Register reg) {
689  return Define(instr, ToUnallocated(reg));
690}
691
692
693template<int I, int T>
694LInstruction* LChunkBuilder::DefineFixedDouble(
695    LTemplateInstruction<1, I, T>* instr,
696    XMMRegister reg) {
697  return Define(instr, ToUnallocated(reg));
698}
699
700
701LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
702  HEnvironment* hydrogen_env = current_block_->last_environment();
703  instr->set_environment(CreateEnvironment(hydrogen_env));
704  return instr;
705}
706
707
708LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
709    LInstruction* instr, int ast_id) {
710  ASSERT(instruction_pending_deoptimization_environment_ == NULL);
711  ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
712  instruction_pending_deoptimization_environment_ = instr;
713  pending_deoptimization_ast_id_ = ast_id;
714  return instr;
715}
716
717
718void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
719  instruction_pending_deoptimization_environment_ = NULL;
720  pending_deoptimization_ast_id_ = AstNode::kNoNumber;
721}
722
723
724LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
725                                        HInstruction* hinstr,
726                                        CanDeoptimize can_deoptimize) {
727#ifdef DEBUG
728  instr->VerifyCall();
729#endif
730  instr->MarkAsCall();
731  instr = AssignPointerMap(instr);
732
733  if (hinstr->HasSideEffects()) {
734    ASSERT(hinstr->next()->IsSimulate());
735    HSimulate* sim = HSimulate::cast(hinstr->next());
736    instr = SetInstructionPendingDeoptimizationEnvironment(
737        instr, sim->ast_id());
738  }
739
740  // If instruction does not have side-effects lazy deoptimization
741  // after the call will try to deoptimize to the point before the call.
742  // Thus we still need to attach environment to this call even if
743  // call sequence can not deoptimize eagerly.
744  bool needs_environment =
745      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects();
746  if (needs_environment && !instr->HasEnvironment()) {
747    instr = AssignEnvironment(instr);
748  }
749
750  return instr;
751}
752
753
754LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
755  instr->MarkAsSaveDoubles();
756  return instr;
757}
758
759
760LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
761  ASSERT(!instr->HasPointerMap());
762  instr->set_pointer_map(new LPointerMap(position_));
763  return instr;
764}
765
766
767LUnallocated* LChunkBuilder::TempRegister() {
768  LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
769  allocator_->RecordTemporary(operand);
770  return operand;
771}
772
773
774LOperand* LChunkBuilder::FixedTemp(Register reg) {
775  LUnallocated* operand = ToUnallocated(reg);
776  allocator_->RecordTemporary(operand);
777  return operand;
778}
779
780
781LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
782  LUnallocated* operand = ToUnallocated(reg);
783  allocator_->RecordTemporary(operand);
784  return operand;
785}
786
787
788LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
789  return new LLabel(instr->block());
790}
791
792
793LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
794  return AssignEnvironment(new LDeoptimize);
795}
796
797
798LInstruction* LChunkBuilder::DoBit(Token::Value op,
799                                   HBitwiseBinaryOperation* instr) {
800  if (instr->representation().IsInteger32()) {
801    ASSERT(instr->left()->representation().IsInteger32());
802    ASSERT(instr->right()->representation().IsInteger32());
803
804    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
805    LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
806    return DefineSameAsFirst(new LBitI(op, left, right));
807  } else {
808    ASSERT(instr->representation().IsTagged());
809    ASSERT(instr->left()->representation().IsTagged());
810    ASSERT(instr->right()->representation().IsTagged());
811
812    LOperand* left = UseFixed(instr->left(), rdx);
813    LOperand* right = UseFixed(instr->right(), rax);
814    LArithmeticT* result = new LArithmeticT(op, left, right);
815    return MarkAsCall(DefineFixed(result, rax), instr);
816  }
817}
818
819
820LInstruction* LChunkBuilder::DoShift(Token::Value op,
821                                     HBitwiseBinaryOperation* instr) {
822  if (instr->representation().IsTagged()) {
823    ASSERT(instr->left()->representation().IsTagged());
824    ASSERT(instr->right()->representation().IsTagged());
825
826    LOperand* left = UseFixed(instr->left(), rdx);
827    LOperand* right = UseFixed(instr->right(), rax);
828    LArithmeticT* result = new LArithmeticT(op, left, right);
829    return MarkAsCall(DefineFixed(result, rax), instr);
830  }
831
832  ASSERT(instr->representation().IsInteger32());
833  ASSERT(instr->OperandAt(0)->representation().IsInteger32());
834  ASSERT(instr->OperandAt(1)->representation().IsInteger32());
835  LOperand* left = UseRegisterAtStart(instr->OperandAt(0));
836
837  HValue* right_value = instr->OperandAt(1);
838  LOperand* right = NULL;
839  int constant_value = 0;
840  if (right_value->IsConstant()) {
841    HConstant* constant = HConstant::cast(right_value);
842    right = chunk_->DefineConstantOperand(constant);
843    constant_value = constant->Integer32Value() & 0x1f;
844  } else {
845    right = UseFixed(right_value, rcx);
846  }
847
848  // Shift operations can only deoptimize if we do a logical shift
849  // by 0 and the result cannot be truncated to int32.
850  bool can_deopt = (op == Token::SHR && constant_value == 0);
851  if (can_deopt) {
852    bool can_truncate = true;
853    for (int i = 0; i < instr->uses()->length(); i++) {
854      if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) {
855        can_truncate = false;
856        break;
857      }
858    }
859    can_deopt = !can_truncate;
860  }
861
862  LShiftI* result = new LShiftI(op, left, right, can_deopt);
863  return can_deopt
864      ? AssignEnvironment(DefineSameAsFirst(result))
865      : DefineSameAsFirst(result);
866}
867
868
869LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
870                                           HArithmeticBinaryOperation* instr) {
871  ASSERT(instr->representation().IsDouble());
872  ASSERT(instr->left()->representation().IsDouble());
873  ASSERT(instr->right()->representation().IsDouble());
874  ASSERT(op != Token::MOD);
875  LOperand* left = UseRegisterAtStart(instr->left());
876  LOperand* right = UseRegisterAtStart(instr->right());
877  LArithmeticD* result = new LArithmeticD(op, left, right);
878  return DefineSameAsFirst(result);
879}
880
881
882LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
883                                           HArithmeticBinaryOperation* instr) {
884  ASSERT(op == Token::ADD ||
885         op == Token::DIV ||
886         op == Token::MOD ||
887         op == Token::MUL ||
888         op == Token::SUB);
889  HValue* left = instr->left();
890  HValue* right = instr->right();
891  ASSERT(left->representation().IsTagged());
892  ASSERT(right->representation().IsTagged());
893  LOperand* left_operand = UseFixed(left, rdx);
894  LOperand* right_operand = UseFixed(right, rax);
895  LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
896  return MarkAsCall(DefineFixed(result, rax), instr);
897}
898
899
900void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
901  ASSERT(is_building());
902  current_block_ = block;
903  next_block_ = next_block;
904  if (block->IsStartBlock()) {
905    block->UpdateEnvironment(graph_->start_environment());
906    argument_count_ = 0;
907  } else if (block->predecessors()->length() == 1) {
908    // We have a single predecessor => copy environment and outgoing
909    // argument count from the predecessor.
910    ASSERT(block->phis()->length() == 0);
911    HBasicBlock* pred = block->predecessors()->at(0);
912    HEnvironment* last_environment = pred->last_environment();
913    ASSERT(last_environment != NULL);
914    // Only copy the environment, if it is later used again.
915    if (pred->end()->SecondSuccessor() == NULL) {
916      ASSERT(pred->end()->FirstSuccessor() == block);
917    } else {
918      if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
919          pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
920        last_environment = last_environment->Copy();
921      }
922    }
923    block->UpdateEnvironment(last_environment);
924    ASSERT(pred->argument_count() >= 0);
925    argument_count_ = pred->argument_count();
926  } else {
927    // We are at a state join => process phis.
928    HBasicBlock* pred = block->predecessors()->at(0);
929    // No need to copy the environment, it cannot be used later.
930    HEnvironment* last_environment = pred->last_environment();
931    for (int i = 0; i < block->phis()->length(); ++i) {
932      HPhi* phi = block->phis()->at(i);
933      last_environment->SetValueAt(phi->merged_index(), phi);
934    }
935    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
936      last_environment->SetValueAt(block->deleted_phis()->at(i),
937                                   graph_->GetConstantUndefined());
938    }
939    block->UpdateEnvironment(last_environment);
940    // Pick up the outgoing argument count of one of the predecessors.
941    argument_count_ = pred->argument_count();
942  }
943  HInstruction* current = block->first();
944  int start = chunk_->instructions()->length();
945  while (current != NULL && !is_aborted()) {
946    // Code for constants in registers is generated lazily.
947    if (!current->EmitAtUses()) {
948      VisitInstruction(current);
949    }
950    current = current->next();
951  }
952  int end = chunk_->instructions()->length() - 1;
953  if (end >= start) {
954    block->set_first_instruction_index(start);
955    block->set_last_instruction_index(end);
956  }
957  block->set_argument_count(argument_count_);
958  next_block_ = NULL;
959  current_block_ = NULL;
960}
961
962
963void LChunkBuilder::VisitInstruction(HInstruction* current) {
964  HInstruction* old_current = current_instruction_;
965  current_instruction_ = current;
966  if (current->has_position()) position_ = current->position();
967  LInstruction* instr = current->CompileToLithium(this);
968
969  if (instr != NULL) {
970    if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
971      instr = AssignPointerMap(instr);
972    }
973    if (FLAG_stress_environments && !instr->HasEnvironment()) {
974      instr = AssignEnvironment(instr);
975    }
976    if (current->IsTest() && !instr->IsGoto()) {
977      ASSERT(instr->IsControl());
978      HTest* test = HTest::cast(current);
979      instr->set_hydrogen_value(test->value());
980      HBasicBlock* first = test->FirstSuccessor();
981      HBasicBlock* second = test->SecondSuccessor();
982      ASSERT(first != NULL && second != NULL);
983      instr->SetBranchTargets(first->block_id(), second->block_id());
984    } else {
985      instr->set_hydrogen_value(current);
986    }
987
988    chunk_->AddInstruction(instr, current_block_);
989  }
990  current_instruction_ = old_current;
991}
992
993
994LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
995  if (hydrogen_env == NULL) return NULL;
996
997  LEnvironment* outer = CreateEnvironment(hydrogen_env->outer());
998  int ast_id = hydrogen_env->ast_id();
999  ASSERT(ast_id != AstNode::kNoNumber);
1000  int value_count = hydrogen_env->length();
1001  LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
1002                                          ast_id,
1003                                          hydrogen_env->parameter_count(),
1004                                          argument_count_,
1005                                          value_count,
1006                                          outer);
1007  int argument_index = 0;
1008  for (int i = 0; i < value_count; ++i) {
1009    HValue* value = hydrogen_env->values()->at(i);
1010    LOperand* op = NULL;
1011    if (value->IsArgumentsObject()) {
1012      op = NULL;
1013    } else if (value->IsPushArgument()) {
1014      op = new LArgument(argument_index++);
1015    } else {
1016      op = UseAny(value);
1017    }
1018    result->AddValue(op, value->representation());
1019  }
1020
1021  return result;
1022}
1023
1024
1025LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1026  LGoto* result = new LGoto(instr->FirstSuccessor()->block_id(),
1027                            instr->include_stack_check());
1028  return (instr->include_stack_check())
1029      ? AssignPointerMap(result)
1030      : result;
1031}
1032
1033
1034LInstruction* LChunkBuilder::DoTest(HTest* instr) {
1035  HValue* v = instr->value();
1036  if (v->EmitAtUses()) {
1037    if (v->IsClassOfTest()) {
1038      HClassOfTest* compare = HClassOfTest::cast(v);
1039      ASSERT(compare->value()->representation().IsTagged());
1040
1041      return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
1042                                       TempRegister());
1043    } else if (v->IsCompare()) {
1044      HCompare* compare = HCompare::cast(v);
1045      Token::Value op = compare->token();
1046      HValue* left = compare->left();
1047      HValue* right = compare->right();
1048      Representation r = compare->GetInputRepresentation();
1049      if (r.IsInteger32()) {
1050        ASSERT(left->representation().IsInteger32());
1051        ASSERT(right->representation().IsInteger32());
1052
1053        return new LCmpIDAndBranch(UseRegisterAtStart(left),
1054                                   UseOrConstantAtStart(right));
1055      } else if (r.IsDouble()) {
1056        ASSERT(left->representation().IsDouble());
1057        ASSERT(right->representation().IsDouble());
1058
1059        return new LCmpIDAndBranch(UseRegisterAtStart(left),
1060                                   UseRegisterAtStart(right));
1061      } else {
1062        ASSERT(left->representation().IsTagged());
1063        ASSERT(right->representation().IsTagged());
1064        bool reversed = op == Token::GT || op == Token::LTE;
1065        LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
1066        LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
1067        LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
1068                                                    right_operand);
1069        return MarkAsCall(result, instr);
1070      }
1071    } else if (v->IsIsSmi()) {
1072      HIsSmi* compare = HIsSmi::cast(v);
1073      ASSERT(compare->value()->representation().IsTagged());
1074
1075      return new LIsSmiAndBranch(Use(compare->value()));
1076    } else if (v->IsHasInstanceType()) {
1077      HHasInstanceType* compare = HHasInstanceType::cast(v);
1078      ASSERT(compare->value()->representation().IsTagged());
1079
1080      return new LHasInstanceTypeAndBranch(
1081          UseRegisterAtStart(compare->value()));
1082    } else if (v->IsHasCachedArrayIndex()) {
1083      HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
1084      ASSERT(compare->value()->representation().IsTagged());
1085
1086      return new LHasCachedArrayIndexAndBranch(
1087          UseRegisterAtStart(compare->value()));
1088    } else if (v->IsIsNull()) {
1089      HIsNull* compare = HIsNull::cast(v);
1090      ASSERT(compare->value()->representation().IsTagged());
1091
1092      // We only need a temp register for non-strict compare.
1093      LOperand* temp = compare->is_strict() ? NULL : TempRegister();
1094      return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
1095                                  temp);
1096    } else if (v->IsIsObject()) {
1097      HIsObject* compare = HIsObject::cast(v);
1098      ASSERT(compare->value()->representation().IsTagged());
1099      return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()));
1100    } else if (v->IsCompareJSObjectEq()) {
1101      HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
1102      return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
1103                                         UseRegisterAtStart(compare->right()));
1104    } else if (v->IsInstanceOf()) {
1105      HInstanceOf* instance_of = HInstanceOf::cast(v);
1106      LInstanceOfAndBranch* result =
1107          new LInstanceOfAndBranch(UseFixed(instance_of->left(), rax),
1108                                   UseFixed(instance_of->right(), rdx));
1109      return MarkAsCall(result, instr);
1110    } else if (v->IsTypeofIs()) {
1111      HTypeofIs* typeof_is = HTypeofIs::cast(v);
1112      return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
1113    } else if (v->IsIsConstructCall()) {
1114      return new LIsConstructCallAndBranch(TempRegister());
1115    } else {
1116      if (v->IsConstant()) {
1117        if (HConstant::cast(v)->ToBoolean()) {
1118          return new LGoto(instr->FirstSuccessor()->block_id());
1119        } else {
1120          return new LGoto(instr->SecondSuccessor()->block_id());
1121        }
1122      }
1123      Abort("Undefined compare before branch");
1124      return NULL;
1125    }
1126  }
1127  return new LBranch(UseRegisterAtStart(v));
1128}
1129
1130
1131LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1132  ASSERT(instr->value()->representation().IsTagged());
1133  LOperand* value = UseRegisterAtStart(instr->value());
1134  return new LCmpMapAndBranch(value);
1135}
1136
1137
1138LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1139  return DefineAsRegister(new LArgumentsLength(Use(length->value())));
1140}
1141
1142
1143LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1144  return DefineAsRegister(new LArgumentsElements);
1145}
1146
1147
1148LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1149  LOperand* left = UseFixed(instr->left(), rax);
1150  LOperand* right = UseFixed(instr->right(), rdx);
1151  LInstanceOf* result = new LInstanceOf(left, right);
1152  return MarkAsCall(DefineFixed(result, rax), instr);
1153}
1154
1155
1156LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1157    HInstanceOfKnownGlobal* instr) {
1158  LInstanceOfKnownGlobal* result =
1159      new LInstanceOfKnownGlobal(UseFixed(instr->value(), rax),
1160                                 FixedTemp(rdi));
1161  return MarkAsCall(DefineFixed(result, rax), instr);
1162}
1163
1164
1165LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1166  LOperand* function = UseFixed(instr->function(), rdi);
1167  LOperand* receiver = UseFixed(instr->receiver(), rax);
1168  LOperand* length = UseFixed(instr->length(), rbx);
1169  LOperand* elements = UseFixed(instr->elements(), rcx);
1170  LApplyArguments* result = new LApplyArguments(function,
1171                                                receiver,
1172                                                length,
1173                                                elements);
1174  return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
1175}
1176
1177
1178LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1179  ++argument_count_;
1180  LOperand* argument = UseOrConstant(instr->argument());
1181  return new LPushArgument(argument);
1182}
1183
1184
1185LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1186  return DefineAsRegister(new LContext);
1187}
1188
1189
1190LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1191  LOperand* context = UseRegisterAtStart(instr->value());
1192  return DefineAsRegister(new LOuterContext(context));
1193}
1194
1195
1196LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1197  return DefineAsRegister(new LGlobalObject);
1198}
1199
1200
1201LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1202  LOperand* global_object = UseRegisterAtStart(instr->value());
1203  return DefineAsRegister(new LGlobalReceiver(global_object));
1204}
1205
1206
1207LInstruction* LChunkBuilder::DoCallConstantFunction(
1208    HCallConstantFunction* instr) {
1209  argument_count_ -= instr->argument_count();
1210  return MarkAsCall(DefineFixed(new LCallConstantFunction, rax), instr);
1211}
1212
1213
1214LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1215  BuiltinFunctionId op = instr->op();
1216  if (op == kMathLog || op == kMathSin || op == kMathCos) {
1217    LOperand* input = UseFixedDouble(instr->value(), xmm1);
1218    LUnaryMathOperation* result = new LUnaryMathOperation(input);
1219    return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1220  } else {
1221    LOperand* input = UseRegisterAtStart(instr->value());
1222    LUnaryMathOperation* result = new LUnaryMathOperation(input);
1223    switch (op) {
1224      case kMathAbs:
1225        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1226      case kMathFloor:
1227        return AssignEnvironment(DefineAsRegister(result));
1228      case kMathRound:
1229        return AssignEnvironment(DefineAsRegister(result));
1230      case kMathSqrt:
1231        return DefineSameAsFirst(result);
1232      case kMathPowHalf:
1233        return DefineSameAsFirst(result);
1234      default:
1235        UNREACHABLE();
1236        return NULL;
1237    }
1238  }
1239}
1240
1241
1242LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1243  ASSERT(instr->key()->representation().IsTagged());
1244  LOperand* key = UseFixed(instr->key(), rcx);
1245  argument_count_ -= instr->argument_count();
1246  LCallKeyed* result = new LCallKeyed(key);
1247  return MarkAsCall(DefineFixed(result, rax), instr);
1248}
1249
1250
1251LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1252  argument_count_ -= instr->argument_count();
1253  return MarkAsCall(DefineFixed(new LCallNamed, rax), instr);
1254}
1255
1256
1257LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1258  argument_count_ -= instr->argument_count();
1259  return MarkAsCall(DefineFixed(new LCallGlobal, rax), instr);
1260}
1261
1262
1263LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1264  argument_count_ -= instr->argument_count();
1265  return MarkAsCall(DefineFixed(new LCallKnownGlobal, rax), instr);
1266}
1267
1268
1269LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1270  LOperand* constructor = UseFixed(instr->constructor(), rdi);
1271  argument_count_ -= instr->argument_count();
1272  LCallNew* result = new LCallNew(constructor);
1273  return MarkAsCall(DefineFixed(result, rax), instr);
1274}
1275
1276
1277LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1278  argument_count_ -= instr->argument_count();
1279  LCallFunction* result = new LCallFunction();
1280  return MarkAsCall(DefineFixed(result, rax), instr);
1281}
1282
1283
1284LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1285  argument_count_ -= instr->argument_count();
1286  return MarkAsCall(DefineFixed(new LCallRuntime, rax), instr);
1287}
1288
1289
1290LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1291  return DoShift(Token::SHR, instr);
1292}
1293
1294
1295LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1296  return DoShift(Token::SAR, instr);
1297}
1298
1299
1300LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1301  return DoShift(Token::SHL, instr);
1302}
1303
1304
1305LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
1306  return DoBit(Token::BIT_AND, instr);
1307}
1308
1309
1310LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1311  ASSERT(instr->value()->representation().IsInteger32());
1312  ASSERT(instr->representation().IsInteger32());
1313  LOperand* input = UseRegisterAtStart(instr->value());
1314  LBitNotI* result = new LBitNotI(input);
1315  return DefineSameAsFirst(result);
1316}
1317
1318
1319LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
1320  return DoBit(Token::BIT_OR, instr);
1321}
1322
1323
1324LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
1325  return DoBit(Token::BIT_XOR, instr);
1326}
1327
1328
1329LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1330  if (instr->representation().IsDouble()) {
1331    return DoArithmeticD(Token::DIV, instr);
1332  } else if (instr->representation().IsInteger32()) {
1333    // The temporary operand is necessary to ensure that right is not allocated
1334    // into rdx.
1335    LOperand* temp = FixedTemp(rdx);
1336    LOperand* dividend = UseFixed(instr->left(), rax);
1337    LOperand* divisor = UseRegister(instr->right());
1338    LDivI* result = new LDivI(dividend, divisor, temp);
1339    return AssignEnvironment(DefineFixed(result, rax));
1340  } else {
1341    ASSERT(instr->representation().IsTagged());
1342    return DoArithmeticT(Token::DIV, instr);
1343  }
1344}
1345
1346
1347LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1348  if (instr->representation().IsInteger32()) {
1349    ASSERT(instr->left()->representation().IsInteger32());
1350    ASSERT(instr->right()->representation().IsInteger32());
1351
1352    LInstruction* result;
1353    if (instr->HasPowerOf2Divisor()) {
1354      ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1355      LOperand* value = UseRegisterAtStart(instr->left());
1356      LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
1357      result = DefineSameAsFirst(mod);
1358    } else {
1359      // The temporary operand is necessary to ensure that right is not
1360      // allocated into edx.
1361      LOperand* temp = FixedTemp(rdx);
1362      LOperand* value = UseFixed(instr->left(), rax);
1363      LOperand* divisor = UseRegister(instr->right());
1364      LModI* mod = new LModI(value, divisor, temp);
1365      result = DefineFixed(mod, rdx);
1366    }
1367
1368    return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1369            instr->CheckFlag(HValue::kCanBeDivByZero))
1370        ? AssignEnvironment(result)
1371        : result;
1372  } else if (instr->representation().IsTagged()) {
1373    return DoArithmeticT(Token::MOD, instr);
1374  } else {
1375    ASSERT(instr->representation().IsDouble());
1376    // We call a C function for double modulo. It can't trigger a GC.
1377    // We need to use fixed result register for the call.
1378    // TODO(fschneider): Allow any register as input registers.
1379    LOperand* left = UseFixedDouble(instr->left(), xmm2);
1380    LOperand* right = UseFixedDouble(instr->right(), xmm1);
1381    LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1382    return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1383  }
1384}
1385
1386
1387LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1388  if (instr->representation().IsInteger32()) {
1389    ASSERT(instr->left()->representation().IsInteger32());
1390    ASSERT(instr->right()->representation().IsInteger32());
1391    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1392    LOperand* right = UseOrConstant(instr->MostConstantOperand());
1393    LMulI* mul = new LMulI(left, right);
1394    return AssignEnvironment(DefineSameAsFirst(mul));
1395  } else if (instr->representation().IsDouble()) {
1396    return DoArithmeticD(Token::MUL, instr);
1397  } else {
1398    ASSERT(instr->representation().IsTagged());
1399    return DoArithmeticT(Token::MUL, instr);
1400  }
1401}
1402
1403
1404LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1405  if (instr->representation().IsInteger32()) {
1406    ASSERT(instr->left()->representation().IsInteger32());
1407    ASSERT(instr->right()->representation().IsInteger32());
1408    LOperand* left = UseRegisterAtStart(instr->left());
1409    LOperand* right = UseOrConstantAtStart(instr->right());
1410    LSubI* sub = new LSubI(left, right);
1411    LInstruction* result = DefineSameAsFirst(sub);
1412    if (instr->CheckFlag(HValue::kCanOverflow)) {
1413      result = AssignEnvironment(result);
1414    }
1415    return result;
1416  } else if (instr->representation().IsDouble()) {
1417    return DoArithmeticD(Token::SUB, instr);
1418  } else {
1419    ASSERT(instr->representation().IsTagged());
1420    return DoArithmeticT(Token::SUB, instr);
1421  }
1422}
1423
1424
1425LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1426  if (instr->representation().IsInteger32()) {
1427    ASSERT(instr->left()->representation().IsInteger32());
1428    ASSERT(instr->right()->representation().IsInteger32());
1429    LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1430    LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1431    LAddI* add = new LAddI(left, right);
1432    LInstruction* result = DefineSameAsFirst(add);
1433    if (instr->CheckFlag(HValue::kCanOverflow)) {
1434      result = AssignEnvironment(result);
1435    }
1436    return result;
1437  } else if (instr->representation().IsDouble()) {
1438    return DoArithmeticD(Token::ADD, instr);
1439  } else {
1440    ASSERT(instr->representation().IsTagged());
1441    return DoArithmeticT(Token::ADD, instr);
1442  }
1443  return NULL;
1444}
1445
1446
1447LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1448  ASSERT(instr->representation().IsDouble());
1449  // We call a C function for double power. It can't trigger a GC.
1450  // We need to use fixed result register for the call.
1451  Representation exponent_type = instr->right()->representation();
1452  ASSERT(instr->left()->representation().IsDouble());
1453  LOperand* left = UseFixedDouble(instr->left(), xmm2);
1454  LOperand* right = exponent_type.IsDouble() ?
1455      UseFixedDouble(instr->right(), xmm1) :
1456#ifdef _WIN64
1457      UseFixed(instr->right(), rdx);
1458#else
1459      UseFixed(instr->right(), rdi);
1460#endif
1461  LPower* result = new LPower(left, right);
1462  return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
1463                    CAN_DEOPTIMIZE_EAGERLY);
1464}
1465
1466
1467LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
1468  Token::Value op = instr->token();
1469  Representation r = instr->GetInputRepresentation();
1470  if (r.IsInteger32()) {
1471    ASSERT(instr->left()->representation().IsInteger32());
1472    ASSERT(instr->right()->representation().IsInteger32());
1473    LOperand* left = UseRegisterAtStart(instr->left());
1474    LOperand* right = UseOrConstantAtStart(instr->right());
1475    return DefineAsRegister(new LCmpID(left, right));
1476  } else if (r.IsDouble()) {
1477    ASSERT(instr->left()->representation().IsDouble());
1478    ASSERT(instr->right()->representation().IsDouble());
1479    LOperand* left = UseRegisterAtStart(instr->left());
1480    LOperand* right = UseRegisterAtStart(instr->right());
1481    return DefineAsRegister(new LCmpID(left, right));
1482  } else {
1483    ASSERT(instr->left()->representation().IsTagged());
1484    ASSERT(instr->right()->representation().IsTagged());
1485    bool reversed = (op == Token::GT || op == Token::LTE);
1486    LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
1487    LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
1488    LCmpT* result = new LCmpT(left, right);
1489    return MarkAsCall(DefineFixed(result, rax), instr);
1490  }
1491}
1492
1493
1494LInstruction* LChunkBuilder::DoCompareJSObjectEq(
1495    HCompareJSObjectEq* instr) {
1496  LOperand* left = UseRegisterAtStart(instr->left());
1497  LOperand* right = UseRegisterAtStart(instr->right());
1498  LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
1499  return DefineAsRegister(result);
1500}
1501
1502
1503LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) {
1504  ASSERT(instr->value()->representation().IsTagged());
1505  LOperand* value = UseRegisterAtStart(instr->value());
1506
1507  return DefineAsRegister(new LIsNull(value));
1508}
1509
1510
1511LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) {
1512  ASSERT(instr->value()->representation().IsTagged());
1513  LOperand* value = UseRegister(instr->value());
1514
1515  return DefineAsRegister(new LIsObject(value));
1516}
1517
1518
1519LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) {
1520  ASSERT(instr->value()->representation().IsTagged());
1521  LOperand* value = UseAtStart(instr->value());
1522
1523  return DefineAsRegister(new LIsSmi(value));
1524}
1525
1526
1527LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) {
1528  ASSERT(instr->value()->representation().IsTagged());
1529  LOperand* value = UseRegisterAtStart(instr->value());
1530
1531  return DefineAsRegister(new LHasInstanceType(value));
1532}
1533
1534
1535LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1536    HGetCachedArrayIndex* instr)  {
1537  ASSERT(instr->value()->representation().IsTagged());
1538  LOperand* value = UseRegisterAtStart(instr->value());
1539
1540  return DefineAsRegister(new LGetCachedArrayIndex(value));
1541}
1542
1543
1544LInstruction* LChunkBuilder::DoHasCachedArrayIndex(
1545    HHasCachedArrayIndex* instr) {
1546  ASSERT(instr->value()->representation().IsTagged());
1547  LOperand* value = UseRegister(instr->value());
1548  return DefineAsRegister(new LHasCachedArrayIndex(value));
1549}
1550
1551
1552LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
1553  Abort("Unimplemented: %s", "DoClassOfTest");
1554  return NULL;
1555}
1556
1557
1558LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1559  LOperand* array = UseRegisterAtStart(instr->value());
1560  return DefineAsRegister(new LJSArrayLength(array));
1561}
1562
1563
1564LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
1565  LOperand* array = UseRegisterAtStart(instr->value());
1566  return DefineAsRegister(new LFixedArrayLength(array));
1567}
1568
1569
1570LInstruction* LChunkBuilder::DoExternalArrayLength(
1571    HExternalArrayLength* instr) {
1572  LOperand* array = UseRegisterAtStart(instr->value());
1573  return DefineAsRegister(new LExternalArrayLength(array));
1574}
1575
1576
1577LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1578  LOperand* object = UseRegister(instr->value());
1579  LValueOf* result = new LValueOf(object);
1580  return AssignEnvironment(DefineSameAsFirst(result));
1581}
1582
1583
1584LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1585  return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
1586                                            Use(instr->length())));
1587}
1588
1589
1590LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1591  // The control instruction marking the end of a block that completed
1592  // abruptly (e.g., threw an exception).  There is nothing specific to do.
1593  return NULL;
1594}
1595
1596
1597LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1598  LOperand* value = UseFixed(instr->value(), rax);
1599  return MarkAsCall(new LThrow(value), instr);
1600}
1601
1602
1603LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1604  Representation from = instr->from();
1605  Representation to = instr->to();
1606  if (from.IsTagged()) {
1607    if (to.IsDouble()) {
1608      LOperand* value = UseRegister(instr->value());
1609      LNumberUntagD* res = new LNumberUntagD(value);
1610      return AssignEnvironment(DefineAsRegister(res));
1611    } else {
1612      ASSERT(to.IsInteger32());
1613      LOperand* value = UseRegister(instr->value());
1614      bool needs_check = !instr->value()->type().IsSmi();
1615      if (needs_check) {
1616        LOperand* xmm_temp = instr->CanTruncateToInt32() ? NULL
1617                                                         : FixedTemp(xmm1);
1618        LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1619        return AssignEnvironment(DefineSameAsFirst(res));
1620      } else {
1621        return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1622      }
1623    }
1624  } else if (from.IsDouble()) {
1625    if (to.IsTagged()) {
1626      LOperand* value = UseRegister(instr->value());
1627      LOperand* temp = TempRegister();
1628
1629      // Make sure that temp and result_temp are different registers.
1630      LUnallocated* result_temp = TempRegister();
1631      LNumberTagD* result = new LNumberTagD(value, temp);
1632      return AssignPointerMap(Define(result, result_temp));
1633    } else {
1634      ASSERT(to.IsInteger32());
1635      LOperand* value = UseRegister(instr->value());
1636      return AssignEnvironment(DefineAsRegister(new LDoubleToI(value)));
1637    }
1638  } else if (from.IsInteger32()) {
1639    if (to.IsTagged()) {
1640      HValue* val = instr->value();
1641      LOperand* value = UseRegister(val);
1642      if (val->HasRange() && val->range()->IsInSmiRange()) {
1643        return DefineSameAsFirst(new LSmiTag(value));
1644      } else {
1645        LNumberTagI* result = new LNumberTagI(value);
1646        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1647      }
1648    } else {
1649      ASSERT(to.IsDouble());
1650      return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1651    }
1652  }
1653  UNREACHABLE();
1654  return NULL;
1655}
1656
1657
1658LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1659  LOperand* value = UseRegisterAtStart(instr->value());
1660  return AssignEnvironment(new LCheckNonSmi(value));
1661}
1662
1663
1664LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1665  LOperand* value = UseRegisterAtStart(instr->value());
1666  LCheckInstanceType* result = new LCheckInstanceType(value);
1667  return AssignEnvironment(result);
1668}
1669
1670
1671LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1672  LOperand* temp = TempRegister();
1673  LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp);
1674  return AssignEnvironment(result);
1675}
1676
1677
1678LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1679  LOperand* value = UseRegisterAtStart(instr->value());
1680  return AssignEnvironment(new LCheckSmi(value));
1681}
1682
1683
1684LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1685  LOperand* value = UseRegisterAtStart(instr->value());
1686  return AssignEnvironment(new LCheckFunction(value));
1687}
1688
1689
1690LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1691  LOperand* value = UseRegisterAtStart(instr->value());
1692  LCheckMap* result = new LCheckMap(value);
1693  return AssignEnvironment(result);
1694}
1695
1696
1697LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1698  return new LReturn(UseFixed(instr->value(), rax));
1699}
1700
1701
1702LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1703  Representation r = instr->representation();
1704  if (r.IsInteger32()) {
1705    return DefineAsRegister(new LConstantI);
1706  } else if (r.IsDouble()) {
1707    LOperand* temp = TempRegister();
1708    return DefineAsRegister(new LConstantD(temp));
1709  } else if (r.IsTagged()) {
1710    return DefineAsRegister(new LConstantT);
1711  } else {
1712    UNREACHABLE();
1713    return NULL;
1714  }
1715}
1716
1717
1718LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1719  LLoadGlobalCell* result = new LLoadGlobalCell;
1720  return instr->check_hole_value()
1721      ? AssignEnvironment(DefineAsRegister(result))
1722      : DefineAsRegister(result);
1723}
1724
1725
1726LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1727  LOperand* global_object = UseFixed(instr->global_object(), rax);
1728  LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
1729  return MarkAsCall(DefineFixed(result, rax), instr);
1730}
1731
1732
1733LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
1734  LStoreGlobalCell* result =
1735      new LStoreGlobalCell(UseRegister(instr->value()), TempRegister());
1736  return instr->check_hole_value() ? AssignEnvironment(result) : result;
1737}
1738
1739
1740LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
1741  LOperand* global_object = UseFixed(instr->global_object(), rdx);
1742  LOperand* value = UseFixed(instr->value(), rax);
1743  LStoreGlobalGeneric* result =  new LStoreGlobalGeneric(global_object, value);
1744  return MarkAsCall(result, instr);
1745}
1746
1747
1748LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1749  LOperand* context = UseRegisterAtStart(instr->value());
1750  return DefineAsRegister(new LLoadContextSlot(context));
1751}
1752
1753
1754LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1755  LOperand* context;
1756  LOperand* value;
1757  LOperand* temp;
1758  if (instr->NeedsWriteBarrier()) {
1759    context = UseTempRegister(instr->context());
1760    value = UseTempRegister(instr->value());
1761    temp = TempRegister();
1762  } else {
1763    context = UseRegister(instr->context());
1764    value = UseRegister(instr->value());
1765    temp = NULL;
1766  }
1767  return new LStoreContextSlot(context, value, temp);
1768}
1769
1770
1771LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1772  ASSERT(instr->representation().IsTagged());
1773  LOperand* obj = UseRegisterAtStart(instr->object());
1774  return DefineAsRegister(new LLoadNamedField(obj));
1775}
1776
1777
1778LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
1779    HLoadNamedFieldPolymorphic* instr) {
1780  ASSERT(instr->representation().IsTagged());
1781  if (instr->need_generic()) {
1782    LOperand* obj = UseFixed(instr->object(), rax);
1783    LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1784    return MarkAsCall(DefineFixed(result, rax), instr);
1785  } else {
1786    LOperand* obj = UseRegisterAtStart(instr->object());
1787    LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1788    return AssignEnvironment(DefineAsRegister(result));
1789  }
1790}
1791
1792
1793LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1794  LOperand* object = UseFixed(instr->object(), rax);
1795  LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
1796  return MarkAsCall(DefineFixed(result, rax), instr);
1797}
1798
1799
1800LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1801    HLoadFunctionPrototype* instr) {
1802  return AssignEnvironment(DefineAsRegister(
1803      new LLoadFunctionPrototype(UseRegister(instr->function()))));
1804}
1805
1806
1807LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1808  LOperand* input = UseRegisterAtStart(instr->value());
1809  return DefineAsRegister(new LLoadElements(input));
1810}
1811
1812
1813LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
1814    HLoadExternalArrayPointer* instr) {
1815  LOperand* input = UseRegisterAtStart(instr->value());
1816  return DefineAsRegister(new LLoadExternalArrayPointer(input));
1817}
1818
1819
1820LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1821    HLoadKeyedFastElement* instr) {
1822  ASSERT(instr->representation().IsTagged());
1823  ASSERT(instr->key()->representation().IsInteger32());
1824  LOperand* obj = UseRegisterAtStart(instr->object());
1825  LOperand* key = UseRegisterAtStart(instr->key());
1826  LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
1827  return AssignEnvironment(DefineSameAsFirst(result));
1828}
1829
1830
1831LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
1832    HLoadKeyedSpecializedArrayElement* instr) {
1833  ExternalArrayType array_type = instr->array_type();
1834  Representation representation(instr->representation());
1835  ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
1836         (representation.IsDouble() && array_type == kExternalFloatArray));
1837  ASSERT(instr->key()->representation().IsInteger32());
1838  LOperand* external_pointer = UseRegister(instr->external_pointer());
1839  LOperand* key = UseRegister(instr->key());
1840  LLoadKeyedSpecializedArrayElement* result =
1841      new LLoadKeyedSpecializedArrayElement(external_pointer, key);
1842  LInstruction* load_instr = DefineAsRegister(result);
1843  // An unsigned int array load might overflow and cause a deopt, make sure it
1844  // has an environment.
1845  return (array_type == kExternalUnsignedIntArray) ?
1846      AssignEnvironment(load_instr) : load_instr;
1847}
1848
1849
1850LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1851  LOperand* object = UseFixed(instr->object(), rdx);
1852  LOperand* key = UseFixed(instr->key(), rax);
1853
1854  LLoadKeyedGeneric* result = new LLoadKeyedGeneric(object, key);
1855  return MarkAsCall(DefineFixed(result, rax), instr);
1856}
1857
1858
1859LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1860    HStoreKeyedFastElement* instr) {
1861  bool needs_write_barrier = instr->NeedsWriteBarrier();
1862  ASSERT(instr->value()->representation().IsTagged());
1863  ASSERT(instr->object()->representation().IsTagged());
1864  ASSERT(instr->key()->representation().IsInteger32());
1865
1866  LOperand* obj = UseTempRegister(instr->object());
1867  LOperand* val = needs_write_barrier
1868      ? UseTempRegister(instr->value())
1869      : UseRegisterAtStart(instr->value());
1870  LOperand* key = needs_write_barrier
1871      ? UseTempRegister(instr->key())
1872      : UseRegisterOrConstantAtStart(instr->key());
1873
1874  return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1875}
1876
1877
1878LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
1879    HStoreKeyedSpecializedArrayElement* instr) {
1880  Representation representation(instr->value()->representation());
1881  ExternalArrayType array_type = instr->array_type();
1882  ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) ||
1883         (representation.IsDouble() && array_type == kExternalFloatArray));
1884  ASSERT(instr->external_pointer()->representation().IsExternal());
1885  ASSERT(instr->key()->representation().IsInteger32());
1886
1887  LOperand* external_pointer = UseRegister(instr->external_pointer());
1888  bool val_is_temp_register = array_type == kExternalPixelArray ||
1889      array_type == kExternalFloatArray;
1890  LOperand* val = val_is_temp_register
1891      ? UseTempRegister(instr->value())
1892      : UseRegister(instr->value());
1893  LOperand* key = UseRegister(instr->key());
1894
1895  return new LStoreKeyedSpecializedArrayElement(external_pointer,
1896                                                key,
1897                                                val);
1898}
1899
1900
1901LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1902  LOperand* object = UseFixed(instr->object(), rdx);
1903  LOperand* key = UseFixed(instr->key(), rcx);
1904  LOperand* value = UseFixed(instr->value(), rax);
1905
1906  ASSERT(instr->object()->representation().IsTagged());
1907  ASSERT(instr->key()->representation().IsTagged());
1908  ASSERT(instr->value()->representation().IsTagged());
1909
1910  LStoreKeyedGeneric* result = new LStoreKeyedGeneric(object, key, value);
1911  return MarkAsCall(result, instr);
1912}
1913
1914
1915LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1916  bool needs_write_barrier = instr->NeedsWriteBarrier();
1917
1918  LOperand* obj = needs_write_barrier
1919      ? UseTempRegister(instr->object())
1920      : UseRegisterAtStart(instr->object());
1921
1922  LOperand* val = needs_write_barrier
1923      ? UseTempRegister(instr->value())
1924      : UseRegister(instr->value());
1925
1926  // We only need a scratch register if we have a write barrier or we
1927  // have a store into the properties array (not in-object-property).
1928  LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1929      ? TempRegister() : NULL;
1930
1931  return new LStoreNamedField(obj, val, temp);
1932}
1933
1934
1935LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1936  LOperand* object = UseFixed(instr->object(), rdx);
1937  LOperand* value = UseFixed(instr->value(), rax);
1938
1939  LStoreNamedGeneric* result = new LStoreNamedGeneric(object, value);
1940  return MarkAsCall(result, instr);
1941}
1942
1943
1944LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1945  LOperand* string = UseRegister(instr->string());
1946  LOperand* index = UseRegisterOrConstant(instr->index());
1947  LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
1948  return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1949}
1950
1951
1952LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
1953  LOperand* char_code = UseRegister(instr->value());
1954  LStringCharFromCode* result = new LStringCharFromCode(char_code);
1955  return AssignPointerMap(DefineAsRegister(result));
1956}
1957
1958
1959LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
1960  LOperand* string = UseRegisterAtStart(instr->value());
1961  return DefineAsRegister(new LStringLength(string));
1962}
1963
1964
1965LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
1966  return MarkAsCall(DefineFixed(new LArrayLiteral, rax), instr);
1967}
1968
1969
1970LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
1971  return MarkAsCall(DefineFixed(new LObjectLiteral, rax), instr);
1972}
1973
1974
1975LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
1976  return MarkAsCall(DefineFixed(new LRegExpLiteral, rax), instr);
1977}
1978
1979
1980LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
1981  return MarkAsCall(DefineFixed(new LFunctionLiteral, rax), instr);
1982}
1983
1984
1985LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
1986  LDeleteProperty* result =
1987      new LDeleteProperty(Use(instr->object()), UseOrConstant(instr->key()));
1988  return MarkAsCall(DefineFixed(result, rax), instr);
1989}
1990
1991
1992LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
1993  allocator_->MarkAsOsrEntry();
1994  current_block_->last_environment()->set_ast_id(instr->ast_id());
1995  return AssignEnvironment(new LOsrEntry);
1996}
1997
1998
1999LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2000  int spill_index = chunk()->GetParameterStackSlot(instr->index());
2001  return DefineAsSpilled(new LParameter, spill_index);
2002}
2003
2004
2005LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2006  int spill_index = chunk()->GetNextSpillIndex(false);  // Not double-width.
2007  if (spill_index > LUnallocated::kMaxFixedIndex) {
2008    Abort("Too many spill slots needed for OSR");
2009    spill_index = 0;
2010  }
2011  return DefineAsSpilled(new LUnknownOSRValue, spill_index);
2012}
2013
2014
2015LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2016  argument_count_ -= instr->argument_count();
2017  return MarkAsCall(DefineFixed(new LCallStub, rax), instr);
2018}
2019
2020
2021LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2022  // There are no real uses of the arguments object.
2023  // arguments.length and element access are supported directly on
2024  // stack arguments, and any real arguments object use causes a bailout.
2025  // So this value is never used.
2026  return NULL;
2027}
2028
2029
2030LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2031  LOperand* arguments = UseRegister(instr->arguments());
2032  LOperand* length = UseTempRegister(instr->length());
2033  LOperand* index = Use(instr->index());
2034  LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
2035  return AssignEnvironment(DefineAsRegister(result));
2036}
2037
2038
2039LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2040  LOperand* object = UseFixed(instr->value(), rax);
2041  LToFastProperties* result = new LToFastProperties(object);
2042  return MarkAsCall(DefineFixed(result, rax), instr);
2043}
2044
2045
2046LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2047  LTypeof* result = new LTypeof(UseAtStart(instr->value()));
2048  return MarkAsCall(DefineFixed(result, rax), instr);
2049}
2050
2051
2052LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
2053  return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
2054}
2055
2056
2057LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
2058  return DefineAsRegister(new LIsConstructCall);
2059}
2060
2061
2062LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2063  HEnvironment* env = current_block_->last_environment();
2064  ASSERT(env != NULL);
2065
2066  env->set_ast_id(instr->ast_id());
2067
2068  env->Drop(instr->pop_count());
2069  for (int i = 0; i < instr->values()->length(); ++i) {
2070    HValue* value = instr->values()->at(i);
2071    if (instr->HasAssignedIndexAt(i)) {
2072      env->Bind(instr->GetAssignedIndexAt(i), value);
2073    } else {
2074      env->Push(value);
2075    }
2076  }
2077
2078  // If there is an instruction pending deoptimization environment create a
2079  // lazy bailout instruction to capture the environment.
2080  if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2081    LLazyBailout* lazy_bailout = new LLazyBailout;
2082    LInstruction* result = AssignEnvironment(lazy_bailout);
2083    instruction_pending_deoptimization_environment_->
2084        set_deoptimization_environment(result->environment());
2085    ClearInstructionPendingDeoptimizationEnvironment();
2086    return result;
2087  }
2088
2089  return NULL;
2090}
2091
2092
2093LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2094  return MarkAsCall(new LStackCheck, instr);
2095}
2096
2097
2098LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2099  HEnvironment* outer = current_block_->last_environment();
2100  HConstant* undefined = graph()->GetConstantUndefined();
2101  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2102                                               instr->function(),
2103                                               false,
2104                                               undefined);
2105  current_block_->UpdateEnvironment(inner);
2106  chunk_->AddInlinedClosure(instr->closure());
2107  return NULL;
2108}
2109
2110
2111LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2112  HEnvironment* outer = current_block_->last_environment()->outer();
2113  current_block_->UpdateEnvironment(outer);
2114  return NULL;
2115}
2116
2117} }  // namespace v8::internal
2118
2119#endif  // V8_TARGET_ARCH_X64
2120