Home | History | Annotate | Download | only in src
      1 // Copyright 2011 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 "hydrogen.h"
     32 #include "safepoint-table.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 class LOperand: public ZoneObject {
     38  public:
     39   enum Kind {
     40     INVALID,
     41     UNALLOCATED,
     42     CONSTANT_OPERAND,
     43     STACK_SLOT,
     44     DOUBLE_STACK_SLOT,
     45     REGISTER,
     46     DOUBLE_REGISTER,
     47     ARGUMENT
     48   };
     49 
     50   LOperand() : value_(KindField::encode(INVALID)) { }
     51 
     52   Kind kind() const { return KindField::decode(value_); }
     53   int index() const { return static_cast<int>(value_) >> kKindFieldWidth; }
     54   bool IsConstantOperand() const { return kind() == CONSTANT_OPERAND; }
     55   bool IsStackSlot() const { return kind() == STACK_SLOT; }
     56   bool IsDoubleStackSlot() const { return kind() == DOUBLE_STACK_SLOT; }
     57   bool IsRegister() const { return kind() == REGISTER; }
     58   bool IsDoubleRegister() const { return kind() == DOUBLE_REGISTER; }
     59   bool IsArgument() const { return kind() == ARGUMENT; }
     60   bool IsUnallocated() const { return kind() == UNALLOCATED; }
     61   bool Equals(LOperand* other) const { return value_ == other->value_; }
     62   int VirtualRegister();
     63 
     64   void PrintTo(StringStream* stream);
     65   void ConvertTo(Kind kind, int index) {
     66     value_ = KindField::encode(kind);
     67     value_ |= index << kKindFieldWidth;
     68     ASSERT(this->index() == index);
     69   }
     70 
     71  protected:
     72   static const int kKindFieldWidth = 3;
     73   class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
     74 
     75   LOperand(Kind kind, int index) { ConvertTo(kind, index); }
     76 
     77   unsigned value_;
     78 };
     79 
     80 
     81 class LUnallocated: public LOperand {
     82  public:
     83   enum Policy {
     84     NONE,
     85     ANY,
     86     FIXED_REGISTER,
     87     FIXED_DOUBLE_REGISTER,
     88     FIXED_SLOT,
     89     MUST_HAVE_REGISTER,
     90     WRITABLE_REGISTER,
     91     SAME_AS_FIRST_INPUT,
     92     IGNORE
     93   };
     94 
     95   // Lifetime of operand inside the instruction.
     96   enum Lifetime {
     97     // USED_AT_START operand is guaranteed to be live only at
     98     // instruction start. Register allocator is free to assign the same register
     99     // to some other operand used inside instruction (i.e. temporary or
    100     // output).
    101     USED_AT_START,
    102 
    103     // USED_AT_END operand is treated as live until the end of
    104     // instruction. This means that register allocator will not reuse it's
    105     // register for any other operand inside instruction.
    106     USED_AT_END
    107   };
    108 
    109   explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) {
    110     Initialize(policy, 0, USED_AT_END);
    111   }
    112 
    113   LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) {
    114     Initialize(policy, fixed_index, USED_AT_END);
    115   }
    116 
    117   LUnallocated(Policy policy, Lifetime lifetime) : LOperand(UNALLOCATED, 0) {
    118     Initialize(policy, 0, lifetime);
    119   }
    120 
    121   // The superclass has a KindField.  Some policies have a signed fixed
    122   // index in the upper bits.
    123   static const int kPolicyWidth = 4;
    124   static const int kLifetimeWidth = 1;
    125   static const int kVirtualRegisterWidth = 17;
    126 
    127   static const int kPolicyShift = kKindFieldWidth;
    128   static const int kLifetimeShift = kPolicyShift + kPolicyWidth;
    129   static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth;
    130   static const int kFixedIndexShift =
    131       kVirtualRegisterShift + kVirtualRegisterWidth;
    132 
    133   class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { };
    134 
    135   class LifetimeField
    136       : public BitField<Lifetime, kLifetimeShift, kLifetimeWidth> {
    137   };
    138 
    139   class VirtualRegisterField
    140       : public BitField<unsigned,
    141                         kVirtualRegisterShift,
    142                         kVirtualRegisterWidth> {
    143   };
    144 
    145   static const int kMaxVirtualRegisters = 1 << (kVirtualRegisterWidth + 1);
    146   static const int kMaxFixedIndex = 63;
    147   static const int kMinFixedIndex = -64;
    148 
    149   bool HasIgnorePolicy() const { return policy() == IGNORE; }
    150   bool HasNoPolicy() const { return policy() == NONE; }
    151   bool HasAnyPolicy() const {
    152     return policy() == ANY;
    153   }
    154   bool HasFixedPolicy() const {
    155     return policy() == FIXED_REGISTER ||
    156         policy() == FIXED_DOUBLE_REGISTER ||
    157         policy() == FIXED_SLOT;
    158   }
    159   bool HasRegisterPolicy() const {
    160     return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER;
    161   }
    162   bool HasSameAsInputPolicy() const {
    163     return policy() == SAME_AS_FIRST_INPUT;
    164   }
    165   Policy policy() const { return PolicyField::decode(value_); }
    166   void set_policy(Policy policy) {
    167     value_ &= ~PolicyField::mask();
    168     value_ |= PolicyField::encode(policy);
    169   }
    170   int fixed_index() const {
    171     return static_cast<int>(value_) >> kFixedIndexShift;
    172   }
    173 
    174   unsigned virtual_register() const {
    175     return VirtualRegisterField::decode(value_);
    176   }
    177 
    178   void set_virtual_register(unsigned id) {
    179     value_ &= ~VirtualRegisterField::mask();
    180     value_ |= VirtualRegisterField::encode(id);
    181   }
    182 
    183   LUnallocated* CopyUnconstrained() {
    184     LUnallocated* result = new LUnallocated(ANY);
    185     result->set_virtual_register(virtual_register());
    186     return result;
    187   }
    188 
    189   static LUnallocated* cast(LOperand* op) {
    190     ASSERT(op->IsUnallocated());
    191     return reinterpret_cast<LUnallocated*>(op);
    192   }
    193 
    194   bool IsUsedAtStart() {
    195     return LifetimeField::decode(value_) == USED_AT_START;
    196   }
    197 
    198  private:
    199   void Initialize(Policy policy, int fixed_index, Lifetime lifetime) {
    200     value_ |= PolicyField::encode(policy);
    201     value_ |= LifetimeField::encode(lifetime);
    202     value_ |= fixed_index << kFixedIndexShift;
    203     ASSERT(this->fixed_index() == fixed_index);
    204   }
    205 };
    206 
    207 
    208 class LMoveOperands BASE_EMBEDDED {
    209  public:
    210   LMoveOperands(LOperand* source, LOperand* destination)
    211       : source_(source), destination_(destination) {
    212   }
    213 
    214   LOperand* source() const { return source_; }
    215   void set_source(LOperand* operand) { source_ = operand; }
    216 
    217   LOperand* destination() const { return destination_; }
    218   void set_destination(LOperand* operand) { destination_ = operand; }
    219 
    220   // The gap resolver marks moves as "in-progress" by clearing the
    221   // destination (but not the source).
    222   bool IsPending() const {
    223     return destination_ == NULL && source_ != NULL;
    224   }
    225 
    226   // True if this move a move into the given destination operand.
    227   bool Blocks(LOperand* operand) const {
    228     return !IsEliminated() && source()->Equals(operand);
    229   }
    230 
    231   // A move is redundant if it's been eliminated, if its source and
    232   // destination are the same, or if its destination is unneeded.
    233   bool IsRedundant() const {
    234     return IsEliminated() || source_->Equals(destination_) || IsIgnored();
    235   }
    236 
    237   bool IsIgnored() const {
    238     return destination_ != NULL &&
    239         destination_->IsUnallocated() &&
    240         LUnallocated::cast(destination_)->HasIgnorePolicy();
    241   }
    242 
    243   // We clear both operands to indicate move that's been eliminated.
    244   void Eliminate() { source_ = destination_ = NULL; }
    245   bool IsEliminated() const {
    246     ASSERT(source_ != NULL || destination_ == NULL);
    247     return source_ == NULL;
    248   }
    249 
    250  private:
    251   LOperand* source_;
    252   LOperand* destination_;
    253 };
    254 
    255 
    256 class LConstantOperand: public LOperand {
    257  public:
    258   static LConstantOperand* Create(int index) {
    259     ASSERT(index >= 0);
    260     if (index < kNumCachedOperands) return &cache[index];
    261     return new LConstantOperand(index);
    262   }
    263 
    264   static LConstantOperand* cast(LOperand* op) {
    265     ASSERT(op->IsConstantOperand());
    266     return reinterpret_cast<LConstantOperand*>(op);
    267   }
    268 
    269   static void SetupCache();
    270 
    271  private:
    272   static const int kNumCachedOperands = 128;
    273   static LConstantOperand cache[];
    274 
    275   LConstantOperand() : LOperand() { }
    276   explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
    277 };
    278 
    279 
    280 class LArgument: public LOperand {
    281  public:
    282   explicit LArgument(int index) : LOperand(ARGUMENT, index) { }
    283 
    284   static LArgument* cast(LOperand* op) {
    285     ASSERT(op->IsArgument());
    286     return reinterpret_cast<LArgument*>(op);
    287   }
    288 };
    289 
    290 
    291 class LStackSlot: public LOperand {
    292  public:
    293   static LStackSlot* Create(int index) {
    294     ASSERT(index >= 0);
    295     if (index < kNumCachedOperands) return &cache[index];
    296     return new LStackSlot(index);
    297   }
    298 
    299   static LStackSlot* cast(LOperand* op) {
    300     ASSERT(op->IsStackSlot());
    301     return reinterpret_cast<LStackSlot*>(op);
    302   }
    303 
    304   static void SetupCache();
    305 
    306  private:
    307   static const int kNumCachedOperands = 128;
    308   static LStackSlot cache[];
    309 
    310   LStackSlot() : LOperand() { }
    311   explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
    312 };
    313 
    314 
    315 class LDoubleStackSlot: public LOperand {
    316  public:
    317   static LDoubleStackSlot* Create(int index) {
    318     ASSERT(index >= 0);
    319     if (index < kNumCachedOperands) return &cache[index];
    320     return new LDoubleStackSlot(index);
    321   }
    322 
    323   static LDoubleStackSlot* cast(LOperand* op) {
    324     ASSERT(op->IsStackSlot());
    325     return reinterpret_cast<LDoubleStackSlot*>(op);
    326   }
    327 
    328   static void SetupCache();
    329 
    330  private:
    331   static const int kNumCachedOperands = 128;
    332   static LDoubleStackSlot cache[];
    333 
    334   LDoubleStackSlot() : LOperand() { }
    335   explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
    336 };
    337 
    338 
    339 class LRegister: public LOperand {
    340  public:
    341   static LRegister* Create(int index) {
    342     ASSERT(index >= 0);
    343     if (index < kNumCachedOperands) return &cache[index];
    344     return new LRegister(index);
    345   }
    346 
    347   static LRegister* cast(LOperand* op) {
    348     ASSERT(op->IsRegister());
    349     return reinterpret_cast<LRegister*>(op);
    350   }
    351 
    352   static void SetupCache();
    353 
    354  private:
    355   static const int kNumCachedOperands = 16;
    356   static LRegister cache[];
    357 
    358   LRegister() : LOperand() { }
    359   explicit LRegister(int index) : LOperand(REGISTER, index) { }
    360 };
    361 
    362 
    363 class LDoubleRegister: public LOperand {
    364  public:
    365   static LDoubleRegister* Create(int index) {
    366     ASSERT(index >= 0);
    367     if (index < kNumCachedOperands) return &cache[index];
    368     return new LDoubleRegister(index);
    369   }
    370 
    371   static LDoubleRegister* cast(LOperand* op) {
    372     ASSERT(op->IsDoubleRegister());
    373     return reinterpret_cast<LDoubleRegister*>(op);
    374   }
    375 
    376   static void SetupCache();
    377 
    378  private:
    379   static const int kNumCachedOperands = 16;
    380   static LDoubleRegister cache[];
    381 
    382   LDoubleRegister() : LOperand() { }
    383   explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
    384 };
    385 
    386 
    387 class LParallelMove : public ZoneObject {
    388  public:
    389   LParallelMove() : move_operands_(4) { }
    390 
    391   void AddMove(LOperand* from, LOperand* to) {
    392     move_operands_.Add(LMoveOperands(from, to));
    393   }
    394 
    395   bool IsRedundant() const;
    396 
    397   const ZoneList<LMoveOperands>* move_operands() const {
    398     return &move_operands_;
    399   }
    400 
    401   void PrintDataTo(StringStream* stream) const;
    402 
    403  private:
    404   ZoneList<LMoveOperands> move_operands_;
    405 };
    406 
    407 
    408 class LPointerMap: public ZoneObject {
    409  public:
    410   explicit LPointerMap(int position)
    411       : pointer_operands_(8), position_(position), lithium_position_(-1) { }
    412 
    413   const ZoneList<LOperand*>* operands() const { return &pointer_operands_; }
    414   int position() const { return position_; }
    415   int lithium_position() const { return lithium_position_; }
    416 
    417   void set_lithium_position(int pos) {
    418     ASSERT(lithium_position_ == -1);
    419     lithium_position_ = pos;
    420   }
    421 
    422   void RecordPointer(LOperand* op);
    423   void PrintTo(StringStream* stream);
    424 
    425  private:
    426   ZoneList<LOperand*> pointer_operands_;
    427   int position_;
    428   int lithium_position_;
    429 };
    430 
    431 
    432 class LEnvironment: public ZoneObject {
    433  public:
    434   LEnvironment(Handle<JSFunction> closure,
    435                int ast_id,
    436                int parameter_count,
    437                int argument_count,
    438                int value_count,
    439                LEnvironment* outer)
    440       : closure_(closure),
    441         arguments_stack_height_(argument_count),
    442         deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
    443         translation_index_(-1),
    444         ast_id_(ast_id),
    445         parameter_count_(parameter_count),
    446         values_(value_count),
    447         representations_(value_count),
    448         spilled_registers_(NULL),
    449         spilled_double_registers_(NULL),
    450         outer_(outer) {
    451   }
    452 
    453   Handle<JSFunction> closure() const { return closure_; }
    454   int arguments_stack_height() const { return arguments_stack_height_; }
    455   int deoptimization_index() const { return deoptimization_index_; }
    456   int translation_index() const { return translation_index_; }
    457   int ast_id() const { return ast_id_; }
    458   int parameter_count() const { return parameter_count_; }
    459   LOperand** spilled_registers() const { return spilled_registers_; }
    460   LOperand** spilled_double_registers() const {
    461     return spilled_double_registers_;
    462   }
    463   const ZoneList<LOperand*>* values() const { return &values_; }
    464   LEnvironment* outer() const { return outer_; }
    465 
    466   void AddValue(LOperand* operand, Representation representation) {
    467     values_.Add(operand);
    468     representations_.Add(representation);
    469   }
    470 
    471   bool HasTaggedValueAt(int index) const {
    472     return representations_[index].IsTagged();
    473   }
    474 
    475   void Register(int deoptimization_index, int translation_index) {
    476     ASSERT(!HasBeenRegistered());
    477     deoptimization_index_ = deoptimization_index;
    478     translation_index_ = translation_index;
    479   }
    480   bool HasBeenRegistered() const {
    481     return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex;
    482   }
    483 
    484   void SetSpilledRegisters(LOperand** registers,
    485                            LOperand** double_registers) {
    486     spilled_registers_ = registers;
    487     spilled_double_registers_ = double_registers;
    488   }
    489 
    490   void PrintTo(StringStream* stream);
    491 
    492  private:
    493   Handle<JSFunction> closure_;
    494   int arguments_stack_height_;
    495   int deoptimization_index_;
    496   int translation_index_;
    497   int ast_id_;
    498   int parameter_count_;
    499   ZoneList<LOperand*> values_;
    500   ZoneList<Representation> representations_;
    501 
    502   // Allocation index indexed arrays of spill slot operands for registers
    503   // that are also in spill slots at an OSR entry.  NULL for environments
    504   // that do not correspond to an OSR entry.
    505   LOperand** spilled_registers_;
    506   LOperand** spilled_double_registers_;
    507 
    508   LEnvironment* outer_;
    509 
    510   friend class LCodegen;
    511 };
    512 
    513 
    514 // Iterates over the non-null, non-constant operands in an environment.
    515 class ShallowIterator BASE_EMBEDDED {
    516  public:
    517   explicit ShallowIterator(LEnvironment* env)
    518       : env_(env),
    519         limit_(env != NULL ? env->values()->length() : 0),
    520         current_(0) {
    521     current_ = AdvanceToNext(0);
    522   }
    523 
    524   inline bool HasNext() {
    525     return env_ != NULL && current_ < limit_;
    526   }
    527 
    528   inline LOperand* Next() {
    529     ASSERT(HasNext());
    530     return env_->values()->at(current_);
    531   }
    532 
    533   inline void Advance() {
    534     current_ = AdvanceToNext(current_ + 1);
    535   }
    536 
    537   inline LEnvironment* env() { return env_; }
    538 
    539  private:
    540   inline bool ShouldSkip(LOperand* op) {
    541     return op == NULL || op->IsConstantOperand() || op->IsArgument();
    542   }
    543 
    544   inline int AdvanceToNext(int start) {
    545     while (start < limit_ && ShouldSkip(env_->values()->at(start))) {
    546       start++;
    547     }
    548     return start;
    549   }
    550 
    551   LEnvironment* env_;
    552   int limit_;
    553   int current_;
    554 };
    555 
    556 
    557 // Iterator for non-null, non-constant operands incl. outer environments.
    558 class DeepIterator BASE_EMBEDDED {
    559  public:
    560   explicit DeepIterator(LEnvironment* env)
    561       : current_iterator_(env) { }
    562 
    563   inline bool HasNext() {
    564     if (current_iterator_.HasNext()) return true;
    565     if (current_iterator_.env() == NULL) return false;
    566     AdvanceToOuter();
    567     return current_iterator_.HasNext();
    568   }
    569 
    570   inline LOperand* Next() {
    571     ASSERT(current_iterator_.HasNext());
    572     return current_iterator_.Next();
    573   }
    574 
    575   inline void Advance() {
    576     if (current_iterator_.HasNext()) {
    577       current_iterator_.Advance();
    578     } else {
    579       AdvanceToOuter();
    580     }
    581   }
    582 
    583  private:
    584   inline void AdvanceToOuter() {
    585     current_iterator_ = ShallowIterator(current_iterator_.env()->outer());
    586   }
    587 
    588   ShallowIterator current_iterator_;
    589 };
    590 
    591 } }  // namespace v8::internal
    592 
    593 #endif  // V8_LITHIUM_H_
    594