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
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.
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.
30 #if defined(V8_TARGET_ARCH_X64)
32 #include "lithium-allocator-inl.h"
33 #include "x64/lithium-x64.h"
34 #include "x64/lithium-codegen-x64.h"
39 #define DEFINE_COMPILE(type) \
40 void L##type::CompileToNative(LCodeGen* generator) { \
41 generator->Do##type(this); \
43 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
46 LOsrEntry::LOsrEntry() {
47 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) {
48 register_spills_[i] = NULL;
50 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) {
51 double_register_spills_[i] = NULL;
56 void LOsrEntry::MarkSpilledRegister(int allocation_index,
57 LOperand* spill_operand) {
58 ASSERT(spill_operand->IsStackSlot());
59 ASSERT(register_spills_[allocation_index] == NULL);
60 register_spills_[allocation_index] = spill_operand;
64 void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
65 LOperand* spill_operand) {
66 ASSERT(spill_operand->IsDoubleStackSlot());
67 ASSERT(double_register_spills_[allocation_index] == NULL);
68 double_register_spills_[allocation_index] = spill_operand;
73 void LInstruction::VerifyCall() {
74 // Call instructions can use only fixed registers as temporaries and
75 // outputs because all registers are blocked by the calling convention.
76 // Inputs operands must use a fixed register or use-at-start policy or
77 // a non-register policy.
78 ASSERT(Output() == NULL ||
79 LUnallocated::cast(Output())->HasFixedPolicy() ||
80 !LUnallocated::cast(Output())->HasRegisterPolicy());
81 for (UseIterator it(this); !it.Done(); it.Advance()) {
82 LUnallocated* operand = LUnallocated::cast(it.Current());
83 ASSERT(operand->HasFixedPolicy() ||
84 operand->IsUsedAtStart());
86 for (TempIterator it(this); !it.Done(); it.Advance()) {
87 LUnallocated* operand = LUnallocated::cast(it.Current());
88 ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
94 void LInstruction::PrintTo(StringStream* stream) {
95 stream->Add("%s ", this->Mnemonic());
97 PrintOutputOperandTo(stream);
101 if (HasEnvironment()) {
103 environment()->PrintTo(stream);
106 if (HasPointerMap()) {
108 pointer_map()->PrintTo(stream);
113 template<int R, int I, int T>
114 void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
116 for (int i = 0; i < inputs_.length(); i++) {
117 if (i > 0) stream->Add(" ");
118 inputs_[i]->PrintTo(stream);
123 template<int R, int I, int T>
124 void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
125 for (int i = 0; i < results_.length(); i++) {
126 if (i > 0) stream->Add(" ");
127 results_[i]->PrintTo(stream);
132 void LLabel::PrintDataTo(StringStream* stream) {
133 LGap::PrintDataTo(stream);
134 LLabel* rep = replacement();
136 stream->Add(" Dead block replaced with B%d", rep->block_id());
141 bool LGap::IsRedundant() const {
142 for (int i = 0; i < 4; i++) {
143 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
152 void LGap::PrintDataTo(StringStream* stream) {
153 for (int i = 0; i < 4; i++) {
155 if (parallel_moves_[i] != NULL) {
156 parallel_moves_[i]->PrintDataTo(stream);
163 const char* LArithmeticD::Mnemonic() const {
165 case Token::ADD: return "add-d";
166 case Token::SUB: return "sub-d";
167 case Token::MUL: return "mul-d";
168 case Token::DIV: return "div-d";
169 case Token::MOD: return "mod-d";
177 const char* LArithmeticT::Mnemonic() const {
179 case Token::ADD: return "add-t";
180 case Token::SUB: return "sub-t";
181 case Token::MUL: return "mul-t";
182 case Token::MOD: return "mod-t";
183 case Token::DIV: return "div-t";
184 case Token::BIT_AND: return "bit-and-t";
185 case Token::BIT_OR: return "bit-or-t";
186 case Token::BIT_XOR: return "bit-xor-t";
187 case Token::SHL: return "sal-t";
188 case Token::SAR: return "sar-t";
189 case Token::SHR: return "shr-t";
197 void LGoto::PrintDataTo(StringStream* stream) {
198 stream->Add("B%d", block_id());
202 void LBranch::PrintDataTo(StringStream* stream) {
203 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
204 InputAt(0)->PrintTo(stream);
208 void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
210 InputAt(0)->PrintTo(stream);
211 stream->Add(" %s ", Token::String(op()));
212 InputAt(1)->PrintTo(stream);
213 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
217 void LIsNilAndBranch::PrintDataTo(StringStream* stream) {
219 InputAt(0)->PrintTo(stream);
220 stream->Add(kind() == kStrictEquality ? " === " : " == ");
221 stream->Add(nil() == kNullValue ? "null" : "undefined");
222 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
226 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
227 stream->Add("if is_object(");
228 InputAt(0)->PrintTo(stream);
229 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
233 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
234 stream->Add("if is_smi(");
235 InputAt(0)->PrintTo(stream);
236 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
240 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
241 stream->Add("if is_undetectable(");
242 InputAt(0)->PrintTo(stream);
243 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
247 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
248 stream->Add("if has_instance_type(");
249 InputAt(0)->PrintTo(stream);
250 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
254 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
255 stream->Add("if has_cached_array_index(");
256 InputAt(0)->PrintTo(stream);
257 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
261 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
262 stream->Add("if class_of_test(");
263 InputAt(0)->PrintTo(stream);
264 stream->Add(", \"%o\") then B%d else B%d",
265 *hydrogen()->class_name(),
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());
280 void LCallConstantFunction::PrintDataTo(StringStream* stream) {
281 stream->Add("#%d / ", arity());
285 void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
286 stream->Add("/%s ", hydrogen()->OpName());
287 InputAt(0)->PrintTo(stream);
291 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
292 InputAt(0)->PrintTo(stream);
293 stream->Add("[%d]", slot_index());
297 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
298 InputAt(0)->PrintTo(stream);
299 stream->Add("[%d] <- ", slot_index());
300 InputAt(1)->PrintTo(stream);
304 void LInvokeFunction::PrintDataTo(StringStream* stream) {
306 InputAt(0)->PrintTo(stream);
307 stream->Add(" #%d / ", arity());
311 void LCallKeyed::PrintDataTo(StringStream* stream) {
312 stream->Add("[rcx] #%d / ", arity());
316 void LCallNamed::PrintDataTo(StringStream* stream) {
317 SmartArrayPointer<char> name_string = name()->ToCString();
318 stream->Add("%s #%d / ", *name_string, arity());
322 void LCallGlobal::PrintDataTo(StringStream* stream) {
323 SmartArrayPointer<char> name_string = name()->ToCString();
324 stream->Add("%s #%d / ", *name_string, arity());
328 void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
329 stream->Add("#%d / ", arity());
333 void LCallNew::PrintDataTo(StringStream* stream) {
335 InputAt(0)->PrintTo(stream);
336 stream->Add(" #%d / ", arity());
340 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
341 arguments()->PrintTo(stream);
343 stream->Add(" length ");
344 length()->PrintTo(stream);
346 stream->Add(" index ");
347 index()->PrintTo(stream);
351 int LChunk::GetNextSpillIndex(bool is_double) {
352 return spill_slot_count_++;
356 LOperand* LChunk::GetNextSpillSlot(bool is_double) {
357 // All stack slots are Double stack slots on x64.
358 // Alternatively, at some point, start using half-size
359 // stack slots for int32 values.
360 int index = GetNextSpillIndex(is_double);
362 return LDoubleStackSlot::Create(index);
364 return LStackSlot::Create(index);
369 void LChunk::MarkEmptyBlocks() {
370 HPhase phase("Mark empty blocks", this);
371 for (int i = 0; i < graph()->blocks()->length(); ++i) {
372 HBasicBlock* block = graph()->blocks()->at(i);
373 int first = block->first_instruction_index();
374 int last = block->last_instruction_index();
375 LInstruction* first_instr = instructions()->at(first);
376 LInstruction* last_instr = instructions()->at(last);
378 LLabel* label = LLabel::cast(first_instr);
379 if (last_instr->IsGoto()) {
380 LGoto* goto_instr = LGoto::cast(last_instr);
381 if (label->IsRedundant() &&
382 !label->is_loop_header()) {
383 bool can_eliminate = true;
384 for (int i = first + 1; i < last && can_eliminate; ++i) {
385 LInstruction* cur = instructions()->at(i);
387 LGap* gap = LGap::cast(cur);
388 if (!gap->IsRedundant()) {
389 can_eliminate = false;
392 can_eliminate = false;
397 label->set_replacement(GetLabel(goto_instr->block_id()));
405 void LStoreNamedField::PrintDataTo(StringStream* stream) {
406 object()->PrintTo(stream);
408 stream->Add(*String::cast(*name())->ToCString());
410 value()->PrintTo(stream);
414 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
415 object()->PrintTo(stream);
417 stream->Add(*String::cast(*name())->ToCString());
419 value()->PrintTo(stream);
423 void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) {
424 object()->PrintTo(stream);
426 key()->PrintTo(stream);
427 stream->Add("] <- ");
428 value()->PrintTo(stream);
432 void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
433 elements()->PrintTo(stream);
435 key()->PrintTo(stream);
436 stream->Add("] <- ");
437 value()->PrintTo(stream);
441 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
442 object()->PrintTo(stream);
444 key()->PrintTo(stream);
445 stream->Add("] <- ");
446 value()->PrintTo(stream);
450 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
451 object()->PrintTo(stream);
452 stream->Add(" %p -> %p", *original_map(), *transitioned_map());
456 void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
457 LInstructionGap* gap = new LInstructionGap(block);
459 if (instr->IsControl()) {
460 instructions_.Add(gap);
461 index = instructions_.length();
462 instructions_.Add(instr);
464 index = instructions_.length();
465 instructions_.Add(instr);
466 instructions_.Add(gap);
468 if (instr->HasPointerMap()) {
469 pointer_maps_.Add(instr->pointer_map());
470 instr->pointer_map()->set_lithium_position(index);
475 LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) {
476 return LConstantOperand::Create(constant->id());
480 int LChunk::GetParameterStackSlot(int index) const {
481 // The receiver is at index 0, the first parameter at index 1, so we
482 // shift all parameter indexes down by the number of parameters, and
483 // make sure they end up negative so they are distinguishable from
485 int result = index - info()->scope()->num_parameters() - 1;
490 // A parameter relative to ebp in the arguments stub.
491 int LChunk::ParameterAt(int index) {
492 ASSERT(-1 <= index); // -1 is the receiver.
493 return (1 + info()->scope()->num_parameters() - index) *
498 LGap* LChunk::GetGapAt(int index) const {
499 return LGap::cast(instructions_[index]);
503 bool LChunk::IsGapAt(int index) const {
504 return instructions_[index]->IsGap();
508 int LChunk::NearestGapPos(int index) const {
509 while (!IsGapAt(index)) index--;
514 void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
515 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
519 Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
520 return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
524 Representation LChunk::LookupLiteralRepresentation(
525 LConstantOperand* operand) const {
526 return graph_->LookupValue(operand->index())->representation();
530 LChunk* LChunkBuilder::Build() {
532 chunk_ = new LChunk(info(), graph());
533 HPhase phase("Building chunk", chunk_);
535 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
536 for (int i = 0; i < blocks->length(); i++) {
537 HBasicBlock* next = NULL;
538 if (i < blocks->length() - 1) next = blocks->at(i + 1);
539 DoBasicBlock(blocks->at(i), next);
540 if (is_aborted()) return NULL;
547 void LChunkBuilder::Abort(const char* format, ...) {
548 if (FLAG_trace_bailout) {
549 SmartArrayPointer<char> name(
550 info()->shared_info()->DebugName()->ToCString());
551 PrintF("Aborting LChunk building in @\"%s\": ", *name);
553 va_start(arguments, format);
554 OS::VPrint(format, arguments);
562 LRegister* LChunkBuilder::ToOperand(Register reg) {
563 return LRegister::Create(Register::ToAllocationIndex(reg));
567 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
568 return new LUnallocated(LUnallocated::FIXED_REGISTER,
569 Register::ToAllocationIndex(reg));
573 LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
574 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
575 XMMRegister::ToAllocationIndex(reg));
579 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
580 return Use(value, ToUnallocated(fixed_register));
584 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
585 return Use(value, ToUnallocated(reg));
589 LOperand* LChunkBuilder::UseRegister(HValue* value) {
590 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
594 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
596 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
597 LUnallocated::USED_AT_START));
601 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
602 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER));
606 LOperand* LChunkBuilder::Use(HValue* value) {
607 return Use(value, new LUnallocated(LUnallocated::NONE));
611 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
612 return Use(value, new LUnallocated(LUnallocated::NONE,
613 LUnallocated::USED_AT_START));
617 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
618 return value->IsConstant()
619 ? chunk_->DefineConstantOperand(HConstant::cast(value))
624 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
625 return value->IsConstant()
626 ? chunk_->DefineConstantOperand(HConstant::cast(value))
631 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
632 return value->IsConstant()
633 ? chunk_->DefineConstantOperand(HConstant::cast(value))
634 : UseRegister(value);
638 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
639 return value->IsConstant()
640 ? chunk_->DefineConstantOperand(HConstant::cast(value))
641 : UseRegisterAtStart(value);
645 LOperand* LChunkBuilder::UseAny(HValue* value) {
646 return value->IsConstant()
647 ? chunk_->DefineConstantOperand(HConstant::cast(value))
648 : Use(value, new LUnallocated(LUnallocated::ANY));
652 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
653 if (value->EmitAtUses()) {
654 HInstruction* instr = HInstruction::cast(value);
655 VisitInstruction(instr);
657 allocator_->RecordUse(value, operand);
662 template<int I, int T>
663 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
664 LUnallocated* result) {
665 allocator_->RecordDefinition(current_instruction_, result);
666 instr->set_result(result);
671 template<int I, int T>
672 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
673 return Define(instr, new LUnallocated(LUnallocated::NONE));
677 template<int I, int T>
678 LInstruction* LChunkBuilder::DefineAsRegister(
679 LTemplateInstruction<1, I, T>* instr) {
680 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
684 template<int I, int T>
685 LInstruction* LChunkBuilder::DefineAsSpilled(
686 LTemplateInstruction<1, I, T>* instr,
688 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
692 template<int I, int T>
693 LInstruction* LChunkBuilder::DefineSameAsFirst(
694 LTemplateInstruction<1, I, T>* instr) {
695 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
699 template<int I, int T>
700 LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr,
702 return Define(instr, ToUnallocated(reg));
706 template<int I, int T>
707 LInstruction* LChunkBuilder::DefineFixedDouble(
708 LTemplateInstruction<1, I, T>* instr,
710 return Define(instr, ToUnallocated(reg));
714 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
715 HEnvironment* hydrogen_env = current_block_->last_environment();
716 int argument_index_accumulator = 0;
717 instr->set_environment(CreateEnvironment(hydrogen_env,
718 &argument_index_accumulator));
723 LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
724 LInstruction* instr, int ast_id) {
725 ASSERT(instruction_pending_deoptimization_environment_ == NULL);
726 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
727 instruction_pending_deoptimization_environment_ = instr;
728 pending_deoptimization_ast_id_ = ast_id;
733 void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
734 instruction_pending_deoptimization_environment_ = NULL;
735 pending_deoptimization_ast_id_ = AstNode::kNoNumber;
739 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
740 HInstruction* hinstr,
741 CanDeoptimize can_deoptimize) {
746 instr = AssignPointerMap(instr);
748 if (hinstr->HasObservableSideEffects()) {
749 ASSERT(hinstr->next()->IsSimulate());
750 HSimulate* sim = HSimulate::cast(hinstr->next());
751 instr = SetInstructionPendingDeoptimizationEnvironment(
752 instr, sim->ast_id());
755 // If instruction does not have side-effects lazy deoptimization
756 // after the call will try to deoptimize to the point before the call.
757 // Thus we still need to attach environment to this call even if
758 // call sequence can not deoptimize eagerly.
759 bool needs_environment =
760 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
761 !hinstr->HasObservableSideEffects();
762 if (needs_environment && !instr->HasEnvironment()) {
763 instr = AssignEnvironment(instr);
770 LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
771 instr->MarkAsSaveDoubles();
776 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
777 ASSERT(!instr->HasPointerMap());
778 instr->set_pointer_map(new LPointerMap(position_));
783 LUnallocated* LChunkBuilder::TempRegister() {
784 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
785 allocator_->RecordTemporary(operand);
790 LOperand* LChunkBuilder::FixedTemp(Register reg) {
791 LUnallocated* operand = ToUnallocated(reg);
792 allocator_->RecordTemporary(operand);
797 LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
798 LUnallocated* operand = ToUnallocated(reg);
799 allocator_->RecordTemporary(operand);
804 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
805 return new LLabel(instr->block());
809 LInstruction* LChunkBuilder::DoSoftDeoptimize(HSoftDeoptimize* instr) {
810 return AssignEnvironment(new LDeoptimize);
814 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
815 return AssignEnvironment(new LDeoptimize);
819 LInstruction* LChunkBuilder::DoShift(Token::Value op,
820 HBitwiseBinaryOperation* instr) {
821 if (instr->representation().IsTagged()) {
822 ASSERT(instr->left()->representation().IsTagged());
823 ASSERT(instr->right()->representation().IsTagged());
825 LOperand* left = UseFixed(instr->left(), rdx);
826 LOperand* right = UseFixed(instr->right(), rax);
827 LArithmeticT* result = new LArithmeticT(op, left, right);
828 return MarkAsCall(DefineFixed(result, rax), instr);
831 ASSERT(instr->representation().IsInteger32());
832 ASSERT(instr->left()->representation().IsInteger32());
833 ASSERT(instr->right()->representation().IsInteger32());
834 LOperand* left = UseRegisterAtStart(instr->left());
836 HValue* right_value = instr->right();
837 LOperand* right = NULL;
838 int constant_value = 0;
839 if (right_value->IsConstant()) {
840 HConstant* constant = HConstant::cast(right_value);
841 right = chunk_->DefineConstantOperand(constant);
842 constant_value = constant->Integer32Value() & 0x1f;
844 right = UseFixed(right_value, rcx);
847 // Shift operations can only deoptimize if we do a logical shift by 0 and
848 // the result cannot be truncated to int32.
849 bool may_deopt = (op == Token::SHR && constant_value == 0);
850 bool does_deopt = false;
852 for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
853 if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
860 LInstruction* result =
861 DefineSameAsFirst(new LShiftI(op, left, right, does_deopt));
862 return does_deopt ? AssignEnvironment(result) : result;
866 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
867 HArithmeticBinaryOperation* instr) {
868 ASSERT(instr->representation().IsDouble());
869 ASSERT(instr->left()->representation().IsDouble());
870 ASSERT(instr->right()->representation().IsDouble());
871 ASSERT(op != Token::MOD);
872 LOperand* left = UseRegisterAtStart(instr->left());
873 LOperand* right = UseRegisterAtStart(instr->right());
874 LArithmeticD* result = new LArithmeticD(op, left, right);
875 return DefineSameAsFirst(result);
879 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
880 HArithmeticBinaryOperation* instr) {
881 ASSERT(op == Token::ADD ||
886 HValue* left = instr->left();
887 HValue* right = instr->right();
888 ASSERT(left->representation().IsTagged());
889 ASSERT(right->representation().IsTagged());
890 LOperand* left_operand = UseFixed(left, rdx);
891 LOperand* right_operand = UseFixed(right, rax);
892 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
893 return MarkAsCall(DefineFixed(result, rax), instr);
897 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
898 ASSERT(is_building());
899 current_block_ = block;
900 next_block_ = next_block;
901 if (block->IsStartBlock()) {
902 block->UpdateEnvironment(graph_->start_environment());
904 } else if (block->predecessors()->length() == 1) {
905 // We have a single predecessor => copy environment and outgoing
906 // argument count from the predecessor.
907 ASSERT(block->phis()->length() == 0);
908 HBasicBlock* pred = block->predecessors()->at(0);
909 HEnvironment* last_environment = pred->last_environment();
910 ASSERT(last_environment != NULL);
911 // Only copy the environment, if it is later used again.
912 if (pred->end()->SecondSuccessor() == NULL) {
913 ASSERT(pred->end()->FirstSuccessor() == block);
915 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
916 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
917 last_environment = last_environment->Copy();
920 block->UpdateEnvironment(last_environment);
921 ASSERT(pred->argument_count() >= 0);
922 argument_count_ = pred->argument_count();
924 // We are at a state join => process phis.
925 HBasicBlock* pred = block->predecessors()->at(0);
926 // No need to copy the environment, it cannot be used later.
927 HEnvironment* last_environment = pred->last_environment();
928 for (int i = 0; i < block->phis()->length(); ++i) {
929 HPhi* phi = block->phis()->at(i);
930 last_environment->SetValueAt(phi->merged_index(), phi);
932 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
933 last_environment->SetValueAt(block->deleted_phis()->at(i),
934 graph_->GetConstantUndefined());
936 block->UpdateEnvironment(last_environment);
937 // Pick up the outgoing argument count of one of the predecessors.
938 argument_count_ = pred->argument_count();
940 HInstruction* current = block->first();
941 int start = chunk_->instructions()->length();
942 while (current != NULL && !is_aborted()) {
943 // Code for constants in registers is generated lazily.
944 if (!current->EmitAtUses()) {
945 VisitInstruction(current);
947 current = current->next();
949 int end = chunk_->instructions()->length() - 1;
951 block->set_first_instruction_index(start);
952 block->set_last_instruction_index(end);
954 block->set_argument_count(argument_count_);
956 current_block_ = NULL;
960 void LChunkBuilder::VisitInstruction(HInstruction* current) {
961 HInstruction* old_current = current_instruction_;
962 current_instruction_ = current;
963 if (current->has_position()) position_ = current->position();
964 LInstruction* instr = current->CompileToLithium(this);
967 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
968 instr = AssignPointerMap(instr);
970 if (FLAG_stress_environments && !instr->HasEnvironment()) {
971 instr = AssignEnvironment(instr);
973 instr->set_hydrogen_value(current);
974 chunk_->AddInstruction(instr, current_block_);
976 current_instruction_ = old_current;
980 LEnvironment* LChunkBuilder::CreateEnvironment(
981 HEnvironment* hydrogen_env,
982 int* argument_index_accumulator) {
983 if (hydrogen_env == NULL) return NULL;
985 LEnvironment* outer =
986 CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
987 int ast_id = hydrogen_env->ast_id();
988 ASSERT(ast_id != AstNode::kNoNumber);
989 int value_count = hydrogen_env->length();
990 LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
992 hydrogen_env->parameter_count(),
996 for (int i = 0; i < value_count; ++i) {
997 if (hydrogen_env->is_special_index(i)) continue;
999 HValue* value = hydrogen_env->values()->at(i);
1000 LOperand* op = NULL;
1001 if (value->IsArgumentsObject()) {
1003 } else if (value->IsPushArgument()) {
1004 op = new LArgument((*argument_index_accumulator)++);
1008 result->AddValue(op, value->representation());
1015 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
1016 return new LGoto(instr->FirstSuccessor()->block_id());
1020 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
1021 HValue* v = instr->value();
1022 if (v->EmitAtUses()) {
1023 ASSERT(v->IsConstant());
1024 ASSERT(!v->representation().IsDouble());
1025 HBasicBlock* successor = HConstant::cast(v)->ToBoolean()
1026 ? instr->FirstSuccessor()
1027 : instr->SecondSuccessor();
1028 return new LGoto(successor->block_id());
1030 return AssignEnvironment(new LBranch(UseRegister(v)));
1034 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
1035 ASSERT(instr->value()->representation().IsTagged());
1036 LOperand* value = UseRegisterAtStart(instr->value());
1037 return new LCmpMapAndBranch(value);
1041 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
1042 return DefineAsRegister(new LArgumentsLength(Use(length->value())));
1046 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
1047 return DefineAsRegister(new LArgumentsElements);
1051 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
1052 LOperand* left = UseFixed(instr->left(), rax);
1053 LOperand* right = UseFixed(instr->right(), rdx);
1054 LInstanceOf* result = new LInstanceOf(left, right);
1055 return MarkAsCall(DefineFixed(result, rax), instr);
1059 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
1060 HInstanceOfKnownGlobal* instr) {
1061 LInstanceOfKnownGlobal* result =
1062 new LInstanceOfKnownGlobal(UseFixed(instr->left(), rax),
1064 return MarkAsCall(DefineFixed(result, rax), instr);
1068 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
1069 LOperand* function = UseFixed(instr->function(), rdi);
1070 LOperand* receiver = UseFixed(instr->receiver(), rax);
1071 LOperand* length = UseFixed(instr->length(), rbx);
1072 LOperand* elements = UseFixed(instr->elements(), rcx);
1073 LApplyArguments* result = new LApplyArguments(function,
1077 return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
1081 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) {
1083 LOperand* argument = UseOrConstant(instr->argument());
1084 return new LPushArgument(argument);
1088 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
1089 return instr->HasNoUses() ? NULL : DefineAsRegister(new LThisFunction);
1093 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
1094 return instr->HasNoUses() ? NULL : DefineAsRegister(new LContext);
1098 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
1099 LOperand* context = UseRegisterAtStart(instr->value());
1100 return DefineAsRegister(new LOuterContext(context));
1104 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
1105 return DefineAsRegister(new LGlobalObject(instr->qml_global()));
1109 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
1110 LOperand* global_object = UseRegisterAtStart(instr->value());
1111 return DefineAsRegister(new LGlobalReceiver(global_object));
1115 LInstruction* LChunkBuilder::DoCallConstantFunction(
1116 HCallConstantFunction* instr) {
1117 argument_count_ -= instr->argument_count();
1118 return MarkAsCall(DefineFixed(new LCallConstantFunction, rax), instr);
1122 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1123 LOperand* function = UseFixed(instr->function(), rdi);
1124 argument_count_ -= instr->argument_count();
1125 LInvokeFunction* result = new LInvokeFunction(function);
1126 return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1130 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1131 BuiltinFunctionId op = instr->op();
1132 if (op == kMathLog || op == kMathSin || op == kMathCos) {
1133 LOperand* input = UseFixedDouble(instr->value(), xmm1);
1134 LUnaryMathOperation* result = new LUnaryMathOperation(input);
1135 return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1137 LOperand* input = UseRegisterAtStart(instr->value());
1138 LUnaryMathOperation* result = new LUnaryMathOperation(input);
1141 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1143 return AssignEnvironment(DefineAsRegister(result));
1145 return AssignEnvironment(DefineAsRegister(result));
1147 return DefineSameAsFirst(result);
1149 return DefineSameAsFirst(result);
1158 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
1159 ASSERT(instr->key()->representation().IsTagged());
1160 LOperand* key = UseFixed(instr->key(), rcx);
1161 argument_count_ -= instr->argument_count();
1162 LCallKeyed* result = new LCallKeyed(key);
1163 return MarkAsCall(DefineFixed(result, rax), instr);
1167 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
1168 argument_count_ -= instr->argument_count();
1169 return MarkAsCall(DefineFixed(new LCallNamed, rax), instr);
1173 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
1174 argument_count_ -= instr->argument_count();
1175 return MarkAsCall(DefineFixed(new LCallGlobal(instr->qml_global()), rax), instr);
1179 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
1180 argument_count_ -= instr->argument_count();
1181 return MarkAsCall(DefineFixed(new LCallKnownGlobal, rax), instr);
1185 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
1186 LOperand* constructor = UseFixed(instr->constructor(), rdi);
1187 argument_count_ -= instr->argument_count();
1188 LCallNew* result = new LCallNew(constructor);
1189 return MarkAsCall(DefineFixed(result, rax), instr);
1193 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
1194 argument_count_ -= instr->argument_count();
1195 LCallFunction* result = new LCallFunction();
1196 return MarkAsCall(DefineFixed(result, rax), instr);
1200 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1201 argument_count_ -= instr->argument_count();
1202 return MarkAsCall(DefineFixed(new LCallRuntime, rax), instr);
1206 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1207 return DoShift(Token::SHR, instr);
1211 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1212 return DoShift(Token::SAR, instr);
1216 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1217 return DoShift(Token::SHL, instr);
1221 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1222 if (instr->representation().IsInteger32()) {
1223 ASSERT(instr->left()->representation().IsInteger32());
1224 ASSERT(instr->right()->representation().IsInteger32());
1226 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1227 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1228 return DefineSameAsFirst(new LBitI(left, right));
1230 ASSERT(instr->representation().IsTagged());
1231 ASSERT(instr->left()->representation().IsTagged());
1232 ASSERT(instr->right()->representation().IsTagged());
1234 LOperand* left = UseFixed(instr->left(), rdx);
1235 LOperand* right = UseFixed(instr->right(), rax);
1236 LArithmeticT* result = new LArithmeticT(instr->op(), left, right);
1237 return MarkAsCall(DefineFixed(result, rax), instr);
1242 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) {
1243 ASSERT(instr->value()->representation().IsInteger32());
1244 ASSERT(instr->representation().IsInteger32());
1245 LOperand* input = UseRegisterAtStart(instr->value());
1246 LBitNotI* result = new LBitNotI(input);
1247 return DefineSameAsFirst(result);
1251 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1252 if (instr->representation().IsDouble()) {
1253 return DoArithmeticD(Token::DIV, instr);
1254 } else if (instr->representation().IsInteger32()) {
1255 // The temporary operand is necessary to ensure that right is not allocated
1257 LOperand* temp = FixedTemp(rdx);
1258 LOperand* dividend = UseFixed(instr->left(), rax);
1259 LOperand* divisor = UseRegister(instr->right());
1260 LDivI* result = new LDivI(dividend, divisor, temp);
1261 return AssignEnvironment(DefineFixed(result, rax));
1263 ASSERT(instr->representation().IsTagged());
1264 return DoArithmeticT(Token::DIV, instr);
1269 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1270 if (instr->representation().IsInteger32()) {
1271 ASSERT(instr->left()->representation().IsInteger32());
1272 ASSERT(instr->right()->representation().IsInteger32());
1274 LInstruction* result;
1275 if (instr->HasPowerOf2Divisor()) {
1276 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero));
1277 LOperand* value = UseRegisterAtStart(instr->left());
1278 LModI* mod = new LModI(value, UseOrConstant(instr->right()), NULL);
1279 result = DefineSameAsFirst(mod);
1281 // The temporary operand is necessary to ensure that right is not
1282 // allocated into edx.
1283 LOperand* temp = FixedTemp(rdx);
1284 LOperand* value = UseFixed(instr->left(), rax);
1285 LOperand* divisor = UseRegister(instr->right());
1286 LModI* mod = new LModI(value, divisor, temp);
1287 result = DefineFixed(mod, rdx);
1290 return (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1291 instr->CheckFlag(HValue::kCanBeDivByZero))
1292 ? AssignEnvironment(result)
1294 } else if (instr->representation().IsTagged()) {
1295 return DoArithmeticT(Token::MOD, instr);
1297 ASSERT(instr->representation().IsDouble());
1298 // We call a C function for double modulo. It can't trigger a GC.
1299 // We need to use fixed result register for the call.
1300 // TODO(fschneider): Allow any register as input registers.
1301 LOperand* left = UseFixedDouble(instr->left(), xmm2);
1302 LOperand* right = UseFixedDouble(instr->right(), xmm1);
1303 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right);
1304 return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
1309 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1310 if (instr->representation().IsInteger32()) {
1311 ASSERT(instr->left()->representation().IsInteger32());
1312 ASSERT(instr->right()->representation().IsInteger32());
1313 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1314 LOperand* right = UseOrConstant(instr->MostConstantOperand());
1315 LMulI* mul = new LMulI(left, right);
1316 return AssignEnvironment(DefineSameAsFirst(mul));
1317 } else if (instr->representation().IsDouble()) {
1318 return DoArithmeticD(Token::MUL, instr);
1320 ASSERT(instr->representation().IsTagged());
1321 return DoArithmeticT(Token::MUL, instr);
1326 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1327 if (instr->representation().IsInteger32()) {
1328 ASSERT(instr->left()->representation().IsInteger32());
1329 ASSERT(instr->right()->representation().IsInteger32());
1330 LOperand* left = UseRegisterAtStart(instr->left());
1331 LOperand* right = UseOrConstantAtStart(instr->right());
1332 LSubI* sub = new LSubI(left, right);
1333 LInstruction* result = DefineSameAsFirst(sub);
1334 if (instr->CheckFlag(HValue::kCanOverflow)) {
1335 result = AssignEnvironment(result);
1338 } else if (instr->representation().IsDouble()) {
1339 return DoArithmeticD(Token::SUB, instr);
1341 ASSERT(instr->representation().IsTagged());
1342 return DoArithmeticT(Token::SUB, instr);
1347 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1348 if (instr->representation().IsInteger32()) {
1349 ASSERT(instr->left()->representation().IsInteger32());
1350 ASSERT(instr->right()->representation().IsInteger32());
1351 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
1352 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
1353 LAddI* add = new LAddI(left, right);
1354 LInstruction* result = DefineSameAsFirst(add);
1355 if (instr->CheckFlag(HValue::kCanOverflow)) {
1356 result = AssignEnvironment(result);
1359 } else if (instr->representation().IsDouble()) {
1360 return DoArithmeticD(Token::ADD, instr);
1362 ASSERT(instr->representation().IsTagged());
1363 return DoArithmeticT(Token::ADD, instr);
1369 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1370 ASSERT(instr->representation().IsDouble());
1371 // We call a C function for double power. It can't trigger a GC.
1372 // We need to use fixed result register for the call.
1373 Representation exponent_type = instr->right()->representation();
1374 ASSERT(instr->left()->representation().IsDouble());
1375 LOperand* left = UseFixedDouble(instr->left(), xmm2);
1376 LOperand* right = exponent_type.IsDouble() ?
1377 UseFixedDouble(instr->right(), xmm1) :
1379 UseFixed(instr->right(), rdx);
1381 UseFixed(instr->right(), rdi);
1383 LPower* result = new LPower(left, right);
1384 return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
1385 CAN_DEOPTIMIZE_EAGERLY);
1389 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1390 ASSERT(instr->left()->representation().IsTagged());
1391 ASSERT(instr->right()->representation().IsTagged());
1392 LOperand* left = UseFixed(instr->left(), rdx);
1393 LOperand* right = UseFixed(instr->right(), rax);
1394 LCmpT* result = new LCmpT(left, right);
1395 return MarkAsCall(DefineFixed(result, rax), instr);
1399 LInstruction* LChunkBuilder::DoCompareIDAndBranch(
1400 HCompareIDAndBranch* instr) {
1401 Representation r = instr->GetInputRepresentation();
1402 if (r.IsInteger32()) {
1403 ASSERT(instr->left()->representation().IsInteger32());
1404 ASSERT(instr->right()->representation().IsInteger32());
1405 LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1406 LOperand* right = UseOrConstantAtStart(instr->right());
1407 return new LCmpIDAndBranch(left, right);
1409 ASSERT(r.IsDouble());
1410 ASSERT(instr->left()->representation().IsDouble());
1411 ASSERT(instr->right()->representation().IsDouble());
1414 if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1415 left = UseRegisterOrConstantAtStart(instr->left());
1416 right = UseRegisterOrConstantAtStart(instr->right());
1418 left = UseRegisterAtStart(instr->left());
1419 right = UseRegisterAtStart(instr->right());
1421 return new LCmpIDAndBranch(left, right);
1426 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1427 HCompareObjectEqAndBranch* instr) {
1428 LOperand* left = UseRegisterAtStart(instr->left());
1429 LOperand* right = UseRegisterAtStart(instr->right());
1430 return new LCmpObjectEqAndBranch(left, right);
1434 LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch(
1435 HCompareConstantEqAndBranch* instr) {
1436 return new LCmpConstantEqAndBranch(UseRegisterAtStart(instr->value()));
1440 LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) {
1441 ASSERT(instr->value()->representation().IsTagged());
1442 LOperand* temp = instr->kind() == kStrictEquality ? NULL : TempRegister();
1443 return new LIsNilAndBranch(UseRegisterAtStart(instr->value()), temp);
1447 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
1448 ASSERT(instr->value()->representation().IsTagged());
1449 return new LIsObjectAndBranch(UseRegisterAtStart(instr->value()));
1453 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1454 ASSERT(instr->value()->representation().IsTagged());
1455 return new LIsSmiAndBranch(Use(instr->value()));
1459 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1460 HIsUndetectableAndBranch* instr) {
1461 ASSERT(instr->value()->representation().IsTagged());
1462 return new LIsUndetectableAndBranch(UseRegisterAtStart(instr->value()),
1467 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1468 HHasInstanceTypeAndBranch* instr) {
1469 ASSERT(instr->value()->representation().IsTagged());
1470 return new LHasInstanceTypeAndBranch(UseRegisterAtStart(instr->value()));
1474 LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
1475 HGetCachedArrayIndex* instr) {
1476 ASSERT(instr->value()->representation().IsTagged());
1477 LOperand* value = UseRegisterAtStart(instr->value());
1479 return DefineAsRegister(new LGetCachedArrayIndex(value));
1483 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
1484 HHasCachedArrayIndexAndBranch* instr) {
1485 ASSERT(instr->value()->representation().IsTagged());
1486 return new LHasCachedArrayIndexAndBranch(UseRegisterAtStart(instr->value()));
1490 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1491 HClassOfTestAndBranch* instr) {
1492 return new LClassOfTestAndBranch(UseTempRegister(instr->value()),
1498 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
1499 LOperand* array = UseRegisterAtStart(instr->value());
1500 return DefineAsRegister(new LJSArrayLength(array));
1504 LInstruction* LChunkBuilder::DoFixedArrayBaseLength(
1505 HFixedArrayBaseLength* instr) {
1506 LOperand* array = UseRegisterAtStart(instr->value());
1507 return DefineAsRegister(new LFixedArrayBaseLength(array));
1511 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) {
1512 LOperand* object = UseRegisterAtStart(instr->value());
1513 return DefineAsRegister(new LElementsKind(object));
1517 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
1518 LOperand* object = UseRegister(instr->value());
1519 LValueOf* result = new LValueOf(object);
1520 return AssignEnvironment(DefineSameAsFirst(result));
1524 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1525 return AssignEnvironment(new LBoundsCheck(
1526 UseRegisterOrConstantAtStart(instr->index()),
1527 Use(instr->length())));
1531 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1532 // The control instruction marking the end of a block that completed
1533 // abruptly (e.g., threw an exception). There is nothing specific to do.
1538 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
1539 LOperand* value = UseFixed(instr->value(), rax);
1540 return MarkAsCall(new LThrow(value), instr);
1544 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1549 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1550 // All HForceRepresentation instructions should be eliminated in the
1551 // representation change phase of Hydrogen.
1557 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1558 Representation from = instr->from();
1559 Representation to = instr->to();
1560 if (from.IsTagged()) {
1561 if (to.IsDouble()) {
1562 LOperand* value = UseRegister(instr->value());
1563 LNumberUntagD* res = new LNumberUntagD(value);
1564 return AssignEnvironment(DefineAsRegister(res));
1566 ASSERT(to.IsInteger32());
1567 LOperand* value = UseRegister(instr->value());
1568 bool needs_check = !instr->value()->type().IsSmi();
1570 bool truncating = instr->CanTruncateToInt32();
1571 LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1572 LTaggedToI* res = new LTaggedToI(value, xmm_temp);
1573 return AssignEnvironment(DefineSameAsFirst(res));
1575 return DefineSameAsFirst(new LSmiUntag(value, needs_check));
1578 } else if (from.IsDouble()) {
1579 if (to.IsTagged()) {
1580 LOperand* value = UseRegister(instr->value());
1581 LOperand* temp = TempRegister();
1583 // Make sure that temp and result_temp are different registers.
1584 LUnallocated* result_temp = TempRegister();
1585 LNumberTagD* result = new LNumberTagD(value, temp);
1586 return AssignPointerMap(Define(result, result_temp));
1588 ASSERT(to.IsInteger32());
1589 LOperand* value = UseRegister(instr->value());
1590 return AssignEnvironment(DefineAsRegister(new LDoubleToI(value)));
1592 } else if (from.IsInteger32()) {
1593 if (to.IsTagged()) {
1594 HValue* val = instr->value();
1595 LOperand* value = UseRegister(val);
1596 if (val->HasRange() && val->range()->IsInSmiRange()) {
1597 return DefineSameAsFirst(new LSmiTag(value));
1599 LNumberTagI* result = new LNumberTagI(value);
1600 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
1603 ASSERT(to.IsDouble());
1604 return DefineAsRegister(new LInteger32ToDouble(Use(instr->value())));
1612 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
1613 LOperand* value = UseRegisterAtStart(instr->value());
1614 return AssignEnvironment(new LCheckNonSmi(value));
1618 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1619 LOperand* value = UseRegisterAtStart(instr->value());
1620 LCheckInstanceType* result = new LCheckInstanceType(value);
1621 return AssignEnvironment(result);
1625 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
1626 LOperand* temp = TempRegister();
1627 LCheckPrototypeMaps* result = new LCheckPrototypeMaps(temp);
1628 return AssignEnvironment(result);
1632 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1633 LOperand* value = UseRegisterAtStart(instr->value());
1634 return AssignEnvironment(new LCheckSmi(value));
1638 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
1639 LOperand* value = UseRegisterAtStart(instr->value());
1640 return AssignEnvironment(new LCheckFunction(value));
1644 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
1645 LOperand* value = UseRegisterAtStart(instr->value());
1646 LCheckMap* result = new LCheckMap(value);
1647 return AssignEnvironment(result);
1651 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1652 HValue* value = instr->value();
1653 Representation input_rep = value->representation();
1654 LOperand* reg = UseRegister(value);
1655 if (input_rep.IsDouble()) {
1656 return DefineAsRegister(new LClampDToUint8(reg,
1658 } else if (input_rep.IsInteger32()) {
1659 return DefineSameAsFirst(new LClampIToUint8(reg));
1661 ASSERT(input_rep.IsTagged());
1662 // Register allocator doesn't (yet) support allocation of double
1663 // temps. Reserve xmm1 explicitly.
1664 LClampTToUint8* result = new LClampTToUint8(reg,
1667 return AssignEnvironment(DefineSameAsFirst(result));
1672 LInstruction* LChunkBuilder::DoToInt32(HToInt32* instr) {
1673 HValue* value = instr->value();
1674 Representation input_rep = value->representation();
1675 LOperand* reg = UseRegister(value);
1676 if (input_rep.IsDouble()) {
1677 return AssignEnvironment(DefineAsRegister(new LDoubleToI(reg)));
1678 } else if (input_rep.IsInteger32()) {
1679 // Canonicalization should already have removed the hydrogen instruction in
1680 // this case, since it is a noop.
1684 ASSERT(input_rep.IsTagged());
1685 LOperand* reg = UseRegister(value);
1686 // Register allocator doesn't (yet) support allocation of double
1687 // temps. Reserve xmm1 explicitly.
1688 LOperand* xmm_temp =
1689 CpuFeatures::IsSupported(SSE3)
1692 return AssignEnvironment(
1693 DefineSameAsFirst(new LTaggedToI(reg, xmm_temp)));
1698 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1699 return new LReturn(UseFixed(instr->value(), rax));
1703 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1704 Representation r = instr->representation();
1705 if (r.IsInteger32()) {
1706 return DefineAsRegister(new LConstantI);
1707 } else if (r.IsDouble()) {
1708 LOperand* temp = TempRegister();
1709 return DefineAsRegister(new LConstantD(temp));
1710 } else if (r.IsTagged()) {
1711 return DefineAsRegister(new LConstantT);
1719 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
1720 LLoadGlobalCell* result = new LLoadGlobalCell;
1721 return instr->RequiresHoleCheck()
1722 ? AssignEnvironment(DefineAsRegister(result))
1723 : DefineAsRegister(result);
1727 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
1728 LOperand* global_object = UseFixed(instr->global_object(), rax);
1729 LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object);
1730 return MarkAsCall(DefineFixed(result, rax), instr);
1734 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
1735 LStoreGlobalCell* result =
1736 new LStoreGlobalCell(UseTempRegister(instr->value()),
1739 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result;
1743 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
1744 LOperand* global_object = UseFixed(instr->global_object(), rdx);
1745 LOperand* value = UseFixed(instr->value(), rax);
1746 LStoreGlobalGeneric* result = new LStoreGlobalGeneric(global_object, value);
1747 return MarkAsCall(result, instr);
1751 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1752 LOperand* context = UseRegisterAtStart(instr->value());
1753 return DefineAsRegister(new LLoadContextSlot(context));
1757 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1761 if (instr->NeedsWriteBarrier()) {
1762 context = UseTempRegister(instr->context());
1763 value = UseTempRegister(instr->value());
1764 temp = TempRegister();
1766 context = UseRegister(instr->context());
1767 value = UseRegister(instr->value());
1770 return new LStoreContextSlot(context, value, temp);
1774 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1775 ASSERT(instr->representation().IsTagged());
1776 LOperand* obj = UseRegisterAtStart(instr->object());
1777 return DefineAsRegister(new LLoadNamedField(obj));
1781 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic(
1782 HLoadNamedFieldPolymorphic* instr) {
1783 ASSERT(instr->representation().IsTagged());
1784 if (instr->need_generic()) {
1785 LOperand* obj = UseFixed(instr->object(), rax);
1786 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1787 return MarkAsCall(DefineFixed(result, rax), instr);
1789 LOperand* obj = UseRegisterAtStart(instr->object());
1790 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj);
1791 return AssignEnvironment(DefineAsRegister(result));
1796 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
1797 LOperand* object = UseFixed(instr->object(), rax);
1798 LLoadNamedGeneric* result = new LLoadNamedGeneric(object);
1799 return MarkAsCall(DefineFixed(result, rax), instr);
1803 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1804 HLoadFunctionPrototype* instr) {
1805 return AssignEnvironment(DefineAsRegister(
1806 new LLoadFunctionPrototype(UseRegister(instr->function()))));
1810 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
1811 LOperand* input = UseRegisterAtStart(instr->value());
1812 return DefineAsRegister(new LLoadElements(input));
1816 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer(
1817 HLoadExternalArrayPointer* instr) {
1818 LOperand* input = UseRegisterAtStart(instr->value());
1819 return DefineAsRegister(new LLoadExternalArrayPointer(input));
1823 LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
1824 HLoadKeyedFastElement* instr) {
1825 ASSERT(instr->representation().IsTagged());
1826 ASSERT(instr->key()->representation().IsInteger32());
1827 LOperand* obj = UseRegisterAtStart(instr->object());
1828 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1829 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
1830 return AssignEnvironment(DefineAsRegister(result));
1834 LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
1835 HLoadKeyedFastDoubleElement* instr) {
1836 ASSERT(instr->representation().IsDouble());
1837 ASSERT(instr->key()->representation().IsInteger32());
1838 LOperand* elements = UseRegisterAtStart(instr->elements());
1839 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1840 LLoadKeyedFastDoubleElement* result =
1841 new LLoadKeyedFastDoubleElement(elements, key);
1842 return AssignEnvironment(DefineAsRegister(result));
1846 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
1847 HLoadKeyedSpecializedArrayElement* instr) {
1848 ElementsKind elements_kind = instr->elements_kind();
1849 Representation representation(instr->representation());
1851 (representation.IsInteger32() &&
1852 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
1853 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1854 (representation.IsDouble() &&
1855 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
1856 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
1857 ASSERT(instr->key()->representation().IsInteger32());
1858 LOperand* external_pointer = UseRegister(instr->external_pointer());
1859 LOperand* key = UseRegisterOrConstant(instr->key());
1860 LLoadKeyedSpecializedArrayElement* result =
1861 new LLoadKeyedSpecializedArrayElement(external_pointer, key);
1862 LInstruction* load_instr = DefineAsRegister(result);
1863 // An unsigned int array load might overflow and cause a deopt, make sure it
1864 // has an environment.
1865 return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ?
1866 AssignEnvironment(load_instr) : load_instr;
1870 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
1871 LOperand* object = UseFixed(instr->object(), rdx);
1872 LOperand* key = UseFixed(instr->key(), rax);
1874 LLoadKeyedGeneric* result = new LLoadKeyedGeneric(object, key);
1875 return MarkAsCall(DefineFixed(result, rax), instr);
1879 LInstruction* LChunkBuilder::DoStoreKeyedFastElement(
1880 HStoreKeyedFastElement* instr) {
1881 bool needs_write_barrier = instr->NeedsWriteBarrier();
1882 ASSERT(instr->value()->representation().IsTagged());
1883 ASSERT(instr->object()->representation().IsTagged());
1884 ASSERT(instr->key()->representation().IsInteger32());
1886 LOperand* obj = UseTempRegister(instr->object());
1887 LOperand* val = needs_write_barrier
1888 ? UseTempRegister(instr->value())
1889 : UseRegisterAtStart(instr->value());
1890 LOperand* key = needs_write_barrier
1891 ? UseTempRegister(instr->key())
1892 : UseRegisterOrConstantAtStart(instr->key());
1894 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val));
1898 LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
1899 HStoreKeyedFastDoubleElement* instr) {
1900 ASSERT(instr->value()->representation().IsDouble());
1901 ASSERT(instr->elements()->representation().IsTagged());
1902 ASSERT(instr->key()->representation().IsInteger32());
1904 LOperand* elements = UseRegisterAtStart(instr->elements());
1905 LOperand* val = UseTempRegister(instr->value());
1906 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1908 return new LStoreKeyedFastDoubleElement(elements, key, val);
1912 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
1913 HStoreKeyedSpecializedArrayElement* instr) {
1914 Representation representation(instr->value()->representation());
1915 ElementsKind elements_kind = instr->elements_kind();
1917 (representation.IsInteger32() &&
1918 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
1919 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) ||
1920 (representation.IsDouble() &&
1921 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
1922 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
1923 ASSERT(instr->external_pointer()->representation().IsExternal());
1924 ASSERT(instr->key()->representation().IsInteger32());
1926 LOperand* external_pointer = UseRegister(instr->external_pointer());
1927 bool val_is_temp_register =
1928 elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
1929 elements_kind == EXTERNAL_FLOAT_ELEMENTS;
1930 LOperand* val = val_is_temp_register
1931 ? UseTempRegister(instr->value())
1932 : UseRegister(instr->value());
1933 LOperand* key = UseRegisterOrConstant(instr->key());
1935 return new LStoreKeyedSpecializedArrayElement(external_pointer,
1941 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
1942 LOperand* object = UseFixed(instr->object(), rdx);
1943 LOperand* key = UseFixed(instr->key(), rcx);
1944 LOperand* value = UseFixed(instr->value(), rax);
1946 ASSERT(instr->object()->representation().IsTagged());
1947 ASSERT(instr->key()->representation().IsTagged());
1948 ASSERT(instr->value()->representation().IsTagged());
1950 LStoreKeyedGeneric* result = new LStoreKeyedGeneric(object, key, value);
1951 return MarkAsCall(result, instr);
1955 LInstruction* LChunkBuilder::DoTransitionElementsKind(
1956 HTransitionElementsKind* instr) {
1957 if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
1958 instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) {
1959 LOperand* object = UseRegister(instr->object());
1960 LOperand* new_map_reg = TempRegister();
1961 LOperand* temp_reg = TempRegister();
1962 LTransitionElementsKind* result =
1963 new LTransitionElementsKind(object, new_map_reg, temp_reg);
1964 return DefineSameAsFirst(result);
1966 LOperand* object = UseFixed(instr->object(), rax);
1967 LOperand* fixed_object_reg = FixedTemp(rdx);
1968 LOperand* new_map_reg = FixedTemp(rbx);
1969 LTransitionElementsKind* result =
1970 new LTransitionElementsKind(object, new_map_reg, fixed_object_reg);
1971 return MarkAsCall(DefineFixed(result, rax), instr);
1976 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1977 bool needs_write_barrier = instr->NeedsWriteBarrier();
1979 LOperand* obj = needs_write_barrier
1980 ? UseTempRegister(instr->object())
1981 : UseRegisterAtStart(instr->object());
1983 LOperand* val = needs_write_barrier
1984 ? UseTempRegister(instr->value())
1985 : UseRegister(instr->value());
1987 // We only need a scratch register if we have a write barrier or we
1988 // have a store into the properties array (not in-object-property).
1989 LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
1990 ? TempRegister() : NULL;
1992 return new LStoreNamedField(obj, val, temp);
1996 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
1997 LOperand* object = UseFixed(instr->object(), rdx);
1998 LOperand* value = UseFixed(instr->value(), rax);
2000 LStoreNamedGeneric* result = new LStoreNamedGeneric(object, value);
2001 return MarkAsCall(result, instr);
2005 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2006 LOperand* left = UseOrConstantAtStart(instr->left());
2007 LOperand* right = UseOrConstantAtStart(instr->right());
2008 return MarkAsCall(DefineFixed(new LStringAdd(left, right), rax), instr);
2012 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2013 LOperand* string = UseTempRegister(instr->string());
2014 LOperand* index = UseTempRegister(instr->index());
2015 LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
2016 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
2020 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2021 LOperand* char_code = UseRegister(instr->value());
2022 LStringCharFromCode* result = new LStringCharFromCode(char_code);
2023 return AssignPointerMap(DefineAsRegister(result));
2027 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
2028 LOperand* string = UseRegisterAtStart(instr->value());
2029 return DefineAsRegister(new LStringLength(string));
2033 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
2034 return MarkAsCall(DefineFixed(new LArrayLiteral, rax), instr);
2038 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) {
2039 return MarkAsCall(DefineFixed(new LObjectLiteral, rax), instr);
2043 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
2044 return MarkAsCall(DefineFixed(new LRegExpLiteral, rax), instr);
2048 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
2049 return MarkAsCall(DefineFixed(new LFunctionLiteral, rax), instr);
2053 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
2054 LDeleteProperty* result =
2055 new LDeleteProperty(UseAtStart(instr->object()),
2056 UseOrConstantAtStart(instr->key()));
2057 return MarkAsCall(DefineFixed(result, rax), instr);
2061 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2062 allocator_->MarkAsOsrEntry();
2063 current_block_->last_environment()->set_ast_id(instr->ast_id());
2064 return AssignEnvironment(new LOsrEntry);
2068 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2069 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2070 return DefineAsSpilled(new LParameter, spill_index);
2074 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2075 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width.
2076 if (spill_index > LUnallocated::kMaxFixedIndex) {
2077 Abort("Too many spill slots needed for OSR");
2080 return DefineAsSpilled(new LUnknownOSRValue, spill_index);
2084 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
2085 argument_count_ -= instr->argument_count();
2086 return MarkAsCall(DefineFixed(new LCallStub, rax), instr);
2090 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2091 // There are no real uses of the arguments object.
2092 // arguments.length and element access are supported directly on
2093 // stack arguments, and any real arguments object use causes a bailout.
2094 // So this value is never used.
2099 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2100 LOperand* arguments = UseRegister(instr->arguments());
2101 LOperand* length = UseTempRegister(instr->length());
2102 LOperand* index = Use(instr->index());
2103 LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
2104 return AssignEnvironment(DefineAsRegister(result));
2108 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
2109 LOperand* object = UseFixed(instr->value(), rax);
2110 LToFastProperties* result = new LToFastProperties(object);
2111 return MarkAsCall(DefineFixed(result, rax), instr);
2115 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2116 LTypeof* result = new LTypeof(UseAtStart(instr->value()));
2117 return MarkAsCall(DefineFixed(result, rax), instr);
2121 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2122 return new LTypeofIsAndBranch(UseTempRegister(instr->value()));
2126 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
2127 HIsConstructCallAndBranch* instr) {
2128 return new LIsConstructCallAndBranch(TempRegister());
2132 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2133 HEnvironment* env = current_block_->last_environment();
2134 ASSERT(env != NULL);
2136 env->set_ast_id(instr->ast_id());
2138 env->Drop(instr->pop_count());
2139 for (int i = 0; i < instr->values()->length(); ++i) {
2140 HValue* value = instr->values()->at(i);
2141 if (instr->HasAssignedIndexAt(i)) {
2142 env->Bind(instr->GetAssignedIndexAt(i), value);
2148 // If there is an instruction pending deoptimization environment create a
2149 // lazy bailout instruction to capture the environment.
2150 if (pending_deoptimization_ast_id_ == instr->ast_id()) {
2151 LLazyBailout* lazy_bailout = new LLazyBailout;
2152 LInstruction* result = AssignEnvironment(lazy_bailout);
2153 instruction_pending_deoptimization_environment_->
2154 set_deoptimization_environment(result->environment());
2155 ClearInstructionPendingDeoptimizationEnvironment();
2163 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2164 if (instr->is_function_entry()) {
2165 return MarkAsCall(new LStackCheck, instr);
2167 ASSERT(instr->is_backwards_branch());
2168 return AssignEnvironment(AssignPointerMap(new LStackCheck));
2173 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2174 HEnvironment* outer = current_block_->last_environment();
2175 HConstant* undefined = graph()->GetConstantUndefined();
2176 HEnvironment* inner = outer->CopyForInlining(instr->closure(),
2179 instr->call_kind());
2180 current_block_->UpdateEnvironment(inner);
2181 chunk_->AddInlinedClosure(instr->closure());
2186 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2187 HEnvironment* outer = current_block_->last_environment()->outer();
2188 current_block_->UpdateEnvironment(outer);
2193 LInstruction* LChunkBuilder::DoIn(HIn* instr) {
2194 LOperand* key = UseOrConstantAtStart(instr->key());
2195 LOperand* object = UseOrConstantAtStart(instr->object());
2196 LIn* result = new LIn(key, object);
2197 return MarkAsCall(DefineFixed(result, rax), instr);
2201 } } // namespace v8::internal
2203 #endif // V8_TARGET_ARCH_X64