1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #if V8_TARGET_ARCH_IA32
9 #include "src/hydrogen-osr.h"
10 #include "src/ia32/lithium-codegen-ia32.h"
11 #include "src/lithium-inl.h"
16 #define DEFINE_COMPILE(type) \
17 void L##type::CompileToNative(LCodeGen* generator) { \
18 generator->Do##type(this); \
20 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
25 void LInstruction::VerifyCall() {
26 // Call instructions can use only fixed registers as temporaries and
27 // outputs because all registers are blocked by the calling convention.
28 // Inputs operands must use a fixed register or use-at-start policy or
29 // a non-register policy.
30 DCHECK(Output() == NULL ||
31 LUnallocated::cast(Output())->HasFixedPolicy() ||
32 !LUnallocated::cast(Output())->HasRegisterPolicy());
33 for (UseIterator it(this); !it.Done(); it.Advance()) {
34 LUnallocated* operand = LUnallocated::cast(it.Current());
35 DCHECK(operand->HasFixedPolicy() ||
36 operand->IsUsedAtStart());
38 for (TempIterator it(this); !it.Done(); it.Advance()) {
39 LUnallocated* operand = LUnallocated::cast(it.Current());
40 DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
46 bool LInstruction::HasDoubleRegisterResult() {
47 return HasResult() && result()->IsDoubleRegister();
51 bool LInstruction::HasDoubleRegisterInput() {
52 for (int i = 0; i < InputCount(); i++) {
53 LOperand* op = InputAt(i);
54 if (op != NULL && op->IsDoubleRegister()) {
62 void LInstruction::PrintTo(StringStream* stream) {
63 stream->Add("%s ", this->Mnemonic());
65 PrintOutputOperandTo(stream);
69 if (HasEnvironment()) {
71 environment()->PrintTo(stream);
74 if (HasPointerMap()) {
76 pointer_map()->PrintTo(stream);
81 void LInstruction::PrintDataTo(StringStream* stream) {
83 for (int i = 0; i < InputCount(); i++) {
84 if (i > 0) stream->Add(" ");
85 if (InputAt(i) == NULL) {
88 InputAt(i)->PrintTo(stream);
94 void LInstruction::PrintOutputOperandTo(StringStream* stream) {
95 if (HasResult()) result()->PrintTo(stream);
99 void LLabel::PrintDataTo(StringStream* stream) {
100 LGap::PrintDataTo(stream);
101 LLabel* rep = replacement();
103 stream->Add(" Dead block replaced with B%d", rep->block_id());
108 bool LGap::IsRedundant() const {
109 for (int i = 0; i < 4; i++) {
110 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
119 void LGap::PrintDataTo(StringStream* stream) {
120 for (int i = 0; i < 4; i++) {
122 if (parallel_moves_[i] != NULL) {
123 parallel_moves_[i]->PrintDataTo(stream);
130 const char* LArithmeticD::Mnemonic() const {
132 case Token::ADD: return "add-d";
133 case Token::SUB: return "sub-d";
134 case Token::MUL: return "mul-d";
135 case Token::DIV: return "div-d";
136 case Token::MOD: return "mod-d";
144 const char* LArithmeticT::Mnemonic() const {
146 case Token::ADD: return "add-t";
147 case Token::SUB: return "sub-t";
148 case Token::MUL: return "mul-t";
149 case Token::MOD: return "mod-t";
150 case Token::DIV: return "div-t";
151 case Token::BIT_AND: return "bit-and-t";
152 case Token::BIT_OR: return "bit-or-t";
153 case Token::BIT_XOR: return "bit-xor-t";
154 case Token::ROR: return "ror-t";
155 case Token::SHL: return "sal-t";
156 case Token::SAR: return "sar-t";
157 case Token::SHR: return "shr-t";
165 bool LGoto::HasInterestingComment(LCodeGen* gen) const {
166 return !gen->IsNextEmittedBlock(block_id());
170 void LGoto::PrintDataTo(StringStream* stream) {
171 stream->Add("B%d", block_id());
175 void LBranch::PrintDataTo(StringStream* stream) {
176 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
177 value()->PrintTo(stream);
181 void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
183 left()->PrintTo(stream);
184 stream->Add(" %s ", Token::String(op()));
185 right()->PrintTo(stream);
186 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
190 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
191 stream->Add("if is_object(");
192 value()->PrintTo(stream);
193 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
197 void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
198 stream->Add("if is_string(");
199 value()->PrintTo(stream);
200 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
204 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
205 stream->Add("if is_smi(");
206 value()->PrintTo(stream);
207 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
211 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
212 stream->Add("if is_undetectable(");
213 value()->PrintTo(stream);
214 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
218 void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
219 stream->Add("if string_compare(");
220 left()->PrintTo(stream);
221 right()->PrintTo(stream);
222 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
226 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
227 stream->Add("if has_instance_type(");
228 value()->PrintTo(stream);
229 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
233 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
234 stream->Add("if has_cached_array_index(");
235 value()->PrintTo(stream);
236 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
240 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
241 stream->Add("if class_of_test(");
242 value()->PrintTo(stream);
243 stream->Add(", \"%o\") then B%d else B%d",
244 *hydrogen()->class_name(),
250 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
251 stream->Add("if typeof ");
252 value()->PrintTo(stream);
253 stream->Add(" == \"%s\" then B%d else B%d",
254 hydrogen()->type_literal()->ToCString().get(),
255 true_block_id(), false_block_id());
259 void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
261 function()->PrintTo(stream);
262 stream->Add(".code_entry = ");
263 code_object()->PrintTo(stream);
267 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
269 base_object()->PrintTo(stream);
271 offset()->PrintTo(stream);
275 void LCallJSFunction::PrintDataTo(StringStream* stream) {
277 function()->PrintTo(stream);
278 stream->Add("#%d / ", arity());
282 void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
283 for (int i = 0; i < InputCount(); i++) {
284 InputAt(i)->PrintTo(stream);
287 stream->Add("#%d / ", arity());
291 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
292 context()->PrintTo(stream);
293 stream->Add("[%d]", slot_index());
297 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
298 context()->PrintTo(stream);
299 stream->Add("[%d] <- ", slot_index());
300 value()->PrintTo(stream);
304 void LInvokeFunction::PrintDataTo(StringStream* stream) {
306 context()->PrintTo(stream);
308 function()->PrintTo(stream);
309 stream->Add(" #%d / ", arity());
313 void LCallNew::PrintDataTo(StringStream* stream) {
315 context()->PrintTo(stream);
317 constructor()->PrintTo(stream);
318 stream->Add(" #%d / ", arity());
322 void LCallNewArray::PrintDataTo(StringStream* stream) {
324 context()->PrintTo(stream);
326 constructor()->PrintTo(stream);
327 stream->Add(" #%d / ", arity());
328 ElementsKind kind = hydrogen()->elements_kind();
329 stream->Add(" (%s) ", ElementsKindToString(kind));
333 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
334 arguments()->PrintTo(stream);
336 stream->Add(" length ");
337 length()->PrintTo(stream);
339 stream->Add(" index ");
340 index()->PrintTo(stream);
344 int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
345 // Skip a slot if for a double-width slot.
346 if (kind == DOUBLE_REGISTERS) {
348 spill_slot_count_ |= 1;
351 return spill_slot_count_++;
355 LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
356 int index = GetNextSpillIndex(kind);
357 if (kind == DOUBLE_REGISTERS) {
358 return LDoubleStackSlot::Create(index, zone());
360 DCHECK(kind == GENERAL_REGISTERS);
361 return LStackSlot::Create(index, zone());
366 void LStoreNamedField::PrintDataTo(StringStream* stream) {
367 object()->PrintTo(stream);
369 os << hydrogen()->access() << " <- ";
370 stream->Add(os.c_str());
371 value()->PrintTo(stream);
375 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
376 object()->PrintTo(stream);
378 stream->Add(String::cast(*name())->ToCString().get());
380 value()->PrintTo(stream);
384 void LLoadKeyed::PrintDataTo(StringStream* stream) {
385 elements()->PrintTo(stream);
387 key()->PrintTo(stream);
388 if (hydrogen()->IsDehoisted()) {
389 stream->Add(" + %d]", base_offset());
396 void LStoreKeyed::PrintDataTo(StringStream* stream) {
397 elements()->PrintTo(stream);
399 key()->PrintTo(stream);
400 if (hydrogen()->IsDehoisted()) {
401 stream->Add(" + %d] <-", base_offset());
403 stream->Add("] <- ");
406 if (value() == NULL) {
407 DCHECK(hydrogen()->IsConstantHoleStore() &&
408 hydrogen()->value()->representation().IsDouble());
409 stream->Add("<the hole(nan)>");
411 value()->PrintTo(stream);
416 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
417 object()->PrintTo(stream);
419 key()->PrintTo(stream);
420 stream->Add("] <- ");
421 value()->PrintTo(stream);
425 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
426 object()->PrintTo(stream);
427 stream->Add(" %p -> %p", *original_map(), *transitioned_map());
431 LPlatformChunk* LChunkBuilder::Build() {
433 chunk_ = new(zone()) LPlatformChunk(info(), graph());
434 LPhase phase("L_Building chunk", chunk_);
437 // Reserve the first spill slot for the state of dynamic alignment.
438 if (info()->IsOptimizing()) {
439 int alignment_state_index = chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
440 DCHECK_EQ(alignment_state_index, 0);
441 USE(alignment_state_index);
444 // If compiling for OSR, reserve space for the unoptimized frame,
445 // which will be subsumed into this frame.
446 if (graph()->has_osr()) {
447 for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
448 chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
452 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
453 for (int i = 0; i < blocks->length(); i++) {
454 HBasicBlock* next = NULL;
455 if (i < blocks->length() - 1) next = blocks->at(i + 1);
456 DoBasicBlock(blocks->at(i), next);
457 if (is_aborted()) return NULL;
464 void LChunkBuilder::Abort(BailoutReason reason) {
465 info()->set_bailout_reason(reason);
470 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
471 return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
472 Register::ToAllocationIndex(reg));
476 LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
477 return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
478 XMMRegister::ToAllocationIndex(reg));
482 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
483 return Use(value, ToUnallocated(fixed_register));
487 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
488 return Use(value, ToUnallocated(reg));
492 LOperand* LChunkBuilder::UseRegister(HValue* value) {
493 return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
497 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
499 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
500 LUnallocated::USED_AT_START));
504 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
505 return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
509 LOperand* LChunkBuilder::Use(HValue* value) {
510 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
514 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
515 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
516 LUnallocated::USED_AT_START));
520 static inline bool CanBeImmediateConstant(HValue* value) {
521 return value->IsConstant() && HConstant::cast(value)->NotInNewSpace();
525 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
526 return CanBeImmediateConstant(value)
527 ? chunk_->DefineConstantOperand(HConstant::cast(value))
532 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
533 return CanBeImmediateConstant(value)
534 ? chunk_->DefineConstantOperand(HConstant::cast(value))
539 LOperand* LChunkBuilder::UseFixedOrConstant(HValue* value,
540 Register fixed_register) {
541 return CanBeImmediateConstant(value)
542 ? chunk_->DefineConstantOperand(HConstant::cast(value))
543 : UseFixed(value, fixed_register);
547 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
548 return CanBeImmediateConstant(value)
549 ? chunk_->DefineConstantOperand(HConstant::cast(value))
550 : UseRegister(value);
554 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
555 return CanBeImmediateConstant(value)
556 ? chunk_->DefineConstantOperand(HConstant::cast(value))
557 : UseRegisterAtStart(value);
561 LOperand* LChunkBuilder::UseConstant(HValue* value) {
562 return chunk_->DefineConstantOperand(HConstant::cast(value));
566 LOperand* LChunkBuilder::UseAny(HValue* value) {
567 return value->IsConstant()
568 ? chunk_->DefineConstantOperand(HConstant::cast(value))
569 : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
573 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
574 if (value->EmitAtUses()) {
575 HInstruction* instr = HInstruction::cast(value);
576 VisitInstruction(instr);
578 operand->set_virtual_register(value->id());
583 LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
584 LUnallocated* result) {
585 result->set_virtual_register(current_instruction_->id());
586 instr->set_result(result);
591 LInstruction* LChunkBuilder::DefineAsRegister(
592 LTemplateResultInstruction<1>* instr) {
594 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
598 LInstruction* LChunkBuilder::DefineAsSpilled(
599 LTemplateResultInstruction<1>* instr,
602 new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
606 LInstruction* LChunkBuilder::DefineSameAsFirst(
607 LTemplateResultInstruction<1>* instr) {
609 new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
613 LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
615 return Define(instr, ToUnallocated(reg));
619 LInstruction* LChunkBuilder::DefineFixedDouble(
620 LTemplateResultInstruction<1>* instr,
622 return Define(instr, ToUnallocated(reg));
626 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
627 HEnvironment* hydrogen_env = current_block_->last_environment();
628 int argument_index_accumulator = 0;
629 ZoneList<HValue*> objects_to_materialize(0, zone());
630 instr->set_environment(CreateEnvironment(hydrogen_env,
631 &argument_index_accumulator,
632 &objects_to_materialize));
637 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
638 HInstruction* hinstr,
639 CanDeoptimize can_deoptimize) {
640 info()->MarkAsNonDeferredCalling();
646 instr = AssignPointerMap(instr);
648 // If instruction does not have side-effects lazy deoptimization
649 // after the call will try to deoptimize to the point before the call.
650 // Thus we still need to attach environment to this call even if
651 // call sequence can not deoptimize eagerly.
652 bool needs_environment =
653 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
654 !hinstr->HasObservableSideEffects();
655 if (needs_environment && !instr->HasEnvironment()) {
656 instr = AssignEnvironment(instr);
657 // We can't really figure out if the environment is needed or not.
658 instr->environment()->set_has_been_used();
665 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
666 DCHECK(!instr->HasPointerMap());
667 instr->set_pointer_map(new(zone()) LPointerMap(zone()));
672 LUnallocated* LChunkBuilder::TempRegister() {
673 LUnallocated* operand =
674 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
675 int vreg = allocator_->GetVirtualRegister();
676 if (!allocator_->AllocationOk()) {
677 Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
680 operand->set_virtual_register(vreg);
685 LOperand* LChunkBuilder::FixedTemp(Register reg) {
686 LUnallocated* operand = ToUnallocated(reg);
687 DCHECK(operand->HasFixedPolicy());
692 LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
693 LUnallocated* operand = ToUnallocated(reg);
694 DCHECK(operand->HasFixedPolicy());
699 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
700 return new(zone()) LLabel(instr->block());
704 LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
705 return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
709 LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
715 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
716 return AssignEnvironment(new(zone()) LDeoptimize);
720 LInstruction* LChunkBuilder::DoShift(Token::Value op,
721 HBitwiseBinaryOperation* instr) {
722 if (instr->representation().IsSmiOrInteger32()) {
723 DCHECK(instr->left()->representation().Equals(instr->representation()));
724 DCHECK(instr->right()->representation().Equals(instr->representation()));
725 LOperand* left = UseRegisterAtStart(instr->left());
727 HValue* right_value = instr->right();
728 LOperand* right = NULL;
729 int constant_value = 0;
730 bool does_deopt = false;
731 if (right_value->IsConstant()) {
732 HConstant* constant = HConstant::cast(right_value);
733 right = chunk_->DefineConstantOperand(constant);
734 constant_value = constant->Integer32Value() & 0x1f;
735 // Left shifts can deoptimize if we shift by > 0 and the result cannot be
737 if (instr->representation().IsSmi() && constant_value > 0) {
738 does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
741 right = UseFixed(right_value, ecx);
744 // Shift operations can only deoptimize if we do a logical shift by 0 and
745 // the result cannot be truncated to int32.
746 if (op == Token::SHR && constant_value == 0) {
747 if (FLAG_opt_safe_uint32_operations) {
748 does_deopt = !instr->CheckFlag(HInstruction::kUint32);
750 does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
754 LInstruction* result =
755 DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
756 return does_deopt ? AssignEnvironment(result) : result;
758 return DoArithmeticT(op, instr);
763 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
764 HArithmeticBinaryOperation* instr) {
765 DCHECK(instr->representation().IsDouble());
766 DCHECK(instr->left()->representation().IsDouble());
767 DCHECK(instr->right()->representation().IsDouble());
768 if (op == Token::MOD) {
769 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
770 LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
771 LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
772 return MarkAsCall(DefineSameAsFirst(result), instr);
774 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
775 LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
776 LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
777 return DefineSameAsFirst(result);
782 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
783 HBinaryOperation* instr) {
784 HValue* left = instr->left();
785 HValue* right = instr->right();
786 DCHECK(left->representation().IsTagged());
787 DCHECK(right->representation().IsTagged());
788 LOperand* context = UseFixed(instr->context(), esi);
789 LOperand* left_operand = UseFixed(left, edx);
790 LOperand* right_operand = UseFixed(right, eax);
791 LArithmeticT* result =
792 new(zone()) LArithmeticT(op, context, left_operand, right_operand);
793 return MarkAsCall(DefineFixed(result, eax), instr);
797 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
798 DCHECK(is_building());
799 current_block_ = block;
800 next_block_ = next_block;
801 if (block->IsStartBlock()) {
802 block->UpdateEnvironment(graph_->start_environment());
804 } else if (block->predecessors()->length() == 1) {
805 // We have a single predecessor => copy environment and outgoing
806 // argument count from the predecessor.
807 DCHECK(block->phis()->length() == 0);
808 HBasicBlock* pred = block->predecessors()->at(0);
809 HEnvironment* last_environment = pred->last_environment();
810 DCHECK(last_environment != NULL);
811 // Only copy the environment, if it is later used again.
812 if (pred->end()->SecondSuccessor() == NULL) {
813 DCHECK(pred->end()->FirstSuccessor() == block);
815 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
816 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
817 last_environment = last_environment->Copy();
820 block->UpdateEnvironment(last_environment);
821 DCHECK(pred->argument_count() >= 0);
822 argument_count_ = pred->argument_count();
824 // We are at a state join => process phis.
825 HBasicBlock* pred = block->predecessors()->at(0);
826 // No need to copy the environment, it cannot be used later.
827 HEnvironment* last_environment = pred->last_environment();
828 for (int i = 0; i < block->phis()->length(); ++i) {
829 HPhi* phi = block->phis()->at(i);
830 if (phi->HasMergedIndex()) {
831 last_environment->SetValueAt(phi->merged_index(), phi);
834 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
835 if (block->deleted_phis()->at(i) < last_environment->length()) {
836 last_environment->SetValueAt(block->deleted_phis()->at(i),
837 graph_->GetConstantUndefined());
840 block->UpdateEnvironment(last_environment);
841 // Pick up the outgoing argument count of one of the predecessors.
842 argument_count_ = pred->argument_count();
844 HInstruction* current = block->first();
845 int start = chunk_->instructions()->length();
846 while (current != NULL && !is_aborted()) {
847 // Code for constants in registers is generated lazily.
848 if (!current->EmitAtUses()) {
849 VisitInstruction(current);
851 current = current->next();
853 int end = chunk_->instructions()->length() - 1;
855 block->set_first_instruction_index(start);
856 block->set_last_instruction_index(end);
858 block->set_argument_count(argument_count_);
860 current_block_ = NULL;
864 void LChunkBuilder::VisitInstruction(HInstruction* current) {
865 HInstruction* old_current = current_instruction_;
866 current_instruction_ = current;
868 LInstruction* instr = NULL;
869 if (current->CanReplaceWithDummyUses()) {
870 if (current->OperandCount() == 0) {
871 instr = DefineAsRegister(new(zone()) LDummy());
873 DCHECK(!current->OperandAt(0)->IsControlInstruction());
874 instr = DefineAsRegister(new(zone())
875 LDummyUse(UseAny(current->OperandAt(0))));
877 for (int i = 1; i < current->OperandCount(); ++i) {
878 if (current->OperandAt(i)->IsControlInstruction()) continue;
879 LInstruction* dummy =
880 new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
881 dummy->set_hydrogen_value(current);
882 chunk_->AddInstruction(dummy, current_block_);
885 HBasicBlock* successor;
886 if (current->IsControlInstruction() &&
887 HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
889 instr = new(zone()) LGoto(successor);
891 instr = current->CompileToLithium(this);
895 argument_count_ += current->argument_delta();
896 DCHECK(argument_count_ >= 0);
899 AddInstruction(instr, current);
902 current_instruction_ = old_current;
906 void LChunkBuilder::AddInstruction(LInstruction* instr,
907 HInstruction* hydrogen_val) {
908 // Associate the hydrogen instruction first, since we may need it for
909 // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
910 instr->set_hydrogen_value(hydrogen_val);
913 // Make sure that the lithium instruction has either no fixed register
914 // constraints in temps or the result OR no uses that are only used at
915 // start. If this invariant doesn't hold, the register allocator can decide
916 // to insert a split of a range immediately before the instruction due to an
917 // already allocated register needing to be used for the instruction's fixed
918 // register constraint. In this case, The register allocator won't see an
919 // interference between the split child and the use-at-start (it would if
920 // the it was just a plain use), so it is free to move the split child into
921 // the same register that is used for the use-at-start.
922 // See https://code.google.com/p/chromium/issues/detail?id=201590
923 if (!(instr->ClobbersRegisters() &&
924 instr->ClobbersDoubleRegisters(isolate()))) {
926 int used_at_start = 0;
927 for (UseIterator it(instr); !it.Done(); it.Advance()) {
928 LUnallocated* operand = LUnallocated::cast(it.Current());
929 if (operand->IsUsedAtStart()) ++used_at_start;
931 if (instr->Output() != NULL) {
932 if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
934 for (TempIterator it(instr); !it.Done(); it.Advance()) {
935 LUnallocated* operand = LUnallocated::cast(it.Current());
936 if (operand->HasFixedPolicy()) ++fixed;
938 DCHECK(fixed == 0 || used_at_start == 0);
942 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
943 instr = AssignPointerMap(instr);
945 if (FLAG_stress_environments && !instr->HasEnvironment()) {
946 instr = AssignEnvironment(instr);
948 chunk_->AddInstruction(instr, current_block_);
950 if (instr->IsCall()) {
951 HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
952 LInstruction* instruction_needing_environment = NULL;
953 if (hydrogen_val->HasObservableSideEffects()) {
954 HSimulate* sim = HSimulate::cast(hydrogen_val->next());
955 instruction_needing_environment = instr;
956 sim->ReplayEnvironment(current_block_->last_environment());
957 hydrogen_value_for_lazy_bailout = sim;
959 LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
960 bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
961 chunk_->AddInstruction(bailout, current_block_);
962 if (instruction_needing_environment != NULL) {
963 // Store the lazy deopt environment with the instruction if needed.
964 // Right now it is only used for LInstanceOfKnownGlobal.
965 instruction_needing_environment->
966 SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
972 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
973 return new(zone()) LGoto(instr->FirstSuccessor());
977 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
978 HValue* value = instr->value();
979 Representation r = value->representation();
980 HType type = value->type();
981 ToBooleanStub::Types expected = instr->expected_input_types();
982 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
984 bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
985 type.IsJSArray() || type.IsHeapNumber() || type.IsString();
986 LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
987 LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
989 ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
990 !expected.IsGeneric())) {
991 branch = AssignEnvironment(branch);
997 LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
998 return new(zone()) LDebugBreak();
1002 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1003 DCHECK(instr->value()->representation().IsTagged());
1004 LOperand* value = UseRegisterAtStart(instr->value());
1005 return new(zone()) LCmpMapAndBranch(value);
1009 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1010 info()->MarkAsRequiresFrame();
1011 return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
1015 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1016 info()->MarkAsRequiresFrame();
1017 return DefineAsRegister(new(zone()) LArgumentsElements);
1021 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1022 LOperand* left = UseFixed(instr->left(), InstanceofStub::left());
1023 LOperand* right = UseFixed(instr->right(), InstanceofStub::right());
1024 LOperand* context = UseFixed(instr->context(), esi);
1025 LInstanceOf* result = new(zone()) LInstanceOf(context, left, right);
1026 return MarkAsCall(DefineFixed(result, eax), instr);
1030 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1031 HInstanceOfKnownGlobal* instr) {
1032 LInstanceOfKnownGlobal* result =
1033 new(zone()) LInstanceOfKnownGlobal(
1034 UseFixed(instr->context(), esi),
1035 UseFixed(instr->left(), InstanceofStub::left()),
1037 return MarkAsCall(DefineFixed(result, eax), instr);
1041 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
1042 LOperand* receiver = UseRegister(instr->receiver());
1043 LOperand* function = UseRegister(instr->function());
1044 LOperand* temp = TempRegister();
1045 LWrapReceiver* result =
1046 new(zone()) LWrapReceiver(receiver, function, temp);
1047 return AssignEnvironment(DefineSameAsFirst(result));
1051 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1052 LOperand* function = UseFixed(instr->function(), edi);
1053 LOperand* receiver = UseFixed(instr->receiver(), eax);
1054 LOperand* length = UseFixed(instr->length(), ebx);
1055 LOperand* elements = UseFixed(instr->elements(), ecx);
1056 LApplyArguments* result = new(zone()) LApplyArguments(function,
1060 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
1064 LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
1065 int argc = instr->OperandCount();
1066 for (int i = 0; i < argc; ++i) {
1067 LOperand* argument = UseAny(instr->argument(i));
1068 AddInstruction(new(zone()) LPushArgument(argument), instr);
1074 LInstruction* LChunkBuilder::DoStoreCodeEntry(
1075 HStoreCodeEntry* store_code_entry) {
1076 LOperand* function = UseRegister(store_code_entry->function());
1077 LOperand* code_object = UseTempRegister(store_code_entry->code_object());
1078 return new(zone()) LStoreCodeEntry(function, code_object);
1082 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
1083 HInnerAllocatedObject* instr) {
1084 LOperand* base_object = UseRegisterAtStart(instr->base_object());
1085 LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
1086 return DefineAsRegister(
1087 new(zone()) LInnerAllocatedObject(base_object, offset));
1091 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1092 return instr->HasNoUses()
1094 : DefineAsRegister(new(zone()) LThisFunction);
1098 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1099 if (instr->HasNoUses()) return NULL;
1101 if (info()->IsStub()) {
1102 return DefineFixed(new(zone()) LContext, esi);
1105 return DefineAsRegister(new(zone()) LContext);
1109 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1110 LOperand* context = UseFixed(instr->context(), esi);
1111 return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1115 LInstruction* LChunkBuilder::DoCallJSFunction(
1116 HCallJSFunction* instr) {
1117 LOperand* function = UseFixed(instr->function(), edi);
1119 LCallJSFunction* result = new(zone()) LCallJSFunction(function);
1121 return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1125 LInstruction* LChunkBuilder::DoCallWithDescriptor(
1126 HCallWithDescriptor* instr) {
1127 const InterfaceDescriptor* descriptor = instr->descriptor();
1128 LOperand* target = UseRegisterOrConstantAtStart(instr->target());
1129 ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1130 ops.Add(target, zone());
1131 for (int i = 1; i < instr->OperandCount(); i++) {
1132 LOperand* op = UseFixed(instr->OperandAt(i),
1133 descriptor->GetParameterRegister(i - 1));
1134 ops.Add(op, zone());
1137 LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
1138 descriptor, ops, zone());
1139 return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1143 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1144 LOperand* context = UseFixed(instr->context(), esi);
1145 LOperand* function = UseFixed(instr->function(), edi);
1146 LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1147 return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1151 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1152 switch (instr->op()) {
1154 return DoMathFloor(instr);
1156 return DoMathRound(instr);
1158 return DoMathFround(instr);
1160 return DoMathAbs(instr);
1162 return DoMathLog(instr);
1164 return DoMathExp(instr);
1166 return DoMathSqrt(instr);
1168 return DoMathPowHalf(instr);
1170 return DoMathClz32(instr);
1178 LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1179 LOperand* input = UseRegisterAtStart(instr->value());
1180 LMathFloor* result = new(zone()) LMathFloor(input);
1181 return AssignEnvironment(DefineAsRegister(result));
1185 LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1186 LOperand* input = UseRegister(instr->value());
1187 LOperand* temp = FixedTemp(xmm4);
1188 LMathRound* result = new(zone()) LMathRound(input, temp);
1189 return AssignEnvironment(DefineAsRegister(result));
1193 LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1194 LOperand* input = UseRegister(instr->value());
1195 LMathFround* result = new (zone()) LMathFround(input);
1196 return DefineAsRegister(result);
1200 LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1201 LOperand* context = UseAny(instr->context()); // Deferred use.
1202 LOperand* input = UseRegisterAtStart(instr->value());
1203 LInstruction* result =
1204 DefineSameAsFirst(new(zone()) LMathAbs(context, input));
1205 Representation r = instr->value()->representation();
1206 if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1207 if (!r.IsDouble()) result = AssignEnvironment(result);
1212 LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1213 DCHECK(instr->representation().IsDouble());
1214 DCHECK(instr->value()->representation().IsDouble());
1215 LOperand* input = UseRegisterAtStart(instr->value());
1216 return MarkAsCall(DefineSameAsFirst(new(zone()) LMathLog(input)), instr);
1220 LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1221 LOperand* input = UseRegisterAtStart(instr->value());
1222 LMathClz32* result = new(zone()) LMathClz32(input);
1223 return DefineAsRegister(result);
1227 LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1228 DCHECK(instr->representation().IsDouble());
1229 DCHECK(instr->value()->representation().IsDouble());
1230 LOperand* value = UseTempRegister(instr->value());
1231 LOperand* temp1 = TempRegister();
1232 LOperand* temp2 = TempRegister();
1233 LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
1234 return DefineAsRegister(result);
1238 LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1239 LOperand* input = UseAtStart(instr->value());
1240 return DefineAsRegister(new(zone()) LMathSqrt(input));
1244 LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1245 LOperand* input = UseRegisterAtStart(instr->value());
1246 LOperand* temp = TempRegister();
1247 LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
1248 return DefineSameAsFirst(result);
1252 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1253 LOperand* context = UseFixed(instr->context(), esi);
1254 LOperand* constructor = UseFixed(instr->constructor(), edi);
1255 LCallNew* result = new(zone()) LCallNew(context, constructor);
1256 return MarkAsCall(DefineFixed(result, eax), instr);
1260 LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1261 LOperand* context = UseFixed(instr->context(), esi);
1262 LOperand* constructor = UseFixed(instr->constructor(), edi);
1263 LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1264 return MarkAsCall(DefineFixed(result, eax), instr);
1268 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1269 LOperand* context = UseFixed(instr->context(), esi);
1270 LOperand* function = UseFixed(instr->function(), edi);
1271 LCallFunction* call = new(zone()) LCallFunction(context, function);
1272 return MarkAsCall(DefineFixed(call, eax), instr);
1276 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1277 LOperand* context = UseFixed(instr->context(), esi);
1278 return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), eax), instr);
1282 LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1283 return DoShift(Token::ROR, instr);
1287 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1288 return DoShift(Token::SHR, instr);
1292 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1293 return DoShift(Token::SAR, instr);
1297 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1298 return DoShift(Token::SHL, instr);
1302 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1303 if (instr->representation().IsSmiOrInteger32()) {
1304 DCHECK(instr->left()->representation().Equals(instr->representation()));
1305 DCHECK(instr->right()->representation().Equals(instr->representation()));
1306 DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1308 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1309 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1310 return DefineSameAsFirst(new(zone()) LBitI(left, right));
1312 return DoArithmeticT(instr->op(), instr);
1317 LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1318 DCHECK(instr->representation().IsSmiOrInteger32());
1319 DCHECK(instr->left()->representation().Equals(instr->representation()));
1320 DCHECK(instr->right()->representation().Equals(instr->representation()));
1321 LOperand* dividend = UseRegister(instr->left());
1322 int32_t divisor = instr->right()->GetInteger32Constant();
1323 LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
1324 dividend, divisor));
1325 if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1326 (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1327 (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1328 divisor != 1 && divisor != -1)) {
1329 result = AssignEnvironment(result);
1335 LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1336 DCHECK(instr->representation().IsInteger32());
1337 DCHECK(instr->left()->representation().Equals(instr->representation()));
1338 DCHECK(instr->right()->representation().Equals(instr->representation()));
1339 LOperand* dividend = UseRegister(instr->left());
1340 int32_t divisor = instr->right()->GetInteger32Constant();
1341 LOperand* temp1 = FixedTemp(eax);
1342 LOperand* temp2 = FixedTemp(edx);
1343 LInstruction* result = DefineFixed(new(zone()) LDivByConstI(
1344 dividend, divisor, temp1, temp2), edx);
1346 (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1347 !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1348 result = AssignEnvironment(result);
1354 LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1355 DCHECK(instr->representation().IsSmiOrInteger32());
1356 DCHECK(instr->left()->representation().Equals(instr->representation()));
1357 DCHECK(instr->right()->representation().Equals(instr->representation()));
1358 LOperand* dividend = UseFixed(instr->left(), eax);
1359 LOperand* divisor = UseRegister(instr->right());
1360 LOperand* temp = FixedTemp(edx);
1361 LInstruction* result = DefineFixed(new(zone()) LDivI(
1362 dividend, divisor, temp), eax);
1363 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1364 instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1365 instr->CheckFlag(HValue::kCanOverflow) ||
1366 !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1367 result = AssignEnvironment(result);
1373 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1374 if (instr->representation().IsSmiOrInteger32()) {
1375 if (instr->RightIsPowerOf2()) {
1376 return DoDivByPowerOf2I(instr);
1377 } else if (instr->right()->IsConstant()) {
1378 return DoDivByConstI(instr);
1380 return DoDivI(instr);
1382 } else if (instr->representation().IsDouble()) {
1383 return DoArithmeticD(Token::DIV, instr);
1385 return DoArithmeticT(Token::DIV, instr);
1390 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1391 LOperand* dividend = UseRegisterAtStart(instr->left());
1392 int32_t divisor = instr->right()->GetInteger32Constant();
1393 LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
1394 dividend, divisor));
1395 if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1396 (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1397 result = AssignEnvironment(result);
1403 LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1404 DCHECK(instr->representation().IsInteger32());
1405 DCHECK(instr->left()->representation().Equals(instr->representation()));
1406 DCHECK(instr->right()->representation().Equals(instr->representation()));
1407 LOperand* dividend = UseRegister(instr->left());
1408 int32_t divisor = instr->right()->GetInteger32Constant();
1409 LOperand* temp1 = FixedTemp(eax);
1410 LOperand* temp2 = FixedTemp(edx);
1412 ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1413 (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
1414 NULL : TempRegister();
1415 LInstruction* result =
1416 DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
1423 (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1424 result = AssignEnvironment(result);
1430 LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1431 DCHECK(instr->representation().IsSmiOrInteger32());
1432 DCHECK(instr->left()->representation().Equals(instr->representation()));
1433 DCHECK(instr->right()->representation().Equals(instr->representation()));
1434 LOperand* dividend = UseFixed(instr->left(), eax);
1435 LOperand* divisor = UseRegister(instr->right());
1436 LOperand* temp = FixedTemp(edx);
1437 LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
1438 dividend, divisor, temp), eax);
1439 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1440 instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1441 instr->CheckFlag(HValue::kCanOverflow)) {
1442 result = AssignEnvironment(result);
1448 LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1449 if (instr->RightIsPowerOf2()) {
1450 return DoFlooringDivByPowerOf2I(instr);
1451 } else if (instr->right()->IsConstant()) {
1452 return DoFlooringDivByConstI(instr);
1454 return DoFlooringDivI(instr);
1459 LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1460 DCHECK(instr->representation().IsSmiOrInteger32());
1461 DCHECK(instr->left()->representation().Equals(instr->representation()));
1462 DCHECK(instr->right()->representation().Equals(instr->representation()));
1463 LOperand* dividend = UseRegisterAtStart(instr->left());
1464 int32_t divisor = instr->right()->GetInteger32Constant();
1465 LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
1466 dividend, divisor));
1467 if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1468 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1469 result = AssignEnvironment(result);
1475 LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1476 DCHECK(instr->representation().IsSmiOrInteger32());
1477 DCHECK(instr->left()->representation().Equals(instr->representation()));
1478 DCHECK(instr->right()->representation().Equals(instr->representation()));
1479 LOperand* dividend = UseRegister(instr->left());
1480 int32_t divisor = instr->right()->GetInteger32Constant();
1481 LOperand* temp1 = FixedTemp(eax);
1482 LOperand* temp2 = FixedTemp(edx);
1483 LInstruction* result = DefineFixed(new(zone()) LModByConstI(
1484 dividend, divisor, temp1, temp2), eax);
1485 if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1486 result = AssignEnvironment(result);
1492 LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1493 DCHECK(instr->representation().IsSmiOrInteger32());
1494 DCHECK(instr->left()->representation().Equals(instr->representation()));
1495 DCHECK(instr->right()->representation().Equals(instr->representation()));
1496 LOperand* dividend = UseFixed(instr->left(), eax);
1497 LOperand* divisor = UseRegister(instr->right());
1498 LOperand* temp = FixedTemp(edx);
1499 LInstruction* result = DefineFixed(new(zone()) LModI(
1500 dividend, divisor, temp), edx);
1501 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1502 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1503 result = AssignEnvironment(result);
1509 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1510 if (instr->representation().IsSmiOrInteger32()) {
1511 if (instr->RightIsPowerOf2()) {
1512 return DoModByPowerOf2I(instr);
1513 } else if (instr->right()->IsConstant()) {
1514 return DoModByConstI(instr);
1516 return DoModI(instr);
1518 } else if (instr->representation().IsDouble()) {
1519 return DoArithmeticD(Token::MOD, instr);
1521 return DoArithmeticT(Token::MOD, instr);
1526 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1527 if (instr->representation().IsSmiOrInteger32()) {
1528 DCHECK(instr->left()->representation().Equals(instr->representation()));
1529 DCHECK(instr->right()->representation().Equals(instr->representation()));
1530 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1531 LOperand* right = UseOrConstant(instr->BetterRightOperand());
1532 LOperand* temp = NULL;
1533 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1534 temp = TempRegister();
1536 LMulI* mul = new(zone()) LMulI(left, right, temp);
1537 if (instr->CheckFlag(HValue::kCanOverflow) ||
1538 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1539 AssignEnvironment(mul);
1541 return DefineSameAsFirst(mul);
1542 } else if (instr->representation().IsDouble()) {
1543 return DoArithmeticD(Token::MUL, instr);
1545 return DoArithmeticT(Token::MUL, instr);
1550 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1551 if (instr->representation().IsSmiOrInteger32()) {
1552 DCHECK(instr->left()->representation().Equals(instr->representation()));
1553 DCHECK(instr->right()->representation().Equals(instr->representation()));
1554 LOperand* left = UseRegisterAtStart(instr->left());
1555 LOperand* right = UseOrConstantAtStart(instr->right());
1556 LSubI* sub = new(zone()) LSubI(left, right);
1557 LInstruction* result = DefineSameAsFirst(sub);
1558 if (instr->CheckFlag(HValue::kCanOverflow)) {
1559 result = AssignEnvironment(result);
1562 } else if (instr->representation().IsDouble()) {
1563 return DoArithmeticD(Token::SUB, instr);
1565 return DoArithmeticT(Token::SUB, instr);
1570 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1571 if (instr->representation().IsSmiOrInteger32()) {
1572 DCHECK(instr->left()->representation().Equals(instr->representation()));
1573 DCHECK(instr->right()->representation().Equals(instr->representation()));
1574 // Check to see if it would be advantageous to use an lea instruction rather
1575 // than an add. This is the case when no overflow check is needed and there
1576 // are multiple uses of the add's inputs, so using a 3-register add will
1577 // preserve all input values for later uses.
1578 bool use_lea = LAddI::UseLea(instr);
1579 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1580 HValue* right_candidate = instr->BetterRightOperand();
1581 LOperand* right = use_lea
1582 ? UseRegisterOrConstantAtStart(right_candidate)
1583 : UseOrConstantAtStart(right_candidate);
1584 LAddI* add = new(zone()) LAddI(left, right);
1585 bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1586 LInstruction* result = use_lea
1587 ? DefineAsRegister(add)
1588 : DefineSameAsFirst(add);
1590 result = AssignEnvironment(result);
1593 } else if (instr->representation().IsDouble()) {
1594 return DoArithmeticD(Token::ADD, instr);
1595 } else if (instr->representation().IsExternal()) {
1596 DCHECK(instr->left()->representation().IsExternal());
1597 DCHECK(instr->right()->representation().IsInteger32());
1598 DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1599 bool use_lea = LAddI::UseLea(instr);
1600 LOperand* left = UseRegisterAtStart(instr->left());
1601 HValue* right_candidate = instr->right();
1602 LOperand* right = use_lea
1603 ? UseRegisterOrConstantAtStart(right_candidate)
1604 : UseOrConstantAtStart(right_candidate);
1605 LAddI* add = new(zone()) LAddI(left, right);
1606 LInstruction* result = use_lea
1607 ? DefineAsRegister(add)
1608 : DefineSameAsFirst(add);
1611 return DoArithmeticT(Token::ADD, instr);
1616 LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1617 LOperand* left = NULL;
1618 LOperand* right = NULL;
1619 if (instr->representation().IsSmiOrInteger32()) {
1620 DCHECK(instr->left()->representation().Equals(instr->representation()));
1621 DCHECK(instr->right()->representation().Equals(instr->representation()));
1622 left = UseRegisterAtStart(instr->BetterLeftOperand());
1623 right = UseOrConstantAtStart(instr->BetterRightOperand());
1625 DCHECK(instr->representation().IsDouble());
1626 DCHECK(instr->left()->representation().IsDouble());
1627 DCHECK(instr->right()->representation().IsDouble());
1628 left = UseRegisterAtStart(instr->left());
1629 right = UseRegisterAtStart(instr->right());
1631 LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
1632 return DefineSameAsFirst(minmax);
1636 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1637 DCHECK(instr->representation().IsDouble());
1638 // We call a C function for double power. It can't trigger a GC.
1639 // We need to use fixed result register for the call.
1640 Representation exponent_type = instr->right()->representation();
1641 DCHECK(instr->left()->representation().IsDouble());
1642 LOperand* left = UseFixedDouble(instr->left(), xmm2);
1643 LOperand* right = exponent_type.IsDouble() ?
1644 UseFixedDouble(instr->right(), xmm1) :
1645 UseFixed(instr->right(), eax);
1646 LPower* result = new(zone()) LPower(left, right);
1647 return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1648 CAN_DEOPTIMIZE_EAGERLY);
1652 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1653 DCHECK(instr->left()->representation().IsSmiOrTagged());
1654 DCHECK(instr->right()->representation().IsSmiOrTagged());
1655 LOperand* context = UseFixed(instr->context(), esi);
1656 LOperand* left = UseFixed(instr->left(), edx);
1657 LOperand* right = UseFixed(instr->right(), eax);
1658 LCmpT* result = new(zone()) LCmpT(context, left, right);
1659 return MarkAsCall(DefineFixed(result, eax), instr);
1663 LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1664 HCompareNumericAndBranch* instr) {
1665 Representation r = instr->representation();
1666 if (r.IsSmiOrInteger32()) {
1667 DCHECK(instr->left()->representation().Equals(r));
1668 DCHECK(instr->right()->representation().Equals(r));
1669 LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1670 LOperand* right = UseOrConstantAtStart(instr->right());
1671 return new(zone()) LCompareNumericAndBranch(left, right);
1673 DCHECK(r.IsDouble());
1674 DCHECK(instr->left()->representation().IsDouble());
1675 DCHECK(instr->right()->representation().IsDouble());
1678 if (CanBeImmediateConstant(instr->left()) &&
1679 CanBeImmediateConstant(instr->right())) {
1680 // The code generator requires either both inputs to be constant
1681 // operands, or neither.
1682 left = UseConstant(instr->left());
1683 right = UseConstant(instr->right());
1685 left = UseRegisterAtStart(instr->left());
1686 right = UseRegisterAtStart(instr->right());
1688 return new(zone()) LCompareNumericAndBranch(left, right);
1693 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1694 HCompareObjectEqAndBranch* instr) {
1695 LOperand* left = UseRegisterAtStart(instr->left());
1696 LOperand* right = UseOrConstantAtStart(instr->right());
1697 return new(zone()) LCmpObjectEqAndBranch(left, right);
1701 LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1702 HCompareHoleAndBranch* instr) {
1703 LOperand* value = UseRegisterAtStart(instr->value());
1704 return new(zone()) LCmpHoleAndBranch(value);
1708 LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
1709 HCompareMinusZeroAndBranch* instr) {
1710 LOperand* value = UseRegister(instr->value());
1711 LOperand* scratch = TempRegister();
1712 return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
1716 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1717 DCHECK(instr->value()->representation().IsSmiOrTagged());
1718 LOperand* temp = TempRegister();
1719 return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp);
1723 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1724 DCHECK(instr->value()->representation().IsTagged());
1725 LOperand* temp = TempRegister();
1726 return new(zone()) LIsStringAndBranch(UseRegister(instr->value()), temp);
1730 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1731 DCHECK(instr->value()->representation().IsTagged());
1732 return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1736 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1737 HIsUndetectableAndBranch* instr) {
1738 DCHECK(instr->value()->representation().IsTagged());
1739 return new(zone()) LIsUndetectableAndBranch(
1740 UseRegisterAtStart(instr->value()), TempRegister());
1744 LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1745 HStringCompareAndBranch* instr) {
1746 DCHECK(instr->left()->representation().IsTagged());
1747 DCHECK(instr->right()->representation().IsTagged());
1748 LOperand* context = UseFixed(instr->context(), esi);
1749 LOperand* left = UseFixed(instr->left(), edx);
1750 LOperand* right = UseFixed(instr->right(), eax);
1752 LStringCompareAndBranch* result = new(zone())
1753 LStringCompareAndBranch(context, left, right);
1755 return MarkAsCall(result, instr);
1759 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1760 HHasInstanceTypeAndBranch* instr) {
1761 DCHECK(instr->value()->representation().IsTagged());
1762 return new(zone()) LHasInstanceTypeAndBranch(
1763 UseRegisterAtStart(instr->value()),
1768 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1769 HGetCachedArrayIndex* instr) {
1770 DCHECK(instr->value()->representation().IsTagged());
1771 LOperand* value = UseRegisterAtStart(instr->value());
1773 return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
1777 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1778 HHasCachedArrayIndexAndBranch* instr) {
1779 DCHECK(instr->value()->representation().IsTagged());
1780 return new(zone()) LHasCachedArrayIndexAndBranch(
1781 UseRegisterAtStart(instr->value()));
1785 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1786 HClassOfTestAndBranch* instr) {
1787 DCHECK(instr->value()->representation().IsTagged());
1788 return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()),
1794 LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
1795 LOperand* map = UseRegisterAtStart(instr->value());
1796 return DefineAsRegister(new(zone()) LMapEnumLength(map));
1800 LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
1801 LOperand* date = UseFixed(instr->value(), eax);
1802 LDateField* result =
1803 new(zone()) LDateField(date, FixedTemp(ecx), instr->index());
1804 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
1808 LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1809 LOperand* string = UseRegisterAtStart(instr->string());
1810 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1811 return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
1815 LOperand* LChunkBuilder::GetSeqStringSetCharOperand(HSeqStringSetChar* instr) {
1816 if (instr->encoding() == String::ONE_BYTE_ENCODING) {
1817 if (FLAG_debug_code) {
1818 return UseFixed(instr->value(), eax);
1820 return UseFixedOrConstant(instr->value(), eax);
1823 if (FLAG_debug_code) {
1824 return UseRegisterAtStart(instr->value());
1826 return UseRegisterOrConstantAtStart(instr->value());
1832 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1833 LOperand* string = UseRegisterAtStart(instr->string());
1834 LOperand* index = FLAG_debug_code
1835 ? UseRegisterAtStart(instr->index())
1836 : UseRegisterOrConstantAtStart(instr->index());
1837 LOperand* value = GetSeqStringSetCharOperand(instr);
1838 LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), esi) : NULL;
1839 LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
1841 if (FLAG_debug_code) {
1842 result = MarkAsCall(result, instr);
1848 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1849 if (!FLAG_debug_code && instr->skip_check()) return NULL;
1850 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1851 LOperand* length = !index->IsConstantOperand()
1852 ? UseOrConstantAtStart(instr->length())
1853 : UseAtStart(instr->length());
1854 LInstruction* result = new(zone()) LBoundsCheck(index, length);
1855 if (!FLAG_debug_code || !instr->skip_check()) {
1856 result = AssignEnvironment(result);
1862 LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
1863 HBoundsCheckBaseIndexInformation* instr) {
1869 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1870 // The control instruction marking the end of a block that completed
1871 // abruptly (e.g., threw an exception). There is nothing specific to do.
1876 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1881 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1882 // All HForceRepresentation instructions should be eliminated in the
1883 // representation change phase of Hydrogen.
1889 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1890 Representation from = instr->from();
1891 Representation to = instr->to();
1892 HValue* val = instr->value();
1894 if (to.IsTagged()) {
1895 LOperand* value = UseRegister(val);
1896 return DefineSameAsFirst(new(zone()) LDummyUse(value));
1898 from = Representation::Tagged();
1900 if (from.IsTagged()) {
1901 if (to.IsDouble()) {
1902 LOperand* value = UseRegister(val);
1903 LOperand* temp = TempRegister();
1904 LInstruction* result =
1905 DefineAsRegister(new(zone()) LNumberUntagD(value, temp));
1906 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1908 } else if (to.IsSmi()) {
1909 LOperand* value = UseRegister(val);
1910 if (val->type().IsSmi()) {
1911 return DefineSameAsFirst(new(zone()) LDummyUse(value));
1913 return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1915 DCHECK(to.IsInteger32());
1916 if (val->type().IsSmi() || val->representation().IsSmi()) {
1917 LOperand* value = UseRegister(val);
1918 return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1920 LOperand* value = UseRegister(val);
1921 bool truncating = instr->CanTruncateToInt32();
1922 LOperand* xmm_temp = !truncating ? FixedTemp(xmm1) : NULL;
1923 LInstruction* result =
1924 DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
1925 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1929 } else if (from.IsDouble()) {
1930 if (to.IsTagged()) {
1931 info()->MarkAsDeferredCalling();
1932 LOperand* value = UseRegisterAtStart(val);
1933 LOperand* temp = FLAG_inline_new ? TempRegister() : NULL;
1934 LUnallocated* result_temp = TempRegister();
1935 LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1936 return AssignPointerMap(Define(result, result_temp));
1937 } else if (to.IsSmi()) {
1938 LOperand* value = UseRegister(val);
1939 return AssignEnvironment(
1940 DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1942 DCHECK(to.IsInteger32());
1943 bool truncating = instr->CanTruncateToInt32();
1944 bool needs_temp = !truncating;
1945 LOperand* value = needs_temp ? UseTempRegister(val) : UseRegister(val);
1946 LOperand* temp = needs_temp ? TempRegister() : NULL;
1947 LInstruction* result =
1948 DefineAsRegister(new(zone()) LDoubleToI(value, temp));
1949 if (!truncating) result = AssignEnvironment(result);
1952 } else if (from.IsInteger32()) {
1953 info()->MarkAsDeferredCalling();
1954 if (to.IsTagged()) {
1955 LOperand* value = UseRegister(val);
1956 if (!instr->CheckFlag(HValue::kCanOverflow)) {
1957 return DefineSameAsFirst(new(zone()) LSmiTag(value));
1958 } else if (val->CheckFlag(HInstruction::kUint32)) {
1959 LOperand* temp = TempRegister();
1960 LNumberTagU* result = new(zone()) LNumberTagU(value, temp);
1961 return AssignPointerMap(DefineSameAsFirst(result));
1963 LOperand* temp = TempRegister();
1964 LNumberTagI* result = new(zone()) LNumberTagI(value, temp);
1965 return AssignPointerMap(DefineSameAsFirst(result));
1967 } else if (to.IsSmi()) {
1968 LOperand* value = UseRegister(val);
1969 LInstruction* result = DefineSameAsFirst(new(zone()) LSmiTag(value));
1970 if (instr->CheckFlag(HValue::kCanOverflow)) {
1971 result = AssignEnvironment(result);
1975 DCHECK(to.IsDouble());
1976 if (val->CheckFlag(HInstruction::kUint32)) {
1977 return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1979 return DefineAsRegister(new(zone()) LInteger32ToDouble(Use(val)));
1988 LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1989 LOperand* value = UseAtStart(instr->value());
1990 LInstruction* result = new(zone()) LCheckNonSmi(value);
1991 if (!instr->value()->type().IsHeapObject()) {
1992 result = AssignEnvironment(result);
1998 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1999 LOperand* value = UseRegisterAtStart(instr->value());
2000 return AssignEnvironment(new(zone()) LCheckSmi(value));
2004 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
2005 LOperand* value = UseRegisterAtStart(instr->value());
2006 LOperand* temp = TempRegister();
2007 LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp);
2008 return AssignEnvironment(result);
2012 LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
2013 // If the object is in new space, we'll emit a global cell compare and so
2014 // want the value in a register. If the object gets promoted before we
2015 // emit code, we will still get the register but will do an immediate
2016 // compare instead of the cell compare. This is safe.
2017 LOperand* value = instr->object_in_new_space()
2018 ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value());
2019 return AssignEnvironment(new(zone()) LCheckValue(value));
2023 LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
2024 if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
2025 LOperand* value = UseRegisterAtStart(instr->value());
2026 LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
2027 if (instr->HasMigrationTarget()) {
2028 info()->MarkAsDeferredCalling();
2029 result = AssignPointerMap(result);
2035 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
2036 HValue* value = instr->value();
2037 Representation input_rep = value->representation();
2038 if (input_rep.IsDouble()) {
2039 LOperand* reg = UseRegister(value);
2040 return DefineFixed(new(zone()) LClampDToUint8(reg), eax);
2041 } else if (input_rep.IsInteger32()) {
2042 LOperand* reg = UseFixed(value, eax);
2043 return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
2045 DCHECK(input_rep.IsSmiOrTagged());
2046 LOperand* reg = UseFixed(value, eax);
2047 // Register allocator doesn't (yet) support allocation of double
2048 // temps. Reserve xmm1 explicitly.
2049 LOperand* temp = FixedTemp(xmm1);
2050 LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp);
2051 return AssignEnvironment(DefineFixed(result, eax));
2056 LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
2057 HValue* value = instr->value();
2058 DCHECK(value->representation().IsDouble());
2059 return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value)));
2063 LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
2064 LOperand* lo = UseRegister(instr->lo());
2065 LOperand* hi = UseRegister(instr->hi());
2066 return DefineAsRegister(new(zone()) LConstructDouble(hi, lo));
2070 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
2071 LOperand* context = info()->IsStub() ? UseFixed(instr->context(), esi) : NULL;
2072 LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
2073 return new(zone()) LReturn(
2074 UseFixed(instr->value(), eax), context, parameter_count);
2078 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
2079 Representation r = instr->representation();
2081 return DefineAsRegister(new(zone()) LConstantS);
2082 } else if (r.IsInteger32()) {
2083 return DefineAsRegister(new(zone()) LConstantI);
2084 } else if (r.IsDouble()) {
2085 double value = instr->DoubleValue();
2086 bool value_is_zero = BitCast<uint64_t, double>(value) == 0;
2087 LOperand* temp = value_is_zero ? NULL : TempRegister();
2088 return DefineAsRegister(new(zone()) LConstantD(temp));
2089 } else if (r.IsExternal()) {
2090 return DefineAsRegister(new(zone()) LConstantE);
2091 } else if (r.IsTagged()) {
2092 return DefineAsRegister(new(zone()) LConstantT);
2100 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
2101 LLoadGlobalCell* result = new(zone()) LLoadGlobalCell;
2102 return instr->RequiresHoleCheck()
2103 ? AssignEnvironment(DefineAsRegister(result))
2104 : DefineAsRegister(result);
2108 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
2109 LOperand* context = UseFixed(instr->context(), esi);
2110 LOperand* global_object = UseFixed(instr->global_object(),
2111 LoadIC::ReceiverRegister());
2112 LOperand* vector = NULL;
2113 if (FLAG_vector_ics) {
2114 vector = FixedTemp(LoadIC::VectorRegister());
2117 LLoadGlobalGeneric* result =
2118 new(zone()) LLoadGlobalGeneric(context, global_object, vector);
2119 return MarkAsCall(DefineFixed(result, eax), instr);
2123 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
2124 LStoreGlobalCell* result =
2125 new(zone()) LStoreGlobalCell(UseRegister(instr->value()));
2126 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
2130 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
2131 LOperand* context = UseRegisterAtStart(instr->value());
2132 LInstruction* result =
2133 DefineAsRegister(new(zone()) LLoadContextSlot(context));
2134 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
2135 result = AssignEnvironment(result);
2141 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
2144 LOperand* context = UseRegister(instr->context());
2145 if (instr->NeedsWriteBarrier()) {
2146 value = UseTempRegister(instr->value());
2147 temp = TempRegister();
2149 value = UseRegister(instr->value());
2152 LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
2153 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
2154 result = AssignEnvironment(result);
2160 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
2161 LOperand* obj = (instr->access().IsExternalMemory() &&
2162 instr->access().offset() == 0)
2163 ? UseRegisterOrConstantAtStart(instr->object())
2164 : UseRegisterAtStart(instr->object());
2165 return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2169 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
2170 LOperand* context = UseFixed(instr->context(), esi);
2171 LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister());
2172 LOperand* vector = NULL;
2173 if (FLAG_vector_ics) {
2174 vector = FixedTemp(LoadIC::VectorRegister());
2176 LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(
2177 context, object, vector);
2178 return MarkAsCall(DefineFixed(result, eax), instr);
2182 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2183 HLoadFunctionPrototype* instr) {
2184 return AssignEnvironment(DefineAsRegister(
2185 new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()),
2190 LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2191 return DefineAsRegister(new(zone()) LLoadRoot);
2195 LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2196 DCHECK(instr->key()->representation().IsSmiOrInteger32());
2197 ElementsKind elements_kind = instr->elements_kind();
2198 bool clobbers_key = ExternalArrayOpRequiresTemp(
2199 instr->key()->representation(), elements_kind);
2200 LOperand* key = clobbers_key
2201 ? UseTempRegister(instr->key())
2202 : UseRegisterOrConstantAtStart(instr->key());
2203 LInstruction* result = NULL;
2205 if (!instr->is_typed_elements()) {
2206 LOperand* obj = UseRegisterAtStart(instr->elements());
2207 result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key));
2210 (instr->representation().IsInteger32() &&
2211 !(IsDoubleOrFloatElementsKind(instr->elements_kind()))) ||
2212 (instr->representation().IsDouble() &&
2213 (IsDoubleOrFloatElementsKind(instr->elements_kind()))));
2214 LOperand* backing_store = UseRegister(instr->elements());
2215 result = DefineAsRegister(new(zone()) LLoadKeyed(backing_store, key));
2218 if ((instr->is_external() || instr->is_fixed_typed_array()) ?
2219 // see LCodeGen::DoLoadKeyedExternalArray
2220 ((instr->elements_kind() == EXTERNAL_UINT32_ELEMENTS ||
2221 instr->elements_kind() == UINT32_ELEMENTS) &&
2222 !instr->CheckFlag(HInstruction::kUint32)) :
2223 // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2224 // LCodeGen::DoLoadKeyedFixedArray
2225 instr->RequiresHoleCheck()) {
2226 result = AssignEnvironment(result);
2232 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
2233 LOperand* context = UseFixed(instr->context(), esi);
2234 LOperand* object = UseFixed(instr->object(), LoadIC::ReceiverRegister());
2235 LOperand* key = UseFixed(instr->key(), LoadIC::NameRegister());
2236 LOperand* vector = NULL;
2237 if (FLAG_vector_ics) {
2238 vector = FixedTemp(LoadIC::VectorRegister());
2240 LLoadKeyedGeneric* result =
2241 new(zone()) LLoadKeyedGeneric(context, object, key, vector);
2242 return MarkAsCall(DefineFixed(result, eax), instr);
2246 LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) {
2247 ElementsKind elements_kind = instr->elements_kind();
2249 // Determine if we need a byte register in this case for the value.
2250 bool val_is_fixed_register =
2251 elements_kind == EXTERNAL_INT8_ELEMENTS ||
2252 elements_kind == EXTERNAL_UINT8_ELEMENTS ||
2253 elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS ||
2254 elements_kind == UINT8_ELEMENTS ||
2255 elements_kind == INT8_ELEMENTS ||
2256 elements_kind == UINT8_CLAMPED_ELEMENTS;
2257 if (val_is_fixed_register) {
2258 return UseFixed(instr->value(), eax);
2261 return UseRegister(instr->value());
2265 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2266 if (!instr->is_typed_elements()) {
2267 DCHECK(instr->elements()->representation().IsTagged());
2268 DCHECK(instr->key()->representation().IsInteger32() ||
2269 instr->key()->representation().IsSmi());
2271 if (instr->value()->representation().IsDouble()) {
2272 LOperand* object = UseRegisterAtStart(instr->elements());
2273 LOperand* val = NULL;
2274 val = UseRegisterAtStart(instr->value());
2275 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
2276 return new(zone()) LStoreKeyed(object, key, val);
2278 DCHECK(instr->value()->representation().IsSmiOrTagged());
2279 bool needs_write_barrier = instr->NeedsWriteBarrier();
2281 LOperand* obj = UseRegister(instr->elements());
2284 if (needs_write_barrier) {
2285 val = UseTempRegister(instr->value());
2286 key = UseTempRegister(instr->key());
2288 val = UseRegisterOrConstantAtStart(instr->value());
2289 key = UseRegisterOrConstantAtStart(instr->key());
2291 return new(zone()) LStoreKeyed(obj, key, val);
2295 ElementsKind elements_kind = instr->elements_kind();
2297 (instr->value()->representation().IsInteger32() &&
2298 !IsDoubleOrFloatElementsKind(elements_kind)) ||
2299 (instr->value()->representation().IsDouble() &&
2300 IsDoubleOrFloatElementsKind(elements_kind)));
2301 DCHECK((instr->is_fixed_typed_array() &&
2302 instr->elements()->representation().IsTagged()) ||
2303 (instr->is_external() &&
2304 instr->elements()->representation().IsExternal()));
2306 LOperand* backing_store = UseRegister(instr->elements());
2307 LOperand* val = GetStoreKeyedValueOperand(instr);
2308 bool clobbers_key = ExternalArrayOpRequiresTemp(
2309 instr->key()->representation(), elements_kind);
2310 LOperand* key = clobbers_key
2311 ? UseTempRegister(instr->key())
2312 : UseRegisterOrConstantAtStart(instr->key());
2313 return new(zone()) LStoreKeyed(backing_store, key, val);
2317 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
2318 LOperand* context = UseFixed(instr->context(), esi);
2319 LOperand* object = UseFixed(instr->object(),
2320 KeyedStoreIC::ReceiverRegister());
2321 LOperand* key = UseFixed(instr->key(), KeyedStoreIC::NameRegister());
2322 LOperand* value = UseFixed(instr->value(), KeyedStoreIC::ValueRegister());
2324 DCHECK(instr->object()->representation().IsTagged());
2325 DCHECK(instr->key()->representation().IsTagged());
2326 DCHECK(instr->value()->representation().IsTagged());
2328 LStoreKeyedGeneric* result =
2329 new(zone()) LStoreKeyedGeneric(context, object, key, value);
2330 return MarkAsCall(result, instr);
2334 LInstruction* LChunkBuilder::DoTransitionElementsKind(
2335 HTransitionElementsKind* instr) {
2336 if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2337 LOperand* object = UseRegister(instr->object());
2338 LOperand* new_map_reg = TempRegister();
2339 LOperand* temp_reg = TempRegister();
2340 LTransitionElementsKind* result =
2341 new(zone()) LTransitionElementsKind(object, NULL,
2342 new_map_reg, temp_reg);
2345 LOperand* object = UseFixed(instr->object(), eax);
2346 LOperand* context = UseFixed(instr->context(), esi);
2347 LTransitionElementsKind* result =
2348 new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2349 return MarkAsCall(result, instr);
2354 LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2355 HTrapAllocationMemento* instr) {
2356 LOperand* object = UseRegister(instr->object());
2357 LOperand* temp = TempRegister();
2358 LTrapAllocationMemento* result =
2359 new(zone()) LTrapAllocationMemento(object, temp);
2360 return AssignEnvironment(result);
2364 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2365 bool is_in_object = instr->access().IsInobject();
2366 bool is_external_location = instr->access().IsExternalMemory() &&
2367 instr->access().offset() == 0;
2368 bool needs_write_barrier = instr->NeedsWriteBarrier();
2369 bool needs_write_barrier_for_map = instr->has_transition() &&
2370 instr->NeedsWriteBarrierForMap();
2373 if (needs_write_barrier) {
2375 ? UseRegister(instr->object())
2376 : UseTempRegister(instr->object());
2377 } else if (is_external_location) {
2378 DCHECK(!is_in_object);
2379 DCHECK(!needs_write_barrier);
2380 DCHECK(!needs_write_barrier_for_map);
2381 obj = UseRegisterOrConstant(instr->object());
2383 obj = needs_write_barrier_for_map
2384 ? UseRegister(instr->object())
2385 : UseRegisterAtStart(instr->object());
2388 bool can_be_constant = instr->value()->IsConstant() &&
2389 HConstant::cast(instr->value())->NotInNewSpace() &&
2390 !instr->field_representation().IsDouble();
2393 if (instr->field_representation().IsInteger8() ||
2394 instr->field_representation().IsUInteger8()) {
2395 // mov_b requires a byte register (i.e. any of eax, ebx, ecx, edx).
2396 // Just force the value to be in eax and we're safe here.
2397 val = UseFixed(instr->value(), eax);
2398 } else if (needs_write_barrier) {
2399 val = UseTempRegister(instr->value());
2400 } else if (can_be_constant) {
2401 val = UseRegisterOrConstant(instr->value());
2402 } else if (instr->field_representation().IsSmi()) {
2403 val = UseTempRegister(instr->value());
2404 } else if (instr->field_representation().IsDouble()) {
2405 val = UseRegisterAtStart(instr->value());
2407 val = UseRegister(instr->value());
2410 // We only need a scratch register if we have a write barrier or we
2411 // have a store into the properties array (not in-object-property).
2412 LOperand* temp = (!is_in_object || needs_write_barrier ||
2413 needs_write_barrier_for_map) ? TempRegister() : NULL;
2415 // We need a temporary register for write barrier of the map field.
2416 LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL;
2418 return new(zone()) LStoreNamedField(obj, val, temp, temp_map);
2422 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
2423 LOperand* context = UseFixed(instr->context(), esi);
2424 LOperand* object = UseFixed(instr->object(), StoreIC::ReceiverRegister());
2425 LOperand* value = UseFixed(instr->value(), StoreIC::ValueRegister());
2427 LStoreNamedGeneric* result =
2428 new(zone()) LStoreNamedGeneric(context, object, value);
2429 return MarkAsCall(result, instr);
2433 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2434 LOperand* context = UseFixed(instr->context(), esi);
2435 LOperand* left = UseFixed(instr->left(), edx);
2436 LOperand* right = UseFixed(instr->right(), eax);
2437 LStringAdd* string_add = new(zone()) LStringAdd(context, left, right);
2438 return MarkAsCall(DefineFixed(string_add, eax), instr);
2442 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2443 LOperand* string = UseTempRegister(instr->string());
2444 LOperand* index = UseTempRegister(instr->index());
2445 LOperand* context = UseAny(instr->context());
2446 LStringCharCodeAt* result =
2447 new(zone()) LStringCharCodeAt(context, string, index);
2448 return AssignPointerMap(DefineAsRegister(result));
2452 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2453 LOperand* char_code = UseRegister(instr->value());
2454 LOperand* context = UseAny(instr->context());
2455 LStringCharFromCode* result =
2456 new(zone()) LStringCharFromCode(context, char_code);
2457 return AssignPointerMap(DefineAsRegister(result));
2461 LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2462 info()->MarkAsDeferredCalling();
2463 LOperand* context = UseAny(instr->context());
2464 LOperand* size = instr->size()->IsConstant()
2465 ? UseConstant(instr->size())
2466 : UseTempRegister(instr->size());
2467 LOperand* temp = TempRegister();
2468 LAllocate* result = new(zone()) LAllocate(context, size, temp);
2469 return AssignPointerMap(DefineAsRegister(result));
2473 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2474 LOperand* context = UseFixed(instr->context(), esi);
2476 DefineFixed(new(zone()) LRegExpLiteral(context), eax), instr);
2480 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2481 LOperand* context = UseFixed(instr->context(), esi);
2483 DefineFixed(new(zone()) LFunctionLiteral(context), eax), instr);
2487 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2488 DCHECK(argument_count_ == 0);
2489 allocator_->MarkAsOsrEntry();
2490 current_block_->last_environment()->set_ast_id(instr->ast_id());
2491 return AssignEnvironment(new(zone()) LOsrEntry);
2495 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2496 LParameter* result = new(zone()) LParameter;
2497 if (instr->kind() == HParameter::STACK_PARAMETER) {
2498 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2499 return DefineAsSpilled(result, spill_index);
2501 DCHECK(info()->IsStub());
2502 CodeStubInterfaceDescriptor* descriptor =
2503 info()->code_stub()->GetInterfaceDescriptor();
2504 int index = static_cast<int>(instr->index());
2505 Register reg = descriptor->GetEnvironmentParameterRegister(index);
2506 return DefineFixed(result, reg);
2511 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2512 // Use an index that corresponds to the location in the unoptimized frame,
2513 // which the optimized frame will subsume.
2514 int env_index = instr->index();
2515 int spill_index = 0;
2516 if (instr->environment()->is_parameter_index(env_index)) {
2517 spill_index = chunk()->GetParameterStackSlot(env_index);
2519 spill_index = env_index - instr->environment()->first_local_index();
2520 if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2521 Abort(kNotEnoughSpillSlotsForOsr);
2524 if (spill_index == 0) {
2525 // The dynamic frame alignment state overwrites the first local.
2526 // The first local is saved at the end of the unoptimized frame.
2527 spill_index = graph()->osr()->UnoptimizedFrameSlots();
2530 return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2534 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2535 LOperand* context = UseFixed(instr->context(), esi);
2536 LCallStub* result = new(zone()) LCallStub(context);
2537 return MarkAsCall(DefineFixed(result, eax), instr);
2541 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2542 // There are no real uses of the arguments object.
2543 // arguments.length and element access are supported directly on
2544 // stack arguments, and any real arguments object use causes a bailout.
2545 // So this value is never used.
2550 LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2551 instr->ReplayEnvironment(current_block_->last_environment());
2553 // There are no real uses of a captured object.
2558 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2559 info()->MarkAsRequiresFrame();
2560 LOperand* args = UseRegister(instr->arguments());
2563 if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2564 length = UseRegisterOrConstant(instr->length());
2565 index = UseOrConstant(instr->index());
2567 length = UseTempRegister(instr->length());
2568 index = Use(instr->index());
2570 return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2574 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2575 LOperand* object = UseFixed(instr->value(), eax);
2576 LToFastProperties* result = new(zone()) LToFastProperties(object);
2577 return MarkAsCall(DefineFixed(result, eax), instr);
2581 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2582 LOperand* context = UseFixed(instr->context(), esi);
2583 LOperand* value = UseAtStart(instr->value());
2584 LTypeof* result = new(zone()) LTypeof(context, value);
2585 return MarkAsCall(DefineFixed(result, eax), instr);
2589 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2590 return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2594 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2595 HIsConstructCallAndBranch* instr) {
2596 return new(zone()) LIsConstructCallAndBranch(TempRegister());
2600 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2601 instr->ReplayEnvironment(current_block_->last_environment());
2606 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2607 info()->MarkAsDeferredCalling();
2608 if (instr->is_function_entry()) {
2609 LOperand* context = UseFixed(instr->context(), esi);
2610 return MarkAsCall(new(zone()) LStackCheck(context), instr);
2612 DCHECK(instr->is_backwards_branch());
2613 LOperand* context = UseAny(instr->context());
2614 return AssignEnvironment(
2615 AssignPointerMap(new(zone()) LStackCheck(context)));
2620 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2621 HEnvironment* outer = current_block_->last_environment();
2622 outer->set_ast_id(instr->ReturnId());
2623 HConstant* undefined = graph()->GetConstantUndefined();
2624 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2625 instr->arguments_count(),
2628 instr->inlining_kind());
2629 // Only replay binding of arguments object if it wasn't removed from graph.
2630 if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2631 inner->Bind(instr->arguments_var(), instr->arguments_object());
2633 inner->set_entry(instr);
2634 current_block_->UpdateEnvironment(inner);
2635 chunk_->AddInlinedClosure(instr->closure());
2640 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2641 LInstruction* pop = NULL;
2643 HEnvironment* env = current_block_->last_environment();
2645 if (env->entry()->arguments_pushed()) {
2646 int argument_count = env->arguments_environment()->parameter_count();
2647 pop = new(zone()) LDrop(argument_count);
2648 DCHECK(instr->argument_delta() == -argument_count);
2651 HEnvironment* outer = current_block_->last_environment()->
2652 DiscardInlined(false);
2653 current_block_->UpdateEnvironment(outer);
2658 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2659 LOperand* context = UseFixed(instr->context(), esi);
2660 LOperand* object = UseFixed(instr->enumerable(), eax);
2661 LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2662 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
2666 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2667 LOperand* map = UseRegister(instr->map());
2668 return AssignEnvironment(DefineAsRegister(
2669 new(zone()) LForInCacheArray(map)));
2673 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2674 LOperand* value = UseRegisterAtStart(instr->value());
2675 LOperand* map = UseRegisterAtStart(instr->map());
2676 return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2680 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2681 LOperand* object = UseRegister(instr->object());
2682 LOperand* index = UseTempRegister(instr->index());
2683 LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
2684 LInstruction* result = DefineSameAsFirst(load);
2685 return AssignPointerMap(result);
2689 LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
2690 LOperand* context = UseRegisterAtStart(instr->context());
2691 return new(zone()) LStoreFrameContext(context);
2695 LInstruction* LChunkBuilder::DoAllocateBlockContext(
2696 HAllocateBlockContext* instr) {
2697 LOperand* context = UseFixed(instr->context(), esi);
2698 LOperand* function = UseRegisterAtStart(instr->function());
2699 LAllocateBlockContext* result =
2700 new(zone()) LAllocateBlockContext(context, function);
2701 return MarkAsCall(DefineFixed(result, esi), instr);
2705 } } // namespace v8::internal
2707 #endif // V8_TARGET_ARCH_IA32