Home | History | Annotate | Download | only in src
      1 // Copyright 2011 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 #include "src/v8.h"
      6 
      7 #include "src/safepoint-table.h"
      8 
      9 #include "src/deoptimizer.h"
     10 #include "src/disasm.h"
     11 #include "src/macro-assembler.h"
     12 #include "src/zone-inl.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 
     18 bool SafepointEntry::HasRegisters() const {
     19   ASSERT(is_valid());
     20   ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte));
     21   const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
     22   for (int i = 0; i < num_reg_bytes; i++) {
     23     if (bits_[i] != SafepointTable::kNoRegisters) return true;
     24   }
     25   return false;
     26 }
     27 
     28 
     29 bool SafepointEntry::HasRegisterAt(int reg_index) const {
     30   ASSERT(is_valid());
     31   ASSERT(reg_index >= 0 && reg_index < kNumSafepointRegisters);
     32   int byte_index = reg_index >> kBitsPerByteLog2;
     33   int bit_index = reg_index & (kBitsPerByte - 1);
     34   return (bits_[byte_index] & (1 << bit_index)) != 0;
     35 }
     36 
     37 
     38 SafepointTable::SafepointTable(Code* code) {
     39   ASSERT(code->is_crankshafted());
     40   code_ = code;
     41   Address header = code->instruction_start() + code->safepoint_table_offset();
     42   length_ = Memory::uint32_at(header + kLengthOffset);
     43   entry_size_ = Memory::uint32_at(header + kEntrySizeOffset);
     44   pc_and_deoptimization_indexes_ = header + kHeaderSize;
     45   entries_ = pc_and_deoptimization_indexes_ +
     46             (length_ * kPcAndDeoptimizationIndexSize);
     47   ASSERT(entry_size_ > 0);
     48   STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
     49                 Safepoint::kNoDeoptimizationIndex);
     50 }
     51 
     52 
     53 SafepointEntry SafepointTable::FindEntry(Address pc) const {
     54   unsigned pc_offset = static_cast<unsigned>(pc - code_->instruction_start());
     55   for (unsigned i = 0; i < length(); i++) {
     56     // TODO(kasperl): Replace the linear search with binary search.
     57     if (GetPcOffset(i) == pc_offset) return GetEntry(i);
     58   }
     59   return SafepointEntry();
     60 }
     61 
     62 
     63 void SafepointTable::PrintEntry(unsigned index, FILE* out) const {
     64   disasm::NameConverter converter;
     65   SafepointEntry entry = GetEntry(index);
     66   uint8_t* bits = entry.bits();
     67 
     68   // Print the stack slot bits.
     69   if (entry_size_ > 0) {
     70     ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte));
     71     const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
     72     int last = entry_size_ - 1;
     73     for (int i = first; i < last; i++) PrintBits(out, bits[i], kBitsPerByte);
     74     int last_bits = code_->stack_slots() - ((last - first) * kBitsPerByte);
     75     PrintBits(out, bits[last], last_bits);
     76 
     77     // Print the registers (if any).
     78     if (!entry.HasRegisters()) return;
     79     for (int j = 0; j < kNumSafepointRegisters; j++) {
     80       if (entry.HasRegisterAt(j)) {
     81         PrintF(out, " | %s", converter.NameOfCPURegister(j));
     82       }
     83     }
     84   }
     85 }
     86 
     87 
     88 void SafepointTable::PrintBits(FILE* out, uint8_t byte, int digits) {
     89   ASSERT(digits >= 0 && digits <= kBitsPerByte);
     90   for (int i = 0; i < digits; i++) {
     91     PrintF(out, "%c", ((byte & (1 << i)) == 0) ? '0' : '1');
     92   }
     93 }
     94 
     95 
     96 void Safepoint::DefinePointerRegister(Register reg, Zone* zone) {
     97   registers_->Add(reg.code(), zone);
     98 }
     99 
    100 
    101 Safepoint SafepointTableBuilder::DefineSafepoint(
    102     Assembler* assembler,
    103     Safepoint::Kind kind,
    104     int arguments,
    105     Safepoint::DeoptMode deopt_mode) {
    106   ASSERT(arguments >= 0);
    107   DeoptimizationInfo info;
    108   info.pc = assembler->pc_offset();
    109   info.arguments = arguments;
    110   info.has_doubles = (kind & Safepoint::kWithDoubles);
    111   deoptimization_info_.Add(info, zone_);
    112   deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex, zone_);
    113   if (deopt_mode == Safepoint::kNoLazyDeopt) {
    114     last_lazy_safepoint_ = deopt_index_list_.length();
    115   }
    116   indexes_.Add(new(zone_) ZoneList<int>(8, zone_), zone_);
    117   registers_.Add((kind & Safepoint::kWithRegisters)
    118       ? new(zone_) ZoneList<int>(4, zone_)
    119       : NULL,
    120       zone_);
    121   return Safepoint(indexes_.last(), registers_.last());
    122 }
    123 
    124 
    125 void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
    126   while (last_lazy_safepoint_ < deopt_index_list_.length()) {
    127     deopt_index_list_[last_lazy_safepoint_++] = index;
    128   }
    129 }
    130 
    131 unsigned SafepointTableBuilder::GetCodeOffset() const {
    132   ASSERT(emitted_);
    133   return offset_;
    134 }
    135 
    136 
    137 void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
    138   // Make sure the safepoint table is properly aligned. Pad with nops.
    139   assembler->Align(kIntSize);
    140   assembler->RecordComment(";;; Safepoint table.");
    141   offset_ = assembler->pc_offset();
    142 
    143   // Take the register bits into account.
    144   bits_per_entry += kNumSafepointRegisters;
    145 
    146   // Compute the number of bytes per safepoint entry.
    147   int bytes_per_entry =
    148       RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
    149 
    150   // Emit the table header.
    151   int length = deoptimization_info_.length();
    152   assembler->dd(length);
    153   assembler->dd(bytes_per_entry);
    154 
    155   // Emit sorted table of pc offsets together with deoptimization indexes.
    156   for (int i = 0; i < length; i++) {
    157     assembler->dd(deoptimization_info_[i].pc);
    158     assembler->dd(EncodeExceptPC(deoptimization_info_[i],
    159                                  deopt_index_list_[i]));
    160   }
    161 
    162   // Emit table of bitmaps.
    163   ZoneList<uint8_t> bits(bytes_per_entry, zone_);
    164   for (int i = 0; i < length; i++) {
    165     ZoneList<int>* indexes = indexes_[i];
    166     ZoneList<int>* registers = registers_[i];
    167     bits.Clear();
    168     bits.AddBlock(0, bytes_per_entry, zone_);
    169 
    170     // Run through the registers (if any).
    171     ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte));
    172     if (registers == NULL) {
    173       const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
    174       for (int j = 0; j < num_reg_bytes; j++) {
    175         bits[j] = SafepointTable::kNoRegisters;
    176       }
    177     } else {
    178       for (int j = 0; j < registers->length(); j++) {
    179         int index = registers->at(j);
    180         ASSERT(index >= 0 && index < kNumSafepointRegisters);
    181         int byte_index = index >> kBitsPerByteLog2;
    182         int bit_index = index & (kBitsPerByte - 1);
    183         bits[byte_index] |= (1 << bit_index);
    184       }
    185     }
    186 
    187     // Run through the indexes and build a bitmap.
    188     for (int j = 0; j < indexes->length(); j++) {
    189       int index = bits_per_entry - 1 - indexes->at(j);
    190       int byte_index = index >> kBitsPerByteLog2;
    191       int bit_index = index & (kBitsPerByte - 1);
    192       bits[byte_index] |= (1U << bit_index);
    193     }
    194 
    195     // Emit the bitmap for the current entry.
    196     for (int k = 0; k < bytes_per_entry; k++) {
    197       assembler->db(bits[k]);
    198     }
    199   }
    200   emitted_ = true;
    201 }
    202 
    203 
    204 uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info,
    205                                                unsigned index) {
    206   uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
    207   encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
    208   encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
    209   return encoding;
    210 }
    211 
    212 
    213 
    214 } }  // namespace v8::internal
    215