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