1 // Copyright 2020 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 #ifndef V8_HEAP_OBJECT_START_BITMAP_H_
6 #define V8_HEAP_OBJECT_START_BITMAP_H_
7 
8 #include <limits.h>
9 #include <stdint.h>
10 
11 #include <array>
12 
13 #include "include/v8-internal.h"
14 #include "src/base/bits.h"
15 #include "src/base/macros.h"
16 #include "src/common/globals.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 static constexpr size_t kAllocationGranularity = kTaggedSize;
22 static constexpr size_t kAllocationMask = kAllocationGranularity - 1;
23 static const int kPageSize = 1 << kPageSizeBits;
24 
25 // A bitmap for recording object starts. Objects have to be allocated at
26 // minimum granularity of kGranularity.
27 //
28 // Depends on internals such as:
29 // - kPageSize
30 // - kAllocationGranularity
31 //
32 // ObjectStartBitmap does not support concurrent access and is used only by the
33 // main thread.
34 class V8_EXPORT_PRIVATE ObjectStartBitmap {
35  public:
36   // Granularity of addresses added to the bitmap.
Granularity()37   static constexpr size_t Granularity() { return kAllocationGranularity; }
38 
39   // Maximum number of entries in the bitmap.
MaxEntries()40   static constexpr size_t MaxEntries() {
41     return kReservedForBitmap * kBitsPerCell;
42   }
43 
44   explicit inline ObjectStartBitmap(size_t offset = 0);
45 
46   // Finds an object header based on a maybe_inner_ptr. Will search for an
47   // object start in decreasing address order.
48   //
49   // This must only be used when there exists at least one entry in the bitmap.
50   inline Address FindBasePtr(Address maybe_inner_ptr) const;
51 
52   inline void SetBit(Address);
53   inline void ClearBit(Address);
54   inline bool CheckBit(Address) const;
55 
56   // Iterates all object starts recorded in the bitmap.
57   //
58   // The callback is of type
59   //   void(Address)
60   // and is passed the object start address as parameter.
61   template <typename Callback>
62   inline void Iterate(Callback) const;
63 
64   // Clear the object start bitmap.
65   inline void Clear();
66 
67  private:
68   inline void store(size_t cell_index, uint32_t value);
69   inline uint32_t load(size_t cell_index) const;
70 
71   inline Address offset() const;
72 
73   static constexpr size_t kBitsPerCell = sizeof(uint32_t) * CHAR_BIT;
74   static constexpr size_t kCellMask = kBitsPerCell - 1;
75   static constexpr size_t kBitmapSize =
76       (kPageSize + ((kBitsPerCell * kAllocationGranularity) - 1)) /
77       (kBitsPerCell * kAllocationGranularity);
78   static constexpr size_t kReservedForBitmap =
79       ((kBitmapSize + kAllocationMask) & ~kAllocationMask);
80 
81   inline void ObjectStartIndexAndBit(Address, size_t*, size_t*) const;
82 
83   inline Address StartIndexToAddress(size_t object_start_index) const;
84 
85   size_t offset_;
86 
87   std::array<uint32_t, kReservedForBitmap> object_start_bit_map_;
88 };
89 
ObjectStartBitmap(size_t offset)90 ObjectStartBitmap::ObjectStartBitmap(size_t offset) : offset_(offset) {
91   Clear();
92 }
93 
FindBasePtr(Address maybe_inner_ptr)94 Address ObjectStartBitmap::FindBasePtr(Address maybe_inner_ptr) const {
95   DCHECK_LE(offset(), maybe_inner_ptr);
96   size_t object_offset = maybe_inner_ptr - offset();
97   size_t object_start_number = object_offset / kAllocationGranularity;
98   size_t cell_index = object_start_number / kBitsPerCell;
99   DCHECK_GT(object_start_bit_map_.size(), cell_index);
100   const size_t bit = object_start_number & kCellMask;
101   // check if maybe_inner_ptr is the base pointer
102   uint32_t byte = load(cell_index) & ((1 << (bit + 1)) - 1);
103   while (!byte && cell_index) {
104     DCHECK_LT(0u, cell_index);
105     byte = load(--cell_index);
106   }
107   const int leading_zeroes = v8::base::bits::CountLeadingZeros(byte);
108   if (leading_zeroes == kBitsPerCell) {
109     return kNullAddress;
110   }
111 
112   object_start_number =
113       (cell_index * kBitsPerCell) + (kBitsPerCell - 1) - leading_zeroes;
114   Address base_ptr = StartIndexToAddress(object_start_number);
115   return base_ptr;
116 }
117 
SetBit(Address base_ptr)118 void ObjectStartBitmap::SetBit(Address base_ptr) {
119   size_t cell_index, object_bit;
120   ObjectStartIndexAndBit(base_ptr, &cell_index, &object_bit);
121   store(cell_index,
122         static_cast<uint32_t>(load(cell_index) | (1 << object_bit)));
123 }
124 
ClearBit(Address base_ptr)125 void ObjectStartBitmap::ClearBit(Address base_ptr) {
126   size_t cell_index, object_bit;
127   ObjectStartIndexAndBit(base_ptr, &cell_index, &object_bit);
128   store(cell_index,
129         static_cast<uint32_t>(load(cell_index) & ~(1 << object_bit)));
130 }
131 
CheckBit(Address base_ptr)132 bool ObjectStartBitmap::CheckBit(Address base_ptr) const {
133   size_t cell_index, object_bit;
134   ObjectStartIndexAndBit(base_ptr, &cell_index, &object_bit);
135   return load(cell_index) & (1 << object_bit);
136 }
137 
store(size_t cell_index,uint32_t value)138 void ObjectStartBitmap::store(size_t cell_index, uint32_t value) {
139   object_start_bit_map_[cell_index] = value;
140   return;
141 }
142 
load(size_t cell_index)143 uint32_t ObjectStartBitmap::load(size_t cell_index) const {
144   return object_start_bit_map_[cell_index];
145 }
146 
offset()147 Address ObjectStartBitmap::offset() const { return offset_; }
148 
ObjectStartIndexAndBit(Address base_ptr,size_t * cell_index,size_t * bit)149 void ObjectStartBitmap::ObjectStartIndexAndBit(Address base_ptr,
150                                                size_t* cell_index,
151                                                size_t* bit) const {
152   const size_t object_offset = base_ptr - offset();
153   DCHECK(!(object_offset & kAllocationMask));
154   const size_t object_start_number = object_offset / kAllocationGranularity;
155   *cell_index = object_start_number / kBitsPerCell;
156   DCHECK_GT(kBitmapSize, *cell_index);
157   *bit = object_start_number & kCellMask;
158 }
159 
StartIndexToAddress(size_t object_start_index)160 Address ObjectStartBitmap::StartIndexToAddress(
161     size_t object_start_index) const {
162   return offset() + (kAllocationGranularity * object_start_index);
163 }
164 
165 template <typename Callback>
Iterate(Callback callback)166 inline void ObjectStartBitmap::Iterate(Callback callback) const {
167   for (size_t cell_index = 0; cell_index < kReservedForBitmap; cell_index++) {
168     uint32_t value = object_start_bit_map_[cell_index];
169     while (value) {
170       const int trailing_zeroes = v8::base::bits::CountTrailingZeros(value);
171       const size_t object_start_number =
172           (cell_index * kBitsPerCell) + trailing_zeroes;
173       const Address object_address = StartIndexToAddress(object_start_number);
174       callback(object_address);
175       // Clear current object bit in temporary value to advance iteration.
176       value &= ~(1 << (object_start_number & kCellMask));
177     }
178   }
179 }
180 
Clear()181 void ObjectStartBitmap::Clear() {
182   std::fill(object_start_bit_map_.begin(), object_start_bit_map_.end(), 0);
183 }
184 
185 }  // namespace internal
186 }  // namespace v8
187 
188 #endif  // V8_HEAP_OBJECT_START_BITMAP_H_
189