| Index: src/arm/lithium-arm.cc
|
| ===================================================================
|
| --- src/arm/lithium-arm.cc (revision 6800)
|
| +++ src/arm/lithium-arm.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -25,6 +25,7 @@
|
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| +#include "lithium-allocator-inl.h"
|
| #include "arm/lithium-arm.h"
|
| #include "arm/lithium-codegen-arm.h"
|
|
|
| @@ -56,6 +57,29 @@
|
| }
|
|
|
|
|
| +#ifdef DEBUG
|
| +void LInstruction::VerifyCall() {
|
| + // Call instructions can use only fixed registers as
|
| + // temporaries and outputs because all registers
|
| + // are blocked by the calling convention.
|
| + // Inputs must use a fixed register.
|
| + ASSERT(Output() == NULL ||
|
| + LUnallocated::cast(Output())->HasFixedPolicy() ||
|
| + !LUnallocated::cast(Output())->HasRegisterPolicy());
|
| + for (UseIterator it(this); it.HasNext(); it.Advance()) {
|
| + LOperand* operand = it.Next();
|
| + ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
|
| + !LUnallocated::cast(operand)->HasRegisterPolicy());
|
| + }
|
| + for (TempIterator it(this); it.HasNext(); it.Advance()) {
|
| + LOperand* operand = it.Next();
|
| + ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() ||
|
| + !LUnallocated::cast(operand)->HasRegisterPolicy());
|
| + }
|
| +}
|
| +#endif
|
| +
|
| +
|
| void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index,
|
| LOperand* spill_operand) {
|
| ASSERT(spill_operand->IsDoubleStackSlot());
|
| @@ -64,12 +88,11 @@
|
| }
|
|
|
|
|
| -void LInstruction::PrintTo(StringStream* stream) const {
|
| +void LInstruction::PrintTo(StringStream* stream) {
|
| stream->Add("%s ", this->Mnemonic());
|
| - if (HasResult()) {
|
| - result()->PrintTo(stream);
|
| - stream->Add(" ");
|
| - }
|
| +
|
| + PrintOutputOperandTo(stream);
|
| +
|
| PrintDataTo(stream);
|
|
|
| if (HasEnvironment()) {
|
| @@ -84,37 +107,33 @@
|
| }
|
|
|
|
|
| -void LLabel::PrintDataTo(StringStream* stream) const {
|
| - LGap::PrintDataTo(stream);
|
| - LLabel* rep = replacement();
|
| - if (rep != NULL) {
|
| - stream->Add(" Dead block replaced with B%d", rep->block_id());
|
| - }
|
| +template<int R, int I, int T>
|
| +void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) {
|
| + stream->Add("= ");
|
| + inputs_.PrintOperandsTo(stream);
|
| }
|
|
|
|
|
| -bool LParallelMove::IsRedundant() const {
|
| - for (int i = 0; i < move_operands_.length(); ++i) {
|
| - if (!move_operands_[i].IsRedundant()) return false;
|
| +template<int R, int I, int T>
|
| +void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) {
|
| + results_.PrintOperandsTo(stream);
|
| +}
|
| +
|
| +
|
| +template<typename T, int N>
|
| +void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) {
|
| + for (int i = 0; i < N; i++) {
|
| + if (i > 0) stream->Add(" ");
|
| + elems_[i]->PrintTo(stream);
|
| }
|
| - return true;
|
| }
|
|
|
|
|
| -void LParallelMove::PrintDataTo(StringStream* stream) const {
|
| - for (int i = move_operands_.length() - 1; i >= 0; --i) {
|
| - if (!move_operands_[i].IsEliminated()) {
|
| - LOperand* from = move_operands_[i].from();
|
| - LOperand* to = move_operands_[i].to();
|
| - if (from->Equals(to)) {
|
| - to->PrintTo(stream);
|
| - } else {
|
| - to->PrintTo(stream);
|
| - stream->Add(" = ");
|
| - from->PrintTo(stream);
|
| - }
|
| - stream->Add("; ");
|
| - }
|
| +void LLabel::PrintDataTo(StringStream* stream) {
|
| + LGap::PrintDataTo(stream);
|
| + LLabel* rep = replacement();
|
| + if (rep != NULL) {
|
| + stream->Add(" Dead block replaced with B%d", rep->block_id());
|
| }
|
| }
|
|
|
| @@ -162,6 +181,12 @@
|
| case Token::MUL: return "mul-t";
|
| case Token::MOD: return "mod-t";
|
| case Token::DIV: return "div-t";
|
| + case Token::BIT_AND: return "bit-and-t";
|
| + case Token::BIT_OR: return "bit-or-t";
|
| + case Token::BIT_XOR: return "bit-xor-t";
|
| + case Token::SHL: return "shl-t";
|
| + case Token::SAR: return "sar-t";
|
| + case Token::SHR: return "shr-t";
|
| default:
|
| UNREACHABLE();
|
| return NULL;
|
| @@ -169,74 +194,65 @@
|
| }
|
|
|
|
|
| -
|
| -void LBinaryOperation::PrintDataTo(StringStream* stream) const {
|
| - stream->Add("= ");
|
| - left()->PrintTo(stream);
|
| - stream->Add(" ");
|
| - right()->PrintTo(stream);
|
| -}
|
| -
|
| -
|
| -void LGoto::PrintDataTo(StringStream* stream) const {
|
| +void LGoto::PrintDataTo(StringStream* stream) {
|
| stream->Add("B%d", block_id());
|
| }
|
|
|
|
|
| -void LBranch::PrintDataTo(StringStream* stream) const {
|
| +void LBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| }
|
|
|
|
|
| -void LCmpIDAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if ");
|
| - left()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(" %s ", Token::String(op()));
|
| - right()->PrintTo(stream);
|
| + InputAt(1)->PrintTo(stream);
|
| stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LIsNullAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LIsNullAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if ");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(is_strict() ? " === null" : " == null");
|
| stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LIsObjectAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if is_object(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LIsSmiAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if is_smi(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if has_instance_type(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if has_cached_array_index(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if class_of_test(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(", \"%o\") then B%d else B%d",
|
| *hydrogen()->class_name(),
|
| true_block_id(),
|
| @@ -244,74 +260,82 @@
|
| }
|
|
|
|
|
| -void LTypeofIs::PrintDataTo(StringStream* stream) const {
|
| - input()->PrintTo(stream);
|
| +void LTypeofIs::PrintDataTo(StringStream* stream) {
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString());
|
| }
|
|
|
|
|
| -void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) const {
|
| +void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
|
| stream->Add("if typeof ");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(" == \"%s\" then B%d else B%d",
|
| *hydrogen()->type_literal()->ToCString(),
|
| true_block_id(), false_block_id());
|
| }
|
|
|
|
|
| -void LCallConstantFunction::PrintDataTo(StringStream* stream) const {
|
| +void LCallConstantFunction::PrintDataTo(StringStream* stream) {
|
| stream->Add("#%d / ", arity());
|
| }
|
|
|
|
|
| -void LUnaryMathOperation::PrintDataTo(StringStream* stream) const {
|
| +void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
|
| stream->Add("/%s ", hydrogen()->OpName());
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| }
|
|
|
|
|
| -void LCallKeyed::PrintDataTo(StringStream* stream) const {
|
| +void LLoadContextSlot::PrintDataTo(StringStream* stream) {
|
| + InputAt(0)->PrintTo(stream);
|
| + stream->Add("[%d]", slot_index());
|
| +}
|
| +
|
| +
|
| +void LStoreContextSlot::PrintDataTo(StringStream* stream) {
|
| + InputAt(0)->PrintTo(stream);
|
| + stream->Add("[%d] <- ", slot_index());
|
| + InputAt(1)->PrintTo(stream);
|
| +}
|
| +
|
| +
|
| +void LCallKeyed::PrintDataTo(StringStream* stream) {
|
| stream->Add("[r2] #%d / ", arity());
|
| }
|
|
|
|
|
| -void LCallNamed::PrintDataTo(StringStream* stream) const {
|
| +void LCallNamed::PrintDataTo(StringStream* stream) {
|
| SmartPointer<char> name_string = name()->ToCString();
|
| stream->Add("%s #%d / ", *name_string, arity());
|
| }
|
|
|
|
|
| -void LCallGlobal::PrintDataTo(StringStream* stream) const {
|
| +void LCallGlobal::PrintDataTo(StringStream* stream) {
|
| SmartPointer<char> name_string = name()->ToCString();
|
| stream->Add("%s #%d / ", *name_string, arity());
|
| }
|
|
|
|
|
| -void LCallKnownGlobal::PrintDataTo(StringStream* stream) const {
|
| +void LCallKnownGlobal::PrintDataTo(StringStream* stream) {
|
| stream->Add("#%d / ", arity());
|
| }
|
|
|
|
|
| -void LCallNew::PrintDataTo(StringStream* stream) const {
|
| - LUnaryOperation::PrintDataTo(stream);
|
| +void LCallNew::PrintDataTo(StringStream* stream) {
|
| + stream->Add("= ");
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(" #%d / ", arity());
|
| }
|
|
|
|
|
| -void LClassOfTest::PrintDataTo(StringStream* stream) const {
|
| +void LClassOfTest::PrintDataTo(StringStream* stream) {
|
| stream->Add("= class_of_test(");
|
| - input()->PrintTo(stream);
|
| + InputAt(0)->PrintTo(stream);
|
| stream->Add(", \"%o\")", *hydrogen()->class_name());
|
| }
|
|
|
|
|
| -void LUnaryOperation::PrintDataTo(StringStream* stream) const {
|
| - stream->Add("= ");
|
| - input()->PrintTo(stream);
|
| -}
|
| -
|
| -
|
| -void LAccessArgumentsAt::PrintDataTo(StringStream* stream) const {
|
| +void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
|
| arguments()->PrintTo(stream);
|
|
|
| stream->Add(" length ");
|
| @@ -322,6 +346,24 @@
|
| }
|
|
|
|
|
| +void LStoreNamed::PrintDataTo(StringStream* stream) {
|
| + object()->PrintTo(stream);
|
| + stream->Add(".");
|
| + stream->Add(*String::cast(*name())->ToCString());
|
| + stream->Add(" <- ");
|
| + value()->PrintTo(stream);
|
| +}
|
| +
|
| +
|
| +void LStoreKeyed::PrintDataTo(StringStream* stream) {
|
| + object()->PrintTo(stream);
|
| + stream->Add("[");
|
| + key()->PrintTo(stream);
|
| + stream->Add("] <- ");
|
| + value()->PrintTo(stream);
|
| +}
|
| +
|
| +
|
| LChunk::LChunk(HGraph* graph)
|
| : spill_slot_count_(0),
|
| graph_(graph),
|
| @@ -331,11 +373,6 @@
|
| }
|
|
|
|
|
| -void LChunk::Verify() const {
|
| - // TODO(twuerthinger): Implement verification for chunk.
|
| -}
|
| -
|
| -
|
| int LChunk::GetNextSpillIndex(bool is_double) {
|
| // Skip a slot if for a double-width slot.
|
| if (is_double) spill_slot_count_++;
|
| @@ -390,25 +427,7 @@
|
| }
|
|
|
|
|
| -void LStoreNamed::PrintDataTo(StringStream* stream) const {
|
| - object()->PrintTo(stream);
|
| - stream->Add(".");
|
| - stream->Add(*String::cast(*name())->ToCString());
|
| - stream->Add(" <- ");
|
| - value()->PrintTo(stream);
|
| -}
|
| -
|
| -
|
| -void LStoreKeyed::PrintDataTo(StringStream* stream) const {
|
| - object()->PrintTo(stream);
|
| - stream->Add("[");
|
| - key()->PrintTo(stream);
|
| - stream->Add("] <- ");
|
| - value()->PrintTo(stream);
|
| -}
|
| -
|
| -
|
| -int LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
|
| +void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) {
|
| LGap* gap = new LGap(block);
|
| int index = -1;
|
| if (instr->IsControl()) {
|
| @@ -424,7 +443,6 @@
|
| pointer_maps_.Add(instr->pointer_map());
|
| instr->pointer_map()->set_lithium_position(index);
|
| }
|
| - return index;
|
| }
|
|
|
|
|
| @@ -472,151 +490,6 @@
|
| }
|
|
|
|
|
| -class LGapNode: public ZoneObject {
|
| - public:
|
| - explicit LGapNode(LOperand* operand)
|
| - : operand_(operand), resolved_(false), visited_id_(-1) { }
|
| -
|
| - LOperand* operand() const { return operand_; }
|
| - bool IsResolved() const { return !IsAssigned() || resolved_; }
|
| - void MarkResolved() {
|
| - ASSERT(!IsResolved());
|
| - resolved_ = true;
|
| - }
|
| - int visited_id() const { return visited_id_; }
|
| - void set_visited_id(int id) {
|
| - ASSERT(id > visited_id_);
|
| - visited_id_ = id;
|
| - }
|
| -
|
| - bool IsAssigned() const { return assigned_from_.is_set(); }
|
| - LGapNode* assigned_from() const { return assigned_from_.get(); }
|
| - void set_assigned_from(LGapNode* n) { assigned_from_.set(n); }
|
| -
|
| - private:
|
| - LOperand* operand_;
|
| - SetOncePointer<LGapNode> assigned_from_;
|
| - bool resolved_;
|
| - int visited_id_;
|
| -};
|
| -
|
| -
|
| -LGapResolver::LGapResolver(const ZoneList<LMoveOperands>* moves,
|
| - LOperand* marker_operand)
|
| - : nodes_(4),
|
| - identified_cycles_(4),
|
| - result_(4),
|
| - marker_operand_(marker_operand),
|
| - next_visited_id_(0) {
|
| - for (int i = 0; i < moves->length(); ++i) {
|
| - LMoveOperands move = moves->at(i);
|
| - if (!move.IsRedundant()) RegisterMove(move);
|
| - }
|
| -}
|
| -
|
| -
|
| -const ZoneList<LMoveOperands>* LGapResolver::ResolveInReverseOrder() {
|
| - for (int i = 0; i < identified_cycles_.length(); ++i) {
|
| - ResolveCycle(identified_cycles_[i]);
|
| - }
|
| -
|
| - int unresolved_nodes;
|
| - do {
|
| - unresolved_nodes = 0;
|
| - for (int j = 0; j < nodes_.length(); j++) {
|
| - LGapNode* node = nodes_[j];
|
| - if (!node->IsResolved() && node->assigned_from()->IsResolved()) {
|
| - AddResultMove(node->assigned_from(), node);
|
| - node->MarkResolved();
|
| - }
|
| - if (!node->IsResolved()) ++unresolved_nodes;
|
| - }
|
| - } while (unresolved_nodes > 0);
|
| - return &result_;
|
| -}
|
| -
|
| -
|
| -void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) {
|
| - AddResultMove(from->operand(), to->operand());
|
| -}
|
| -
|
| -
|
| -void LGapResolver::AddResultMove(LOperand* from, LOperand* to) {
|
| - result_.Add(LMoveOperands(from, to));
|
| -}
|
| -
|
| -
|
| -void LGapResolver::ResolveCycle(LGapNode* start) {
|
| - ZoneList<LOperand*> circle_operands(8);
|
| - circle_operands.Add(marker_operand_);
|
| - LGapNode* cur = start;
|
| - do {
|
| - cur->MarkResolved();
|
| - circle_operands.Add(cur->operand());
|
| - cur = cur->assigned_from();
|
| - } while (cur != start);
|
| - circle_operands.Add(marker_operand_);
|
| -
|
| - for (int i = circle_operands.length() - 1; i > 0; --i) {
|
| - LOperand* from = circle_operands[i];
|
| - LOperand* to = circle_operands[i - 1];
|
| - AddResultMove(from, to);
|
| - }
|
| -}
|
| -
|
| -
|
| -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) {
|
| - ASSERT(a != b);
|
| - LGapNode* cur = a;
|
| - while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) {
|
| - cur->set_visited_id(visited_id);
|
| - cur = cur->assigned_from();
|
| - }
|
| -
|
| - return cur == b;
|
| -}
|
| -
|
| -
|
| -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) {
|
| - ASSERT(a != b);
|
| - return CanReach(a, b, next_visited_id_++);
|
| -}
|
| -
|
| -
|
| -void LGapResolver::RegisterMove(LMoveOperands move) {
|
| - if (move.from()->IsConstantOperand()) {
|
| - // Constant moves should be last in the machine code. Therefore add them
|
| - // first to the result set.
|
| - AddResultMove(move.from(), move.to());
|
| - } else {
|
| - LGapNode* from = LookupNode(move.from());
|
| - LGapNode* to = LookupNode(move.to());
|
| - if (to->IsAssigned() && to->assigned_from() == from) {
|
| - move.Eliminate();
|
| - return;
|
| - }
|
| - ASSERT(!to->IsAssigned());
|
| - if (CanReach(from, to)) {
|
| - // This introduces a circle. Save.
|
| - identified_cycles_.Add(from);
|
| - }
|
| - to->set_assigned_from(from);
|
| - }
|
| -}
|
| -
|
| -
|
| -LGapNode* LGapResolver::LookupNode(LOperand* operand) {
|
| - for (int i = 0; i < nodes_.length(); ++i) {
|
| - if (nodes_[i]->operand()->Equals(operand)) return nodes_[i];
|
| - }
|
| -
|
| - // No node found => create a new one.
|
| - LGapNode* result = new LGapNode(operand);
|
| - nodes_.Add(result);
|
| - return result;
|
| -}
|
| -
|
| -
|
| Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const {
|
| return HConstant::cast(graph_->LookupValue(operand->index()))->handle();
|
| }
|
| @@ -742,6 +615,13 @@
|
| }
|
|
|
|
|
| +LOperand* LChunkBuilder::UseAny(HValue* value) {
|
| + return value->IsConstant()
|
| + ? chunk_->DefineConstantOperand(HConstant::cast(value))
|
| + : Use(value, new LUnallocated(LUnallocated::ANY));
|
| +}
|
| +
|
| +
|
| LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
|
| if (value->EmitAtUses()) {
|
| HInstruction* instr = HInstruction::cast(value);
|
| @@ -752,33 +632,52 @@
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::Define(LInstruction* instr) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr,
|
| + LUnallocated* result) {
|
| + allocator_->RecordDefinition(current_instruction_, result);
|
| + instr->set_result(result);
|
| + return instr;
|
| +}
|
| +
|
| +
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) {
|
| return Define(instr, new LUnallocated(LUnallocated::NONE));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DefineAsRegister(LInstruction* instr) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::DefineAsRegister(
|
| + LTemplateInstruction<1, I, T>* instr) {
|
| return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DefineAsSpilled(LInstruction* instr, int index) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::DefineAsSpilled(
|
| + LTemplateInstruction<1, I, T>* instr, int index) {
|
| return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DefineSameAsFirst(LInstruction* instr) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::DefineSameAsFirst(
|
| + LTemplateInstruction<1, I, T>* instr) {
|
| return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DefineFixed(LInstruction* instr, Register reg) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::DefineFixed(
|
| + LTemplateInstruction<1, I, T>* instr, Register reg) {
|
| return Define(instr, ToUnallocated(reg));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DefineFixedDouble(LInstruction* instr,
|
| - DoubleRegister reg) {
|
| +template<int I, int T>
|
| +LInstruction* LChunkBuilder::DefineFixedDouble(
|
| + LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) {
|
| return Define(instr, ToUnallocated(reg));
|
| }
|
|
|
| @@ -792,16 +691,16 @@
|
|
|
| LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment(
|
| LInstruction* instr, int ast_id) {
|
| - ASSERT(instructions_pending_deoptimization_environment_ == NULL);
|
| + ASSERT(instruction_pending_deoptimization_environment_ == NULL);
|
| ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber);
|
| - instructions_pending_deoptimization_environment_ = instr;
|
| + instruction_pending_deoptimization_environment_ = instr;
|
| pending_deoptimization_ast_id_ = ast_id;
|
| return instr;
|
| }
|
|
|
|
|
| void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() {
|
| - instructions_pending_deoptimization_environment_ = NULL;
|
| + instruction_pending_deoptimization_environment_ = NULL;
|
| pending_deoptimization_ast_id_ = AstNode::kNoNumber;
|
| }
|
|
|
| @@ -809,7 +708,10 @@
|
| LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
|
| HInstruction* hinstr,
|
| CanDeoptimize can_deoptimize) {
|
| - allocator_->MarkAsCall();
|
| +#ifdef DEBUG
|
| + instr->VerifyCall();
|
| +#endif
|
| + instr->MarkAsCall();
|
| instr = AssignPointerMap(instr);
|
|
|
| if (hinstr->HasSideEffects()) {
|
| @@ -833,27 +735,19 @@
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
|
| - ASSERT(!instr->HasPointerMap());
|
| - instr->set_pointer_map(new LPointerMap(position_));
|
| +LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) {
|
| + instr->MarkAsSaveDoubles();
|
| return instr;
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::Define(LInstruction* instr, LUnallocated* result) {
|
| - allocator_->RecordDefinition(current_instruction_, result);
|
| - instr->set_result(result);
|
| +LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
|
| + ASSERT(!instr->HasPointerMap());
|
| + instr->set_pointer_map(new LPointerMap(position_));
|
| return instr;
|
| }
|
|
|
|
|
| -LOperand* LChunkBuilder::Temp() {
|
| - LUnallocated* operand = new LUnallocated(LUnallocated::NONE);
|
| - allocator_->RecordTemporary(operand);
|
| - return operand;
|
| -}
|
| -
|
| -
|
| LUnallocated* LChunkBuilder::TempRegister() {
|
| LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
|
| allocator_->RecordTemporary(operand);
|
| @@ -887,18 +781,38 @@
|
|
|
| LInstruction* LChunkBuilder::DoBit(Token::Value op,
|
| HBitwiseBinaryOperation* instr) {
|
| - ASSERT(instr->representation().IsInteger32());
|
| - ASSERT(instr->left()->representation().IsInteger32());
|
| - ASSERT(instr->right()->representation().IsInteger32());
|
| + if (instr->representation().IsInteger32()) {
|
| + ASSERT(instr->left()->representation().IsInteger32());
|
| + ASSERT(instr->right()->representation().IsInteger32());
|
|
|
| - LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
| - LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
| - return DefineSameAsFirst(new LBitI(op, left, right));
|
| + LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
| + LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
| + return DefineSameAsFirst(new LBitI(op, left, right));
|
| + } else {
|
| + ASSERT(instr->representation().IsTagged());
|
| + ASSERT(instr->left()->representation().IsTagged());
|
| + ASSERT(instr->right()->representation().IsTagged());
|
| +
|
| + LOperand* left = UseFixed(instr->left(), r1);
|
| + LOperand* right = UseFixed(instr->right(), r0);
|
| + LArithmeticT* result = new LArithmeticT(op, left, right);
|
| + return MarkAsCall(DefineFixed(result, r0), instr);
|
| + }
|
| }
|
|
|
|
|
| LInstruction* LChunkBuilder::DoShift(Token::Value op,
|
| HBitwiseBinaryOperation* instr) {
|
| + if (instr->representation().IsTagged()) {
|
| + ASSERT(instr->left()->representation().IsTagged());
|
| + ASSERT(instr->right()->representation().IsTagged());
|
| +
|
| + LOperand* left = UseFixed(instr->left(), r1);
|
| + LOperand* right = UseFixed(instr->right(), r0);
|
| + LArithmeticT* result = new LArithmeticT(op, left, right);
|
| + return MarkAsCall(DefineFixed(result, r0), instr);
|
| + }
|
| +
|
| ASSERT(instr->representation().IsInteger32());
|
| ASSERT(instr->OperandAt(0)->representation().IsInteger32());
|
| ASSERT(instr->OperandAt(1)->representation().IsInteger32());
|
| @@ -961,10 +875,11 @@
|
| ASSERT(right->representation().IsTagged());
|
| LOperand* left_operand = UseFixed(left, r1);
|
| LOperand* right_operand = UseFixed(right, r0);
|
| - LInstruction* result = new LArithmeticT(op, left_operand, right_operand);
|
| + LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand);
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
|
|
| +
|
| void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
|
| ASSERT(is_building());
|
| current_block_ = block;
|
| @@ -1031,7 +946,6 @@
|
| void LChunkBuilder::VisitInstruction(HInstruction* current) {
|
| HInstruction* old_current = current_instruction_;
|
| current_instruction_ = current;
|
| - allocator_->BeginInstruction();
|
| if (current->has_position()) position_ = current->position();
|
| LInstruction* instr = current->CompileToLithium(this);
|
|
|
| @@ -1042,75 +956,24 @@
|
| if (FLAG_stress_environments && !instr->HasEnvironment()) {
|
| instr = AssignEnvironment(instr);
|
| }
|
| - if (current->IsBranch()) {
|
| - instr->set_hydrogen_value(HBranch::cast(current)->value());
|
| + if (current->IsTest() && !instr->IsGoto()) {
|
| + ASSERT(instr->IsControl());
|
| + HTest* test = HTest::cast(current);
|
| + instr->set_hydrogen_value(test->value());
|
| + HBasicBlock* first = test->FirstSuccessor();
|
| + HBasicBlock* second = test->SecondSuccessor();
|
| + ASSERT(first != NULL && second != NULL);
|
| + instr->SetBranchTargets(first->block_id(), second->block_id());
|
| } else {
|
| instr->set_hydrogen_value(current);
|
| }
|
|
|
| - int index = chunk_->AddInstruction(instr, current_block_);
|
| - allocator_->SummarizeInstruction(index);
|
| - } else {
|
| - // This instruction should be omitted.
|
| - allocator_->OmitInstruction();
|
| + chunk_->AddInstruction(instr, current_block_);
|
| }
|
| current_instruction_ = old_current;
|
| }
|
|
|
|
|
| -void LEnvironment::WriteTranslation(LCodeGen* cgen,
|
| - Translation* translation) const {
|
| - if (this == NULL) return;
|
| -
|
| - // The translation includes one command per value in the environment.
|
| - int translation_size = values()->length();
|
| - // The output frame height does not include the parameters.
|
| - int height = translation_size - parameter_count();
|
| -
|
| - outer()->WriteTranslation(cgen, translation);
|
| - int closure_id = cgen->DefineDeoptimizationLiteral(closure());
|
| - translation->BeginFrame(ast_id(), closure_id, height);
|
| - for (int i = 0; i < translation_size; ++i) {
|
| - LOperand* value = values()->at(i);
|
| - // spilled_registers_ and spilled_double_registers_ are either
|
| - // both NULL or both set.
|
| - if (spilled_registers_ != NULL && value != NULL) {
|
| - if (value->IsRegister() &&
|
| - spilled_registers_[value->index()] != NULL) {
|
| - translation->MarkDuplicate();
|
| - cgen->AddToTranslation(translation,
|
| - spilled_registers_[value->index()],
|
| - HasTaggedValueAt(i));
|
| - } else if (value->IsDoubleRegister() &&
|
| - spilled_double_registers_[value->index()] != NULL) {
|
| - translation->MarkDuplicate();
|
| - cgen->AddToTranslation(translation,
|
| - spilled_double_registers_[value->index()],
|
| - false);
|
| - }
|
| - }
|
| -
|
| - cgen->AddToTranslation(translation, value, HasTaggedValueAt(i));
|
| - }
|
| -}
|
| -
|
| -
|
| -void LEnvironment::PrintTo(StringStream* stream) const {
|
| - stream->Add("[id=%d|", ast_id());
|
| - stream->Add("[parameters=%d|", parameter_count());
|
| - stream->Add("[arguments_stack_height=%d|", arguments_stack_height());
|
| - for (int i = 0; i < values_.length(); ++i) {
|
| - if (i != 0) stream->Add(";");
|
| - if (values_[i] == NULL) {
|
| - stream->Add("[hole]");
|
| - } else {
|
| - values_[i]->PrintTo(stream);
|
| - }
|
| - }
|
| - stream->Add("]");
|
| -}
|
| -
|
| -
|
| LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) {
|
| if (hydrogen_env == NULL) return NULL;
|
|
|
| @@ -1133,11 +996,7 @@
|
| } else if (value->IsPushArgument()) {
|
| op = new LArgument(argument_index++);
|
| } else {
|
| - op = UseOrConstant(value);
|
| - if (op->IsUnallocated()) {
|
| - LUnallocated* unalloc = LUnallocated::cast(op);
|
| - unalloc->set_policy(LUnallocated::ANY);
|
| - }
|
| + op = UseAny(value);
|
| }
|
| result->AddValue(op, value->representation());
|
| }
|
| @@ -1154,45 +1013,31 @@
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
|
| +LInstruction* LChunkBuilder::DoTest(HTest* instr) {
|
| HValue* v = instr->value();
|
| - HBasicBlock* first = instr->FirstSuccessor();
|
| - HBasicBlock* second = instr->SecondSuccessor();
|
| - ASSERT(first != NULL && second != NULL);
|
| - int first_id = first->block_id();
|
| - int second_id = second->block_id();
|
| -
|
| if (v->EmitAtUses()) {
|
| if (v->IsClassOfTest()) {
|
| HClassOfTest* compare = HClassOfTest::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
|
|
| return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
|
| - TempRegister(),
|
| - TempRegister(),
|
| - first_id,
|
| - second_id);
|
| + TempRegister());
|
| } else if (v->IsCompare()) {
|
| HCompare* compare = HCompare::cast(v);
|
| Token::Value op = compare->token();
|
| HValue* left = compare->left();
|
| HValue* right = compare->right();
|
| - if (left->representation().IsInteger32()) {
|
| + Representation r = compare->GetInputRepresentation();
|
| + if (r.IsInteger32()) {
|
| + ASSERT(left->representation().IsInteger32());
|
| ASSERT(right->representation().IsInteger32());
|
| - return new LCmpIDAndBranch(op,
|
| - UseRegisterAtStart(left),
|
| - UseOrConstantAtStart(right),
|
| - first_id,
|
| - second_id,
|
| - false);
|
| - } else if (left->representation().IsDouble()) {
|
| + return new LCmpIDAndBranch(UseRegisterAtStart(left),
|
| + UseRegisterAtStart(right));
|
| + } else if (r.IsDouble()) {
|
| + ASSERT(left->representation().IsDouble());
|
| ASSERT(right->representation().IsDouble());
|
| - return new LCmpIDAndBranch(op,
|
| - UseRegisterAtStart(left),
|
| - UseRegisterAtStart(right),
|
| - first_id,
|
| - second_id,
|
| - true);
|
| + return new LCmpIDAndBranch(UseRegisterAtStart(left),
|
| + UseRegisterAtStart(right));
|
| } else {
|
| ASSERT(left->representation().IsTagged());
|
| ASSERT(right->representation().IsTagged());
|
| @@ -1200,87 +1045,68 @@
|
| LOperand* left_operand = UseFixed(left, reversed ? r0 : r1);
|
| LOperand* right_operand = UseFixed(right, reversed ? r1 : r0);
|
| LInstruction* result = new LCmpTAndBranch(left_operand,
|
| - right_operand,
|
| - first_id,
|
| - second_id);
|
| + right_operand);
|
| return MarkAsCall(result, instr);
|
| }
|
| } else if (v->IsIsSmi()) {
|
| HIsSmi* compare = HIsSmi::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
|
|
| - return new LIsSmiAndBranch(Use(compare->value()),
|
| - first_id,
|
| - second_id);
|
| + return new LIsSmiAndBranch(Use(compare->value()));
|
| } else if (v->IsHasInstanceType()) {
|
| HHasInstanceType* compare = HHasInstanceType::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
| -
|
| - return new LHasInstanceTypeAndBranch(UseRegisterAtStart(compare->value()),
|
| - first_id,
|
| - second_id);
|
| + return new LHasInstanceTypeAndBranch(
|
| + UseRegisterAtStart(compare->value()));
|
| } else if (v->IsHasCachedArrayIndex()) {
|
| HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
|
|
| return new LHasCachedArrayIndexAndBranch(
|
| - UseRegisterAtStart(compare->value()), first_id, second_id);
|
| + UseRegisterAtStart(compare->value()));
|
| } else if (v->IsIsNull()) {
|
| HIsNull* compare = HIsNull::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
|
|
| - return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
|
| - compare->is_strict(),
|
| - first_id,
|
| - second_id);
|
| + return new LIsNullAndBranch(UseRegisterAtStart(compare->value()));
|
| } else if (v->IsIsObject()) {
|
| HIsObject* compare = HIsObject::cast(v);
|
| ASSERT(compare->value()->representation().IsTagged());
|
|
|
| - LOperand* temp1 = TempRegister();
|
| - LOperand* temp2 = TempRegister();
|
| - return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
|
| - temp1,
|
| - temp2,
|
| - first_id,
|
| - second_id);
|
| + LOperand* temp = TempRegister();
|
| + return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()), temp);
|
| } else if (v->IsCompareJSObjectEq()) {
|
| HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
|
| return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()),
|
| - UseRegisterAtStart(compare->right()),
|
| - first_id,
|
| - second_id);
|
| + UseRegisterAtStart(compare->right()));
|
| } else if (v->IsInstanceOf()) {
|
| HInstanceOf* instance_of = HInstanceOf::cast(v);
|
| LInstruction* result =
|
| - new LInstanceOfAndBranch(Use(instance_of->left()),
|
| - Use(instance_of->right()),
|
| - first_id,
|
| - second_id);
|
| + new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0),
|
| + UseFixed(instance_of->right(), r1));
|
| return MarkAsCall(result, instr);
|
| } else if (v->IsTypeofIs()) {
|
| HTypeofIs* typeof_is = HTypeofIs::cast(v);
|
| - return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()),
|
| - first_id,
|
| - second_id);
|
| + return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
|
| + } else if (v->IsIsConstructCall()) {
|
| + return new LIsConstructCallAndBranch(TempRegister());
|
| } else {
|
| if (v->IsConstant()) {
|
| if (HConstant::cast(v)->handle()->IsTrue()) {
|
| - return new LGoto(first_id);
|
| + return new LGoto(instr->FirstSuccessor()->block_id());
|
| } else if (HConstant::cast(v)->handle()->IsFalse()) {
|
| - return new LGoto(second_id);
|
| + return new LGoto(instr->SecondSuccessor()->block_id());
|
| }
|
| }
|
| Abort("Undefined compare before branch");
|
| return NULL;
|
| }
|
| }
|
| - return new LBranch(UseRegisterAtStart(v), first_id, second_id);
|
| + return new LBranch(UseRegisterAtStart(v));
|
| }
|
|
|
|
|
| -LInstruction* LChunkBuilder::DoCompareMapAndBranch(
|
| - HCompareMapAndBranch* instr) {
|
| +LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
|
| ASSERT(instr->value()->representation().IsTagged());
|
| LOperand* value = UseRegisterAtStart(instr->value());
|
| LOperand* temp = TempRegister();
|
| @@ -1289,7 +1115,7 @@
|
|
|
|
|
| LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
|
| - return DefineAsRegister(new LArgumentsLength(Use(length->value())));
|
| + return DefineAsRegister(new LArgumentsLength(UseRegister(length->value())));
|
| }
|
|
|
|
|
| @@ -1299,22 +1125,31 @@
|
|
|
|
|
| LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
|
| - LInstruction* result =
|
| + LInstanceOf* result =
|
| new LInstanceOf(UseFixed(instr->left(), r0),
|
| UseFixed(instr->right(), r1));
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
|
| + HInstanceOfKnownGlobal* instr) {
|
| + LInstanceOfKnownGlobal* result =
|
| + new LInstanceOfKnownGlobal(UseFixed(instr->value(), r0), FixedTemp(r4));
|
| + MarkAsSaveDoubles(result);
|
| + return AssignEnvironment(AssignPointerMap(DefineFixed(result, r0)));
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
|
| LOperand* function = UseFixed(instr->function(), r1);
|
| LOperand* receiver = UseFixed(instr->receiver(), r0);
|
| - LOperand* length = UseRegisterAtStart(instr->length());
|
| - LOperand* elements = UseRegisterAtStart(instr->elements());
|
| - LInstruction* result = new LApplyArguments(function,
|
| - receiver,
|
| - length,
|
| - elements);
|
| + LOperand* length = UseFixed(instr->length(), r2);
|
| + LOperand* elements = UseFixed(instr->elements(), r3);
|
| + LApplyArguments* result = new LApplyArguments(function,
|
| + receiver,
|
| + length,
|
| + elements);
|
| return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
|
| }
|
|
|
| @@ -1326,13 +1161,26 @@
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoContext(HContext* instr) {
|
| + return DefineAsRegister(new LContext);
|
| +}
|
| +
|
| +
|
| +LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) {
|
| + LOperand* context = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LOuterContext(context));
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) {
|
| - return DefineAsRegister(new LGlobalObject);
|
| + LOperand* context = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LGlobalObject(context));
|
| }
|
|
|
|
|
| LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) {
|
| - return DefineAsRegister(new LGlobalReceiver);
|
| + LOperand* global_object = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LGlobalReceiver(global_object));
|
| }
|
|
|
|
|
| @@ -1346,12 +1194,13 @@
|
| LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
|
| BuiltinFunctionId op = instr->op();
|
| LOperand* input = UseRegisterAtStart(instr->value());
|
| - LInstruction* result = new LUnaryMathOperation(input);
|
| + LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
|
| + LUnaryMathOperation* result = new LUnaryMathOperation(input, temp);
|
| switch (op) {
|
| case kMathAbs:
|
| return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
| case kMathFloor:
|
| - return AssignEnvironment(DefineAsRegister(result));
|
| + return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
| case kMathSqrt:
|
| return DefineSameAsFirst(result);
|
| case kMathRound:
|
| @@ -1379,8 +1228,8 @@
|
| LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
|
| ASSERT(instr->key()->representation().IsTagged());
|
| argument_count_ -= instr->argument_count();
|
| - UseFixed(instr->key(), r2);
|
| - return MarkAsCall(DefineFixed(new LCallKeyed, r0), instr);
|
| + LOperand* key = UseFixed(instr->key(), r2);
|
| + return MarkAsCall(DefineFixed(new LCallKeyed(key), r0), instr);
|
| }
|
|
|
|
|
| @@ -1405,7 +1254,7 @@
|
| LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
|
| LOperand* constructor = UseFixed(instr->constructor(), r1);
|
| argument_count_ -= instr->argument_count();
|
| - LInstruction* result = new LCallNew(constructor);
|
| + LCallNew* result = new LCallNew(constructor);
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
|
|
| @@ -1463,12 +1312,15 @@
|
| if (instr->representation().IsDouble()) {
|
| return DoArithmeticD(Token::DIV, instr);
|
| } else if (instr->representation().IsInteger32()) {
|
| - // The temporary operand is necessary to ensure that right is not allocated
|
| - // into edx.
|
| - FixedTemp(r1);
|
| - LOperand* value = UseFixed(instr->left(), r0);
|
| - LOperand* divisor = UseRegister(instr->right());
|
| - return AssignEnvironment(DefineFixed(new LDivI(value, divisor), r0));
|
| + // TODO(1042) The fixed register allocation
|
| + // is needed because we call GenericBinaryOpStub from
|
| + // the generated code, which requires registers r0
|
| + // and r1 to be used. We should remove that
|
| + // when we provide a native implementation.
|
| + LOperand* dividend = UseFixed(instr->left(), r0);
|
| + LOperand* divisor = UseFixed(instr->right(), r1);
|
| + return AssignEnvironment(AssignPointerMap(
|
| + DefineFixed(new LDivI(dividend, divisor), r0)));
|
| } else {
|
| return DoArithmeticT(Token::DIV, instr);
|
| }
|
| @@ -1477,18 +1329,17 @@
|
|
|
| LInstruction* LChunkBuilder::DoMod(HMod* instr) {
|
| if (instr->representation().IsInteger32()) {
|
| + // TODO(1042) The fixed register allocation
|
| + // is needed because we call GenericBinaryOpStub from
|
| + // the generated code, which requires registers r0
|
| + // and r1 to be used. We should remove that
|
| + // when we provide a native implementation.
|
| ASSERT(instr->left()->representation().IsInteger32());
|
| ASSERT(instr->right()->representation().IsInteger32());
|
| - // The temporary operand is necessary to ensure that right is not allocated
|
| - // into edx.
|
| - FixedTemp(r1);
|
| LOperand* value = UseFixed(instr->left(), r0);
|
| - LOperand* divisor = UseRegister(instr->right());
|
| - LInstruction* result = DefineFixed(new LModI(value, divisor), r1);
|
| - if (instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
|
| - instr->CheckFlag(HValue::kCanBeDivByZero)) {
|
| - result = AssignEnvironment(result);
|
| - }
|
| + LOperand* divisor = UseFixed(instr->right(), r1);
|
| + LInstruction* result = DefineFixed(new LModI(value, divisor), r0);
|
| + result = AssignEnvironment(AssignPointerMap(result));
|
| return result;
|
| } else if (instr->representation().IsTagged()) {
|
| return DoArithmeticT(Token::MOD, instr);
|
| @@ -1529,8 +1380,8 @@
|
| if (instr->representation().IsInteger32()) {
|
| ASSERT(instr->left()->representation().IsInteger32());
|
| ASSERT(instr->right()->representation().IsInteger32());
|
| - LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand());
|
| - LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand());
|
| + LOperand* left = UseRegisterAtStart(instr->left());
|
| + LOperand* right = UseOrConstantAtStart(instr->right());
|
| LSubI* sub = new LSubI(left, right);
|
| LInstruction* result = DefineSameAsFirst(sub);
|
| if (instr->CheckFlag(HValue::kCanOverflow)) {
|
| @@ -1574,21 +1425,26 @@
|
|
|
| LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
|
| Token::Value op = instr->token();
|
| - if (instr->left()->representation().IsInteger32()) {
|
| + Representation r = instr->GetInputRepresentation();
|
| + if (r.IsInteger32()) {
|
| + ASSERT(instr->left()->representation().IsInteger32());
|
| ASSERT(instr->right()->representation().IsInteger32());
|
| LOperand* left = UseRegisterAtStart(instr->left());
|
| - LOperand* right = UseOrConstantAtStart(instr->right());
|
| - return DefineAsRegister(new LCmpID(op, left, right, false));
|
| - } else if (instr->left()->representation().IsDouble()) {
|
| + LOperand* right = UseRegisterAtStart(instr->right());
|
| + return DefineAsRegister(new LCmpID(left, right));
|
| + } else if (r.IsDouble()) {
|
| + ASSERT(instr->left()->representation().IsDouble());
|
| ASSERT(instr->right()->representation().IsDouble());
|
| LOperand* left = UseRegisterAtStart(instr->left());
|
| LOperand* right = UseRegisterAtStart(instr->right());
|
| - return DefineAsRegister(new LCmpID(op, left, right, true));
|
| + return DefineAsRegister(new LCmpID(left, right));
|
| } else {
|
| + ASSERT(instr->left()->representation().IsTagged());
|
| + ASSERT(instr->right()->representation().IsTagged());
|
| bool reversed = (op == Token::GT || op == Token::LTE);
|
| LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1);
|
| LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0);
|
| - LInstruction* result = new LCmpT(left, right);
|
| + LCmpT* result = new LCmpT(left, right);
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
| }
|
| @@ -1598,7 +1454,7 @@
|
| HCompareJSObjectEq* instr) {
|
| LOperand* left = UseRegisterAtStart(instr->left());
|
| LOperand* right = UseRegisterAtStart(instr->right());
|
| - LInstruction* result = new LCmpJSObjectEq(left, right);
|
| + LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right);
|
| return DefineAsRegister(result);
|
| }
|
|
|
| @@ -1607,8 +1463,7 @@
|
| ASSERT(instr->value()->representation().IsTagged());
|
| LOperand* value = UseRegisterAtStart(instr->value());
|
|
|
| - return DefineAsRegister(new LIsNull(value,
|
| - instr->is_strict()));
|
| + return DefineAsRegister(new LIsNull(value));
|
| }
|
|
|
|
|
| @@ -1616,7 +1471,7 @@
|
| ASSERT(instr->value()->representation().IsTagged());
|
| LOperand* value = UseRegisterAtStart(instr->value());
|
|
|
| - return DefineAsRegister(new LIsObject(value, TempRegister()));
|
| + return DefineAsRegister(new LIsObject(value));
|
| }
|
|
|
|
|
| @@ -1648,8 +1503,7 @@
|
| LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
|
| ASSERT(instr->value()->representation().IsTagged());
|
| LOperand* value = UseTempRegister(instr->value());
|
| -
|
| - return DefineSameAsFirst(new LClassOfTest(value, TempRegister()));
|
| + return DefineSameAsFirst(new LClassOfTest(value));
|
| }
|
|
|
|
|
| @@ -1659,6 +1513,12 @@
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoPixelArrayLength(HPixelArrayLength* instr) {
|
| + LOperand* array = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LPixelArrayLength(array));
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) {
|
| LOperand* array = UseRegisterAtStart(instr->value());
|
| return DefineAsRegister(new LFixedArrayLength(array));
|
| @@ -1667,17 +1527,24 @@
|
|
|
| LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) {
|
| LOperand* object = UseRegister(instr->value());
|
| - LInstruction* result = new LValueOf(object, TempRegister());
|
| + LValueOf* result = new LValueOf(object, TempRegister());
|
| return AssignEnvironment(DefineSameAsFirst(result));
|
| }
|
|
|
|
|
| LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
|
| return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()),
|
| - Use(instr->length())));
|
| + UseRegister(instr->length())));
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
|
| + // The control instruction marking the end of a block that completed
|
| + // abruptly (e.g., threw an exception). There is nothing specific to do.
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
|
| LOperand* value = UseFixed(instr->value(), r0);
|
| return MarkAsCall(new LThrow(value), instr);
|
| @@ -1690,7 +1557,7 @@
|
| if (from.IsTagged()) {
|
| if (to.IsDouble()) {
|
| LOperand* value = UseRegister(instr->value());
|
| - LInstruction* res = new LNumberUntagD(value);
|
| + LNumberUntagD* res = new LNumberUntagD(value);
|
| return AssignEnvironment(DefineAsRegister(res));
|
| } else {
|
| ASSERT(to.IsInteger32());
|
| @@ -1716,13 +1583,13 @@
|
| // Make sure that the temp and result_temp registers are
|
| // different.
|
| LUnallocated* result_temp = TempRegister();
|
| - LInstruction* result = new LNumberTagD(value, temp1, temp2);
|
| + LNumberTagD* result = new LNumberTagD(value, temp1, temp2);
|
| Define(result, result_temp);
|
| return AssignPointerMap(result);
|
| } else {
|
| ASSERT(to.IsInteger32());
|
| LOperand* value = UseRegister(instr->value());
|
| - LInstruction* res = new LDoubleToI(value);
|
| + LDoubleToI* res = new LDoubleToI(value, TempRegister());
|
| return AssignEnvironment(DefineAsRegister(res));
|
| }
|
| } else if (from.IsInteger32()) {
|
| @@ -1732,7 +1599,7 @@
|
| if (val->HasRange() && val->range()->IsInSmiRange()) {
|
| return DefineSameAsFirst(new LSmiTag(value));
|
| } else {
|
| - LInstruction* result = new LNumberTagI(value);
|
| + LNumberTagI* result = new LNumberTagI(value);
|
| return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
|
| }
|
| } else {
|
| @@ -1754,8 +1621,7 @@
|
|
|
| LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
|
| LOperand* value = UseRegisterAtStart(instr->value());
|
| - LOperand* temp = TempRegister();
|
| - LInstruction* result = new LCheckInstanceType(value, temp);
|
| + LInstruction* result = new LCheckInstanceType(value);
|
| return AssignEnvironment(result);
|
| }
|
|
|
| @@ -1763,11 +1629,7 @@
|
| LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) {
|
| LOperand* temp1 = TempRegister();
|
| LOperand* temp2 = TempRegister();
|
| - LInstruction* result =
|
| - new LCheckPrototypeMaps(temp1,
|
| - temp2,
|
| - instr->holder(),
|
| - instr->receiver_map());
|
| + LInstruction* result = new LCheckPrototypeMaps(temp1, temp2);
|
| return AssignEnvironment(result);
|
| }
|
|
|
| @@ -1799,22 +1661,20 @@
|
| LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
|
| Representation r = instr->representation();
|
| if (r.IsInteger32()) {
|
| - int32_t value = instr->Integer32Value();
|
| - return DefineAsRegister(new LConstantI(value));
|
| + return DefineAsRegister(new LConstantI);
|
| } else if (r.IsDouble()) {
|
| - double value = instr->DoubleValue();
|
| - return DefineAsRegister(new LConstantD(value));
|
| + return DefineAsRegister(new LConstantD);
|
| } else if (r.IsTagged()) {
|
| - return DefineAsRegister(new LConstantT(instr->handle()));
|
| + return DefineAsRegister(new LConstantT);
|
| } else {
|
| - Abort("unsupported constant of type double");
|
| + UNREACHABLE();
|
| return NULL;
|
| }
|
| }
|
|
|
|
|
| LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
|
| - LInstruction* result = new LLoadGlobal();
|
| + LLoadGlobal* result = new LLoadGlobal();
|
| return instr->check_hole_value()
|
| ? AssignEnvironment(DefineAsRegister(result))
|
| : DefineAsRegister(result);
|
| @@ -1822,10 +1682,35 @@
|
|
|
|
|
| LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
|
| - return new LStoreGlobal(UseRegisterAtStart(instr->value()));
|
| + if (instr->check_hole_value()) {
|
| + LOperand* temp = TempRegister();
|
| + LOperand* value = UseRegister(instr->value());
|
| + return AssignEnvironment(new LStoreGlobal(value, temp));
|
| + } else {
|
| + LOperand* value = UseRegisterAtStart(instr->value());
|
| + return new LStoreGlobal(value, NULL);
|
| + }
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
| + LOperand* context = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LLoadContextSlot(context));
|
| +}
|
| +
|
| +
|
| +LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
|
| + LOperand* context = UseTempRegister(instr->context());
|
| + LOperand* value;
|
| + if (instr->NeedsWriteBarrier()) {
|
| + value = UseTempRegister(instr->value());
|
| + } else {
|
| + value = UseRegister(instr->value());
|
| + }
|
| + return new LStoreContextSlot(context, value);
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
|
| return DefineAsRegister(
|
| new LLoadNamedField(UseRegisterAtStart(instr->object())));
|
| @@ -1848,29 +1733,38 @@
|
|
|
| LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) {
|
| LOperand* input = UseRegisterAtStart(instr->value());
|
| - return DefineSameAsFirst(new LLoadElements(input));
|
| + return DefineAsRegister(new LLoadElements(input));
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoLoadPixelArrayExternalPointer(
|
| + HLoadPixelArrayExternalPointer* instr) {
|
| + LOperand* input = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LLoadPixelArrayExternalPointer(input));
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoLoadKeyedFastElement(
|
| HLoadKeyedFastElement* instr) {
|
| - Representation r = instr->representation();
|
| + ASSERT(instr->representation().IsTagged());
|
| + ASSERT(instr->key()->representation().IsInteger32());
|
| LOperand* obj = UseRegisterAtStart(instr->object());
|
| + LOperand* key = UseRegisterAtStart(instr->key());
|
| + LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key);
|
| + return AssignEnvironment(DefineSameAsFirst(result));
|
| +}
|
| +
|
| +
|
| +LInstruction* LChunkBuilder::DoLoadPixelArrayElement(
|
| + HLoadPixelArrayElement* instr) {
|
| + ASSERT(instr->representation().IsInteger32());
|
| ASSERT(instr->key()->representation().IsInteger32());
|
| + LOperand* external_pointer =
|
| + UseRegisterAtStart(instr->external_pointer());
|
| LOperand* key = UseRegisterAtStart(instr->key());
|
| - LOperand* load_result = NULL;
|
| - // Double needs an extra temp, because the result is converted from heap
|
| - // number to a double register.
|
| - if (r.IsDouble()) load_result = TempRegister();
|
| - LInstruction* result = new LLoadKeyedFastElement(obj,
|
| - key,
|
| - load_result);
|
| - if (r.IsDouble()) {
|
| - result = DefineAsRegister(result);
|
| - } else {
|
| - result = DefineSameAsFirst(result);
|
| - }
|
| - return AssignEnvironment(result);
|
| + LLoadPixelArrayElement* result =
|
| + new LLoadPixelArrayElement(external_pointer, key);
|
| + return DefineAsRegister(result);
|
| }
|
|
|
|
|
| @@ -1917,7 +1811,7 @@
|
|
|
|
|
| LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
|
| - bool needs_write_barrier = !instr->value()->type().IsSmi();
|
| + bool needs_write_barrier = instr->NeedsWriteBarrier();
|
|
|
| LOperand* obj = needs_write_barrier
|
| ? UseTempRegister(instr->object())
|
| @@ -1927,19 +1821,7 @@
|
| ? UseTempRegister(instr->value())
|
| : UseRegister(instr->value());
|
|
|
| - // We only need a scratch register if we have a write barrier or we
|
| - // have a store into the properties array (not in-object-property).
|
| - LOperand* temp = (!instr->is_in_object() || needs_write_barrier)
|
| - ? TempRegister() : NULL;
|
| -
|
| - return new LStoreNamedField(obj,
|
| - instr->name(),
|
| - val,
|
| - instr->is_in_object(),
|
| - instr->offset(),
|
| - temp,
|
| - needs_write_barrier,
|
| - instr->transition());
|
| + return new LStoreNamedField(obj, val);
|
| }
|
|
|
|
|
| @@ -1947,11 +1829,25 @@
|
| LOperand* obj = UseFixed(instr->object(), r1);
|
| LOperand* val = UseFixed(instr->value(), r0);
|
|
|
| - LInstruction* result = new LStoreNamedGeneric(obj, instr->name(), val);
|
| + LInstruction* result = new LStoreNamedGeneric(obj, val);
|
| return MarkAsCall(result, instr);
|
| }
|
|
|
|
|
| +LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
|
| + LOperand* string = UseRegister(instr->string());
|
| + LOperand* index = UseRegisterOrConstant(instr->index());
|
| + LStringCharCodeAt* result = new LStringCharCodeAt(string, index);
|
| + return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
|
| +}
|
| +
|
| +
|
| +LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) {
|
| + LOperand* string = UseRegisterAtStart(instr->value());
|
| + return DefineAsRegister(new LStringLength(string));
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) {
|
| return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr);
|
| }
|
| @@ -1973,8 +1869,9 @@
|
|
|
|
|
| LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) {
|
| - LInstruction* result = new LDeleteProperty(Use(instr->object()),
|
| - UseOrConstant(instr->key()));
|
| + LOperand* object = UseFixed(instr->object(), r0);
|
| + LOperand* key = UseFixed(instr->key(), r1);
|
| + LDeleteProperty* result = new LDeleteProperty(object, key);
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
|
|
| @@ -2014,14 +1911,14 @@
|
| LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
|
| LOperand* arguments = UseRegister(instr->arguments());
|
| LOperand* length = UseTempRegister(instr->length());
|
| - LOperand* index = Use(instr->index());
|
| - LInstruction* result = new LAccessArgumentsAt(arguments, length, index);
|
| - return DefineAsRegister(AssignEnvironment(result));
|
| + LOperand* index = UseRegister(instr->index());
|
| + LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index);
|
| + return AssignEnvironment(DefineAsRegister(result));
|
| }
|
|
|
|
|
| LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
|
| - LInstruction* result = new LTypeof(Use(instr->value()));
|
| + LTypeof* result = new LTypeof(UseFixed(instr->value(), r0));
|
| return MarkAsCall(DefineFixed(result, r0), instr);
|
| }
|
|
|
| @@ -2030,6 +1927,12 @@
|
| return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
|
| }
|
|
|
| +
|
| +LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
|
| + return DefineAsRegister(new LIsConstructCall());
|
| +}
|
| +
|
| +
|
| LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
|
| HEnvironment* env = current_block_->last_environment();
|
| ASSERT(env != NULL);
|
| @@ -2053,7 +1956,7 @@
|
| if (pending_deoptimization_ast_id_ == instr->ast_id()) {
|
| LInstruction* result = new LLazyBailout;
|
| result = AssignEnvironment(result);
|
| - instructions_pending_deoptimization_environment_->
|
| + instruction_pending_deoptimization_environment_->
|
| set_deoptimization_environment(result->environment());
|
| ClearInstructionPendingDeoptimizationEnvironment();
|
| return result;
|
| @@ -2088,21 +1991,4 @@
|
| }
|
|
|
|
|
| -void LPointerMap::RecordPointer(LOperand* op) {
|
| - // Do not record arguments as pointers.
|
| - if (op->IsStackSlot() && op->index() < 0) return;
|
| - ASSERT(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
|
| - pointer_operands_.Add(op);
|
| -}
|
| -
|
| -
|
| -void LPointerMap::PrintTo(StringStream* stream) const {
|
| - stream->Add("{");
|
| - for (int i = 0; i < pointer_operands_.length(); ++i) {
|
| - if (i != 0) stream->Add(";");
|
| - pointer_operands_[i]->PrintTo(stream);
|
| - }
|
| - stream->Add("} @%d", position());
|
| -}
|
| -
|
| } } // namespace v8::internal
|
|
|