1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 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 #include "card_table-inl.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <string>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include "base/atomic.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/common_art_test.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "mirror/string-inl.h" // Strings are easiest to allocate
27*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "thread_pool.h"
29*795d594fSAndroid Build Coastguard Worker
30*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker namespace mirror {
33*795d594fSAndroid Build Coastguard Worker class Object;
34*795d594fSAndroid Build Coastguard Worker } // namespace mirror
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker namespace gc {
37*795d594fSAndroid Build Coastguard Worker namespace accounting {
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker class CardTableTest : public CommonArtTest {
40*795d594fSAndroid Build Coastguard Worker public:
41*795d594fSAndroid Build Coastguard Worker std::unique_ptr<CardTable> card_table_;
42*795d594fSAndroid Build Coastguard Worker
CommonSetup()43*795d594fSAndroid Build Coastguard Worker void CommonSetup() {
44*795d594fSAndroid Build Coastguard Worker if (card_table_.get() == nullptr) {
45*795d594fSAndroid Build Coastguard Worker card_table_.reset(CardTable::Create(heap_begin_, heap_size_));
46*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(card_table_.get() != nullptr);
47*795d594fSAndroid Build Coastguard Worker } else {
48*795d594fSAndroid Build Coastguard Worker ClearCardTable();
49*795d594fSAndroid Build Coastguard Worker }
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker // Default values for the test, not random to avoid undeterministic behaviour.
CardTableTest()52*795d594fSAndroid Build Coastguard Worker CardTableTest() : heap_begin_(reinterpret_cast<uint8_t*>(0x2000000)), heap_size_(2 * MB) {
53*795d594fSAndroid Build Coastguard Worker }
ClearCardTable()54*795d594fSAndroid Build Coastguard Worker void ClearCardTable() {
55*795d594fSAndroid Build Coastguard Worker card_table_->ClearCardTable();
56*795d594fSAndroid Build Coastguard Worker }
HeapBegin() const57*795d594fSAndroid Build Coastguard Worker uint8_t* HeapBegin() const {
58*795d594fSAndroid Build Coastguard Worker return heap_begin_;
59*795d594fSAndroid Build Coastguard Worker }
HeapLimit() const60*795d594fSAndroid Build Coastguard Worker uint8_t* HeapLimit() const {
61*795d594fSAndroid Build Coastguard Worker return HeapBegin() + heap_size_;
62*795d594fSAndroid Build Coastguard Worker }
63*795d594fSAndroid Build Coastguard Worker // Return a non-zero pseudo random card for an address.
PseudoRandomCard(const uint8_t * addr) const64*795d594fSAndroid Build Coastguard Worker uint8_t PseudoRandomCard(const uint8_t* addr) const {
65*795d594fSAndroid Build Coastguard Worker size_t offset = RoundDown(addr - heap_begin_, CardTable::kCardSize);
66*795d594fSAndroid Build Coastguard Worker return 1 + offset % 254;
67*795d594fSAndroid Build Coastguard Worker }
FillRandom()68*795d594fSAndroid Build Coastguard Worker void FillRandom() {
69*795d594fSAndroid Build Coastguard Worker for (const uint8_t* addr = HeapBegin(); addr != HeapLimit(); addr += CardTable::kCardSize) {
70*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(card_table_->AddrIsInCardTable(addr));
71*795d594fSAndroid Build Coastguard Worker uint8_t* card = card_table_->CardFromAddr(addr);
72*795d594fSAndroid Build Coastguard Worker *card = PseudoRandomCard(addr);
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker
76*795d594fSAndroid Build Coastguard Worker private:
77*795d594fSAndroid Build Coastguard Worker uint8_t* const heap_begin_;
78*795d594fSAndroid Build Coastguard Worker const size_t heap_size_;
79*795d594fSAndroid Build Coastguard Worker };
80*795d594fSAndroid Build Coastguard Worker
TEST_F(CardTableTest,TestMarkCard)81*795d594fSAndroid Build Coastguard Worker TEST_F(CardTableTest, TestMarkCard) {
82*795d594fSAndroid Build Coastguard Worker CommonSetup();
83*795d594fSAndroid Build Coastguard Worker for (const uint8_t* addr = HeapBegin(); addr < HeapLimit(); addr += kObjectAlignment) {
84*795d594fSAndroid Build Coastguard Worker auto obj = reinterpret_cast<const mirror::Object*>(addr);
85*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardClean);
86*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(!card_table_->IsDirty(obj));
87*795d594fSAndroid Build Coastguard Worker card_table_->MarkCard(addr);
88*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(card_table_->IsDirty(obj));
89*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(card_table_->GetCard(obj), CardTable::kCardDirty);
90*795d594fSAndroid Build Coastguard Worker uint8_t* card_addr = card_table_->CardFromAddr(addr);
91*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(*card_addr, CardTable::kCardDirty);
92*795d594fSAndroid Build Coastguard Worker *card_addr = CardTable::kCardClean;
93*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(*card_addr, CardTable::kCardClean);
94*795d594fSAndroid Build Coastguard Worker }
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker class UpdateVisitor {
98*795d594fSAndroid Build Coastguard Worker public:
operator ()(uint8_t c) const99*795d594fSAndroid Build Coastguard Worker uint8_t operator()(uint8_t c) const {
100*795d594fSAndroid Build Coastguard Worker // Must map zero to zero. Never applied to zero.
101*795d594fSAndroid Build Coastguard Worker return c == 0 ? 0 : c * 93 + 123;
102*795d594fSAndroid Build Coastguard Worker }
operator ()(uint8_t *,uint8_t,uint8_t) const103*795d594fSAndroid Build Coastguard Worker void operator()(uint8_t* /*card*/, uint8_t /*expected_value*/, uint8_t /*new_value*/) const {
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker };
106*795d594fSAndroid Build Coastguard Worker
TEST_F(CardTableTest,TestModifyCardsAtomic)107*795d594fSAndroid Build Coastguard Worker TEST_F(CardTableTest, TestModifyCardsAtomic) {
108*795d594fSAndroid Build Coastguard Worker CommonSetup();
109*795d594fSAndroid Build Coastguard Worker FillRandom();
110*795d594fSAndroid Build Coastguard Worker const size_t delta = std::min(static_cast<size_t>(HeapLimit() - HeapBegin()),
111*795d594fSAndroid Build Coastguard Worker 8U * CardTable::kCardSize);
112*795d594fSAndroid Build Coastguard Worker UpdateVisitor visitor;
113*795d594fSAndroid Build Coastguard Worker size_t start_offset = 0;
114*795d594fSAndroid Build Coastguard Worker for (uint8_t* cstart = HeapBegin(); cstart < HeapBegin() + delta; cstart += CardTable::kCardSize) {
115*795d594fSAndroid Build Coastguard Worker start_offset = (start_offset + kObjectAlignment) % CardTable::kCardSize;
116*795d594fSAndroid Build Coastguard Worker size_t end_offset = 0;
117*795d594fSAndroid Build Coastguard Worker for (uint8_t* cend = HeapLimit() - delta; cend < HeapLimit(); cend += CardTable::kCardSize) {
118*795d594fSAndroid Build Coastguard Worker // Don't always start at a card boundary.
119*795d594fSAndroid Build Coastguard Worker uint8_t* start = cstart + start_offset;
120*795d594fSAndroid Build Coastguard Worker uint8_t* end = cend - end_offset;
121*795d594fSAndroid Build Coastguard Worker end_offset = (end_offset + kObjectAlignment) % CardTable::kCardSize;
122*795d594fSAndroid Build Coastguard Worker // Modify cards.
123*795d594fSAndroid Build Coastguard Worker card_table_->ModifyCardsAtomic(start, end, visitor, visitor);
124*795d594fSAndroid Build Coastguard Worker // Check adjacent cards not modified.
125*795d594fSAndroid Build Coastguard Worker for (uint8_t* cur = start - CardTable::kCardSize; cur >= HeapBegin();
126*795d594fSAndroid Build Coastguard Worker cur -= CardTable::kCardSize) {
127*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)),
128*795d594fSAndroid Build Coastguard Worker PseudoRandomCard(cur));
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker for (uint8_t* cur = end + CardTable::kCardSize; cur < HeapLimit();
131*795d594fSAndroid Build Coastguard Worker cur += CardTable::kCardSize) {
132*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(card_table_->GetCard(reinterpret_cast<mirror::Object*>(cur)),
133*795d594fSAndroid Build Coastguard Worker PseudoRandomCard(cur));
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker // Verify Range.
136*795d594fSAndroid Build Coastguard Worker for (uint8_t* cur = start; cur < AlignUp(end, CardTable::kCardSize);
137*795d594fSAndroid Build Coastguard Worker cur += CardTable::kCardSize) {
138*795d594fSAndroid Build Coastguard Worker uint8_t* card = card_table_->CardFromAddr(cur);
139*795d594fSAndroid Build Coastguard Worker uint8_t value = PseudoRandomCard(cur);
140*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(visitor(value), *card);
141*795d594fSAndroid Build Coastguard Worker // Restore for next iteration.
142*795d594fSAndroid Build Coastguard Worker *card = value;
143*795d594fSAndroid Build Coastguard Worker }
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker
148*795d594fSAndroid Build Coastguard Worker // TODO: Add test for CardTable::Scan.
149*795d594fSAndroid Build Coastguard Worker } // namespace accounting
150*795d594fSAndroid Build Coastguard Worker } // namespace gc
151*795d594fSAndroid Build Coastguard Worker } // namespace art
152