Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_LITHIUM_H_
      6 #define V8_LITHIUM_H_
      7 
      8 #include <set>
      9 
     10 #include "src/allocation.h"
     11 #include "src/bailout-reason.h"
     12 #include "src/hydrogen.h"
     13 #include "src/safepoint-table.h"
     14 #include "src/zone-allocator.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 #define LITHIUM_OPERAND_LIST(V)               \
     20   V(ConstantOperand, CONSTANT_OPERAND,  128)  \
     21   V(StackSlot,       STACK_SLOT,        128)  \
     22   V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128)  \
     23   V(Register,        REGISTER,          16)   \
     24   V(DoubleRegister,  DOUBLE_REGISTER,   16)
     25 
     26 class LOperand : public ZoneObject {
     27  public:
     28   enum Kind {
     29     INVALID,
     30     UNALLOCATED,
     31     CONSTANT_OPERAND,
     32     STACK_SLOT,
     33     DOUBLE_STACK_SLOT,
     34     REGISTER,
     35     DOUBLE_REGISTER
     36   };
     37 
     38   LOperand() : value_(KindField::encode(INVALID)) { }
     39 
     40   Kind kind() const { return KindField::decode(value_); }
     41   int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
     42 #define LITHIUM_OPERAND_PREDICATE(name, type, number) \
     43   bool Is##name() const { return kind() == type; }
     44   LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE)
     45   LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0)
     46   LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0)
     47 #undef LITHIUM_OPERAND_PREDICATE
     48   bool Equals(LOperand* other) const { return value_ == other->value_; }
     49 
     50   void PrintTo(StringStream* stream);
     51   void ConvertTo(Kind kind, int index) {
     52     if (kind == REGISTER) DCHECK(index >= 0);
     53     value_ = KindField::encode(kind);
     54     value_ |= index << kKindFieldWidth;
     55     DCHECK(this->index() == index);
     56   }
     57 
     58   // Calls SetUpCache()/TearDownCache() for each subclass.
     59   static void SetUpCaches();
     60   static void TearDownCaches();
     61 
     62  protected:
     63   static const int kKindFieldWidth = 3;
     64   class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
     65 
     66   LOperand(Kind kind, int index) { ConvertTo(kind, index); }
     67 
     68   unsigned value_;
     69 };
     70 
     71 
     72 class LUnallocated : public LOperand {
     73  public:
     74   enum BasicPolicy {
     75     FIXED_SLOT,
     76     EXTENDED_POLICY
     77   };
     78 
     79   enum ExtendedPolicy {
     80     NONE,
     81     ANY,
     82     FIXED_REGISTER,
     83     FIXED_DOUBLE_REGISTER,
     84     MUST_HAVE_REGISTER,
     85     MUST_HAVE_DOUBLE_REGISTER,
     86     WRITABLE_REGISTER,
     87     SAME_AS_FIRST_INPUT
     88   };
     89 
     90   // Lifetime of operand inside the instruction.
     91   enum Lifetime {
     92     // USED_AT_START operand is guaranteed to be live only at
     93     // instruction start. Register allocator is free to assign the same register
     94     // to some other operand used inside instruction (i.e. temporary or
     95     // output).
     96     USED_AT_START,
     97 
     98     // USED_AT_END operand is treated as live until the end of
     99     // instruction. This means that register allocator will not reuse it's
    100     // register for any other operand inside instruction.
    101     USED_AT_END
    102   };
    103 
    104   explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) {
    105     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    106     value_ |= ExtendedPolicyField::encode(policy);
    107     value_ |= LifetimeField::encode(USED_AT_END);
    108   }
    109 
    110   LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
    111     DCHECK(policy == FIXED_SLOT);
    112     value_ |= BasicPolicyField::encode(policy);
    113     value_ |= index << FixedSlotIndexField::kShift;
    114     DCHECK(this->fixed_slot_index() == index);
    115   }
    116 
    117   LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) {
    118     DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
    119     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    120     value_ |= ExtendedPolicyField::encode(policy);
    121     value_ |= LifetimeField::encode(USED_AT_END);
    122     value_ |= FixedRegisterField::encode(index);
    123   }
    124 
    125   LUnallocated(ExtendedPolicy policy, Lifetime lifetime)
    126       : LOperand(UNALLOCATED, 0) {
    127     value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    128     value_ |= ExtendedPolicyField::encode(policy);
    129     value_ |= LifetimeField::encode(lifetime);
    130   }
    131 
    132   LUnallocated* CopyUnconstrained(Zone* zone) {
    133     LUnallocated* result = new(zone) LUnallocated(ANY);
    134     result->set_virtual_register(virtual_register());
    135     return result;
    136   }
    137 
    138   static LUnallocated* cast(LOperand* op) {
    139     DCHECK(op->IsUnallocated());
    140     return reinterpret_cast<LUnallocated*>(op);
    141   }
    142 
    143   // The encoding used for LUnallocated operands depends on the policy that is
    144   // stored within the operand. The FIXED_SLOT policy uses a compact encoding
    145   // because it accommodates a larger pay-load.
    146   //
    147   // For FIXED_SLOT policy:
    148   //     +------------------------------------------+
    149   //     |       slot_index      |  vreg  | 0 | 001 |
    150   //     +------------------------------------------+
    151   //
    152   // For all other (extended) policies:
    153   //     +------------------------------------------+
    154   //     |  reg_index  | L | PPP |  vreg  | 1 | 001 |    L ... Lifetime
    155   //     +------------------------------------------+    P ... Policy
    156   //
    157   // The slot index is a signed value which requires us to decode it manually
    158   // instead of using the BitField utility class.
    159 
    160   // The superclass has a KindField.
    161   STATIC_ASSERT(kKindFieldWidth == 3);
    162 
    163   // BitFields for all unallocated operands.
    164   class BasicPolicyField     : public BitField<BasicPolicy,     3,  1> {};
    165   class VirtualRegisterField : public BitField<unsigned,        4, 18> {};
    166 
    167   // BitFields specific to BasicPolicy::FIXED_SLOT.
    168   class FixedSlotIndexField  : public BitField<int,            22, 10> {};
    169 
    170   // BitFields specific to BasicPolicy::EXTENDED_POLICY.
    171   class ExtendedPolicyField  : public BitField<ExtendedPolicy, 22,  3> {};
    172   class LifetimeField        : public BitField<Lifetime,       25,  1> {};
    173   class FixedRegisterField   : public BitField<int,            26,  6> {};
    174 
    175   static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1;
    176   static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
    177   static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
    178   static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
    179 
    180   // Predicates for the operand policy.
    181   bool HasAnyPolicy() const {
    182     return basic_policy() == EXTENDED_POLICY &&
    183         extended_policy() == ANY;
    184   }
    185   bool HasFixedPolicy() const {
    186     return basic_policy() == FIXED_SLOT ||
    187         extended_policy() == FIXED_REGISTER ||
    188         extended_policy() == FIXED_DOUBLE_REGISTER;
    189   }
    190   bool HasRegisterPolicy() const {
    191     return basic_policy() == EXTENDED_POLICY && (
    192         extended_policy() == WRITABLE_REGISTER ||
    193         extended_policy() == MUST_HAVE_REGISTER);
    194   }
    195   bool HasDoubleRegisterPolicy() const {
    196     return basic_policy() == EXTENDED_POLICY &&
    197         extended_policy() == MUST_HAVE_DOUBLE_REGISTER;
    198   }
    199   bool HasSameAsInputPolicy() const {
    200     return basic_policy() == EXTENDED_POLICY &&
    201         extended_policy() == SAME_AS_FIRST_INPUT;
    202   }
    203   bool HasFixedSlotPolicy() const {
    204     return basic_policy() == FIXED_SLOT;
    205   }
    206   bool HasFixedRegisterPolicy() const {
    207     return basic_policy() == EXTENDED_POLICY &&
    208         extended_policy() == FIXED_REGISTER;
    209   }
    210   bool HasFixedDoubleRegisterPolicy() const {
    211     return basic_policy() == EXTENDED_POLICY &&
    212         extended_policy() == FIXED_DOUBLE_REGISTER;
    213   }
    214   bool HasWritableRegisterPolicy() const {
    215     return basic_policy() == EXTENDED_POLICY &&
    216         extended_policy() == WRITABLE_REGISTER;
    217   }
    218 
    219   // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
    220   BasicPolicy basic_policy() const {
    221     return BasicPolicyField::decode(value_);
    222   }
    223 
    224   // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
    225   ExtendedPolicy extended_policy() const {
    226     DCHECK(basic_policy() == EXTENDED_POLICY);
    227     return ExtendedPolicyField::decode(value_);
    228   }
    229 
    230   // [fixed_slot_index]: Only for FIXED_SLOT.
    231   int fixed_slot_index() const {
    232     DCHECK(HasFixedSlotPolicy());
    233     return static_cast<int>(value_) >> FixedSlotIndexField::kShift;
    234   }
    235 
    236   // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
    237   int fixed_register_index() const {
    238     DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
    239     return FixedRegisterField::decode(value_);
    240   }
    241 
    242   // [virtual_register]: The virtual register ID for this operand.
    243   int virtual_register() const {
    244     return VirtualRegisterField::decode(value_);
    245   }
    246   void set_virtual_register(unsigned id) {
    247     value_ = VirtualRegisterField::update(value_, id);
    248   }
    249 
    250   // [lifetime]: Only for non-FIXED_SLOT.
    251   bool IsUsedAtStart() {
    252     DCHECK(basic_policy() == EXTENDED_POLICY);
    253     return LifetimeField::decode(value_) == USED_AT_START;
    254   }
    255 };
    256 
    257 
    258 class LMoveOperands FINAL BASE_EMBEDDED {
    259  public:
    260   LMoveOperands(LOperand* source, LOperand* destination)
    261       : source_(source), destination_(destination) {
    262   }
    263 
    264   LOperand* source() const { return source_; }
    265   void set_source(LOperand* operand) { source_ = operand; }
    266 
    267   LOperand* destination() const { return destination_; }
    268   void set_destination(LOperand* operand) { destination_ = operand; }
    269 
    270   // The gap resolver marks moves as "in-progress" by clearing the
    271   // destination (but not the source).
    272   bool IsPending() const {
    273     return destination_ == NULL && source_ != NULL;
    274   }
    275 
    276   // True if this move a move into the given destination operand.
    277   bool Blocks(LOperand* operand) const {
    278     return !IsEliminated() && source()->Equals(operand);
    279   }
    280 
    281   // A move is redundant if it's been eliminated, if its source and
    282   // destination are the same, or if its destination is unneeded or constant.
    283   bool IsRedundant() const {
    284     return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
    285            (destination_ != NULL && destination_->IsConstantOperand());
    286   }
    287 
    288   bool IsIgnored() const {
    289     return destination_ != NULL && destination_->IsIgnored();
    290   }
    291 
    292   // We clear both operands to indicate move that's been eliminated.
    293   void Eliminate() { source_ = destination_ = NULL; }
    294   bool IsEliminated() const {
    295     DCHECK(source_ != NULL || destination_ == NULL);
    296     return source_ == NULL;
    297   }
    298 
    299  private:
    300   LOperand* source_;
    301   LOperand* destination_;
    302 };
    303 
    304 
    305 template<LOperand::Kind kOperandKind, int kNumCachedOperands>
    306 class LSubKindOperand FINAL : public LOperand {
    307  public:
    308   static LSubKindOperand* Create(int index, Zone* zone) {
    309     DCHECK(index >= 0);
    310     if (index < kNumCachedOperands) return &cache[index];
    311     return new(zone) LSubKindOperand(index);
    312   }
    313 
    314   static LSubKindOperand* cast(LOperand* op) {
    315     DCHECK(op->kind() == kOperandKind);
    316     return reinterpret_cast<LSubKindOperand*>(op);
    317   }
    318 
    319   static void SetUpCache();
    320   static void TearDownCache();
    321 
    322  private:
    323   static LSubKindOperand* cache;
    324 
    325   LSubKindOperand() : LOperand() { }
    326   explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { }
    327 };
    328 
    329 
    330 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number)   \
    331 typedef LSubKindOperand<LOperand::type, number> L##name;
    332 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)
    333 #undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS
    334 
    335 
    336 class LParallelMove FINAL : public ZoneObject {
    337  public:
    338   explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
    339 
    340   void AddMove(LOperand* from, LOperand* to, Zone* zone) {
    341     move_operands_.Add(LMoveOperands(from, to), zone);
    342   }
    343 
    344   bool IsRedundant() const;
    345 
    346   ZoneList<LMoveOperands>* move_operands() { return &move_operands_; }
    347 
    348   void PrintDataTo(StringStream* stream) const;
    349 
    350  private:
    351   ZoneList<LMoveOperands> move_operands_;
    352 };
    353 
    354 
    355 class LPointerMap FINAL : public ZoneObject {
    356  public:
    357   explicit LPointerMap(Zone* zone)
    358       : pointer_operands_(8, zone),
    359         untagged_operands_(0, zone),
    360         lithium_position_(-1) { }
    361 
    362   const ZoneList<LOperand*>* GetNormalizedOperands() {
    363     for (int i = 0; i < untagged_operands_.length(); ++i) {
    364       RemovePointer(untagged_operands_[i]);
    365     }
    366     untagged_operands_.Clear();
    367     return &pointer_operands_;
    368   }
    369   int lithium_position() const { return lithium_position_; }
    370 
    371   void set_lithium_position(int pos) {
    372     DCHECK(lithium_position_ == -1);
    373     lithium_position_ = pos;
    374   }
    375 
    376   void RecordPointer(LOperand* op, Zone* zone);
    377   void RemovePointer(LOperand* op);
    378   void RecordUntagged(LOperand* op, Zone* zone);
    379   void PrintTo(StringStream* stream);
    380 
    381  private:
    382   ZoneList<LOperand*> pointer_operands_;
    383   ZoneList<LOperand*> untagged_operands_;
    384   int lithium_position_;
    385 };
    386 
    387 
    388 class LEnvironment FINAL : public ZoneObject {
    389  public:
    390   LEnvironment(Handle<JSFunction> closure,
    391                FrameType frame_type,
    392                BailoutId ast_id,
    393                int parameter_count,
    394                int argument_count,
    395                int value_count,
    396                LEnvironment* outer,
    397                HEnterInlined* entry,
    398                Zone* zone)
    399       : closure_(closure),
    400         frame_type_(frame_type),
    401         arguments_stack_height_(argument_count),
    402         deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
    403         translation_index_(-1),
    404         ast_id_(ast_id),
    405         translation_size_(value_count),
    406         parameter_count_(parameter_count),
    407         pc_offset_(-1),
    408         values_(value_count, zone),
    409         is_tagged_(value_count, zone),
    410         is_uint32_(value_count, zone),
    411         object_mapping_(0, zone),
    412         outer_(outer),
    413         entry_(entry),
    414         zone_(zone),
    415         has_been_used_(false) { }
    416 
    417   Handle<JSFunction> closure() const { return closure_; }
    418   FrameType frame_type() const { return frame_type_; }
    419   int arguments_stack_height() const { return arguments_stack_height_; }
    420   int deoptimization_index() const { return deoptimization_index_; }
    421   int translation_index() const { return translation_index_; }
    422   BailoutId ast_id() const { return ast_id_; }
    423   int translation_size() const { return translation_size_; }
    424   int parameter_count() const { return parameter_count_; }
    425   int pc_offset() const { return pc_offset_; }
    426   const ZoneList<LOperand*>* values() const { return &values_; }
    427   LEnvironment* outer() const { return outer_; }
    428   HEnterInlined* entry() { return entry_; }
    429   Zone* zone() const { return zone_; }
    430 
    431   bool has_been_used() const { return has_been_used_; }
    432   void set_has_been_used() { has_been_used_ = true; }
    433 
    434   void AddValue(LOperand* operand,
    435                 Representation representation,
    436                 bool is_uint32) {
    437     values_.Add(operand, zone());
    438     if (representation.IsSmiOrTagged()) {
    439       DCHECK(!is_uint32);
    440       is_tagged_.Add(values_.length() - 1, zone());
    441     }
    442 
    443     if (is_uint32) {
    444       is_uint32_.Add(values_.length() - 1, zone());
    445     }
    446   }
    447 
    448   bool HasTaggedValueAt(int index) const {
    449     return is_tagged_.Contains(index);
    450   }
    451 
    452   bool HasUint32ValueAt(int index) const {
    453     return is_uint32_.Contains(index);
    454   }
    455 
    456   void AddNewObject(int length, bool is_arguments) {
    457     uint32_t encoded = LengthOrDupeField::encode(length) |
    458                        IsArgumentsField::encode(is_arguments) |
    459                        IsDuplicateField::encode(false);
    460     object_mapping_.Add(encoded, zone());
    461   }
    462 
    463   void AddDuplicateObject(int dupe_of) {
    464     uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
    465                        IsDuplicateField::encode(true);
    466     object_mapping_.Add(encoded, zone());
    467   }
    468 
    469   int ObjectDuplicateOfAt(int index) {
    470     DCHECK(ObjectIsDuplicateAt(index));
    471     return LengthOrDupeField::decode(object_mapping_[index]);
    472   }
    473 
    474   int ObjectLengthAt(int index) {
    475     DCHECK(!ObjectIsDuplicateAt(index));
    476     return LengthOrDupeField::decode(object_mapping_[index]);
    477   }
    478 
    479   bool ObjectIsArgumentsAt(int index) {
    480     DCHECK(!ObjectIsDuplicateAt(index));
    481     return IsArgumentsField::decode(object_mapping_[index]);
    482   }
    483 
    484   bool ObjectIsDuplicateAt(int index) {
    485     return IsDuplicateField::decode(object_mapping_[index]);
    486   }
    487 
    488   void Register(int deoptimization_index,
    489                 int translation_index,
    490                 int pc_offset) {
    491     DCHECK(!HasBeenRegistered());
    492     deoptimization_index_ = deoptimization_index;
    493     translation_index_ = translation_index;
    494     pc_offset_ = pc_offset;
    495   }
    496   bool HasBeenRegistered() const {
    497     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
    498   }
    499 
    500   void PrintTo(StringStream* stream);
    501 
    502   // Marker value indicating a de-materialized object.
    503   static LOperand* materialization_marker() { return NULL; }
    504 
    505   // Encoding used for the object_mapping map below.
    506   class LengthOrDupeField : public BitField<int,   0, 30> { };
    507   class IsArgumentsField  : public BitField<bool, 30,  1> { };
    508   class IsDuplicateField  : public BitField<bool, 31,  1> { };
    509 
    510  private:
    511   Handle<JSFunction> closure_;
    512   FrameType frame_type_;
    513   int arguments_stack_height_;
    514   int deoptimization_index_;
    515   int translation_index_;
    516   BailoutId ast_id_;
    517   int translation_size_;
    518   int parameter_count_;
    519   int pc_offset_;
    520 
    521   // Value array: [parameters] [locals] [expression stack] [de-materialized].
    522   //              |>--------- translation_size ---------<|
    523   ZoneList<LOperand*> values_;
    524   GrowableBitVector is_tagged_;
    525   GrowableBitVector is_uint32_;
    526 
    527   // Map with encoded information about materialization_marker operands.
    528   ZoneList<uint32_t> object_mapping_;
    529 
    530   LEnvironment* outer_;
    531   HEnterInlined* entry_;
    532   Zone* zone_;
    533   bool has_been_used_;
    534 };
    535 
    536 
    537 // Iterates over the non-null, non-constant operands in an environment.
    538 class ShallowIterator FINAL BASE_EMBEDDED {
    539  public:
    540   explicit ShallowIterator(LEnvironment* env)
    541       : env_(env),
    542         limit_(env != NULL ? env->values()->length() : 0),
    543         current_(0) {
    544     SkipUninteresting();
    545   }
    546 
    547   bool Done() { return current_ >= limit_; }
    548 
    549   LOperand* Current() {
    550     DCHECK(!Done());
    551     DCHECK(env_->values()->at(current_) != NULL);
    552     return env_->values()->at(current_);
    553   }
    554 
    555   void Advance() {
    556     DCHECK(!Done());
    557     ++current_;
    558     SkipUninteresting();
    559   }
    560 
    561   LEnvironment* env() { return env_; }
    562 
    563  private:
    564   bool ShouldSkip(LOperand* op) {
    565     return op == NULL || op->IsConstantOperand();
    566   }
    567 
    568   // Skip until something interesting, beginning with and including current_.
    569   void SkipUninteresting() {
    570     while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
    571       ++current_;
    572     }
    573   }
    574 
    575   LEnvironment* env_;
    576   int limit_;
    577   int current_;
    578 };
    579 
    580 
    581 // Iterator for non-null, non-constant operands incl. outer environments.
    582 class DeepIterator FINAL BASE_EMBEDDED {
    583  public:
    584   explicit DeepIterator(LEnvironment* env)
    585       : current_iterator_(env) {
    586     SkipUninteresting();
    587   }
    588 
    589   bool Done() { return current_iterator_.Done(); }
    590 
    591   LOperand* Current() {
    592     DCHECK(!current_iterator_.Done());
    593     DCHECK(current_iterator_.Current() != NULL);
    594     return current_iterator_.Current();
    595   }
    596 
    597   void Advance() {
    598     current_iterator_.Advance();
    599     SkipUninteresting();
    600   }
    601 
    602  private:
    603   void SkipUninteresting() {
    604     while (current_iterator_.env() != NULL && current_iterator_.Done()) {
    605       current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
    606     }
    607   }
    608 
    609   ShallowIterator current_iterator_;
    610 };
    611 
    612 
    613 class LPlatformChunk;
    614 class LGap;
    615 class LLabel;
    616 
    617 // Superclass providing data and behavior common to all the
    618 // arch-specific LPlatformChunk classes.
    619 class LChunk : public ZoneObject {
    620  public:
    621   static LChunk* NewChunk(HGraph* graph);
    622 
    623   void AddInstruction(LInstruction* instruction, HBasicBlock* block);
    624   LConstantOperand* DefineConstantOperand(HConstant* constant);
    625   HConstant* LookupConstant(LConstantOperand* operand) const;
    626   Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
    627 
    628   int ParameterAt(int index);
    629   int GetParameterStackSlot(int index) const;
    630   int spill_slot_count() const { return spill_slot_count_; }
    631   CompilationInfo* info() const { return info_; }
    632   HGraph* graph() const { return graph_; }
    633   Isolate* isolate() const { return graph_->isolate(); }
    634   const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
    635   void AddGapMove(int index, LOperand* from, LOperand* to);
    636   LGap* GetGapAt(int index) const;
    637   bool IsGapAt(int index) const;
    638   int NearestGapPos(int index) const;
    639   void MarkEmptyBlocks();
    640   const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
    641   LLabel* GetLabel(int block_id) const;
    642   int LookupDestination(int block_id) const;
    643   Label* GetAssemblyLabel(int block_id) const;
    644 
    645   const ZoneList<Handle<JSFunction> >* inlined_closures() const {
    646     return &inlined_closures_;
    647   }
    648 
    649   void AddInlinedClosure(Handle<JSFunction> closure) {
    650     inlined_closures_.Add(closure, zone());
    651   }
    652 
    653   void AddDeprecationDependency(Handle<Map> map) {
    654     DCHECK(!map->is_deprecated());
    655     if (!map->CanBeDeprecated()) return;
    656     DCHECK(!info_->IsStub());
    657     deprecation_dependencies_.insert(map);
    658   }
    659 
    660   void AddStabilityDependency(Handle<Map> map) {
    661     DCHECK(map->is_stable());
    662     if (!map->CanTransition()) return;
    663     DCHECK(!info_->IsStub());
    664     stability_dependencies_.insert(map);
    665   }
    666 
    667   Zone* zone() const { return info_->zone(); }
    668 
    669   Handle<Code> Codegen();
    670 
    671   void set_allocated_double_registers(BitVector* allocated_registers);
    672   BitVector* allocated_double_registers() {
    673     return allocated_double_registers_;
    674   }
    675 
    676  protected:
    677   LChunk(CompilationInfo* info, HGraph* graph);
    678 
    679   int spill_slot_count_;
    680 
    681  private:
    682   typedef std::less<Handle<Map> > MapLess;
    683   typedef zone_allocator<Handle<Map> > MapAllocator;
    684   typedef std::set<Handle<Map>, MapLess, MapAllocator> MapSet;
    685 
    686   void CommitDependencies(Handle<Code> code) const;
    687 
    688   CompilationInfo* info_;
    689   HGraph* const graph_;
    690   BitVector* allocated_double_registers_;
    691   ZoneList<LInstruction*> instructions_;
    692   ZoneList<LPointerMap*> pointer_maps_;
    693   ZoneList<Handle<JSFunction> > inlined_closures_;
    694   MapSet deprecation_dependencies_;
    695   MapSet stability_dependencies_;
    696 };
    697 
    698 
    699 class LChunkBuilderBase BASE_EMBEDDED {
    700  public:
    701   explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
    702       : argument_count_(0),
    703         chunk_(NULL),
    704         info_(info),
    705         graph_(graph),
    706         status_(UNUSED),
    707         zone_(graph->zone()) {}
    708 
    709   virtual ~LChunkBuilderBase() { }
    710 
    711   void Abort(BailoutReason reason);
    712   void Retry(BailoutReason reason);
    713 
    714  protected:
    715   enum Status { UNUSED, BUILDING, DONE, ABORTED };
    716 
    717   LPlatformChunk* chunk() const { return chunk_; }
    718   CompilationInfo* info() const { return info_; }
    719   HGraph* graph() const { return graph_; }
    720   int argument_count() const { return argument_count_; }
    721   Isolate* isolate() const { return graph_->isolate(); }
    722   Heap* heap() const { return isolate()->heap(); }
    723 
    724   bool is_unused() const { return status_ == UNUSED; }
    725   bool is_building() const { return status_ == BUILDING; }
    726   bool is_done() const { return status_ == DONE; }
    727   bool is_aborted() const { return status_ == ABORTED; }
    728 
    729   // An input operand in register, stack slot or a constant operand.
    730   // Will not be moved to a register even if one is freely available.
    731   virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
    732 
    733   LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
    734                                   int* argument_index_accumulator,
    735                                   ZoneList<HValue*>* objects_to_materialize);
    736   void AddObjectToMaterialize(HValue* value,
    737                               ZoneList<HValue*>* objects_to_materialize,
    738                               LEnvironment* result);
    739 
    740   Zone* zone() const { return zone_; }
    741 
    742   int argument_count_;
    743   LPlatformChunk* chunk_;
    744   CompilationInfo* info_;
    745   HGraph* const graph_;
    746   Status status_;
    747 
    748  private:
    749   Zone* zone_;
    750 };
    751 
    752 
    753 int StackSlotOffset(int index);
    754 
    755 enum NumberUntagDMode {
    756   NUMBER_CANDIDATE_IS_SMI,
    757   NUMBER_CANDIDATE_IS_ANY_TAGGED
    758 };
    759 
    760 
    761 class LPhase : public CompilationPhase {
    762  public:
    763   LPhase(const char* name, LChunk* chunk)
    764       : CompilationPhase(name, chunk->info()),
    765         chunk_(chunk) { }
    766   ~LPhase();
    767 
    768  private:
    769   LChunk* chunk_;
    770 
    771   DISALLOW_COPY_AND_ASSIGN(LPhase);
    772 };
    773 
    774 
    775 // A register-allocator view of a Lithium instruction. It contains the id of
    776 // the output operand and a list of input operand uses.
    777 
    778 enum RegisterKind {
    779   UNALLOCATED_REGISTERS,
    780   GENERAL_REGISTERS,
    781   DOUBLE_REGISTERS
    782 };
    783 
    784 // Iterator for non-null temp operands.
    785 class TempIterator BASE_EMBEDDED {
    786  public:
    787   inline explicit TempIterator(LInstruction* instr);
    788   inline bool Done();
    789   inline LOperand* Current();
    790   inline void Advance();
    791 
    792  private:
    793   inline void SkipUninteresting();
    794   LInstruction* instr_;
    795   int limit_;
    796   int current_;
    797 };
    798 
    799 
    800 // Iterator for non-constant input operands.
    801 class InputIterator BASE_EMBEDDED {
    802  public:
    803   inline explicit InputIterator(LInstruction* instr);
    804   inline bool Done();
    805   inline LOperand* Current();
    806   inline void Advance();
    807 
    808  private:
    809   inline void SkipUninteresting();
    810   LInstruction* instr_;
    811   int limit_;
    812   int current_;
    813 };
    814 
    815 
    816 class UseIterator BASE_EMBEDDED {
    817  public:
    818   inline explicit UseIterator(LInstruction* instr);
    819   inline bool Done();
    820   inline LOperand* Current();
    821   inline void Advance();
    822 
    823  private:
    824   InputIterator input_iterator_;
    825   DeepIterator env_iterator_;
    826 };
    827 
    828 class LInstruction;
    829 class LCodeGen;
    830 } }  // namespace v8::internal
    831 
    832 #endif  // V8_LITHIUM_H_
    833