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