1 /*
2 * Copyright (C) 2016 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 "system_weak.h"
18
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <memory>
22
23 #include "base/mutex.h"
24 #include "collector_type.h"
25 #include "common_runtime_test.h"
26 #include "gc_root-inl.h"
27 #include "handle_scope-inl.h"
28 #include "heap.h"
29 #include "mirror/object-inl.h"
30 #include "mirror/string.h"
31 #include "scoped_thread_state_change-inl.h"
32 #include "thread_list.h"
33
34 namespace art HIDDEN {
35 namespace gc {
36
37 class SystemWeakTest : public CommonRuntimeTest {
38 protected:
SystemWeakTest()39 SystemWeakTest() {
40 use_boot_image_ = true; // Make the Runtime creation cheaper.
41 }
42 };
43
44 struct CountingSystemWeakHolder : public SystemWeakHolder {
CountingSystemWeakHolderart::gc::CountingSystemWeakHolder45 CountingSystemWeakHolder()
46 : SystemWeakHolder(kAllocTrackerLock),
47 allow_count_(0),
48 disallow_count_(0),
49 sweep_count_(0) {}
50
Allowart::gc::CountingSystemWeakHolder51 void Allow() override
52 REQUIRES_SHARED(Locks::mutator_lock_)
53 REQUIRES(!allow_disallow_lock_) {
54 SystemWeakHolder::Allow();
55
56 allow_count_++;
57 }
58
Disallowart::gc::CountingSystemWeakHolder59 void Disallow() override
60 REQUIRES_SHARED(Locks::mutator_lock_)
61 REQUIRES(!allow_disallow_lock_) {
62 SystemWeakHolder::Disallow();
63
64 disallow_count_++;
65 }
66
Broadcastart::gc::CountingSystemWeakHolder67 void Broadcast(bool broadcast_for_checkpoint) override
68 REQUIRES(!allow_disallow_lock_) {
69 SystemWeakHolder::Broadcast(broadcast_for_checkpoint);
70
71 if (!broadcast_for_checkpoint) {
72 // Don't count the broadcasts for running checkpoints.
73 allow_count_++;
74 }
75 }
76
Sweepart::gc::CountingSystemWeakHolder77 void Sweep(IsMarkedVisitor* visitor) override
78 REQUIRES_SHARED(Locks::mutator_lock_)
79 REQUIRES(!allow_disallow_lock_) {
80 MutexLock mu(Thread::Current(), allow_disallow_lock_);
81 mirror::Object* old_object = weak_.Read<kWithoutReadBarrier>();
82 mirror::Object* new_object = old_object == nullptr ? nullptr : visitor->IsMarked(old_object);
83 weak_ = GcRoot<mirror::Object>(new_object);
84
85 sweep_count_++;
86 }
87
Getart::gc::CountingSystemWeakHolder88 GcRoot<mirror::Object> Get()
89 REQUIRES_SHARED(Locks::mutator_lock_)
90 REQUIRES(!allow_disallow_lock_) {
91 Thread* self = Thread::Current();
92 MutexLock mu(self, allow_disallow_lock_);
93 Wait(self);
94
95 return weak_;
96 }
97
Setart::gc::CountingSystemWeakHolder98 void Set(GcRoot<mirror::Object> obj)
99 REQUIRES_SHARED(Locks::mutator_lock_)
100 REQUIRES(!allow_disallow_lock_) {
101 Thread* self = Thread::Current();
102 MutexLock mu(self, allow_disallow_lock_);
103 Wait(self);
104
105 weak_ = obj;
106 }
107
108 size_t allow_count_;
109 size_t disallow_count_;
110 size_t sweep_count_;
111 GcRoot<mirror::Object> weak_ GUARDED_BY(allow_disallow_lock_);
112 };
113
CollectorDoesAllowOrBroadcast()114 static bool CollectorDoesAllowOrBroadcast() {
115 CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
116 switch (type) {
117 case CollectorType::kCollectorTypeCMS:
118 case CollectorType::kCollectorTypeCMC:
119 case CollectorType::kCollectorTypeCC:
120 case CollectorType::kCollectorTypeSS:
121 return true;
122
123 default:
124 return false;
125 }
126 }
127
CollectorDoesDisallow()128 static bool CollectorDoesDisallow() {
129 CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
130 switch (type) {
131 case CollectorType::kCollectorTypeCMS:
132 case CollectorType::kCollectorTypeCMC:
133 return true;
134
135 default:
136 return false;
137 }
138 }
139
TEST_F(SystemWeakTest,Keep)140 TEST_F(SystemWeakTest, Keep) {
141 CountingSystemWeakHolder cswh;
142 Runtime::Current()->AddSystemWeakHolder(&cswh);
143
144 ScopedObjectAccess soa(Thread::Current());
145
146 StackHandleScope<1> hs(soa.Self());
147
148 // We use Strings because they are very easy to allocate.
149 Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
150 cswh.Set(GcRoot<mirror::Object>(s.Get()));
151
152 // Trigger a GC.
153 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
154
155 // Expect the holder to have been called.
156 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
157 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
158 // Userfaultfd GC uses SweepSystemWeaks also for concurrent updation.
159 // TODO: Explore this can be reverted back to unconditionally compare with 1
160 // once concurrent updation of native roots is full implemented in userfaultfd
161 // GC.
162 size_t expected_sweep_count = gUseUserfaultfd ? 2U : 1U;
163 EXPECT_EQ(expected_sweep_count, cswh.sweep_count_);
164
165 // Expect the weak to not be cleared.
166 EXPECT_FALSE(cswh.Get().IsNull());
167 EXPECT_EQ(cswh.Get().Read(), s.Get());
168 }
169
TEST_F(SystemWeakTest,Discard)170 TEST_F(SystemWeakTest, Discard) {
171 CountingSystemWeakHolder cswh;
172 Runtime::Current()->AddSystemWeakHolder(&cswh);
173
174 ScopedObjectAccess soa(Thread::Current());
175
176 cswh.Set(GcRoot<mirror::Object>(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
177
178 // Trigger a GC.
179 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
180
181 // Expect the holder to have been called.
182 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
183 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
184 // Userfaultfd GC uses SweepSystemWeaks also for concurrent updation.
185 // TODO: Explore this can be reverted back to unconditionally compare with 1
186 // once concurrent updation of native roots is full implemented in userfaultfd
187 // GC.
188 size_t expected_sweep_count = gUseUserfaultfd ? 2U : 1U;
189 EXPECT_EQ(expected_sweep_count, cswh.sweep_count_);
190
191 // Expect the weak to be cleared.
192 EXPECT_TRUE(cswh.Get().IsNull());
193 }
194
TEST_F(SystemWeakTest,Remove)195 TEST_F(SystemWeakTest, Remove) {
196 CountingSystemWeakHolder cswh;
197 Runtime::Current()->AddSystemWeakHolder(&cswh);
198
199 ScopedObjectAccess soa(Thread::Current());
200
201 StackHandleScope<1> hs(soa.Self());
202
203 // We use Strings because they are very easy to allocate.
204 Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
205 cswh.Set(GcRoot<mirror::Object>(s.Get()));
206
207 // Trigger a GC.
208 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
209
210 // Expect the holder to have been called.
211 ASSERT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
212 ASSERT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
213 // Userfaultfd GC uses SweepSystemWeaks also for concurrent updation.
214 // TODO: Explore this can be reverted back to unconditionally compare with 1
215 // once concurrent updation of native roots is full implemented in userfaultfd
216 // GC.
217 size_t expected_sweep_count = gUseUserfaultfd ? 2U : 1U;
218 EXPECT_EQ(expected_sweep_count, cswh.sweep_count_);
219
220 // Expect the weak to not be cleared.
221 ASSERT_FALSE(cswh.Get().IsNull());
222 ASSERT_EQ(cswh.Get().Read(), s.Get());
223
224 // Remove the holder.
225 Runtime::Current()->RemoveSystemWeakHolder(&cswh);
226
227 // Trigger another GC.
228 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
229
230 // Expectation: no change in the numbers.
231 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
232 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
233 EXPECT_EQ(expected_sweep_count, cswh.sweep_count_);
234 }
235
236 } // namespace gc
237 } // namespace art
238