LCOV - code coverage report
Current view: top level - src - safepoint-table.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 96 129 74.4 %
Date: 2019-01-20 Functions: 14 19 73.7 %

          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     1061973 : bool SafepointEntry::HasRegisters() const {
      19             :   DCHECK(is_valid());
      20             :   DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
      21             :   const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
      22     3185919 :   for (int i = 0; i < num_reg_bytes; i++) {
      23     2123946 :     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       12649 : 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     3035404 :       has_deopt_(has_deopt) {
      43     3035404 :   Address header = instruction_start_ + safepoint_table_offset;
      44     3035404 :   length_ = Memory<uint32_t>(header + kLengthOffset);
      45     6070808 :   entry_size_ = Memory<uint32_t>(header + kEntrySizeOffset);
      46     3035404 :   pc_and_deoptimization_indexes_ = header + kHeaderSize;
      47     3035404 :   entries_ = pc_and_deoptimization_indexes_ + (length_ * kFixedEntrySize);
      48             :   DCHECK_GT(entry_size_, 0);
      49             :   STATIC_ASSERT(SafepointEntry::DeoptimizationIndexOrArgumentsField::kMax ==
      50             :                 Safepoint::kNoDeoptimizationIndex);
      51       12649 : }
      52             : 
      53     3022755 : SafepointTable::SafepointTable(Code code)
      54             :     : SafepointTable(code->InstructionStart(), code->safepoint_table_offset(),
      55     6045510 :                      code->stack_slots(), true) {}
      56             : 
      57       51463 : unsigned SafepointTable::find_return_pc(unsigned pc_offset) {
      58       92028 :   for (unsigned i = 0; i < length(); i++) {
      59       46014 :     if (GetTrampolinePcOffset(i) == static_cast<int>(pc_offset)) {
      60        5449 :       return GetPcOffset(i);
      61       40565 :     } else if (GetPcOffset(i) == pc_offset) {
      62             :       return pc_offset;
      63             :     }
      64             :   }
      65           0 :   UNREACHABLE();
      66             :   return 0;
      67             : }
      68             : 
      69     6059910 : SafepointEntry SafepointTable::FindEntry(Address pc) const {
      70     3029955 :   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     3029955 :   CHECK_GT(len, 0);
      75             :   // If pc == kMaxUInt32, then this entry covers all call sites in the function.
      76     3060834 :   if (len == 1 && GetPcOffset(0) == kMaxUInt32) return GetEntry(0);
      77    28655397 :   for (unsigned i = 0; i < len; i++) {
      78             :     // TODO(kasperl): Replace the linear search with binary search.
      79    63348946 :     if (GetPcOffset(i) == pc_offset ||
      80    28791947 :         (has_deopt_ &&
      81    28791947 :          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     5991333 : Safepoint SafepointTableBuilder::DefineSafepoint(
     130             :     Assembler* assembler,
     131             :     Safepoint::Kind kind,
     132             :     int arguments,
     133             :     Safepoint::DeoptMode deopt_mode) {
     134             :   DCHECK_GE(arguments, 0);
     135             :   deoptimization_info_.push_back(
     136    21354439 :       DeoptimizationInfo(zone_, assembler->pc_offset(), arguments, kind));
     137     5991325 :   if (deopt_mode == Safepoint::kNoLazyDeopt) {
     138     3380448 :     last_lazy_safepoint_ = deoptimization_info_.size();
     139             :   }
     140             :   DeoptimizationInfo& new_info = deoptimization_info_.back();
     141     5991325 :   return Safepoint(new_info.indexes, new_info.registers);
     142             : }
     143             : 
     144     2610903 : void SafepointTableBuilder::RecordLazyDeoptimizationIndex(int index) {
     145    13054475 :   for (auto it = deoptimization_info_.Find(last_lazy_safepoint_);
     146             :        it != deoptimization_info_.end(); it++, last_lazy_safepoint_++) {
     147     2610883 :     it->deopt_index = index;
     148             :   }
     149     2610903 : }
     150             : 
     151     3636529 : unsigned SafepointTableBuilder::GetCodeOffset() const {
     152             :   DCHECK(emitted_);
     153     3636529 :   return offset_;
     154             : }
     155             : 
     156     2348759 : int SafepointTableBuilder::UpdateDeoptimizationInfo(int pc, int trampoline,
     157             :                                                     int start) {
     158             :   int index = start;
     159    12194467 :   for (auto it = deoptimization_info_.Find(start);
     160             :        it != deoptimization_info_.end(); it++, index++) {
     161     4922854 :     if (static_cast<int>(it->pc) == pc) {
     162     2348759 :       it->trampoline = trampoline;
     163     2348759 :       return index;
     164             :     }
     165             :   }
     166           0 :   UNREACHABLE();
     167             : }
     168             : 
     169     3636391 : void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) {
     170     3636391 :   RemoveDuplicates();
     171             : 
     172             :   // Make sure the safepoint table is properly aligned. Pad with nops.
     173     3636432 :   assembler->Align(kIntSize);
     174     3636421 :   assembler->RecordComment(";;; Safepoint table.");
     175     3636439 :   offset_ = assembler->pc_offset();
     176             : 
     177             :   // Take the register bits into account.
     178     3636439 :   bits_per_entry += kNumSafepointRegisters;
     179             : 
     180             :   // Compute the number of bytes per safepoint entry.
     181             :   int bytes_per_entry =
     182     3636439 :       RoundUp(bits_per_entry, kBitsPerByte) >> kBitsPerByteLog2;
     183             : 
     184             :   // Emit the table header.
     185             :   STATIC_ASSERT(SafepointTable::kLengthOffset == 0 * kIntSize);
     186             :   STATIC_ASSERT(SafepointTable::kEntrySizeOffset == 1 * kIntSize);
     187             :   STATIC_ASSERT(SafepointTable::kHeaderSize == 2 * kIntSize);
     188     3636439 :   int length = static_cast<int>(deoptimization_info_.size());
     189     3636439 :   assembler->dd(length);
     190     3636355 :   assembler->dd(bytes_per_entry);
     191             : 
     192             :   // Emit sorted table of pc offsets together with additional info (i.e. the
     193             :   // deoptimization index or arguments count) and trampoline offsets.
     194             :   STATIC_ASSERT(SafepointTable::kPcOffset == 0 * kIntSize);
     195             :   STATIC_ASSERT(SafepointTable::kEncodedInfoOffset == 1 * kIntSize);
     196             :   STATIC_ASSERT(SafepointTable::kTrampolinePcOffset == 2 * kIntSize);
     197             :   STATIC_ASSERT(SafepointTable::kFixedEntrySize == 3 * kIntSize);
     198    12515202 :   for (const DeoptimizationInfo& info : deoptimization_info_) {
     199     5241888 :     assembler->dd(info.pc);
     200     5241865 :     assembler->dd(EncodeExceptPC(info));
     201     5241937 :     assembler->dd(info.trampoline);
     202             :   }
     203             : 
     204             :   // Emit table of bitmaps.
     205     3636691 :   ZoneVector<uint8_t> bits(bytes_per_entry, 0, zone_);
     206    12515212 :   for (const DeoptimizationInfo& info : deoptimization_info_) {
     207     5241839 :     ZoneChunkList<int>* indexes = info.indexes;
     208     5241839 :     ZoneChunkList<int>* registers = info.registers;
     209             :     std::fill(bits.begin(), bits.end(), 0);
     210             : 
     211             :     // Run through the registers (if any).
     212             :     DCHECK(IsAligned(kNumSafepointRegisters, kBitsPerByte));
     213     5241839 :     if (registers == nullptr) {
     214             :       const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2;
     215    10483795 :       for (int j = 0; j < num_reg_bytes; j++) {
     216    20967590 :         bits[j] = SafepointTable::kNoRegisters;
     217             :       }
     218             :     } else {
     219           0 :       for (int index : *registers) {
     220             :         DCHECK(index >= 0 && index < kNumSafepointRegisters);
     221           0 :         int byte_index = index >> kBitsPerByteLog2;
     222           0 :         int bit_index = index & (kBitsPerByte - 1);
     223           0 :         bits[byte_index] |= (1 << bit_index);
     224             :       }
     225             :     }
     226             : 
     227             :     // Run through the indexes and build a bitmap.
     228    37801636 :     for (int idx : *indexes) {
     229    13658979 :       int index = bits_per_entry - 1 - idx;
     230    13658979 :       int byte_index = index >> kBitsPerByteLog2;
     231    13658979 :       int bit_index = index & (kBitsPerByte - 1);
     232    27317958 :       bits[byte_index] |= (1U << bit_index);
     233             :     }
     234             : 
     235             :     // Emit the bitmap for the current entry.
     236    19496397 :     for (int k = 0; k < bytes_per_entry; k++) {
     237    38992284 :       assembler->db(bits[k]);
     238             :     }
     239             :   }
     240     3636814 :   emitted_ = true;
     241     3636814 : }
     242             : 
     243           0 : uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
     244     5241865 :   bool has_argc = info.arguments != 0;
     245     5241865 :   int argc = has_argc ? info.arguments : info.deopt_index;
     246             :   DCHECK(info.deopt_index == Safepoint::kNoDeoptimizationIndex || !has_argc);
     247     5241865 :   return SafepointEntry::DeoptimizationIndexOrArgumentsField::encode(argc) |
     248             :          SafepointEntry::HasArgumentsField::encode(has_argc) |
     249    10483730 :          SafepointEntry::SaveDoublesField::encode(info.has_doubles);
     250             : }
     251             : 
     252     3636249 : void SafepointTableBuilder::RemoveDuplicates() {
     253             :   // If the table contains more than one entry, and all entries are identical
     254             :   // (except for the pc), replace the whole table by a single entry with pc =
     255             :   // kMaxUInt32. This especially compacts the table for wasm code without tagged
     256             :   // pointers and without deoptimization info.
     257             : 
     258     3831080 :   if (deoptimization_info_.size() < 2) return;
     259             : 
     260             :   // Check that all entries (1, size] are identical to entry 0.
     261      635617 :   const DeoptimizationInfo& first_info = deoptimization_info_.front();
     262     1839315 :   for (auto it = deoptimization_info_.Find(1); it != deoptimization_info_.end();
     263             :        it++) {
     264     1008880 :     if (!IsIdenticalExceptForPc(first_info, *it)) return;
     265             :   }
     266             : 
     267             :   // If we get here, all entries were identical. Rewind the list to just one
     268             :   // entry, and set the pc to kMaxUInt32.
     269      194818 :   deoptimization_info_.Rewind(1);
     270      194831 :   deoptimization_info_.front().pc = kMaxUInt32;
     271             : }
     272             : 
     273     1008917 : bool SafepointTableBuilder::IsIdenticalExceptForPc(
     274             :     const DeoptimizationInfo& info1, const DeoptimizationInfo& info2) const {
     275     1008917 :   if (info1.arguments != info2.arguments) return false;
     276     1008966 :   if (info1.has_doubles != info2.has_doubles) return false;
     277             : 
     278     1008990 :   if (info1.deopt_index != info2.deopt_index) return false;
     279             : 
     280     1358702 :   ZoneChunkList<int>* indexes1 = info1.indexes;
     281     1358702 :   ZoneChunkList<int>* indexes2 = info2.indexes;
     282      679351 :   if (indexes1->size() != indexes2->size()) return false;
     283      572515 :   if (!std::equal(indexes1->begin(), indexes1->end(), indexes2->begin())) {
     284             :     return false;
     285             :   }
     286             : 
     287      568082 :   ZoneChunkList<int>* registers1 = info1.registers;
     288      568082 :   ZoneChunkList<int>* registers2 = info2.registers;
     289      568082 :   if (registers1) {
     290           0 :     if (!registers2) return false;
     291           0 :     if (registers1->size() != registers2->size()) return false;
     292           0 :     if (!std::equal(registers1->begin(), registers1->end(),
     293           0 :                     registers2->begin())) {
     294             :       return false;
     295             :     }
     296      568082 :   } else if (registers2) {
     297             :     return false;
     298             :   }
     299             : 
     300             :   return true;
     301             : }
     302             : 
     303             : }  // namespace internal
     304      183867 : }  // namespace v8

Generated by: LCOV version 1.10