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