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