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