LCOV - code coverage report
Current view: top level - src - safepoint-table.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 102 136 75.0 %
Date: 2017-10-20 Functions: 11 16 68.8 %

          Line data    Source code
       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/safepoint-table.h"
       6             : 
       7             : #include "src/assembler-inl.h"
       8             : #include "src/deoptimizer.h"
       9             : #include "src/disasm.h"
      10             : #include "src/frames-inl.h"
      11             : #include "src/macro-assembler.h"
      12             : #include "src/ostreams.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : 
      18      604927 : bool SafepointEntry::HasRegisters() const {
      19             :   DCHECK(is_valid());
      20             :   DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
      21             :   const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
      22     1814781 :   for (int i = 0; i < num_reg_bytes; i++) {
      23     1209854 :     if (bits_[i] != SafepointTable::kNoRegisters) return true;
      24             :   }
      25             :   return false;
      26             : }
      27             : 
      28             : 
      29           0 : bool SafepointEntry::HasRegisterAt(int reg_index) const {
      30             :   DCHECK(is_valid());
      31             :   DCHECK(reg_index >= 0 && reg_index < kNumSafepointRegisters);
      32           0 :   int byte_index = reg_index >> kBitsPerByteLog2;
      33           0 :   int bit_index = reg_index & (kBitsPerByte - 1);
      34           0 :   return (bits_[byte_index] & (1 << bit_index)) != 0;
      35             : }
      36             : 
      37             : 
      38     2762125 : SafepointTable::SafepointTable(Code* code) {
      39             :   DCHECK(code->is_turbofanned());
      40     2762125 :   code_ = code;
      41     5524250 :   Address header = code->instruction_start() + code->safepoint_table_offset();
      42     2762125 :   length_ = Memory::uint32_at(header + kLengthOffset);
      43     2762125 :   entry_size_ = Memory::uint32_at(header + kEntrySizeOffset);
      44     2762125 :   pc_and_deoptimization_indexes_ = header + kHeaderSize;
      45     2762125 :   entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
      46             :   DCHECK_GT(entry_size_, 0);
      47             :   STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
      48             :                 Safepoint::kNoDeoptimizationIndex);
      49     2762125 : }
      50             : 
      51       29354 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
      52       52420 :   for (unsigned i = 0; i < length(); i++) {
      53       26210 :     if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
      54        3144 :       return GetPcOffset(i);
      55       23066 :     } else if (GetPcOffset(i) == pc_offset) {
      56             :       return pc_offset;
      57             :     }
      58             :   }
      59           0 :   UNREACHABLE();
      60             :   return 0;
      61             : }
      62             : 
      63     5517962 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
      64     2758981 :   unsigned pc_offset = static_cast<unsigned>(pc - code_->instruction_start());
      65             :   // We use kMaxUInt32 as sentinel value, so check that we don't hit that.
      66             :   DCHECK_NE(kMaxUInt32, pc_offset);
      67             :   unsigned len = length();
      68             :   // If pc == kMaxUInt32, then this entry covers all call sites in the function.
      69     2776681 :   if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
      70    21876791 :   for (unsigned i = 0; i < len; i++) {
      71             :     // TODO(kasperl): Replace the linear search with binary search.
      72    46662101 :     if (GetPcOffset(i) == pc_offset ||
      73    22034480 :         GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
      74             :       return GetEntry(i);
      75             :     }
      76             :   }
      77           0 :   UNREACHABLE();
      78             :   return SafepointEntry();
      79             : }
      80             : 
      81             : 
      82           0 : void SafepointTable::PrintEntry(unsigned index,
      83             :                                 std::ostream& os) const {  // NOLINT
      84             :   disasm::NameConverter converter;
      85             :   SafepointEntry entry = GetEntry(index);
      86             :   uint8_t* bits = entry.bits();
      87             : 
      88             :   // Print the stack slot bits.
      89           0 :   if (entry_size_ > 0) {
      90             :     DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
      91             :     const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
      92           0 :     int last = entry_size_ - 1;
      93           0 :     for (int i = first; i < last; i++) PrintBits(os, bits[i], kBitsPerByte);
      94           0 :     int last_bits = code_->stack_slots() - ((last - first) * kBitsPerByte);
      95           0 :     PrintBits(os, bits[last], last_bits);
      96             : 
      97             :     // Print the registers (if any).
      98           0 :     if (!entry.HasRegisters()) return;
      99           0 :     for (int j = 0; j < kNumSafepointRegisters; j++) {
     100           0 :       if (entry.HasRegisterAt(j)) {
     101           0 :         os << " | " << converter.NameOfCPURegister(j);
     102             :       }
     103             :     }
     104             :   }
     105             : }
     106             : 
     107             : 
     108           0 : void SafepointTable::PrintBits(std::ostream& os,  // NOLINT
     109             :                                uint8_t byte, int digits) {
     110             :   DCHECK(digits >= 0 && digits <= kBitsPerByte);
     111           0 :   for (int i = 0; i < digits; i++) {
     112           0 :     os << (((byte & (1 << i)) == 0) ? "0" : "1");
     113             :   }
     114           0 : }
     115             : 
     116             : 
     117           0 : void Safepoint::DefinePointerRegister(Register reg, Zone* zone) {
     118           0 :   registers_->Add(reg.code(), zone);
     119           0 : }
     120             : 
     121             : 
     122     4710795 : Safepoint SafepointTableBuilder::DefineSafepoint(
     123             :     Assembler* assembler,
     124             :     Safepoint::Kind kind,
     125             :     int arguments,
     126             :     Safepoint::DeoptMode deopt_mode) {
     127             :   DCHECK_GE(arguments, 0);
     128             :   DeoptimizationInfo info;
     129     9421590 :   info.pc = assembler->pc_offset();
     130     4710795 :   info.arguments = arguments;
     131     4710795 :   info.has_doubles = (kind & Safepoint::kWithDoubles);
     132     4710795 :   info.trampoline = -1;
     133     4710795 :   deoptimization_info_.Add(info, zone_);
     134     6687882 :   deopt_index_list_.Add(Safepoint::kNoDeoptimizationIndex, zone_);
     135     4710747 :   if (deopt_mode == Safepoint::kNoLazyDeopt) {
     136     1977066 :     last_lazy_safepoint_ = deopt_index_list_.length();
     137             :   }
     138     9421537 :   indexes_.Add(new(zone_) ZoneList<int>(8, zone_), zone_);
     139     4710774 :   registers_.Add((kind & Safepoint::kWithRegisters)
     140           0 :                      ? new (zone_) ZoneList<int>(4, zone_)
     141             :                      : nullptr,
     142    14132322 :                  zone_);
     143     9421560 :   return Safepoint(indexes_.last(), registers_.last());
     144             : }
     145             : 
     146             : 
     147     2733718 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
     148    13668580 :   while (last_lazy_safepoint_ < deopt_index_list_.length()) {
     149    10934857 :     deopt_index_list_[last_lazy_safepoint_++] = index;
     150             :   }
     151     2733718 : }
     152             : 
     153     1300545 : unsigned SafepointTableBuilder::GetCodeOffset() const {
     154             :   DCHECK(emitted_);
     155     1300545 :   return offset_;
     156             : }
     157             : 
     158     2733716 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
     159             :                                                     int start) {
     160             :   int index = -1;
     161    11703380 :   for (int i = start; i < deoptimization_info_.length(); i++) {
     162    20288774 :     if (static_cast<int>(deoptimization_info_[i].pc) == pc) {
     163             :       index = i;
     164             :       break;
     165             :     }
     166             :   }
     167     2733716 :   CHECK_GE(index, 0);
     168             :   DCHECK(index < deoptimization_info_.length());
     169     2733716 :   deoptimization_info_[index].trampoline = trampoline;
     170     2733716 :   return index;
     171             : }
     172             : 
     173     1301308 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
     174     1301308 :   RemoveDuplicates();
     175             : 
     176             :   // Make sure the safepoint table is properly aligned. Pad with nops.
     177     1301357 :   assembler->Align(kIntSize);
     178     1301374 :   assembler->RecordComment(";;; Safepoint table.");
     179     2602718 :   offset_ = assembler->pc_offset();
     180             : 
     181             :   // Take the register bits into account.
     182     1301359 :   bits_per_entry += kNumSafepointRegisters;
     183             : 
     184             :   // Compute the number of bytes per safepoint entry.
     185             :   int bytes_per_entry =
     186     1301359 :       RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
     187             : 
     188             :   // Emit the table header.
     189    14036154 :   int length = deoptimization_info_.length();
     190     1301359 :   assembler->dd(length);
     191     1301287 :   assembler->dd(bytes_per_entry);
     192             : 
     193             :   // Emit sorted table of pc offsets together with deoptimization indexes.
     194     5546392 :   for (int i = 0; i < length; i++) {
     195     4244917 :     assembler->dd(deoptimization_info_[i].pc);
     196             :     assembler->dd(EncodeExceptPC(deoptimization_info_[i],
     197    12734808 :                                  deopt_index_list_[i]));
     198     4244942 :     assembler->dd(deoptimization_info_[i].trampoline);
     199             :   }
     200             : 
     201             :   // Emit table of bitmaps.
     202     1301475 :   ZoneList<uint8_t> bits(bytes_per_entry, zone_);
     203     5546372 :   for (int i = 0; i < length; i++) {
     204    20230453 :     ZoneList<int>* indexes = indexes_[i];
     205     8489903 :     ZoneList<int>* registers = registers_[i];
     206             :     bits.Clear();
     207     4244908 :     bits.AddBlock(0, bytes_per_entry, zone_);
     208             : 
     209             :     // Run through the registers (if any).
     210             :     DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
     211     4244997 :     if (registers == nullptr) {
     212             :       const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
     213     8489832 :       for (int j = 0; j < num_reg_bytes; j++) {
     214    16979664 :         bits[j] = SafepointTable::kNoRegisters;
     215             :       }
     216             :     } else {
     217          87 :       for (int j = 0; j < registers->length(); j++) {
     218           0 :         int index = registers->at(j);
     219             :         DCHECK(index >= 0 && index < kNumSafepointRegisters);
     220           0 :         int byte_index = index >> kBitsPerByteLog2;
     221           0 :         int bit_index = index & (kBitsPerByte - 1);
     222           0 :         bits[byte_index] |= (1 << bit_index);
     223             :       }
     224             :     }
     225             : 
     226             :     // Run through the indexes and build a bitmap.
     227    19236277 :     for (int j = 0; j < indexes->length(); j++) {
     228    14991280 :       int index = bits_per_entry - 1 - indexes->at(j);
     229     7495640 :       int byte_index = index >> kBitsPerByteLog2;
     230     7495640 :       int bit_index = index & (kBitsPerByte - 1);
     231    14991280 :       bits[byte_index] |= (1U << bit_index);
     232             :     }
     233             : 
     234             :     // Emit the bitmap for the current entry.
     235    14717272 :     for (int k = 0; k < bytes_per_entry; k++) {
     236    29434600 :       assembler->db(bits[k]);
     237             :     }
     238             :   }
     239     1301464 :   emitted_ = true;
     240     1301464 : }
     241             : 
     242             : 
     243           0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info,
     244             :                                                unsigned index) {
     245             :   uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index);
     246     8489872 :   encoding |= SafepointEntry::ArgumentsField::encode(info.arguments);
     247     8489872 :   encoding |= SafepointEntry::SaveDoublesField::encode(info.has_doubles);
     248           0 :   return encoding;
     249             : }
     250             : 
     251     1301272 : void SafepointTableBuilder::RemoveDuplicates() {
     252             :   // If the table contains more than one entry, and all entries are identical
     253             :   // (except for the pc), replace the whole table by a single entry with pc =
     254             :   // kMaxUInt32. This especially compacts the table for wasm code without tagged
     255             :   // pointers and without deoptimization info.
     256             : 
     257     1476667 :   int length = deoptimization_info_.length();
     258             :   DCHECK_EQ(length, deopt_index_list_.length());
     259             :   DCHECK_EQ(length, indexes_.length());
     260             :   DCHECK_EQ(length, registers_.length());
     261             : 
     262     1301272 :   if (length < 2) return;
     263             : 
     264             :   // Check that all entries (1, length] are identical to entry 0.
     265      496785 :   for (int i = 1; i < length; ++i) {
     266      867617 :     if (!IsIdenticalExceptForPc(0, i)) return;
     267             :   }
     268             : 
     269             :   // If we get here, all entries were identical. Rewind all lists to just one
     270             :   // entry, and set the pc to kMaxUInt32.
     271             :   deoptimization_info_.Rewind(1);
     272             :   deopt_index_list_.Rewind(1);
     273             :   indexes_.Rewind(1);
     274             :   registers_.Rewind(1);
     275      175395 :   deoptimization_info_[0].pc = kMaxUInt32;
     276             : }
     277             : 
     278      867623 : bool SafepointTableBuilder::IsIdenticalExceptForPc(int index1,
     279             :                                                    int index2) const {
     280      867623 :   DeoptimizationInfo& deopt_info_1 = deoptimization_info_[index1];
     281             :   DeoptimizationInfo& deopt_info_2 = deoptimization_info_[index2];
     282      867623 :   if (deopt_info_1.arguments != deopt_info_2.arguments) return false;
     283      867653 :   if (deopt_info_1.has_doubles != deopt_info_2.has_doubles) return false;
     284             : 
     285     2602962 :   if (deopt_index_list_[index1] != deopt_index_list_[index2]) return false;
     286             : 
     287     1614333 :   ZoneList<int>* indexes1 = indexes_[index1];
     288     1076222 :   ZoneList<int>* indexes2 = indexes_[index2];
     289      538111 :   if (indexes1->length() != indexes2->length()) return false;
     290       44751 :   for (int i = 0; i < indexes1->length(); ++i) {
     291       97500 :     if (indexes1->at(i) != indexes2->at(i)) return false;
     292             :   }
     293             : 
     294      993642 :   ZoneList<int>* registers1 = registers_[index1];
     295      496821 :   ZoneList<int>* registers2 = registers_[index2];
     296      496821 :   if (registers1) {
     297           0 :     if (!registers2) return false;
     298           0 :     if (registers1->length() != registers2->length()) return false;
     299           0 :     for (int i = 0; i < registers1->length(); ++i) {
     300           0 :       if (registers1->at(i) != registers2->at(i)) return false;
     301             :     }
     302      496821 :   } else if (registers2) {
     303             :     return false;
     304             :   }
     305             : 
     306      496782 :   return true;
     307             : }
     308             : 
     309             : }  // namespace internal
     310             : }  // namespace v8

Generated by: LCOV version 1.10