1 // Copyright 2016 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_MARKING_H
6 #define V8_MARKING_H
7 
8 #include "src/utils.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 class MarkBit {
14  public:
15   typedef uint32_t CellType;
16 
MarkBit(CellType * cell,CellType mask)17   inline MarkBit(CellType* cell, CellType mask) : cell_(cell), mask_(mask) {}
18 
19 #ifdef DEBUG
20   bool operator==(const MarkBit& other) {
21     return cell_ == other.cell_ && mask_ == other.mask_;
22   }
23 #endif
24 
25  private:
cell()26   inline CellType* cell() { return cell_; }
mask()27   inline CellType mask() { return mask_; }
28 
Next()29   inline MarkBit Next() {
30     CellType new_mask = mask_ << 1;
31     if (new_mask == 0) {
32       return MarkBit(cell_ + 1, 1);
33     } else {
34       return MarkBit(cell_, new_mask);
35     }
36   }
37 
Set()38   inline void Set() { *cell_ |= mask_; }
Get()39   inline bool Get() { return (*cell_ & mask_) != 0; }
Clear()40   inline void Clear() { *cell_ &= ~mask_; }
41 
42   CellType* cell_;
43   CellType mask_;
44 
45   friend class IncrementalMarking;
46   friend class Marking;
47 };
48 
49 // Bitmap is a sequence of cells each containing fixed number of bits.
50 class Bitmap {
51  public:
52   static const uint32_t kBitsPerCell = 32;
53   static const uint32_t kBitsPerCellLog2 = 5;
54   static const uint32_t kBitIndexMask = kBitsPerCell - 1;
55   static const uint32_t kBytesPerCell = kBitsPerCell / kBitsPerByte;
56   static const uint32_t kBytesPerCellLog2 = kBitsPerCellLog2 - kBitsPerByteLog2;
57 
58   static const size_t kLength = (1 << kPageSizeBits) >> (kPointerSizeLog2);
59 
60   static const size_t kSize = (1 << kPageSizeBits) >>
61                               (kPointerSizeLog2 + kBitsPerByteLog2);
62 
CellsForLength(int length)63   static int CellsForLength(int length) {
64     return (length + kBitsPerCell - 1) >> kBitsPerCellLog2;
65   }
66 
CellsCount()67   int CellsCount() { return CellsForLength(kLength); }
68 
SizeFor(int cells_count)69   static int SizeFor(int cells_count) {
70     return sizeof(MarkBit::CellType) * cells_count;
71   }
72 
INLINE(static uint32_t IndexToCell (uint32_t index))73   INLINE(static uint32_t IndexToCell(uint32_t index)) {
74     return index >> kBitsPerCellLog2;
75   }
76 
IndexInCell(uint32_t index)77   V8_INLINE static uint32_t IndexInCell(uint32_t index) {
78     return index & kBitIndexMask;
79   }
80 
INLINE(static uint32_t CellToIndex (uint32_t index))81   INLINE(static uint32_t CellToIndex(uint32_t index)) {
82     return index << kBitsPerCellLog2;
83   }
84 
INLINE(static uint32_t CellAlignIndex (uint32_t index))85   INLINE(static uint32_t CellAlignIndex(uint32_t index)) {
86     return (index + kBitIndexMask) & ~kBitIndexMask;
87   }
88 
INLINE(MarkBit::CellType * cells ())89   INLINE(MarkBit::CellType* cells()) {
90     return reinterpret_cast<MarkBit::CellType*>(this);
91   }
92 
INLINE(Address address ())93   INLINE(Address address()) { return reinterpret_cast<Address>(this); }
94 
INLINE(static Bitmap * FromAddress (Address addr))95   INLINE(static Bitmap* FromAddress(Address addr)) {
96     return reinterpret_cast<Bitmap*>(addr);
97   }
98 
MarkBitFromIndex(uint32_t index)99   inline MarkBit MarkBitFromIndex(uint32_t index) {
100     MarkBit::CellType mask = 1u << IndexInCell(index);
101     MarkBit::CellType* cell = this->cells() + (index >> kBitsPerCellLog2);
102     return MarkBit(cell, mask);
103   }
104 
Clear()105   void Clear() {
106     for (int i = 0; i < CellsCount(); i++) cells()[i] = 0;
107   }
108 
109   // Sets all bits in the range [start_index, end_index).
SetRange(uint32_t start_index,uint32_t end_index)110   void SetRange(uint32_t start_index, uint32_t end_index) {
111     unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2;
112     MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index);
113 
114     unsigned int end_cell_index = end_index >> Bitmap::kBitsPerCellLog2;
115     MarkBit::CellType end_index_mask = 1u << Bitmap::IndexInCell(end_index);
116 
117     if (start_cell_index != end_cell_index) {
118       // Firstly, fill all bits from the start address to the end of the first
119       // cell with 1s.
120       cells()[start_cell_index] |= ~(start_index_mask - 1);
121       // Then fill all in between cells with 1s.
122       for (unsigned int i = start_cell_index + 1; i < end_cell_index; i++) {
123         cells()[i] = ~0u;
124       }
125       // Finally, fill all bits until the end address in the last cell with 1s.
126       cells()[end_cell_index] |= (end_index_mask - 1);
127     } else {
128       cells()[start_cell_index] |= end_index_mask - start_index_mask;
129     }
130   }
131 
132   // Clears all bits in the range [start_index, end_index).
ClearRange(uint32_t start_index,uint32_t end_index)133   void ClearRange(uint32_t start_index, uint32_t end_index) {
134     unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2;
135     MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index);
136 
137     unsigned int end_cell_index = end_index >> Bitmap::kBitsPerCellLog2;
138     MarkBit::CellType end_index_mask = 1u << Bitmap::IndexInCell(end_index);
139 
140     if (start_cell_index != end_cell_index) {
141       // Firstly, fill all bits from the start address to the end of the first
142       // cell with 0s.
143       cells()[start_cell_index] &= (start_index_mask - 1);
144       // Then fill all in between cells with 0s.
145       for (unsigned int i = start_cell_index + 1; i < end_cell_index; i++) {
146         cells()[i] = 0;
147       }
148       // Finally, set all bits until the end address in the last cell with 0s.
149       cells()[end_cell_index] &= ~(end_index_mask - 1);
150     } else {
151       cells()[start_cell_index] &= ~(end_index_mask - start_index_mask);
152     }
153   }
154 
155   // Returns true if all bits in the range [start_index, end_index) are set.
AllBitsSetInRange(uint32_t start_index,uint32_t end_index)156   bool AllBitsSetInRange(uint32_t start_index, uint32_t end_index) {
157     unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2;
158     MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index);
159 
160     unsigned int end_cell_index = end_index >> Bitmap::kBitsPerCellLog2;
161     MarkBit::CellType end_index_mask = 1u << Bitmap::IndexInCell(end_index);
162 
163     MarkBit::CellType matching_mask;
164     if (start_cell_index != end_cell_index) {
165       matching_mask = ~(start_index_mask - 1);
166       if ((cells()[start_cell_index] & matching_mask) != matching_mask) {
167         return false;
168       }
169       for (unsigned int i = start_cell_index + 1; i < end_cell_index; i++) {
170         if (cells()[i] != ~0u) return false;
171       }
172       matching_mask = (end_index_mask - 1);
173       return ((cells()[end_cell_index] & matching_mask) == matching_mask);
174     } else {
175       matching_mask = end_index_mask - start_index_mask;
176       return (cells()[end_cell_index] & matching_mask) == matching_mask;
177     }
178   }
179 
180   // Returns true if all bits in the range [start_index, end_index) are cleared.
AllBitsClearInRange(uint32_t start_index,uint32_t end_index)181   bool AllBitsClearInRange(uint32_t start_index, uint32_t end_index) {
182     unsigned int start_cell_index = start_index >> Bitmap::kBitsPerCellLog2;
183     MarkBit::CellType start_index_mask = 1u << Bitmap::IndexInCell(start_index);
184 
185     unsigned int end_cell_index = end_index >> Bitmap::kBitsPerCellLog2;
186     MarkBit::CellType end_index_mask = 1u << Bitmap::IndexInCell(end_index);
187 
188     MarkBit::CellType matching_mask;
189     if (start_cell_index != end_cell_index) {
190       matching_mask = ~(start_index_mask - 1);
191       if ((cells()[start_cell_index] & matching_mask)) return false;
192       for (unsigned int i = start_cell_index + 1; i < end_cell_index; i++) {
193         if (cells()[i]) return false;
194       }
195       matching_mask = (end_index_mask - 1);
196       return !(cells()[end_cell_index] & matching_mask);
197     } else {
198       matching_mask = end_index_mask - start_index_mask;
199       return !(cells()[end_cell_index] & matching_mask);
200     }
201   }
202 
203   static void PrintWord(uint32_t word, uint32_t himask = 0) {
204     for (uint32_t mask = 1; mask != 0; mask <<= 1) {
205       if ((mask & himask) != 0) PrintF("[");
206       PrintF((mask & word) ? "1" : "0");
207       if ((mask & himask) != 0) PrintF("]");
208     }
209   }
210 
211   class CellPrinter {
212    public:
CellPrinter()213     CellPrinter() : seq_start(0), seq_type(0), seq_length(0) {}
214 
Print(uint32_t pos,uint32_t cell)215     void Print(uint32_t pos, uint32_t cell) {
216       if (cell == seq_type) {
217         seq_length++;
218         return;
219       }
220 
221       Flush();
222 
223       if (IsSeq(cell)) {
224         seq_start = pos;
225         seq_length = 0;
226         seq_type = cell;
227         return;
228       }
229 
230       PrintF("%d: ", pos);
231       PrintWord(cell);
232       PrintF("\n");
233     }
234 
Flush()235     void Flush() {
236       if (seq_length > 0) {
237         PrintF("%d: %dx%d\n", seq_start, seq_type == 0 ? 0 : 1,
238                seq_length * kBitsPerCell);
239         seq_length = 0;
240       }
241     }
242 
IsSeq(uint32_t cell)243     static bool IsSeq(uint32_t cell) { return cell == 0 || cell == 0xFFFFFFFF; }
244 
245    private:
246     uint32_t seq_start;
247     uint32_t seq_type;
248     uint32_t seq_length;
249   };
250 
Print()251   void Print() {
252     CellPrinter printer;
253     for (int i = 0; i < CellsCount(); i++) {
254       printer.Print(i, cells()[i]);
255     }
256     printer.Flush();
257     PrintF("\n");
258   }
259 
IsClean()260   bool IsClean() {
261     for (int i = 0; i < CellsCount(); i++) {
262       if (cells()[i] != 0) {
263         return false;
264       }
265     }
266     return true;
267   }
268 };
269 
270 class Marking : public AllStatic {
271  public:
272   // Impossible markbits: 01
273   static const char* kImpossibleBitPattern;
INLINE(static bool IsImpossible (MarkBit mark_bit))274   INLINE(static bool IsImpossible(MarkBit mark_bit)) {
275     return !mark_bit.Get() && mark_bit.Next().Get();
276   }
277 
278   // Black markbits: 11
279   static const char* kBlackBitPattern;
INLINE(static bool IsBlack (MarkBit mark_bit))280   INLINE(static bool IsBlack(MarkBit mark_bit)) {
281     return mark_bit.Get() && mark_bit.Next().Get();
282   }
283 
284   // White markbits: 00 - this is required by the mark bit clearer.
285   static const char* kWhiteBitPattern;
INLINE(static bool IsWhite (MarkBit mark_bit))286   INLINE(static bool IsWhite(MarkBit mark_bit)) {
287     DCHECK(!IsImpossible(mark_bit));
288     return !mark_bit.Get();
289   }
290 
291   // Grey markbits: 10
292   static const char* kGreyBitPattern;
INLINE(static bool IsGrey (MarkBit mark_bit))293   INLINE(static bool IsGrey(MarkBit mark_bit)) {
294     return mark_bit.Get() && !mark_bit.Next().Get();
295   }
296 
297   // IsBlackOrGrey assumes that the first bit is set for black or grey
298   // objects.
INLINE(static bool IsBlackOrGrey (MarkBit mark_bit))299   INLINE(static bool IsBlackOrGrey(MarkBit mark_bit)) { return mark_bit.Get(); }
300 
INLINE(static void MarkBlack (MarkBit mark_bit))301   INLINE(static void MarkBlack(MarkBit mark_bit)) {
302     mark_bit.Set();
303     mark_bit.Next().Set();
304   }
305 
INLINE(static void MarkWhite (MarkBit mark_bit))306   INLINE(static void MarkWhite(MarkBit mark_bit)) {
307     mark_bit.Clear();
308     mark_bit.Next().Clear();
309   }
310 
INLINE(static void BlackToWhite (MarkBit markbit))311   INLINE(static void BlackToWhite(MarkBit markbit)) {
312     DCHECK(IsBlack(markbit));
313     markbit.Clear();
314     markbit.Next().Clear();
315   }
316 
INLINE(static void GreyToWhite (MarkBit markbit))317   INLINE(static void GreyToWhite(MarkBit markbit)) {
318     DCHECK(IsGrey(markbit));
319     markbit.Clear();
320     markbit.Next().Clear();
321   }
322 
INLINE(static void BlackToGrey (MarkBit markbit))323   INLINE(static void BlackToGrey(MarkBit markbit)) {
324     DCHECK(IsBlack(markbit));
325     markbit.Next().Clear();
326   }
327 
INLINE(static void WhiteToGrey (MarkBit markbit))328   INLINE(static void WhiteToGrey(MarkBit markbit)) {
329     DCHECK(IsWhite(markbit));
330     markbit.Set();
331   }
332 
INLINE(static void WhiteToBlack (MarkBit markbit))333   INLINE(static void WhiteToBlack(MarkBit markbit)) {
334     DCHECK(IsWhite(markbit));
335     markbit.Set();
336     markbit.Next().Set();
337   }
338 
INLINE(static void GreyToBlack (MarkBit markbit))339   INLINE(static void GreyToBlack(MarkBit markbit)) {
340     DCHECK(IsGrey(markbit));
341     markbit.Next().Set();
342   }
343 
INLINE(static void AnyToGrey (MarkBit markbit))344   INLINE(static void AnyToGrey(MarkBit markbit)) {
345     markbit.Set();
346     markbit.Next().Clear();
347   }
348 
349   enum ObjectColor {
350     BLACK_OBJECT,
351     WHITE_OBJECT,
352     GREY_OBJECT,
353     IMPOSSIBLE_COLOR
354   };
355 
ColorName(ObjectColor color)356   static const char* ColorName(ObjectColor color) {
357     switch (color) {
358       case BLACK_OBJECT:
359         return "black";
360       case WHITE_OBJECT:
361         return "white";
362       case GREY_OBJECT:
363         return "grey";
364       case IMPOSSIBLE_COLOR:
365         return "impossible";
366     }
367     return "error";
368   }
369 
Color(MarkBit mark_bit)370   static ObjectColor Color(MarkBit mark_bit) {
371     if (IsBlack(mark_bit)) return BLACK_OBJECT;
372     if (IsWhite(mark_bit)) return WHITE_OBJECT;
373     if (IsGrey(mark_bit)) return GREY_OBJECT;
374     UNREACHABLE();
375     return IMPOSSIBLE_COLOR;
376   }
377 
378  private:
379   DISALLOW_IMPLICIT_CONSTRUCTORS(Marking);
380 };
381 
382 }  // namespace internal
383 }  // namespace v8
384 
385 #endif  // V8_MARKING_H_
386