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/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   static bool TooManyParameters(int num_parameters) {
    257     const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
    258     return num_parameters + 1 > parameter_limit;
    259   }
    260 
    261   static bool TooManyParametersOrStackSlots(int num_parameters,
    262                                             int num_stack_slots) {
    263     const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
    264     return num_parameters + 1 + num_stack_slots > locals_limit;
    265   }
    266 };
    267 
    268 
    269 class LMoveOperands final BASE_EMBEDDED {
    270  public:
    271   LMoveOperands(LOperand* source, LOperand* destination)
    272       : source_(source), destination_(destination) {
    273   }
    274 
    275   LOperand* source() const { return source_; }
    276   void set_source(LOperand* operand) { source_ = operand; }
    277 
    278   LOperand* destination() const { return destination_; }
    279   void set_destination(LOperand* operand) { destination_ = operand; }
    280 
    281   // The gap resolver marks moves as "in-progress" by clearing the
    282   // destination (but not the source).
    283   bool IsPending() const {
    284     return destination_ == NULL && source_ != NULL;
    285   }
    286 
    287   // True if this move a move into the given destination operand.
    288   bool Blocks(LOperand* operand) const {
    289     return !IsEliminated() && source()->Equals(operand);
    290   }
    291 
    292   // A move is redundant if it's been eliminated, if its source and
    293   // destination are the same, or if its destination is unneeded or constant.
    294   bool IsRedundant() const {
    295     return IsEliminated() || source_->Equals(destination_) || IsIgnored() ||
    296            (destination_ != NULL && destination_->IsConstantOperand());
    297   }
    298 
    299   bool IsIgnored() const {
    300     return destination_ != NULL && destination_->IsIgnored();
    301   }
    302 
    303   // We clear both operands to indicate move that's been eliminated.
    304   void Eliminate() { source_ = destination_ = NULL; }
    305   bool IsEliminated() const {
    306     DCHECK(source_ != NULL || destination_ == NULL);
    307     return source_ == NULL;
    308   }
    309 
    310  private:
    311   LOperand* source_;
    312   LOperand* destination_;
    313 };
    314 
    315 
    316 template <LOperand::Kind kOperandKind, int kNumCachedOperands>
    317 class LSubKindOperand final : public LOperand {
    318  public:
    319   static LSubKindOperand* Create(int index, Zone* zone) {
    320     DCHECK(index >= 0);
    321     if (index < kNumCachedOperands) return &cache[index];
    322     return new(zone) LSubKindOperand(index);
    323   }
    324 
    325   static LSubKindOperand* cast(LOperand* op) {
    326     DCHECK(op->kind() == kOperandKind);
    327     return reinterpret_cast<LSubKindOperand*>(op);
    328   }
    329 
    330   static void SetUpCache();
    331   static void TearDownCache();
    332 
    333  private:
    334   static LSubKindOperand* cache;
    335 
    336   LSubKindOperand() : LOperand() { }
    337   explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { }
    338 };
    339 
    340 
    341 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number)   \
    342 typedef LSubKindOperand<LOperand::type, number> L##name;
    343 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS)
    344 #undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS
    345 
    346 
    347 class LParallelMove final : public ZoneObject {
    348  public:
    349   explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { }
    350 
    351   void AddMove(LOperand* from, LOperand* to, Zone* zone) {
    352     move_operands_.Add(LMoveOperands(from, to), zone);
    353   }
    354 
    355   bool IsRedundant() const;
    356 
    357   ZoneList<LMoveOperands>* move_operands() { return &move_operands_; }
    358 
    359   void PrintDataTo(StringStream* stream) const;
    360 
    361  private:
    362   ZoneList<LMoveOperands> move_operands_;
    363 };
    364 
    365 
    366 class LPointerMap final : public ZoneObject {
    367  public:
    368   explicit LPointerMap(Zone* zone)
    369       : pointer_operands_(8, zone),
    370         untagged_operands_(0, zone),
    371         lithium_position_(-1) { }
    372 
    373   const ZoneList<LOperand*>* GetNormalizedOperands() {
    374     for (int i = 0; i < untagged_operands_.length(); ++i) {
    375       RemovePointer(untagged_operands_[i]);
    376     }
    377     untagged_operands_.Clear();
    378     return &pointer_operands_;
    379   }
    380   int lithium_position() const { return lithium_position_; }
    381 
    382   void set_lithium_position(int pos) {
    383     DCHECK(lithium_position_ == -1);
    384     lithium_position_ = pos;
    385   }
    386 
    387   void RecordPointer(LOperand* op, Zone* zone);
    388   void RemovePointer(LOperand* op);
    389   void RecordUntagged(LOperand* op, Zone* zone);
    390   void PrintTo(StringStream* stream);
    391 
    392  private:
    393   ZoneList<LOperand*> pointer_operands_;
    394   ZoneList<LOperand*> untagged_operands_;
    395   int lithium_position_;
    396 };
    397 
    398 
    399 class LEnvironment final : public ZoneObject {
    400  public:
    401   LEnvironment(Handle<JSFunction> closure,
    402                FrameType frame_type,
    403                BailoutId ast_id,
    404                int parameter_count,
    405                int argument_count,
    406                int value_count,
    407                LEnvironment* outer,
    408                HEnterInlined* entry,
    409                Zone* zone)
    410       : closure_(closure),
    411         frame_type_(frame_type),
    412         arguments_stack_height_(argument_count),
    413         deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
    414         translation_index_(-1),
    415         ast_id_(ast_id),
    416         translation_size_(value_count),
    417         parameter_count_(parameter_count),
    418         pc_offset_(-1),
    419         values_(value_count, zone),
    420         is_tagged_(value_count, zone),
    421         is_uint32_(value_count, zone),
    422         object_mapping_(0, zone),
    423         outer_(outer),
    424         entry_(entry),
    425         zone_(zone),
    426         has_been_used_(false) { }
    427 
    428   Handle<JSFunction> closure() const { return closure_; }
    429   FrameType frame_type() const { return frame_type_; }
    430   int arguments_stack_height() const { return arguments_stack_height_; }
    431   int deoptimization_index() const { return deoptimization_index_; }
    432   int translation_index() const { return translation_index_; }
    433   BailoutId ast_id() const { return ast_id_; }
    434   int translation_size() const { return translation_size_; }
    435   int parameter_count() const { return parameter_count_; }
    436   int pc_offset() const { return pc_offset_; }
    437   const ZoneList<LOperand*>* values() const { return &values_; }
    438   LEnvironment* outer() const { return outer_; }
    439   HEnterInlined* entry() { return entry_; }
    440   Zone* zone() const { return zone_; }
    441 
    442   bool has_been_used() const { return has_been_used_; }
    443   void set_has_been_used() { has_been_used_ = true; }
    444 
    445   void AddValue(LOperand* operand,
    446                 Representation representation,
    447                 bool is_uint32) {
    448     values_.Add(operand, zone());
    449     if (representation.IsSmiOrTagged()) {
    450       DCHECK(!is_uint32);
    451       is_tagged_.Add(values_.length() - 1, zone());
    452     }
    453 
    454     if (is_uint32) {
    455       is_uint32_.Add(values_.length() - 1, zone());
    456     }
    457   }
    458 
    459   bool HasTaggedValueAt(int index) const {
    460     return is_tagged_.Contains(index);
    461   }
    462 
    463   bool HasUint32ValueAt(int index) const {
    464     return is_uint32_.Contains(index);
    465   }
    466 
    467   void AddNewObject(int length, bool is_arguments) {
    468     uint32_t encoded = LengthOrDupeField::encode(length) |
    469                        IsArgumentsField::encode(is_arguments) |
    470                        IsDuplicateField::encode(false);
    471     object_mapping_.Add(encoded, zone());
    472   }
    473 
    474   void AddDuplicateObject(int dupe_of) {
    475     uint32_t encoded = LengthOrDupeField::encode(dupe_of) |
    476                        IsDuplicateField::encode(true);
    477     object_mapping_.Add(encoded, zone());
    478   }
    479 
    480   int ObjectDuplicateOfAt(int index) {
    481     DCHECK(ObjectIsDuplicateAt(index));
    482     return LengthOrDupeField::decode(object_mapping_[index]);
    483   }
    484 
    485   int ObjectLengthAt(int index) {
    486     DCHECK(!ObjectIsDuplicateAt(index));
    487     return LengthOrDupeField::decode(object_mapping_[index]);
    488   }
    489 
    490   bool ObjectIsArgumentsAt(int index) {
    491     DCHECK(!ObjectIsDuplicateAt(index));
    492     return IsArgumentsField::decode(object_mapping_[index]);
    493   }
    494 
    495   bool ObjectIsDuplicateAt(int index) {
    496     return IsDuplicateField::decode(object_mapping_[index]);
    497   }
    498 
    499   void Register(int deoptimization_index,
    500                 int translation_index,
    501                 int pc_offset) {
    502     DCHECK(!HasBeenRegistered());
    503     deoptimization_index_ = deoptimization_index;
    504     translation_index_ = translation_index;
    505     pc_offset_ = pc_offset;
    506   }
    507   bool HasBeenRegistered() const {
    508     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
    509   }
    510 
    511   void PrintTo(StringStream* stream);
    512 
    513   // Marker value indicating a de-materialized object.
    514   static LOperand* materialization_marker() { return NULL; }
    515 
    516   // Encoding used for the object_mapping map below.
    517   class LengthOrDupeField : public BitField<int,   0, 30> { };
    518   class IsArgumentsField  : public BitField<bool, 30,  1> { };
    519   class IsDuplicateField  : public BitField<bool, 31,  1> { };
    520 
    521  private:
    522   Handle<JSFunction> closure_;
    523   FrameType frame_type_;
    524   int arguments_stack_height_;
    525   int deoptimization_index_;
    526   int translation_index_;
    527   BailoutId ast_id_;
    528   int translation_size_;
    529   int parameter_count_;
    530   int pc_offset_;
    531 
    532   // Value array: [parameters] [locals] [expression stack] [de-materialized].
    533   //              |>--------- translation_size ---------<|
    534   ZoneList<LOperand*> values_;
    535   GrowableBitVector is_tagged_;
    536   GrowableBitVector is_uint32_;
    537 
    538   // Map with encoded information about materialization_marker operands.
    539   ZoneList<uint32_t> object_mapping_;
    540 
    541   LEnvironment* outer_;
    542   HEnterInlined* entry_;
    543   Zone* zone_;
    544   bool has_been_used_;
    545 };
    546 
    547 
    548 // Iterates over the non-null, non-constant operands in an environment.
    549 class ShallowIterator final BASE_EMBEDDED {
    550  public:
    551   explicit ShallowIterator(LEnvironment* env)
    552       : env_(env),
    553         limit_(env != NULL ? env->values()->length() : 0),
    554         current_(0) {
    555     SkipUninteresting();
    556   }
    557 
    558   bool Done() { return current_ >= limit_; }
    559 
    560   LOperand* Current() {
    561     DCHECK(!Done());
    562     DCHECK(env_->values()->at(current_) != NULL);
    563     return env_->values()->at(current_);
    564   }
    565 
    566   void Advance() {
    567     DCHECK(!Done());
    568     ++current_;
    569     SkipUninteresting();
    570   }
    571 
    572   LEnvironment* env() { return env_; }
    573 
    574  private:
    575   bool ShouldSkip(LOperand* op) {
    576     return op == NULL || op->IsConstantOperand();
    577   }
    578 
    579   // Skip until something interesting, beginning with and including current_.
    580   void SkipUninteresting() {
    581     while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) {
    582       ++current_;
    583     }
    584   }
    585 
    586   LEnvironment* env_;
    587   int limit_;
    588   int current_;
    589 };
    590 
    591 
    592 // Iterator for non-null, non-constant operands incl. outer environments.
    593 class DeepIterator final BASE_EMBEDDED {
    594  public:
    595   explicit DeepIterator(LEnvironment* env)
    596       : current_iterator_(env) {
    597     SkipUninteresting();
    598   }
    599 
    600   bool Done() { return current_iterator_.Done(); }
    601 
    602   LOperand* Current() {
    603     DCHECK(!current_iterator_.Done());
    604     DCHECK(current_iterator_.Current() != NULL);
    605     return current_iterator_.Current();
    606   }
    607 
    608   void Advance() {
    609     current_iterator_.Advance();
    610     SkipUninteresting();
    611   }
    612 
    613  private:
    614   void SkipUninteresting() {
    615     while (current_iterator_.env() != NULL && current_iterator_.Done()) {
    616       current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
    617     }
    618   }
    619 
    620   ShallowIterator current_iterator_;
    621 };
    622 
    623 
    624 class LPlatformChunk;
    625 class LGap;
    626 class LLabel;
    627 
    628 // Superclass providing data and behavior common to all the
    629 // arch-specific LPlatformChunk classes.
    630 class LChunk : public ZoneObject {
    631  public:
    632   static LChunk* NewChunk(HGraph* graph);
    633 
    634   void AddInstruction(LInstruction* instruction, HBasicBlock* block);
    635   LConstantOperand* DefineConstantOperand(HConstant* constant);
    636   HConstant* LookupConstant(LConstantOperand* operand) const;
    637   Representation LookupLiteralRepresentation(LConstantOperand* operand) const;
    638 
    639   int ParameterAt(int index);
    640   int GetParameterStackSlot(int index) const;
    641   int spill_slot_count() const { return spill_slot_count_; }
    642   CompilationInfo* info() const { return info_; }
    643   HGraph* graph() const { return graph_; }
    644   Isolate* isolate() const { return graph_->isolate(); }
    645   const ZoneList<LInstruction*>* instructions() const { return &instructions_; }
    646   void AddGapMove(int index, LOperand* from, LOperand* to);
    647   LGap* GetGapAt(int index) const;
    648   bool IsGapAt(int index) const;
    649   int NearestGapPos(int index) const;
    650   void MarkEmptyBlocks();
    651   const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
    652   LLabel* GetLabel(int block_id) const;
    653   int LookupDestination(int block_id) const;
    654   Label* GetAssemblyLabel(int block_id) const;
    655 
    656   const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const {
    657     return inlined_functions_;
    658   }
    659 
    660   void AddInlinedFunction(Handle<SharedFunctionInfo> closure) {
    661     inlined_functions_.Add(closure, zone());
    662   }
    663 
    664   void AddDeprecationDependency(Handle<Map> map) {
    665     DCHECK(!map->is_deprecated());
    666     if (!map->CanBeDeprecated()) return;
    667     DCHECK(!info_->IsStub());
    668     deprecation_dependencies_.Add(map, zone());
    669   }
    670 
    671   void AddStabilityDependency(Handle<Map> map) {
    672     DCHECK(map->is_stable());
    673     if (!map->CanTransition()) return;
    674     DCHECK(!info_->IsStub());
    675     stability_dependencies_.Add(map, zone());
    676   }
    677 
    678   Zone* zone() const { return info_->zone(); }
    679 
    680   Handle<Code> Codegen();
    681 
    682   void set_allocated_double_registers(BitVector* allocated_registers);
    683   BitVector* allocated_double_registers() {
    684     return allocated_double_registers_;
    685   }
    686 
    687  protected:
    688   LChunk(CompilationInfo* info, HGraph* graph);
    689 
    690   int spill_slot_count_;
    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<SharedFunctionInfo>> inlined_functions_;
    701   ZoneList<Handle<Map>> deprecation_dependencies_;
    702   ZoneList<Handle<Map>> stability_dependencies_;
    703 };
    704 
    705 
    706 class LChunkBuilderBase BASE_EMBEDDED {
    707  public:
    708   explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph)
    709       : argument_count_(0),
    710         chunk_(NULL),
    711         info_(info),
    712         graph_(graph),
    713         status_(UNUSED),
    714         zone_(graph->zone()) {}
    715 
    716   virtual ~LChunkBuilderBase() { }
    717 
    718   void Abort(BailoutReason reason);
    719   void Retry(BailoutReason reason);
    720 
    721  protected:
    722   enum Status { UNUSED, BUILDING, DONE, ABORTED };
    723 
    724   LPlatformChunk* chunk() const { return chunk_; }
    725   CompilationInfo* info() const { return info_; }
    726   HGraph* graph() const { return graph_; }
    727   int argument_count() const { return argument_count_; }
    728   Isolate* isolate() const { return graph_->isolate(); }
    729   Heap* heap() const { return isolate()->heap(); }
    730 
    731   bool is_unused() const { return status_ == UNUSED; }
    732   bool is_building() const { return status_ == BUILDING; }
    733   bool is_done() const { return status_ == DONE; }
    734   bool is_aborted() const { return status_ == ABORTED; }
    735 
    736   // An input operand in register, stack slot or a constant operand.
    737   // Will not be moved to a register even if one is freely available.
    738   virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
    739 
    740   LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
    741                                   int* argument_index_accumulator,
    742                                   ZoneList<HValue*>* objects_to_materialize);
    743   void AddObjectToMaterialize(HValue* value,
    744                               ZoneList<HValue*>* objects_to_materialize,
    745                               LEnvironment* result);
    746 
    747   Zone* zone() const { return zone_; }
    748 
    749   int argument_count_;
    750   LPlatformChunk* chunk_;
    751   CompilationInfo* info_;
    752   HGraph* const graph_;
    753   Status status_;
    754 
    755  private:
    756   Zone* zone_;
    757 };
    758 
    759 
    760 int StackSlotOffset(int index);
    761 
    762 enum NumberUntagDMode {
    763   NUMBER_CANDIDATE_IS_SMI,
    764   NUMBER_CANDIDATE_IS_ANY_TAGGED
    765 };
    766 
    767 
    768 class LPhase : public CompilationPhase {
    769  public:
    770   LPhase(const char* name, LChunk* chunk)
    771       : CompilationPhase(name, chunk->info()),
    772         chunk_(chunk) { }
    773   ~LPhase();
    774 
    775  private:
    776   LChunk* chunk_;
    777 
    778   DISALLOW_COPY_AND_ASSIGN(LPhase);
    779 };
    780 
    781 
    782 // A register-allocator view of a Lithium instruction. It contains the id of
    783 // the output operand and a list of input operand uses.
    784 
    785 enum RegisterKind {
    786   UNALLOCATED_REGISTERS,
    787   GENERAL_REGISTERS,
    788   DOUBLE_REGISTERS
    789 };
    790 
    791 // Iterator for non-null temp operands.
    792 class TempIterator BASE_EMBEDDED {
    793  public:
    794   inline explicit TempIterator(LInstruction* instr);
    795   inline bool Done();
    796   inline LOperand* Current();
    797   inline void Advance();
    798 
    799  private:
    800   inline void SkipUninteresting();
    801   LInstruction* instr_;
    802   int limit_;
    803   int current_;
    804 };
    805 
    806 
    807 // Iterator for non-constant input operands.
    808 class InputIterator BASE_EMBEDDED {
    809  public:
    810   inline explicit InputIterator(LInstruction* instr);
    811   inline bool Done();
    812   inline LOperand* Current();
    813   inline void Advance();
    814 
    815  private:
    816   inline void SkipUninteresting();
    817   LInstruction* instr_;
    818   int limit_;
    819   int current_;
    820 };
    821 
    822 
    823 class UseIterator BASE_EMBEDDED {
    824  public:
    825   inline explicit UseIterator(LInstruction* instr);
    826   inline bool Done();
    827   inline LOperand* Current();
    828   inline void Advance();
    829 
    830  private:
    831   InputIterator input_iterator_;
    832   DeepIterator env_iterator_;
    833 };
    834 
    835 class LInstruction;
    836 class LCodeGen;
    837 }  // namespace internal
    838 }  // namespace v8
    839 
    840 #endif  // V8_CRANKSHAFT_LITHIUM_H_
    841