summaryrefslogtreecommitdiff
path: root/deps/v8/src/lithium-allocator.h
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-12-07 13:56:11 -0800
committerRyan Dahl <ry@tinyclouds.org>2010-12-07 13:56:11 -0800
commitc30f1137121315b0d3641af6dc61e3b047f940e1 (patch)
treef118eaf670505e6a63f28bc8df845520f67adc55 /deps/v8/src/lithium-allocator.h
parent5b8c62f7d12c1c5a553e765ba05bbd8a7e17ee47 (diff)
downloadnode-new-c30f1137121315b0d3641af6dc61e3b047f940e1.tar.gz
Upgrade V8 to 3.0.0
Diffstat (limited to 'deps/v8/src/lithium-allocator.h')
-rw-r--r--deps/v8/src/lithium-allocator.h954
1 files changed, 954 insertions, 0 deletions
diff --git a/deps/v8/src/lithium-allocator.h b/deps/v8/src/lithium-allocator.h
new file mode 100644
index 0000000000..52fee6455f
--- /dev/null
+++ b/deps/v8/src/lithium-allocator.h
@@ -0,0 +1,954 @@
+// Copyright 2010 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_LITHIUM_ALLOCATOR_H_
+#define V8_LITHIUM_ALLOCATOR_H_
+
+#include "v8.h"
+
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class HBasicBlock;
+class HGraph;
+class HInstruction;
+class HPhi;
+class HTracer;
+class HValue;
+class BitVector;
+class StringStream;
+
+class LArgument;
+class LChunk;
+class LConstantOperand;
+class LGap;
+class LInstruction;
+class LParallelMove;
+class LPointerMap;
+class LStackSlot;
+class LRegister;
+
+// This class represents a single point of a LOperand's lifetime.
+// For each lithium instruction there are exactly two lifetime positions:
+// the beginning and the end of the instruction. Lifetime positions for
+// different lithium instructions are disjoint.
+class LifetimePosition {
+ public:
+ // Return the lifetime position that corresponds to the beginning of
+ // the instruction with the given index.
+ static LifetimePosition FromInstructionIndex(int index) {
+ return LifetimePosition(index * kStep);
+ }
+
+ // Returns a numeric representation of this lifetime position.
+ int Value() const {
+ return value_;
+ }
+
+ // Returns the index of the instruction to which this lifetime position
+ // corresponds.
+ int InstructionIndex() const {
+ ASSERT(IsValid());
+ return value_ / kStep;
+ }
+
+ // Returns true if this lifetime position corresponds to the instruction
+ // start.
+ bool IsInstructionStart() const {
+ return (value_ & (kStep - 1)) == 0;
+ }
+
+ // Returns the lifetime position for the start of the instruction which
+ // corresponds to this lifetime position.
+ LifetimePosition InstructionStart() const {
+ ASSERT(IsValid());
+ return LifetimePosition(value_ & ~(kStep - 1));
+ }
+
+ // Returns the lifetime position for the end of the instruction which
+ // corresponds to this lifetime position.
+ LifetimePosition InstructionEnd() const {
+ ASSERT(IsValid());
+ return LifetimePosition(InstructionStart().Value() + kStep/2);
+ }
+
+ // Returns the lifetime position for the beginning of the next instruction.
+ LifetimePosition NextInstruction() const {
+ ASSERT(IsValid());
+ return LifetimePosition(InstructionStart().Value() + kStep);
+ }
+
+ // Returns the lifetime position for the beginning of the previous
+ // instruction.
+ LifetimePosition PrevInstruction() const {
+ ASSERT(IsValid());
+ ASSERT(value_ > 1);
+ return LifetimePosition(InstructionStart().Value() - kStep);
+ }
+
+ // Constructs the lifetime position which does not correspond to any
+ // instruction.
+ LifetimePosition() : value_(-1) {}
+
+ // Returns true if this lifetime positions corrensponds to some
+ // instruction.
+ bool IsValid() const { return value_ != -1; }
+
+ static LifetimePosition Invalid() { return LifetimePosition(); }
+
+ private:
+ static const int kStep = 2;
+
+ // Code relies on kStep being a power of two.
+ STATIC_ASSERT(IS_POWER_OF_TWO(kStep));
+
+ explicit LifetimePosition(int value) : value_(value) { }
+
+ int value_;
+};
+
+
+class LOperand: public ZoneObject {
+ public:
+ enum Kind {
+ INVALID,
+ UNALLOCATED,
+ CONSTANT_OPERAND,
+ STACK_SLOT,
+ DOUBLE_STACK_SLOT,
+ REGISTER,
+ DOUBLE_REGISTER,
+ ARGUMENT
+ };
+
+ LOperand() : value_(KindField::encode(INVALID)) { }
+
+ Kind kind() const { return KindField::decode(value_); }
+ int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
+ bool IsConstantOperand() const { return kind() == CONSTANT_OPERAND; }
+ bool IsStackSlot() const { return kind() == STACK_SLOT; }
+ bool IsDoubleStackSlot() const { return kind() == DOUBLE_STACK_SLOT; }
+ bool IsRegister() const { return kind() == REGISTER; }
+ bool IsDoubleRegister() const { return kind() == DOUBLE_REGISTER; }
+ bool IsArgument() const { return kind() == ARGUMENT; }
+ bool IsUnallocated() const { return kind() == UNALLOCATED; }
+ bool Equals(LOperand* other) const { return value_ == other->value_; }
+ int VirtualRegister();
+
+ void PrintTo(StringStream* stream);
+ void ConvertTo(Kind kind, int index) {
+ value_ = KindField::encode(kind);
+ value_ |= index << kKindFieldWidth;
+ ASSERT(this->index() == index);
+ }
+
+ protected:
+ static const int kKindFieldWidth = 3;
+ class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
+
+ LOperand(Kind kind, int index) { ConvertTo(kind, index); }
+
+ unsigned value_;
+};
+
+
+class LUnallocated: public LOperand {
+ public:
+ enum Policy {
+ NONE,
+ ANY,
+ FIXED_REGISTER,
+ FIXED_DOUBLE_REGISTER,
+ FIXED_SLOT,
+ MUST_HAVE_REGISTER,
+ WRITABLE_REGISTER,
+ SAME_AS_FIRST_INPUT,
+ SAME_AS_ANY_INPUT,
+ IGNORE
+ };
+
+ // Lifetime of operand inside the instruction.
+ enum Lifetime {
+ // USED_AT_START operand is guaranteed to be live only at
+ // instruction start. Register allocator is free to assign the same register
+ // to some other operand used inside instruction (i.e. temporary or
+ // output).
+ USED_AT_START,
+
+ // USED_AT_END operand is treated as live until the end of
+ // instruction. This means that register allocator will not reuse it's
+ // register for any other operand inside instruction.
+ USED_AT_END
+ };
+
+ explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) {
+ Initialize(policy, 0, USED_AT_END);
+ }
+
+ LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) {
+ Initialize(policy, fixed_index, USED_AT_END);
+ }
+
+ LUnallocated(Policy policy, Lifetime lifetime) : LOperand(UNALLOCATED, 0) {
+ Initialize(policy, 0, lifetime);
+ }
+
+ // The superclass has a KindField. Some policies have a signed fixed
+ // index in the upper bits.
+ static const int kPolicyWidth = 4;
+ static const int kLifetimeWidth = 1;
+ static const int kVirtualRegisterWidth = 17;
+
+ static const int kPolicyShift = kKindFieldWidth;
+ static const int kLifetimeShift = kPolicyShift + kPolicyWidth;
+ static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth;
+ static const int kFixedIndexShift =
+ kVirtualRegisterShift + kVirtualRegisterWidth;
+
+ class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { };
+
+ class LifetimeField
+ : public BitField<Lifetime, kLifetimeShift, kLifetimeWidth> {
+ };
+
+ class VirtualRegisterField
+ : public BitField<unsigned,
+ kVirtualRegisterShift,
+ kVirtualRegisterWidth> {
+ };
+
+ static const int kMaxVirtualRegisters = 1 << (kVirtualRegisterWidth + 1);
+ static const int kMaxFixedIndices = 128;
+
+ bool HasIgnorePolicy() const { return policy() == IGNORE; }
+ bool HasNoPolicy() const { return policy() == NONE; }
+ bool HasAnyPolicy() const {
+ return policy() == ANY;
+ }
+ bool HasFixedPolicy() const {
+ return policy() == FIXED_REGISTER ||
+ policy() == FIXED_DOUBLE_REGISTER ||
+ policy() == FIXED_SLOT;
+ }
+ bool HasRegisterPolicy() const {
+ return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
+ }
+ bool HasSameAsInputPolicy() const {
+ return policy() == SAME_AS_FIRST_INPUT || policy() == SAME_AS_ANY_INPUT;
+ }
+ Policy policy() const { return PolicyField::decode(value_); }
+ void set_policy(Policy policy) {
+ value_ &= ~PolicyField::mask();
+ value_ |= PolicyField::encode(policy);
+ }
+ int fixed_index() const {
+ return static_cast<int>(value_) >> kFixedIndexShift;
+ }
+
+ unsigned virtual_register() const {
+ return VirtualRegisterField::decode(value_);
+ }
+
+ void set_virtual_register(unsigned id) {
+ value_ &= ~VirtualRegisterField::mask();
+ value_ |= VirtualRegisterField::encode(id);
+ }
+
+ LUnallocated* CopyUnconstrained() {
+ LUnallocated* result = new LUnallocated(ANY);
+ result->set_virtual_register(virtual_register());
+ return result;
+ }
+
+ static LUnallocated* cast(LOperand* op) {
+ ASSERT(op->IsUnallocated());
+ return reinterpret_cast<LUnallocated*>(op);
+ }
+
+ bool IsUsedAtStart() {
+ return LifetimeField::decode(value_) == USED_AT_START;
+ }
+
+ private:
+ void Initialize(Policy policy, int fixed_index, Lifetime lifetime) {
+ value_ |= PolicyField::encode(policy);
+ value_ |= LifetimeField::encode(lifetime);
+ value_ |= fixed_index << kFixedIndexShift;
+ ASSERT(this->fixed_index() == fixed_index);
+ }
+};
+
+
+class LMoveOperands BASE_EMBEDDED {
+ public:
+ LMoveOperands(LOperand* from, LOperand* to) : from_(from), to_(to) { }
+
+ LOperand* from() const { return from_; }
+ LOperand* to() const { return to_; }
+ bool IsRedundant() const {
+ return IsEliminated() || from_->Equals(to_) || IsIgnored();
+ }
+ bool IsEliminated() const { return from_ == NULL; }
+ bool IsIgnored() const {
+ if (to_ != NULL && to_->IsUnallocated() &&
+ LUnallocated::cast(to_)->HasIgnorePolicy()) {
+ return true;
+ }
+ return false;
+ }
+
+ void Eliminate() { from_ = to_ = NULL; }
+
+ private:
+ LOperand* from_;
+ LOperand* to_;
+};
+
+
+class LConstantOperand: public LOperand {
+ public:
+ static LConstantOperand* Create(int index) {
+ ASSERT(index >= 0);
+ if (index < kNumCachedOperands) return &cache[index];
+ return new LConstantOperand(index);
+ }
+
+ static LConstantOperand* cast(LOperand* op) {
+ ASSERT(op->IsConstantOperand());
+ return reinterpret_cast<LConstantOperand*>(op);
+ }
+
+ static void SetupCache();
+
+ private:
+ static const int kNumCachedOperands = 128;
+ static LConstantOperand cache[];
+
+ LConstantOperand() : LOperand() { }
+ explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
+};
+
+
+class LArgument: public LOperand {
+ public:
+ explicit LArgument(int index) : LOperand(ARGUMENT, index) { }
+
+ static LArgument* cast(LOperand* op) {
+ ASSERT(op->IsArgument());
+ return reinterpret_cast<LArgument*>(op);
+ }
+};
+
+
+class LStackSlot: public LOperand {
+ public:
+ static LStackSlot* Create(int index) {
+ ASSERT(index >= 0);
+ if (index < kNumCachedOperands) return &cache[index];
+ return new LStackSlot(index);
+ }
+
+ static LStackSlot* cast(LOperand* op) {
+ ASSERT(op->IsStackSlot());
+ return reinterpret_cast<LStackSlot*>(op);
+ }
+
+ static void SetupCache();
+
+ private:
+ static const int kNumCachedOperands = 128;
+ static LStackSlot cache[];
+
+ LStackSlot() : LOperand() { }
+ explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
+};
+
+
+class LDoubleStackSlot: public LOperand {
+ public:
+ static LDoubleStackSlot* Create(int index) {
+ ASSERT(index >= 0);
+ if (index < kNumCachedOperands) return &cache[index];
+ return new LDoubleStackSlot(index);
+ }
+
+ static LDoubleStackSlot* cast(LOperand* op) {
+ ASSERT(op->IsStackSlot());
+ return reinterpret_cast<LDoubleStackSlot*>(op);
+ }
+
+ static void SetupCache();
+
+ private:
+ static const int kNumCachedOperands = 128;
+ static LDoubleStackSlot cache[];
+
+ LDoubleStackSlot() : LOperand() { }
+ explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
+};
+
+
+class LRegister: public LOperand {
+ public:
+ static LRegister* Create(int index) {
+ ASSERT(index >= 0);
+ if (index < kNumCachedOperands) return &cache[index];
+ return new LRegister(index);
+ }
+
+ static LRegister* cast(LOperand* op) {
+ ASSERT(op->IsRegister());
+ return reinterpret_cast<LRegister*>(op);
+ }
+
+ static void SetupCache();
+
+ private:
+ static const int kNumCachedOperands = 16;
+ static LRegister cache[];
+
+ LRegister() : LOperand() { }
+ explicit LRegister(int index) : LOperand(REGISTER, index) { }
+};
+
+
+class LDoubleRegister: public LOperand {
+ public:
+ static LDoubleRegister* Create(int index) {
+ ASSERT(index >= 0);
+ if (index < kNumCachedOperands) return &cache[index];
+ return new LDoubleRegister(index);
+ }
+
+ static LDoubleRegister* cast(LOperand* op) {
+ ASSERT(op->IsDoubleRegister());
+ return reinterpret_cast<LDoubleRegister*>(op);
+ }
+
+ static void SetupCache();
+
+ private:
+ static const int kNumCachedOperands = 16;
+ static LDoubleRegister cache[];
+
+ LDoubleRegister() : LOperand() { }
+ explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
+};
+
+
+// A register-allocator view of a Lithium instruction. It contains the id of
+// the output operand and a list of input operand uses.
+class InstructionSummary: public ZoneObject {
+ public:
+ InstructionSummary()
+ : output_operand_(NULL), input_count_(0), operands_(4), is_call_(false) {}
+
+ // Output operands.
+ LOperand* Output() const { return output_operand_; }
+ void SetOutput(LOperand* output) {
+ ASSERT(output_operand_ == NULL);
+ output_operand_ = output;
+ }
+
+ // Input operands.
+ int InputCount() const { return input_count_; }
+ LOperand* InputAt(int i) const {
+ ASSERT(i < input_count_);
+ return operands_[i];
+ }
+ void AddInput(LOperand* input) {
+ operands_.InsertAt(input_count_, input);
+ input_count_++;
+ }
+
+ // Temporary operands.
+ int TempCount() const { return operands_.length() - input_count_; }
+ LOperand* TempAt(int i) const { return operands_[i + input_count_]; }
+ void AddTemp(LOperand* temp) { operands_.Add(temp); }
+
+ void MarkAsCall() { is_call_ = true; }
+ bool IsCall() const { return is_call_; }
+
+ private:
+ LOperand* output_operand_;
+ int input_count_;
+ ZoneList<LOperand*> operands_;
+ bool is_call_;
+};
+
+// Representation of the non-empty interval [start,end[.
+class UseInterval: public ZoneObject {
+ public:
+ UseInterval(LifetimePosition start, LifetimePosition end)
+ : start_(start), end_(end), next_(NULL) {
+ ASSERT(start.Value() < end.Value());
+ }
+
+ LifetimePosition start() const { return start_; }
+ LifetimePosition end() const { return end_; }
+ UseInterval* next() const { return next_; }
+
+ // Split this interval at the given position without effecting the
+ // live range that owns it. The interval must contain the position.
+ void SplitAt(LifetimePosition pos);
+
+ // If this interval intersects with other return smallest position
+ // that belongs to both of them.
+ LifetimePosition Intersect(const UseInterval* other) const {
+ if (other->start().Value() < start_.Value()) return other->Intersect(this);
+ if (other->start().Value() < end_.Value()) return other->start();
+ return LifetimePosition::Invalid();
+ }
+
+ bool Contains(LifetimePosition point) const {
+ return start_.Value() <= point.Value() && point.Value() < end_.Value();
+ }
+
+ private:
+ void set_start(LifetimePosition start) { start_ = start; }
+ void set_next(UseInterval* next) { next_ = next; }
+
+ LifetimePosition start_;
+ LifetimePosition end_;
+ UseInterval* next_;
+
+ friend class LiveRange; // Assigns to start_.
+};
+
+// Representation of a use position.
+class UsePosition: public ZoneObject {
+ public:
+ UsePosition(LifetimePosition pos, LOperand* operand)
+ : operand_(operand),
+ hint_(NULL),
+ pos_(pos),
+ next_(NULL),
+ requires_reg_(false),
+ register_beneficial_(true) {
+ if (operand_ != NULL && operand_->IsUnallocated()) {
+ LUnallocated* unalloc = LUnallocated::cast(operand_);
+ requires_reg_ = unalloc->HasRegisterPolicy();
+ register_beneficial_ = !unalloc->HasAnyPolicy();
+ }
+ ASSERT(pos_.IsValid());
+ }
+
+ LOperand* operand() const { return operand_; }
+ bool HasOperand() const { return operand_ != NULL; }
+
+ LOperand* hint() const { return hint_; }
+ void set_hint(LOperand* hint) { hint_ = hint; }
+ bool HasHint() const { return hint_ != NULL && !hint_->IsUnallocated(); }
+ bool RequiresRegister() const;
+ bool RegisterIsBeneficial() const;
+
+ LifetimePosition pos() const { return pos_; }
+ UsePosition* next() const { return next_; }
+
+ private:
+ void set_next(UsePosition* next) { next_ = next; }
+
+ LOperand* operand_;
+ LOperand* hint_;
+ LifetimePosition pos_;
+ UsePosition* next_;
+ bool requires_reg_;
+ bool register_beneficial_;
+
+ friend class LiveRange;
+};
+
+// Representation of SSA values' live ranges as a collection of (continuous)
+// intervals over the instruction ordering.
+class LiveRange: public ZoneObject {
+ public:
+ static const int kInvalidAssignment = 0x7fffffff;
+
+ explicit LiveRange(int id)
+ : id_(id),
+ spilled_(false),
+ assigned_double_(false),
+ assigned_register_(kInvalidAssignment),
+ last_interval_(NULL),
+ first_interval_(NULL),
+ first_pos_(NULL),
+ parent_(NULL),
+ next_(NULL),
+ current_interval_(NULL),
+ last_processed_use_(NULL),
+ spill_start_index_(kMaxInt) {
+ spill_operand_ = new LUnallocated(LUnallocated::IGNORE);
+ }
+
+ UseInterval* first_interval() const { return first_interval_; }
+ UsePosition* first_pos() const { return first_pos_; }
+ LiveRange* parent() const { return parent_; }
+ LiveRange* TopLevel() { return (parent_ == NULL) ? this : parent_; }
+ LiveRange* next() const { return next_; }
+ bool IsChild() const { return parent() != NULL; }
+ bool IsParent() const { return parent() == NULL; }
+ int id() const { return id_; }
+ bool IsFixed() const { return id_ < 0; }
+ bool IsEmpty() const { return first_interval() == NULL; }
+ LOperand* CreateAssignedOperand();
+ int assigned_register() const { return assigned_register_; }
+ int spill_start_index() const { return spill_start_index_; }
+ void set_assigned_register(int reg, bool double_reg) {
+ ASSERT(!HasRegisterAssigned() && !IsSpilled());
+ assigned_register_ = reg;
+ assigned_double_ = double_reg;
+ ConvertOperands();
+ }
+ void MakeSpilled() {
+ ASSERT(!IsSpilled());
+ ASSERT(TopLevel()->HasAllocatedSpillOperand());
+ spilled_ = true;
+ assigned_register_ = kInvalidAssignment;
+ ConvertOperands();
+ }
+
+ // Returns use position in this live range that follows both start
+ // and last processed use position.
+ // Modifies internal state of live range!
+ UsePosition* NextUsePosition(LifetimePosition start);
+
+ // Returns use position for which register is required in this live
+ // range and which follows both start and last processed use position
+ // Modifies internal state of live range!
+ UsePosition* NextRegisterPosition(LifetimePosition start);
+
+ // Returns use position for which register is beneficial in this live
+ // range and which follows both start and last processed use position
+ // Modifies internal state of live range!
+ UsePosition* NextUsePositionRegisterIsBeneficial(LifetimePosition start);
+
+ // Can this live range be spilled at this position.
+ bool CanBeSpilled(LifetimePosition pos);
+
+ void SplitAt(LifetimePosition position, LiveRange* result);
+
+ bool IsDouble() const { return assigned_double_; }
+ bool HasRegisterAssigned() const {
+ return assigned_register_ != kInvalidAssignment;
+ }
+ bool IsSpilled() const { return spilled_; }
+ UsePosition* FirstPosWithHint() const;
+
+ LOperand* FirstHint() const {
+ UsePosition* pos = FirstPosWithHint();
+ if (pos != NULL) return pos->hint();
+ return NULL;
+ }
+
+ LifetimePosition Start() const {
+ ASSERT(!IsEmpty());
+ return first_interval()->start();
+ }
+
+ LifetimePosition End() const {
+ ASSERT(!IsEmpty());
+ return last_interval_->end();
+ }
+
+ bool HasAllocatedSpillOperand() const {
+ return spill_operand_ != NULL && !spill_operand_->IsUnallocated();
+ }
+ LOperand* GetSpillOperand() const { return spill_operand_; }
+ void SetSpillOperand(LOperand* operand) {
+ ASSERT(!operand->IsUnallocated());
+ ASSERT(spill_operand_ != NULL);
+ ASSERT(spill_operand_->IsUnallocated());
+ spill_operand_->ConvertTo(operand->kind(), operand->index());
+ }
+
+ void SetSpillStartIndex(int start) {
+ spill_start_index_ = Min(start, spill_start_index_);
+ }
+
+ bool ShouldBeAllocatedBefore(const LiveRange* other) const;
+ bool CanCover(LifetimePosition position) const;
+ bool Covers(LifetimePosition position);
+ LifetimePosition FirstIntersection(LiveRange* other);
+
+
+ // Add a new interval or a new use position to this live range.
+ void EnsureInterval(LifetimePosition start, LifetimePosition end);
+ void AddUseInterval(LifetimePosition start, LifetimePosition end);
+ UsePosition* AddUsePosition(LifetimePosition pos, LOperand* operand);
+ UsePosition* AddUsePosition(LifetimePosition pos);
+
+ // Shorten the most recently added interval by setting a new start.
+ void ShortenTo(LifetimePosition start);
+
+#ifdef DEBUG
+ // True if target overlaps an existing interval.
+ bool HasOverlap(UseInterval* target) const;
+ void Verify() const;
+#endif
+
+ private:
+ void ConvertOperands();
+ UseInterval* FirstSearchIntervalForPosition(LifetimePosition position) const;
+ void AdvanceLastProcessedMarker(UseInterval* to_start_of,
+ LifetimePosition but_not_past) const;
+
+ int id_;
+ bool spilled_;
+ bool assigned_double_;
+ int assigned_register_;
+ UseInterval* last_interval_;
+ UseInterval* first_interval_;
+ UsePosition* first_pos_;
+ LiveRange* parent_;
+ LiveRange* next_;
+ // This is used as a cache, it doesn't affect correctness.
+ mutable UseInterval* current_interval_;
+ UsePosition* last_processed_use_;
+ LOperand* spill_operand_;
+ int spill_start_index_;
+};
+
+
+class LAllocator BASE_EMBEDDED {
+ public:
+ explicit LAllocator(int first_virtual_register, HGraph* graph)
+ : chunk_(NULL),
+ summaries_(0),
+ next_summary_(NULL),
+ summary_stack_(2),
+ live_in_sets_(0),
+ live_ranges_(16),
+ fixed_live_ranges_(8),
+ fixed_double_live_ranges_(8),
+ unhandled_live_ranges_(8),
+ active_live_ranges_(8),
+ inactive_live_ranges_(8),
+ reusable_slots_(8),
+ next_virtual_register_(first_virtual_register),
+ mode_(NONE),
+ num_registers_(-1),
+ graph_(graph),
+ has_osr_entry_(false) {}
+
+ static void Setup();
+ static void TraceAlloc(const char* msg, ...);
+
+ // Lithium translation support.
+ // Record a use of an input operand in the current instruction.
+ void RecordUse(HValue* value, LUnallocated* operand);
+ // Record the definition of the output operand.
+ void RecordDefinition(HInstruction* instr, LUnallocated* operand);
+ // Record a temporary operand.
+ void RecordTemporary(LUnallocated* operand);
+
+ // Marks the current instruction as a call.
+ void MarkAsCall();
+
+ // Checks whether the value of a given virtual register is tagged.
+ bool HasTaggedValue(int virtual_register) const;
+
+ // Checks whether the value of a given virtual register is a double.
+ bool HasDoubleValue(int virtual_register) const;
+
+ // Begin a new instruction.
+ void BeginInstruction();
+
+ // Summarize the current instruction.
+ void SummarizeInstruction(int index);
+
+ // Summarize the current instruction.
+ void OmitInstruction();
+
+ // Control max function size.
+ static int max_initial_value_ids();
+
+ void Allocate(LChunk* chunk);
+
+ const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; }
+ const ZoneList<LiveRange*>* fixed_live_ranges() const {
+ return &fixed_live_ranges_;
+ }
+ const ZoneList<LiveRange*>* fixed_double_live_ranges() const {
+ return &fixed_double_live_ranges_;
+ }
+
+ LChunk* chunk() const { return chunk_; }
+ HGraph* graph() const { return graph_; }
+
+ void MarkAsOsrEntry() {
+ // There can be only one.
+ ASSERT(!has_osr_entry_);
+ // Simply set a flag to find and process instruction later.
+ has_osr_entry_ = true;
+ }
+
+#ifdef DEBUG
+ void Verify() const;
+#endif
+
+ private:
+ enum OperationMode {
+ NONE,
+ CPU_REGISTERS,
+ XMM_REGISTERS
+ };
+
+ void MeetRegisterConstraints();
+ void ResolvePhis();
+ void BuildLiveRanges();
+ void AllocateGeneralRegisters();
+ void AllocateDoubleRegisters();
+ void ConnectRanges();
+ void ResolveControlFlow();
+ void PopulatePointerMaps();
+ void ProcessOsrEntry();
+ void AllocateRegisters();
+ bool CanEagerlyResolveControlFlow(HBasicBlock* block) const;
+ inline bool SafePointsAreInOrder() const;
+
+ // Liveness analysis support.
+ void InitializeLivenessAnalysis();
+ BitVector* ComputeLiveOut(HBasicBlock* block);
+ void AddInitialIntervals(HBasicBlock* block, BitVector* live_out);
+ void ProcessInstructions(HBasicBlock* block, BitVector* live);
+ void MeetRegisterConstraints(HBasicBlock* block);
+ void MeetConstraintsBetween(InstructionSummary* first,
+ InstructionSummary* second,
+ int gap_index);
+ void ResolvePhis(HBasicBlock* block);
+
+ // Helper methods for building intervals.
+ LOperand* AllocateFixed(LUnallocated* operand, int pos, bool is_tagged);
+ LiveRange* LiveRangeFor(LOperand* operand);
+ void Define(LifetimePosition position, LOperand* operand, LOperand* hint);
+ void Use(LifetimePosition block_start,
+ LifetimePosition position,
+ LOperand* operand,
+ LOperand* hint);
+ void AddConstraintsGapMove(int index, LOperand* from, LOperand* to);
+
+ // Helper methods for updating the life range lists.
+ void AddToActive(LiveRange* range);
+ void AddToInactive(LiveRange* range);
+ void AddToUnhandledSorted(LiveRange* range);
+ void AddToUnhandledUnsorted(LiveRange* range);
+ void SortUnhandled();
+ bool UnhandledIsSorted();
+ void ActiveToHandled(LiveRange* range);
+ void ActiveToInactive(LiveRange* range);
+ void InactiveToHandled(LiveRange* range);
+ void InactiveToActive(LiveRange* range);
+ void FreeSpillSlot(LiveRange* range);
+ LOperand* TryReuseSpillSlot(LiveRange* range);
+
+ // Helper methods for allocating registers.
+ bool TryAllocateFreeReg(LiveRange* range);
+ void AllocateBlockedReg(LiveRange* range);
+ void SplitAndSpillIntersecting(LiveRange* range);
+ LifetimePosition FindOptimalSplitPos(LifetimePosition start,
+ LifetimePosition end);
+ LiveRange* Split(LiveRange* range,
+ LifetimePosition start,
+ LifetimePosition end);
+ LiveRange* Split(LiveRange* range, LifetimePosition split_pos);
+ void SplitAndSpill(LiveRange* range,
+ LifetimePosition start,
+ LifetimePosition end);
+ void SplitAndSpill(LiveRange* range, LifetimePosition at);
+ void Spill(LiveRange* range);
+ bool IsBlockBoundary(LifetimePosition pos);
+ void AddGapMove(int pos, LiveRange* prev, LiveRange* next);
+
+ // Helper methods for resolving control flow.
+ void ResolveControlFlow(LiveRange* range,
+ HBasicBlock* block,
+ HBasicBlock* pred);
+
+ // Return parallel move that should be used to connect ranges split at the
+ // given position.
+ LParallelMove* GetConnectingParallelMove(LifetimePosition pos);
+
+ // Return the block which contains give lifetime position.
+ HBasicBlock* GetBlock(LifetimePosition pos);
+
+ // Current active summary.
+ InstructionSummary* current_summary() const { return summary_stack_.last(); }
+
+ // Get summary for given instruction index.
+ InstructionSummary* GetSummary(int index) const { return summaries_[index]; }
+
+ // Helper methods for the fixed registers.
+ int RegisterCount() const;
+ static int FixedLiveRangeID(int index) { return -index - 1; }
+ static int FixedDoubleLiveRangeID(int index);
+ LiveRange* FixedLiveRangeFor(int index);
+ LiveRange* FixedDoubleLiveRangeFor(int index);
+ LiveRange* LiveRangeFor(int index);
+ HPhi* LookupPhi(LOperand* operand) const;
+ LGap* GetLastGap(HBasicBlock* block) const;
+
+ LChunk* chunk_;
+ ZoneList<InstructionSummary*> summaries_;
+ InstructionSummary* next_summary_;
+
+ ZoneList<InstructionSummary*> summary_stack_;
+
+ // During liveness analysis keep a mapping from block id to live_in sets
+ // for blocks already analyzed.
+ ZoneList<BitVector*> live_in_sets_;
+
+ // Liveness analysis results.
+ ZoneList<LiveRange*> live_ranges_;
+
+ // Lists of live ranges
+ ZoneList<LiveRange*> fixed_live_ranges_;
+ ZoneList<LiveRange*> fixed_double_live_ranges_;
+ ZoneList<LiveRange*> unhandled_live_ranges_;
+ ZoneList<LiveRange*> active_live_ranges_;
+ ZoneList<LiveRange*> inactive_live_ranges_;
+ ZoneList<LiveRange*> reusable_slots_;
+
+ // Next virtual register number to be assigned to temporaries.
+ int next_virtual_register_;
+
+ OperationMode mode_;
+ int num_registers_;
+
+ HGraph* graph_;
+
+ bool has_osr_entry_;
+
+ DISALLOW_COPY_AND_ASSIGN(LAllocator);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_LITHIUM_ALLOCATOR_H_