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