Home | History | Annotate | Download | only in arm
      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 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 #define DEFINE_COMPILE(type)                            \
     38   void L##type::CompileToNative(LCodeGen* generator) {  \
     39     generator->Do##type(this);                          \
     40   }
     41 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
     42 #undef DEFINE_COMPILE
     43 
     44 LOsrEntry::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 
     54 void 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
     63 void 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 
     85 void 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 
     93 void 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 
    112 template<int R, int I, int T>
    113 void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
    114   stream->Add("= ");
    115   inputs_.PrintOperandsTo(stream);
    116 }
    117 
    118 
    119 template<int R, int I, int T>
    120 void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
    121   results_.PrintOperandsTo(stream);
    122 }
    123 
    124 
    125 template<typename T, int N>
    126 void 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 
    134 void 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 
    143 bool 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 
    154 void 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 
    165 const 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 
    179 const 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 
    199 void LGoto::PrintDataTo(StringStream* stream) {
    200   stream->Add("B%d", block_id());
    201 }
    202 
    203 
    204 void 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 
    210 void 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 
    219 void 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 
    227 void 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 
    234 void 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 
    241 void 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 
    248 void 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 
    255 void 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 
    265 void LTypeofIs::PrintDataTo(StringStream* stream) {
    266   InputAt(0)->PrintTo(stream);
    267   stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
    268 }
    269 
    270 
    271 void 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 
    280 void LCallConstantFunction::PrintDataTo(StringStream* stream) {
    281   stream->Add("#%d / ", arity());
    282 }
    283 
    284 
    285 void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
    286   stream->Add("/%s ", hydrogen()->OpName());
    287   InputAt(0)->PrintTo(stream);
    288 }
    289 
    290 
    291 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
    292   InputAt(0)->PrintTo(stream);
    293   stream->Add("[%d]", slot_index());
    294 }
    295 
    296 
    297 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
    298   InputAt(0)->PrintTo(stream);
    299   stream->Add("[%d] <- ", slot_index());
    300   InputAt(1)->PrintTo(stream);
    301 }
    302 
    303 
    304 void LCallKeyed::PrintDataTo(StringStream* stream) {
    305   stream->Add("[r2] #%d / ", arity());
    306 }
    307 
    308 
    309 void LCallNamed::PrintDataTo(StringStream* stream) {
    310   SmartPointer<char> name_string = name()->ToCString();
    311   stream->Add("%s #%d / ", *name_string, arity());
    312 }
    313 
    314 
    315 void LCallGlobal::PrintDataTo(StringStream* stream) {
    316   SmartPointer<char> name_string = name()->ToCString();
    317   stream->Add("%s #%d / ", *name_string, arity());
    318 }
    319 
    320 
    321 void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
    322   stream->Add("#%d / ", arity());
    323 }
    324 
    325 
    326 void LCallNew::PrintDataTo(StringStream* stream) {
    327   stream->Add("= ");
    328   InputAt(0)->PrintTo(stream);
    329   stream->Add(" #%d / ", arity());
    330 }
    331 
    332 
    333 void 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 
    340 void 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 
    351 void 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 
    360 void 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 
    369 void 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 
    378 void 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 
    387 LChunk::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 
    397 int 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 
    404 LOperand* 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 
    414 void 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 
    451 void 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 
    470 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
    471   return LConstantOperand::Create(constant->id());
    472 }
    473 
    474 
    475 int 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.
    486 int 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 
    493 LGap* LChunk::GetGapAt(int index) const {
    494   return LGap::cast(instructions_[index]);
    495 }
    496 
    497 
    498 bool LChunk::IsGapAt(int index) const {
    499   return instructions_[index]->IsGap();
    500 }
    501 
    502 
    503 int LChunk::NearestGapPos(int index) const {
    504   while (!IsGapAt(index)) index--;
    505   return index;
    506 }
    507 
    508 
    509 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
    510   GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
    511 }
    512 
    513 
    514 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
    515   return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
    516 }
    517 
    518 
    519 Representation LChunk::LookupLiteralRepresentation(
    520     LConstantOperand* operand) const {
    521   return graph_->LookupValue(operand->index())->representation();
    522 }
    523 
    524 
    525 LChunk* 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 
    542 void 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 
    556 LRegister* LChunkBuilder::ToOperand(Register reg) {
    557   return LRegister::Create(Register::ToAllocationIndex(reg));
    558 }
    559 
    560 
    561 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
    562   return new LUnallocated(LUnallocated::FIXED_REGISTER,
    563                           Register::ToAllocationIndex(reg));
    564 }
    565 
    566 
    567 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
    568   return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
    569                           DoubleRegister::ToAllocationIndex(reg));
    570 }
    571 
    572 
    573 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
    574   return Use(value, ToUnallocated(fixed_register));
    575 }
    576 
    577 
    578 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
    579   return Use(value, ToUnallocated(reg));
    580 }
    581 
    582 
    583 LOperand* LChunkBuilder::UseRegister(HValue* value) {
    584   return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
    585 }
    586 
    587 
    588 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
    589   return Use(value,
    590              new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
    591                               LUnallocated::USED_AT_START));
    592 }
    593 
    594 
    595 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
    596   return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
    597 }
    598 
    599 
    600 LOperand* LChunkBuilder::Use(HValue* value) {
    601   return Use(value, new LUnallocated(LUnallocated::NONE));
    602 }
    603 
    604 
    605 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
    606   return Use(value, new LUnallocated(LUnallocated::NONE,
    607                                      LUnallocated::USED_AT_START));
    608 }
    609 
    610 
    611 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
    612   return value->IsConstant()
    613       ? chunk_->DefineConstantOperand(HConstant::cast(value))
    614       : Use(value);
    615 }
    616 
    617 
    618 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
    619   return value->IsConstant()
    620       ? chunk_->DefineConstantOperand(HConstant::cast(value))
    621       : UseAtStart(value);
    622 }
    623 
    624 
    625 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
    626   return value->IsConstant()
    627       ? chunk_->DefineConstantOperand(HConstant::cast(value))
    628       : UseRegister(value);
    629 }
    630 
    631 
    632 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
    633   return value->IsConstant()
    634       ? chunk_->DefineConstantOperand(HConstant::cast(value))
    635       : UseRegisterAtStart(value);
    636 }
    637 
    638 
    639 LOperand* LChunkBuilder::UseAny(HValue* value) {
    640   return value->IsConstant()
    641       ? chunk_->DefineConstantOperand(HConstant::cast(value))
    642       :  Use(value, new LUnallocated(LUnallocated::ANY));
    643 }
    644 
    645 
    646 LOperand* 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 
    656 template<int I, int T>
    657 LInstruction* 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 
    665 template<int I, int T>
    666 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
    667   return Define(instr, new LUnallocated(LUnallocated::NONE));
    668 }
    669 
    670 
    671 template<int I, int T>
    672 LInstruction* LChunkBuilder::DefineAsRegister(
    673     LTemplateInstruction<1, I, T>* instr) {
    674   return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
    675 }
    676 
    677 
    678 template<int I, int T>
    679 LInstruction* LChunkBuilder::DefineAsSpilled(
    680     LTemplateInstruction<1, I, T>* instr, int index) {
    681   return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
    682 }
    683 
    684 
    685 template<int I, int T>
    686 LInstruction* LChunkBuilder::DefineSameAsFirst(
    687     LTemplateInstruction<1, I, T>* instr) {
    688   return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
    689 }
    690 
    691 
    692 template<int I, int T>
    693 LInstruction* LChunkBuilder::DefineFixed(
    694     LTemplateInstruction<1, I, T>* instr, Register reg) {
    695   return Define(instr, ToUnallocated(reg));
    696 }
    697 
    698 
    699 template<int I, int T>
    700 LInstruction* LChunkBuilder::DefineFixedDouble(
    701     LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
    702   return Define(instr, ToUnallocated(reg));
    703 }
    704 
    705 
    706 LInstruction* 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 
    713 LInstruction* 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 
    723 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
    724   instruction_pending_deoptimization_environment_ = NULL;
    725   pending_deoptimization_ast_id_ = AstNode::kNoNumber;
    726 }
    727 
    728 
    729 LInstruction* 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 
    759 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
    760   instr->MarkAsSaveDoubles();
    761   return instr;
    762 }
    763 
    764 
    765 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
    766   ASSERT(!instr->HasPointerMap());
    767   instr->set_pointer_map(new LPointerMap(position_));
    768   return instr;
    769 }
    770 
    771 
    772 LUnallocated* LChunkBuilder::TempRegister() {
    773   LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
    774   allocator_->RecordTemporary(operand);
    775   return operand;
    776 }
    777 
    778 
    779 LOperand* LChunkBuilder::FixedTemp(Register reg) {
    780   LUnallocated* operand = ToUnallocated(reg);
    781   allocator_->RecordTemporary(operand);
    782   return operand;
    783 }
    784 
    785 
    786 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
    787   LUnallocated* operand = ToUnallocated(reg);
    788   allocator_->RecordTemporary(operand);
    789   return operand;
    790 }
    791 
    792 
    793 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
    794   return new LLabel(instr->block());
    795 }
    796 
    797 
    798 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
    799   return AssignEnvironment(new LDeoptimize);
    800 }
    801 
    802 
    803 LInstruction* 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 
    825 LInstruction* 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 
    874 LInstruction* 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 
    887 LInstruction* 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 
    905 void 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 
    968 void 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 
    999 LEnvironment* 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 
   1030 LInstruction* 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 
   1038 LInstruction* 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 
   1131 LInstruction* 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 
   1139 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
   1140   return DefineAsRegister(new LArgumentsLength(UseRegister(length->value())));
   1141 }
   1142 
   1143 
   1144 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
   1145   return DefineAsRegister(new LArgumentsElements);
   1146 }
   1147 
   1148 
   1149 LInstruction* 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 
   1157 LInstruction* 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 
   1165 LInstruction* 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 
   1178 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
   1179   ++argument_count_;
   1180   LOperand* argument = Use(instr->argument());
   1181   return new LPushArgument(argument);
   1182 }
   1183 
   1184 
   1185 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
   1186   return DefineAsRegister(new LContext);
   1187 }
   1188 
   1189 
   1190 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
   1191   LOperand* context = UseRegisterAtStart(instr->value());
   1192   return DefineAsRegister(new LOuterContext(context));
   1193 }
   1194 
   1195 
   1196 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
   1197   LOperand* context = UseRegisterAtStart(instr->value());
   1198   return DefineAsRegister(new LGlobalObject(context));
   1199 }
   1200 
   1201 
   1202 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
   1203   LOperand* global_object = UseRegisterAtStart(instr->value());
   1204   return DefineAsRegister(new LGlobalReceiver(global_object));
   1205 }
   1206 
   1207 
   1208 LInstruction* LChunkBuilder::DoCallConstantFunction(
   1209     HCallConstantFunction* instr) {
   1210   argument_count_ -= instr->argument_count();
   1211   return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr);
   1212 }
   1213 
   1214 
   1215 LInstruction* 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 
   1244 LInstruction* 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 
   1252 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
   1253   argument_count_ -= instr->argument_count();
   1254   return MarkAsCall(DefineFixed(new LCallNamed, r0), instr);
   1255 }
   1256 
   1257 
   1258 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
   1259   argument_count_ -= instr->argument_count();
   1260   return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr);
   1261 }
   1262 
   1263 
   1264 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
   1265   argument_count_ -= instr->argument_count();
   1266   return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr);
   1267 }
   1268 
   1269 
   1270 LInstruction* 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 
   1278 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
   1279   argument_count_ -= instr->argument_count();
   1280   return MarkAsCall(DefineFixed(new LCallFunction, r0), instr);
   1281 }
   1282 
   1283 
   1284 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
   1285   argument_count_ -= instr->argument_count();
   1286   return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr);
   1287 }
   1288 
   1289 
   1290 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
   1291   return DoShift(Token::SHR, instr);
   1292 }
   1293 
   1294 
   1295 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
   1296   return DoShift(Token::SAR, instr);
   1297 }
   1298 
   1299 
   1300 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
   1301   return DoShift(Token::SHL, instr);
   1302 }
   1303 
   1304 
   1305 LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) {
   1306   return DoBit(Token::BIT_AND, instr);
   1307 }
   1308 
   1309 
   1310 LInstruction* 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 
   1317 LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) {
   1318   return DoBit(Token::BIT_OR, instr);
   1319 }
   1320 
   1321 
   1322 LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) {
   1323   return DoBit(Token::BIT_XOR, instr);
   1324 }
   1325 
   1326 
   1327 LInstruction* 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 
   1346 LInstruction* 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 
   1382 LInstruction* 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 
   1402 LInstruction* 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 
   1422 LInstruction* 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 
   1443 LInstruction* 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 
   1460 LInstruction* 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 
   1487 LInstruction* 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 
   1496 LInstruction* 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 
   1504 LInstruction* 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 
   1512 LInstruction* 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 
   1520 LInstruction* 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 
   1528 LInstruction* 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 
   1537 LInstruction* 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 
   1546 LInstruction* 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 
   1553 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
   1554   LOperand* array = UseRegisterAtStart(instr->value());
   1555   return DefineAsRegister(new LJSArrayLength(array));
   1556 }
   1557 
   1558 
   1559 LInstruction* LChunkBuilder::DoExternalArrayLength(
   1560     HExternalArrayLength* instr) {
   1561   LOperand* array = UseRegisterAtStart(instr->value());
   1562   return DefineAsRegister(new LExternalArrayLength(array));
   1563 }
   1564 
   1565 
   1566 LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
   1567   LOperand* array = UseRegisterAtStart(instr->value());
   1568   return DefineAsRegister(new LFixedArrayLength(array));
   1569 }
   1570 
   1571 
   1572 LInstruction* 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 
   1579 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
   1580   return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
   1581                                             UseRegister(instr->length())));
   1582 }
   1583 
   1584 
   1585 LInstruction* 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 
   1592 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
   1593   LOperand* value = UseFixed(instr->value(), r0);
   1594   return MarkAsCall(new LThrow(value), instr);
   1595 }
   1596 
   1597 
   1598 LInstruction* 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 
   1666 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
   1667   LOperand* value = UseRegisterAtStart(instr->value());
   1668   return AssignEnvironment(new LCheckNonSmi(value));
   1669 }
   1670 
   1671 
   1672 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
   1673   LOperand* value = UseRegisterAtStart(instr->value());
   1674   LInstruction* result = new LCheckInstanceType(value);
   1675   return AssignEnvironment(result);
   1676 }
   1677 
   1678 
   1679 LInstruction* 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 
   1687 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
   1688   LOperand* value = UseRegisterAtStart(instr->value());
   1689   return AssignEnvironment(new LCheckSmi(value));
   1690 }
   1691 
   1692 
   1693 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
   1694   LOperand* value = UseRegisterAtStart(instr->value());
   1695   return AssignEnvironment(new LCheckFunction(value));
   1696 }
   1697 
   1698 
   1699 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
   1700   LOperand* value = UseRegisterAtStart(instr->value());
   1701   LInstruction* result = new LCheckMap(value);
   1702   return AssignEnvironment(result);
   1703 }
   1704 
   1705 
   1706 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
   1707   return new LReturn(UseFixed(instr->value(), r0));
   1708 }
   1709 
   1710 
   1711 LInstruction* 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 
   1726 LInstruction* 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 
   1734 LInstruction* 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 
   1741 LInstruction* 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 
   1753 LInstruction* 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 
   1762 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   1763   LOperand* context = UseRegisterAtStart(instr->value());
   1764   return DefineAsRegister(new LLoadContextSlot(context));
   1765 }
   1766 
   1767 
   1768 LInstruction* 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 
   1782 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
   1783   return DefineAsRegister(
   1784       new LLoadNamedField(UseRegisterAtStart(instr->object())));
   1785 }
   1786 
   1787 
   1788 LInstruction* 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 
   1803 LInstruction* 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 
   1810 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
   1811     HLoadFunctionPrototype* instr) {
   1812   return AssignEnvironment(DefineAsRegister(
   1813       new LLoadFunctionPrototype(UseRegister(instr->function()))));
   1814 }
   1815 
   1816 
   1817 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
   1818   LOperand* input = UseRegisterAtStart(instr->value());
   1819   return DefineAsRegister(new LLoadElements(input));
   1820 }
   1821 
   1822 
   1823 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
   1824     HLoadExternalArrayPointer* instr) {
   1825   LOperand* input = UseRegisterAtStart(instr->value());
   1826   return DefineAsRegister(new LLoadExternalArrayPointer(input));
   1827 }
   1828 
   1829 
   1830 LInstruction* 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 
   1841 LInstruction* 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 
   1860 LInstruction* 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 
   1870 LInstruction* 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 
   1889 LInstruction* 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 
   1912 LInstruction* 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 
   1925 LInstruction* 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 
   1940 LInstruction* 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 
   1949 LInstruction* 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 
   1957 LInstruction* 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 
   1964 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
   1965   LOperand* string = UseRegisterAtStart(instr->value());
   1966   return DefineAsRegister(new LStringLength(string));
   1967 }
   1968 
   1969 
   1970 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
   1971   return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
   1972 }
   1973 
   1974 
   1975 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
   1976   return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr);
   1977 }
   1978 
   1979 
   1980 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
   1981   return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr);
   1982 }
   1983 
   1984 
   1985 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
   1986   return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr);
   1987 }
   1988 
   1989 
   1990 LInstruction* 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 
   1998 LInstruction* 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 
   2005 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
   2006   int spill_index = chunk()->GetParameterStackSlot(instr->index());
   2007   return DefineAsSpilled(new LParameter, spill_index);
   2008 }
   2009 
   2010 
   2011 LInstruction* 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 
   2021 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
   2022   argument_count_ -= instr->argument_count();
   2023   return MarkAsCall(DefineFixed(new LCallStub, r0), instr);
   2024 }
   2025 
   2026 
   2027 LInstruction* 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 
   2036 LInstruction* 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 
   2045 LInstruction* 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 
   2052 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
   2053   LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
   2054   return MarkAsCall(DefineFixed(result, r0), instr);
   2055 }
   2056 
   2057 
   2058 LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
   2059   return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
   2060 }
   2061 
   2062 
   2063 LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
   2064   return DefineAsRegister(new LIsConstructCall());
   2065 }
   2066 
   2067 
   2068 LInstruction* 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 
   2099 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
   2100   return MarkAsCall(new LStackCheck, instr);
   2101 }
   2102 
   2103 
   2104 LInstruction* 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 
   2117 LInstruction* 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