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_SAFEPOINT_TABLE_H_
     29 #define V8_SAFEPOINT_TABLE_H_
     30 
     31 #include "heap.h"
     32 #include "v8memory.h"
     33 #include "zone.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 struct Register;
     39 
     40 class SafepointEntry BASE_EMBEDDED {
     41  public:
     42   SafepointEntry() : info_(0), bits_(NULL) {}
     43 
     44   SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) {
     45     ASSERT(is_valid());
     46   }
     47 
     48   bool is_valid() const { return bits_ != NULL; }
     49 
     50   bool Equals(const SafepointEntry& other) const {
     51     return info_ == other.info_ && bits_ == other.bits_;
     52   }
     53 
     54   void Reset() {
     55     info_ = 0;
     56     bits_ = NULL;
     57   }
     58 
     59   int deoptimization_index() const {
     60     ASSERT(is_valid());
     61     return DeoptimizationIndexField::decode(info_);
     62   }
     63 
     64   int gap_code_size() const {
     65     ASSERT(is_valid());
     66     return GapCodeSizeField::decode(info_);
     67   }
     68 
     69   int argument_count() const {
     70     ASSERT(is_valid());
     71     return ArgumentsField::decode(info_);
     72   }
     73 
     74   bool has_doubles() const {
     75     ASSERT(is_valid());
     76     return SaveDoublesField::decode(info_);
     77   }
     78 
     79   uint8_t* bits() {
     80     ASSERT(is_valid());
     81     return bits_;
     82   }
     83 
     84   bool HasRegisters() const;
     85   bool HasRegisterAt(int reg_index) const;
     86 
     87   // Reserve 13 bits for the gap code size. On ARM a constant pool can be
     88   // emitted when generating the gap code. The size of the const pool is less
     89   // than what can be represented in 12 bits, so 13 bits gives room for having
     90   // instructions before potentially emitting a constant pool.
     91   static const int kGapCodeSizeBits = 13;
     92   static const int kArgumentsFieldBits = 3;
     93   static const int kSaveDoublesFieldBits = 1;
     94   static const int kDeoptIndexBits =
     95       32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits;
     96   class GapCodeSizeField: public BitField<unsigned, 0, kGapCodeSizeBits> {};
     97   class DeoptimizationIndexField: public BitField<int,
     98                                                   kGapCodeSizeBits,
     99                                                   kDeoptIndexBits> {};  // NOLINT
    100   class ArgumentsField: public BitField<unsigned,
    101                                         kGapCodeSizeBits + kDeoptIndexBits,
    102                                         kArgumentsFieldBits> {};  // NOLINT
    103   class SaveDoublesField: public BitField<bool,
    104                                           kGapCodeSizeBits + kDeoptIndexBits +
    105                                           kArgumentsFieldBits,
    106                                           kSaveDoublesFieldBits> { }; // NOLINT
    107 
    108  private:
    109   unsigned info_;
    110   uint8_t* bits_;
    111 };
    112 
    113 
    114 class SafepointTable BASE_EMBEDDED {
    115  public:
    116   explicit SafepointTable(Code* code);
    117 
    118   int size() const {
    119     return kHeaderSize +
    120            (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); }
    121   unsigned length() const { return length_; }
    122   unsigned entry_size() const { return entry_size_; }
    123 
    124   unsigned GetPcOffset(unsigned index) const {
    125     ASSERT(index < length_);
    126     return Memory::uint32_at(GetPcOffsetLocation(index));
    127   }
    128 
    129   SafepointEntry GetEntry(unsigned index) const {
    130     ASSERT(index < length_);
    131     unsigned info = Memory::uint32_at(GetInfoLocation(index));
    132     uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_));
    133     return SafepointEntry(info, bits);
    134   }
    135 
    136   // Returns the entry for the given pc.
    137   SafepointEntry FindEntry(Address pc) const;
    138 
    139   void PrintEntry(unsigned index) const;
    140 
    141  private:
    142   static const uint8_t kNoRegisters = 0xFF;
    143 
    144   static const int kLengthOffset = 0;
    145   static const int kEntrySizeOffset = kLengthOffset + kIntSize;
    146   static const int kHeaderSize = kEntrySizeOffset + kIntSize;
    147 
    148   static const int kPcSize = kIntSize;
    149   static const int kDeoptimizationIndexSize = kIntSize;
    150   static const int kPcAndDeoptimizationIndexSize =
    151       kPcSize + kDeoptimizationIndexSize;
    152 
    153   Address GetPcOffsetLocation(unsigned index) const {
    154     return pc_and_deoptimization_indexes_ +
    155            (index * kPcAndDeoptimizationIndexSize);
    156   }
    157 
    158   Address GetInfoLocation(unsigned index) const {
    159     return GetPcOffsetLocation(index) + kPcSize;
    160   }
    161 
    162   static void PrintBits(uint8_t byte, int digits);
    163 
    164   AssertNoAllocation no_allocation_;
    165   Code* code_;
    166   unsigned length_;
    167   unsigned entry_size_;
    168 
    169   Address pc_and_deoptimization_indexes_;
    170   Address entries_;
    171 
    172   friend class SafepointTableBuilder;
    173   friend class SafepointEntry;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(SafepointTable);
    176 };
    177 
    178 
    179 class Safepoint BASE_EMBEDDED {
    180  public:
    181   typedef enum {
    182     kSimple = 0,
    183     kWithRegisters = 1 << 0,
    184     kWithDoubles = 1 << 1,
    185     kWithRegistersAndDoubles = kWithRegisters | kWithDoubles
    186   } Kind;
    187 
    188   static const int kNoDeoptimizationIndex =
    189       (1 << (SafepointEntry::kDeoptIndexBits)) - 1;
    190 
    191   void DefinePointerSlot(int index) { indexes_->Add(index); }
    192   void DefinePointerRegister(Register reg);
    193 
    194  private:
    195   Safepoint(ZoneList<int>* indexes, ZoneList<int>* registers) :
    196       indexes_(indexes), registers_(registers) { }
    197   ZoneList<int>* indexes_;
    198   ZoneList<int>* registers_;
    199 
    200   friend class SafepointTableBuilder;
    201 };
    202 
    203 
    204 class SafepointTableBuilder BASE_EMBEDDED {
    205  public:
    206   SafepointTableBuilder()
    207       : deoptimization_info_(32),
    208         indexes_(32),
    209         registers_(32),
    210         emitted_(false) { }
    211 
    212   // Get the offset of the emitted safepoint table in the code.
    213   unsigned GetCodeOffset() const;
    214 
    215   // Define a new safepoint for the current position in the body.
    216   Safepoint DefineSafepoint(Assembler* assembler,
    217                             Safepoint::Kind kind,
    218                             int arguments,
    219                             int deoptimization_index);
    220 
    221   // Update the last safepoint with the size of the code generated until the
    222   // end of the gap following it.
    223   void SetPcAfterGap(int pc) {
    224     ASSERT(!deoptimization_info_.is_empty());
    225     int index = deoptimization_info_.length() - 1;
    226     deoptimization_info_[index].pc_after_gap = pc;
    227   }
    228 
    229   // Get the end pc offset of the last safepoint, including the code generated
    230   // until the end of the gap following it.
    231   unsigned GetPcAfterGap() {
    232     int index = deoptimization_info_.length();
    233     if (index == 0) return 0;
    234     return deoptimization_info_[index - 1].pc_after_gap;
    235   }
    236 
    237   // Emit the safepoint table after the body. The number of bits per
    238   // entry must be enough to hold all the pointer indexes.
    239   void Emit(Assembler* assembler, int bits_per_entry);
    240 
    241   // Count the number of deoptimization points where the next
    242   // following deoptimization point comes less than limit bytes
    243   // after the end of this point's gap.
    244   int CountShortDeoptimizationIntervals(unsigned limit);
    245 
    246  private:
    247   struct DeoptimizationInfo {
    248     unsigned pc;
    249     unsigned deoptimization_index;
    250     unsigned pc_after_gap;
    251     unsigned arguments;
    252     bool has_doubles;
    253   };
    254 
    255   uint32_t EncodeExceptPC(const DeoptimizationInfo& info);
    256 
    257   ZoneList<DeoptimizationInfo> deoptimization_info_;
    258   ZoneList<ZoneList<int>*> indexes_;
    259   ZoneList<ZoneList<int>*> registers_;
    260 
    261   unsigned offset_;
    262   bool emitted_;
    263 
    264   DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
    265 };
    266 
    267 } }  // namespace v8::internal
    268 
    269 #endif  // V8_SAFEPOINT_TABLE_H_
    270