1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "card_table-inl.h"
18 
19 #include <string>
20 
21 #include "atomic.h"
22 #include "common_runtime_test.h"
23 #include "handle_scope-inl.h"
24 #include "mirror/class-inl.h"
25 #include "mirror/string-inl.h"  // Strings are easiest to allocate
26 #include "scoped_thread_state_change.h"
27 #include "thread_pool.h"
28 #include "utils.h"
29 
30 namespace art {
31 
32 namespace mirror {
33   class Object;
34 }  // namespace mirror
35 
36 class CardTableTest : public CommonRuntimeTest {
37  public:
38   std::unique_ptr<gc::accounting::CardTable> card_table_;
39   static constexpr size_t kCardSize = gc::accounting::CardTable::kCardSize;
40 
CommonSetup()41   void CommonSetup() {
42     if (card_table_.get() == nullptr) {
43       card_table_.reset(gc::accounting::CardTable::Create(heap_begin_, heap_size_));
44       EXPECT_TRUE(card_table_.get() != nullptr);
45     } else {
46       ClearCardTable();
47     }
48   }
49   // Default values for the test, not random to avoid undeterministic behaviour.
CardTableTest()50   CardTableTest() : heap_begin_(reinterpret_cast<byte*>(0x2000000)), heap_size_(2 * MB) {
51   }
ClearCardTable()52   void ClearCardTable() {
53     card_table_->ClearCardTable();
54   }
HeapBegin() const55   byte* HeapBegin() const {
56     return heap_begin_;
57   }
HeapLimit() const58   byte* HeapLimit() const {
59     return HeapBegin() + heap_size_;
60   }
PRandCard(const byte * addr) const61   byte PRandCard(const byte* addr) const {
62     size_t offset = RoundDown(addr - heap_begin_, kCardSize);
63     return 1 + offset % 254;
64   }
FillRandom()65   void FillRandom() {
66     for (const byte* addr = HeapBegin(); addr != HeapLimit(); addr += kCardSize) {
67       EXPECT_TRUE(card_table_->AddrIsInCardTable(addr));
68       byte* card = card_table_->CardFromAddr(addr);
69       *card = PRandCard(addr);
70     }
71   }
72 
73  private:
74   byte* const heap_begin_;
75   const size_t heap_size_;
76 };
77 
TEST_F(CardTableTest,TestMarkCard)78 TEST_F(CardTableTest, TestMarkCard) {
79   CommonSetup();
80   for (const byte* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) {
81     auto obj = reinterpret_cast<const mirror::Object*>(addr);
82     EXPECT_EQ(card_table_->GetCard(obj), gc::accounting::CardTable::kCardClean);
83     EXPECT_TRUE(!card_table_->IsDirty(obj));
84     card_table_->MarkCard(addr);
85     EXPECT_TRUE(card_table_->IsDirty(obj));
86     EXPECT_EQ(card_table_->GetCard(obj), gc::accounting::CardTable::kCardDirty);
87     byte* card_addr = card_table_->CardFromAddr(addr);
88     EXPECT_EQ(*card_addr, gc::accounting::CardTable::kCardDirty);
89     *card_addr = gc::accounting::CardTable::kCardClean;
90     EXPECT_EQ(*card_addr, gc::accounting::CardTable::kCardClean);
91   }
92 }
93 
94 class UpdateVisitor {
95  public:
operator ()(byte c) const96   byte operator()(byte c) const {
97     return c * 93 + 123;
98   }
operator ()(byte *,byte,byte) const99   void operator()(byte* /*card*/, byte /*expected_value*/, byte /*new_value*/) const {
100   }
101 };
102 
TEST_F(CardTableTest,TestModifyCardsAtomic)103 TEST_F(CardTableTest, TestModifyCardsAtomic) {
104   CommonSetup();
105   FillRandom();
106   const size_t delta = std::min(static_cast<size_t>(HeapLimit() - HeapBegin()), 8U * kCardSize);
107   UpdateVisitor visitor;
108   size_t start_offset = 0;
109   for (byte* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += kCardSize) {
110     start_offset = (start_offset + kObjectAlignment) % kCardSize;
111     size_t end_offset = 0;
112     for (byte* cend = HeapLimit() - delta; cend < HeapLimit(); cend += kCardSize) {
113       // Don't always start at a card boundary.
114       byte* start = cstart + start_offset;
115       byte* end = cend - end_offset;
116       end_offset = (end_offset + kObjectAlignment) % kCardSize;
117       // Modify cards.
118       card_table_->ModifyCardsAtomic(start, end, visitor, visitor);
119       // Check adjacent cards not modified.
120       for (byte* cur = start - kCardSize; cur >= HeapBegin(); cur -= kCardSize) {
121         EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), PRandCard(cur));
122       }
123       for (byte* cur = end + kCardSize; cur < HeapLimit(); cur += kCardSize) {
124         EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)), PRandCard(cur));
125       }
126       // Verify Range.
127       for (byte* cur = start; cur < AlignUp(end, kCardSize); cur += kCardSize) {
128         byte* card = card_table_->CardFromAddr(cur);
129         byte value = PRandCard(cur);
130         if (visitor(value) != *card) {
131           LOG(ERROR) << reinterpret_cast<void*>(start) << " " << reinterpret_cast<void*>(cur) << " " << reinterpret_cast<void*>(end);
132         }
133         EXPECT_EQ(visitor(value), *card);
134         // Restore for next iteration.
135         *card = value;
136       }
137     }
138   }
139 }
140 
141 // TODO: Add test for CardTable::Scan.
142 
143 }  // namespace art
144