xref: /aosp_15_r20/art/runtime/gc/accounting/card_table.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <memory>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "base/locks.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/mem_map.h"
24*795d594fSAndroid Build Coastguard Worker #include "runtime_globals.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker namespace mirror {
29*795d594fSAndroid Build Coastguard Worker class Object;
30*795d594fSAndroid Build Coastguard Worker }  // namespace mirror
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace gc {
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace space {
35*795d594fSAndroid Build Coastguard Worker class ContinuousSpace;
36*795d594fSAndroid Build Coastguard Worker }  // namespace space
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker class Heap;
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker namespace accounting {
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker template<size_t kAlignment> class SpaceBitmap;
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker // Maintain a card table from the the write barrier. All writes of
45*795d594fSAndroid Build Coastguard Worker // non-null values to heap addresses should go through an entry in
46*795d594fSAndroid Build Coastguard Worker // WriteBarrier, and from there to here.
47*795d594fSAndroid Build Coastguard Worker class CardTable {
48*795d594fSAndroid Build Coastguard Worker  public:
49*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kCardShift = 10;
50*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kCardSize = 1 << kCardShift;
51*795d594fSAndroid Build Coastguard Worker   static constexpr uint8_t kCardClean = 0x0;
52*795d594fSAndroid Build Coastguard Worker   static constexpr uint8_t kCardDirty = 0x70;
53*795d594fSAndroid Build Coastguard Worker   static constexpr uint8_t kCardAged = kCardDirty - 1;
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker   static CardTable* Create(const uint8_t* heap_begin, size_t heap_capacity);
56*795d594fSAndroid Build Coastguard Worker   ~CardTable();
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker   // Set the card associated with the given address to `kCardDirty`.
MarkCard(const void * addr)59*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void MarkCard(const void *addr) {
60*795d594fSAndroid Build Coastguard Worker     *CardFromAddr(addr) = kCardDirty;
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   // Is the object on a dirty card?
IsDirty(const mirror::Object * obj)64*795d594fSAndroid Build Coastguard Worker   bool IsDirty(const mirror::Object* obj) const {
65*795d594fSAndroid Build Coastguard Worker     return GetCard(obj) == kCardDirty;
66*795d594fSAndroid Build Coastguard Worker   }
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker   // Is the object on a clean card?
IsClean(const mirror::Object * obj)69*795d594fSAndroid Build Coastguard Worker   bool IsClean(const mirror::Object* obj) const {
70*795d594fSAndroid Build Coastguard Worker     return GetCard(obj) == kCardClean;
71*795d594fSAndroid Build Coastguard Worker   }
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker   // Return the state of the card at an address.
GetCard(const mirror::Object * obj)74*795d594fSAndroid Build Coastguard Worker   uint8_t GetCard(const mirror::Object* obj) const {
75*795d594fSAndroid Build Coastguard Worker     return *CardFromAddr(obj);
76*795d594fSAndroid Build Coastguard Worker   }
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker   // Visit and clear cards within memory range, only visits dirty cards.
79*795d594fSAndroid Build Coastguard Worker   template <typename Visitor>
VisitClear(const void * start,const void * end,const Visitor & visitor)80*795d594fSAndroid Build Coastguard Worker   void VisitClear(const void* start, const void* end, const Visitor& visitor) {
81*795d594fSAndroid Build Coastguard Worker     uint8_t* card_start = CardFromAddr(start);
82*795d594fSAndroid Build Coastguard Worker     uint8_t* card_end = CardFromAddr(end);
83*795d594fSAndroid Build Coastguard Worker     for (uint8_t* it = card_start; it != card_end; ++it) {
84*795d594fSAndroid Build Coastguard Worker       if (*it == kCardDirty) {
85*795d594fSAndroid Build Coastguard Worker         *it = kCardClean;
86*795d594fSAndroid Build Coastguard Worker         visitor(it);
87*795d594fSAndroid Build Coastguard Worker       }
88*795d594fSAndroid Build Coastguard Worker     }
89*795d594fSAndroid Build Coastguard Worker   }
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker   // Returns a value that when added to a heap address >> `kCardShift` will address the appropriate
92*795d594fSAndroid Build Coastguard Worker   // card table byte. For convenience this value is cached in every Thread.
GetBiasedBegin()93*795d594fSAndroid Build Coastguard Worker   uint8_t* GetBiasedBegin() const {
94*795d594fSAndroid Build Coastguard Worker     return biased_begin_;
95*795d594fSAndroid Build Coastguard Worker   }
96*795d594fSAndroid Build Coastguard Worker 
MemMapBegin()97*795d594fSAndroid Build Coastguard Worker   void* MemMapBegin() const {
98*795d594fSAndroid Build Coastguard Worker     return mem_map_.BaseBegin();
99*795d594fSAndroid Build Coastguard Worker   }
100*795d594fSAndroid Build Coastguard Worker 
MemMapSize()101*795d594fSAndroid Build Coastguard Worker   size_t MemMapSize() const {
102*795d594fSAndroid Build Coastguard Worker     return mem_map_.BaseSize();
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker   /*
106*795d594fSAndroid Build Coastguard Worker    * Modify cards in the range from scan_begin (inclusive) to scan_end (exclusive). Each card
107*795d594fSAndroid Build Coastguard Worker    * value v is replaced by visitor(v). Visitor() should not have side-effects.
108*795d594fSAndroid Build Coastguard Worker    * Whenever a card value is changed, modified(card_address, old_value, new_value) is invoked.
109*795d594fSAndroid Build Coastguard Worker    * For opportunistic performance reasons, this assumes that visitor(kCardClean) is kCardClean!
110*795d594fSAndroid Build Coastguard Worker    */
111*795d594fSAndroid Build Coastguard Worker   template <typename Visitor, typename ModifiedVisitor>
112*795d594fSAndroid Build Coastguard Worker   void ModifyCardsAtomic(uint8_t* scan_begin,
113*795d594fSAndroid Build Coastguard Worker                          uint8_t* scan_end,
114*795d594fSAndroid Build Coastguard Worker                          const Visitor& visitor,
115*795d594fSAndroid Build Coastguard Worker                          const ModifiedVisitor& modified);
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker   // For every dirty at least minumum age between begin and end invoke the visitor with the
118*795d594fSAndroid Build Coastguard Worker   // specified argument. Returns how many cards the visitor was run on.
119*795d594fSAndroid Build Coastguard Worker   template <bool kClearCard, typename Visitor>
120*795d594fSAndroid Build Coastguard Worker   size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap,
121*795d594fSAndroid Build Coastguard Worker               uint8_t* scan_begin,
122*795d594fSAndroid Build Coastguard Worker               uint8_t* scan_end,
123*795d594fSAndroid Build Coastguard Worker               const Visitor& visitor,
124*795d594fSAndroid Build Coastguard Worker               const uint8_t minimum_age = kCardDirty)
125*795d594fSAndroid Build Coastguard Worker       REQUIRES(Locks::heap_bitmap_lock_)
126*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_);
127*795d594fSAndroid Build Coastguard Worker 
128*795d594fSAndroid Build Coastguard Worker   // Assertion used to check the given address is covered by the card table
129*795d594fSAndroid Build Coastguard Worker   void CheckAddrIsInCardTable(const uint8_t* addr) const;
130*795d594fSAndroid Build Coastguard Worker 
131*795d594fSAndroid Build Coastguard Worker   // Resets all of the bytes in the card table to clean.
132*795d594fSAndroid Build Coastguard Worker   void ClearCardTable();
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker   // Clear a range of cards that covers start to end, start and end must be aligned to kCardSize.
135*795d594fSAndroid Build Coastguard Worker   void ClearCardRange(uint8_t* start, uint8_t* end);
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker   // Returns the first address in the heap which maps to this card.
138*795d594fSAndroid Build Coastguard Worker   void* AddrFromCard(const uint8_t *card_addr) const ALWAYS_INLINE;
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker   // Returns the address of the relevant byte in the card table, given an address on the heap.
141*795d594fSAndroid Build Coastguard Worker   uint8_t* CardFromAddr(const void *addr) const ALWAYS_INLINE;
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker   bool AddrIsInCardTable(const void* addr) const;
144*795d594fSAndroid Build Coastguard Worker 
145*795d594fSAndroid Build Coastguard Worker  private:
146*795d594fSAndroid Build Coastguard Worker   CardTable(MemMap&& mem_map, uint8_t* biased_begin, size_t offset);
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker   // Returns true iff the card table address is within the bounds of the card table.
149*795d594fSAndroid Build Coastguard Worker   bool IsValidCard(const uint8_t* card_addr) const ALWAYS_INLINE;
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker   void CheckCardValid(uint8_t* card) const ALWAYS_INLINE;
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker   // Verifies that all gray objects are on a dirty card.
154*795d594fSAndroid Build Coastguard Worker   void VerifyCardTable();
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   // Mmapped pages for the card table
157*795d594fSAndroid Build Coastguard Worker   MemMap mem_map_;
158*795d594fSAndroid Build Coastguard Worker   // Value used to compute card table addresses from object addresses, see GetBiasedBegin
159*795d594fSAndroid Build Coastguard Worker   uint8_t* const biased_begin_;
160*795d594fSAndroid Build Coastguard Worker   // Card table doesn't begin at the beginning of the mem_map_, instead it is displaced by offset
161*795d594fSAndroid Build Coastguard Worker   // to allow the byte value of `biased_begin_` to equal `kCardDirty`.
162*795d594fSAndroid Build Coastguard Worker   const size_t offset_;
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker   DISALLOW_IMPLICIT_CONSTRUCTORS(CardTable);
165*795d594fSAndroid Build Coastguard Worker };
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker }  // namespace accounting
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker class AgeCardVisitor {
170*795d594fSAndroid Build Coastguard Worker  public:
operator()171*795d594fSAndroid Build Coastguard Worker   uint8_t operator()(uint8_t card) const {
172*795d594fSAndroid Build Coastguard Worker     return (card == accounting::CardTable::kCardDirty) ? card - 1 : 0;
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker };
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker }  // namespace gc
177*795d594fSAndroid Build Coastguard Worker }  // namespace art
178*795d594fSAndroid Build Coastguard Worker 
179*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_H_
180