LCOV - code coverage report
Current view: top level - src - safepoint-table.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 91 123 74.0 %
Date: 2019-04-17 Functions: 13 18 72.2 %

          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     1222106 : bool SafepointEntry::HasRegisters() const {
      19             :   DCHECK(is_valid());
      20             :   DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
      21             :   const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
      22     6110530 :   for (int i = 0; i < num_reg_bytes; i++) {
      23     2444212 :     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       12661 : SafepointTable::SafepointTable(Address instruction_start,
      38             :                                size_t safepoint_table_offset,
      39             :                                uint32_t stack_slots, bool has_deopt)
      40             :     : instruction_start_(instruction_start),
      41             :       stack_slots_(stack_slots),
      42     2870474 :       has_deopt_(has_deopt) {
      43     2870474 :   Address header = instruction_start_ + safepoint_table_offset;
      44     2870474 :   length_ = Memory<uint32_t>(header + kLengthOffset);
      45     5740948 :   entry_size_ = Memory<uint32_t>(header + kEntrySizeOffset);
      46     2870474 :   pc_and_deoptimization_indexes_ = header + kHeaderSize;
      47     2870474 :   entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
      48             :   DCHECK_GT(entry_size_, 0);
      49             :   STATIC_ASSERT(SafepointEntry::DeoptimizationIndexField::kMax ==
      50             :                 Safepoint::kNoDeoptimizationIndex);
      51       12661 : }
      52             : 
      53     2857813 : SafepointTable::SafepointTable(Code code)
      54             :     : SafepointTable(code->InstructionStart(), code->safepoint_table_offset(),
      55     5715626 :                      code->stack_slots(), true) {}
      56             : 
      57        6124 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
      58       87250 :   for (unsigned i = 0; i < length(); i++) {
      59       46687 :     if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
      60        6124 :       return GetPcOffset(i);
      61       40563 :     } else if (GetPcOffset(i) == pc_offset) {
      62             :       return pc_offset;
      63             :     }
      64             :   }
      65           0 :   UNREACHABLE();
      66             :   return 0;
      67             : }
      68             : 
      69     2864350 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
      70     2864350 :   unsigned pc_offset = static_cast<unsigned>(pc - instruction_start_);
      71             :   // We use kMaxUInt32 as sentinel value, so check that we don't hit that.
      72             :   DCHECK_NE(kMaxUInt32, pc_offset);
      73             :   unsigned len = length();
      74     2864350 :   CHECK_GT(len, 0);
      75             :   // If pc == kMaxUInt32, then this entry covers all call sites in the function.
      76     2890570 :   if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
      77    72101539 :   for (unsigned i = 0; i < len; i++) {
      78             :     // TODO(kasperl): Replace the linear search with binary search.
      79   109607698 :     if (GetPcOffset(i) == pc_offset ||
      80    69277457 :         (has_deopt_ &&
      81    34627839 :          GetTrampolinePcOffset(i) == static_cast<int>(pc_offset))) {
      82             :       return GetEntry(i);
      83             :     }
      84             :   }
      85           0 :   UNREACHABLE();
      86             :   return SafepointEntry();
      87             : }
      88             : 
      89             : 
      90           0 : void SafepointTable::PrintEntry(unsigned index,
      91             :                                 std::ostream& os) const {  // NOLINT
      92             :   disasm::NameConverter converter;
      93             :   SafepointEntry entry = GetEntry(index);
      94             :   uint8_t* bits = entry.bits();
      95             : 
      96             :   // Print the stack slot bits.
      97           0 :   if (entry_size_ > 0) {
      98             :     DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
      99             :     const int first = kNumSafepointRegisters >> kBitsPerByteLog2;
     100           0 :     int last = entry_size_ - 1;
     101           0 :     for (int i = first; i < last; i++) PrintBits(os, bits[i], kBitsPerByte);
     102           0 :     int last_bits = stack_slots_ - ((last - first) * kBitsPerByte);
     103           0 :     PrintBits(os, bits[last], last_bits);
     104             : 
     105             :     // Print the registers (if any).
     106           0 :     if (!entry.HasRegisters()) return;
     107           0 :     for (int j = 0; j < kNumSafepointRegisters; j++) {
     108           0 :       if (entry.HasRegisterAt(j)) {
     109           0 :         os << " | " << converter.NameOfCPURegister(j);
     110             :       }
     111             :     }
     112             :   }
     113             : }
     114             : 
     115             : 
     116           0 : void SafepointTable::PrintBits(std::ostream& os,  // NOLINT
     117             :                                uint8_t byte, int digits) {
     118             :   DCHECK(digits >= 0 && digits <= kBitsPerByte);
     119           0 :   for (int i = 0; i < digits; i++) {
     120           0 :     os << (((byte & (1 << i)) == 0) ? "0" : "1");
     121             :   }
     122           0 : }
     123             : 
     124           0 : void Safepoint::DefinePointerRegister(Register reg) {
     125           0 :   registers_->push_back(reg.code());
     126           0 : }
     127             : 
     128             : 
     129     6450075 : Safepoint SafepointTableBuilder::DefineSafepoint(
     130             :     Assembler* assembler,
     131             :     Safepoint::Kind kind,
     132             :     Safepoint::DeoptMode deopt_mode) {
     133    12900654 :   deoptimization_info_.push_back(
     134     6450241 :       DeoptimizationInfo(zone_, assembler->pc_offset(), kind));
     135     6450579 :   if (deopt_mode == Safepoint::kNoLazyDeopt) {
     136     3495309 :     last_lazy_safepoint_ = deoptimization_info_.size();
     137             :   }
     138             :   DeoptimizationInfo& new_info = deoptimization_info_.back();
     139     6450579 :   return Safepoint(new_info.indexes, new_info.registers);
     140             : }
     141             : 
     142     2955123 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
     143    11820462 :   for (auto it = deoptimization_info_.Find(last_lazy_safepoint_);
     144     2955108 :        it != deoptimization_info_.end(); it++, last_lazy_safepoint_++) {
     145     2955108 :     it->deopt_index = index;
     146             :   }
     147     2955123 : }
     148             : 
     149     3024537 : unsigned SafepointTableBuilder::GetCodeOffset() const {
     150             :   DCHECK(emitted_);
     151     3024537 :   return offset_;
     152             : }
     153             : 
     154     2955123 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
     155             :                                                     int start) {
     156             :   int index = start;
     157    12341266 :   for (auto it = deoptimization_info_.Find(start);
     158             :        it != deoptimization_info_.end(); it++, index++) {
     159             :     if (static_cast<int>(it->pc) == pc) {
     160     2955123 :       it->trampoline = trampoline;
     161     2955123 :       return index;
     162             :     }
     163             :   }
     164           0 :   UNREACHABLE();
     165             : }
     166             : 
     167     3081022 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
     168     3081022 :   RemoveDuplicates();
     169             : 
     170             :   // Make sure the safepoint table is properly aligned. Pad with nops.
     171     3080692 :   assembler->Align(kIntSize);
     172     3081022 :   assembler->RecordComment(";;; Safepoint table.");
     173     3081313 :   offset_ = assembler->pc_offset();
     174             : 
     175             :   // Take the register bits into account.
     176     3081313 :   bits_per_entry += kNumSafepointRegisters;
     177             : 
     178             :   // Compute the number of bytes per safepoint entry.
     179             :   int bytes_per_entry =
     180     3081313 :       RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
     181             : 
     182             :   // Emit the table header.
     183             :   STATIC_ASSERT(SafepointTable::kLengthOffset == 0 * kIntSize);
     184             :   STATIC_ASSERT(SafepointTable::kEntrySizeOffset == 1 * kIntSize);
     185             :   STATIC_ASSERT(SafepointTable::kHeaderSize == 2 * kIntSize);
     186             :   int length = static_cast<int>(deoptimization_info_.size());
     187     3081313 :   assembler->dd(length);
     188     3081197 :   assembler->dd(bytes_per_entry);
     189             : 
     190             :   // Emit sorted table of pc offsets together with additional info (i.e. the
     191             :   // deoptimization index or arguments count) and trampoline offsets.
     192             :   STATIC_ASSERT(SafepointTable::kPcOffset == 0 * kIntSize);
     193             :   STATIC_ASSERT(SafepointTable::kEncodedInfoOffset == 1 * kIntSize);
     194             :   STATIC_ASSERT(SafepointTable::kTrampolinePcOffset == 2 * kIntSize);
     195             :   STATIC_ASSERT(SafepointTable::kFixedEntrySize == 3 * kIntSize);
     196     9067471 :   for (const DeoptimizationInfo& info : deoptimization_info_) {
     197     5985068 :     assembler->dd(info.pc);
     198     5985421 :     assembler->dd(EncodeExceptPC(info));
     199     5985792 :     assembler->dd(info.trampoline);
     200             :   }
     201             : 
     202             :   // Emit table of bitmaps.
     203     3082403 :   ZoneVector<uint8_t> bits(bytes_per_entry, 0, zone_);
     204     9067594 :   for (const DeoptimizationInfo& info : deoptimization_info_) {
     205     5985278 :     ZoneChunkList<int>* indexes = info.indexes;
     206     5985278 :     ZoneChunkList<int>* registers = info.registers;
     207             :     std::fill(bits.begin(), bits.end(), 0);
     208             : 
     209             :     // Run through the registers (if any).
     210             :     DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
     211     5985278 :     if (registers == nullptr) {
     212             :       const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
     213    29929390 :       for (int j = 0; j < num_reg_bytes; j++) {
     214    23944112 :         bits[j] = SafepointTable::kNoRegisters;
     215             :       }
     216             :     } else {
     217           0 :       for (int index : *registers) {
     218             :         DCHECK(index >= 0 && index < kNumSafepointRegisters);
     219           0 :         int byte_index = index >> kBitsPerByteLog2;
     220           0 :         int bit_index = index & (kBitsPerByte - 1);
     221           0 :         bits[byte_index] |= (1 << bit_index);
     222             :       }
     223             :     }
     224             : 
     225             :     // Run through the indexes and build a bitmap.
     226    37626778 :     for (int idx : *indexes) {
     227    15820750 :       int index = bits_per_entry - 1 - idx;
     228    15820750 :       int byte_index = index >> kBitsPerByteLog2;
     229    15820750 :       int bit_index = index & (kBitsPerByte - 1);
     230    31641500 :       bits[byte_index] |= (1U << bit_index);
     231             :     }
     232             : 
     233             :     // Emit the bitmap for the current entry.
     234    51561302 :     for (int k = 0; k < bytes_per_entry; k++) {
     235    45575496 :       assembler->db(bits[k]);
     236             :     }
     237             :   }
     238     3082316 :   emitted_ = true;
     239     3082316 : }
     240             : 
     241           0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
     242     5985421 :   return SafepointEntry::DeoptimizationIndexField::encode(info.deopt_index) |
     243    11970842 :          SafepointEntry::SaveDoublesField::encode(info.has_doubles);
     244             : }
     245             : 
     246     3080666 : void SafepointTableBuilder::RemoveDuplicates() {
     247             :   // If the table contains more than one entry, and all entries are identical
     248             :   // (except for the pc), replace the whole table by a single entry with pc =
     249             :   // kMaxUInt32. This especially compacts the table for wasm code without tagged
     250             :   // pointers and without deoptimization info.
     251             : 
     252     3080666 :   if (deoptimization_info_.size() < 2) return;
     253             : 
     254             :   // Check that all entries (1, size] are identical to entry 0.
     255             :   const DeoptimizationInfo& first_info = deoptimization_info_.front();
     256     1219538 :   for (auto it = deoptimization_info_.Find(1); it != deoptimization_info_.end();
     257             :        it++) {
     258     1014541 :     if (!IsIdenticalExceptForPc(first_info, *it)) return;
     259             :   }
     260             : 
     261             :   // If we get here, all entries were identical. Rewind the list to just one
     262             :   // entry, and set the pc to kMaxUInt32.
     263             :   deoptimization_info_.Rewind(1);
     264      204997 :   deoptimization_info_.front().pc = kMaxUInt32;
     265             : }
     266             : 
     267     1014551 : bool SafepointTableBuilder::IsIdenticalExceptForPc(
     268             :     const DeoptimizationInfo& info1, const DeoptimizationInfo& info2) const {
     269     1014551 :   if (info1.has_doubles != info2.has_doubles) return false;
     270     1014560 :   if (info1.deopt_index != info2.deopt_index) return false;
     271             : 
     272      674636 :   ZoneChunkList<int>* indexes1 = info1.indexes;
     273      674636 :   ZoneChunkList<int>* indexes2 = info2.indexes;
     274      674636 :   if (indexes1->size() != indexes2->size()) return false;
     275      570376 :   if (!std::equal(indexes1->begin(), indexes1->end(), indexes2->begin())) {
     276             :     return false;
     277             :   }
     278             : 
     279      565394 :   ZoneChunkList<int>* registers1 = info1.registers;
     280      565394 :   ZoneChunkList<int>* registers2 = info2.registers;
     281      565394 :   if (registers1) {
     282           0 :     if (!registers2) return false;
     283           0 :     if (registers1->size() != registers2->size()) return false;
     284           0 :     if (!std::equal(registers1->begin(), registers1->end(),
     285             :                     registers2->begin())) {
     286             :       return false;
     287             :     }
     288      565394 :   } else if (registers2) {
     289             :     return false;
     290             :   }
     291             : 
     292             :   return true;
     293             : }
     294             : 
     295             : }  // namespace internal
     296      121996 : }  // namespace v8

Generated by: LCOV version 1.10