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 {
35 namespace gc {
36
37 class SystemWeakTest : public CommonRuntimeTest {
38 };
39
40 struct CountingSystemWeakHolder : public SystemWeakHolder {
CountingSystemWeakHolderart::gc::CountingSystemWeakHolder41 CountingSystemWeakHolder()
42 : SystemWeakHolder(kAllocTrackerLock),
43 allow_count_(0),
44 disallow_count_(0),
45 sweep_count_(0) {}
46
Allowart::gc::CountingSystemWeakHolder47 void Allow() override
48 REQUIRES_SHARED(Locks::mutator_lock_)
49 REQUIRES(!allow_disallow_lock_) {
50 SystemWeakHolder::Allow();
51
52 allow_count_++;
53 }
54
Disallowart::gc::CountingSystemWeakHolder55 void Disallow() override
56 REQUIRES_SHARED(Locks::mutator_lock_)
57 REQUIRES(!allow_disallow_lock_) {
58 SystemWeakHolder::Disallow();
59
60 disallow_count_++;
61 }
62
Broadcastart::gc::CountingSystemWeakHolder63 void Broadcast(bool broadcast_for_checkpoint) override
64 REQUIRES(!allow_disallow_lock_) {
65 SystemWeakHolder::Broadcast(broadcast_for_checkpoint);
66
67 if (!broadcast_for_checkpoint) {
68 // Don't count the broadcasts for running checkpoints.
69 allow_count_++;
70 }
71 }
72
Sweepart::gc::CountingSystemWeakHolder73 void Sweep(IsMarkedVisitor* visitor) override
74 REQUIRES_SHARED(Locks::mutator_lock_)
75 REQUIRES(!allow_disallow_lock_) {
76 MutexLock mu(Thread::Current(), allow_disallow_lock_);
77 mirror::Object* old_object = weak_.Read<kWithoutReadBarrier>();
78 mirror::Object* new_object = old_object == nullptr ? nullptr : visitor->IsMarked(old_object);
79 weak_ = GcRoot<mirror::Object>(new_object);
80
81 sweep_count_++;
82 }
83
Getart::gc::CountingSystemWeakHolder84 GcRoot<mirror::Object> Get()
85 REQUIRES_SHARED(Locks::mutator_lock_)
86 REQUIRES(!allow_disallow_lock_) {
87 Thread* self = Thread::Current();
88 MutexLock mu(self, allow_disallow_lock_);
89 Wait(self);
90
91 return weak_;
92 }
93
Setart::gc::CountingSystemWeakHolder94 void Set(GcRoot<mirror::Object> obj)
95 REQUIRES_SHARED(Locks::mutator_lock_)
96 REQUIRES(!allow_disallow_lock_) {
97 Thread* self = Thread::Current();
98 MutexLock mu(self, allow_disallow_lock_);
99 Wait(self);
100
101 weak_ = obj;
102 }
103
104 size_t allow_count_;
105 size_t disallow_count_;
106 size_t sweep_count_;
107 GcRoot<mirror::Object> weak_ GUARDED_BY(allow_disallow_lock_);
108 };
109
CollectorDoesAllowOrBroadcast()110 static bool CollectorDoesAllowOrBroadcast() {
111 CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
112 switch (type) {
113 case CollectorType::kCollectorTypeCMS:
114 case CollectorType::kCollectorTypeCC:
115 case CollectorType::kCollectorTypeSS:
116 case CollectorType::kCollectorTypeGSS:
117 return true;
118
119 default:
120 return false;
121 }
122 }
123
CollectorDoesDisallow()124 static bool CollectorDoesDisallow() {
125 CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
126 switch (type) {
127 case CollectorType::kCollectorTypeCMS:
128 return true;
129
130 default:
131 return false;
132 }
133 }
134
TEST_F(SystemWeakTest,Keep)135 TEST_F(SystemWeakTest, Keep) {
136 CountingSystemWeakHolder cswh;
137 Runtime::Current()->AddSystemWeakHolder(&cswh);
138
139 ScopedObjectAccess soa(Thread::Current());
140
141 StackHandleScope<1> hs(soa.Self());
142
143 // We use Strings because they are very easy to allocate.
144 Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
145 cswh.Set(GcRoot<mirror::Object>(s.Get()));
146
147 // Trigger a GC.
148 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
149
150 // Expect the holder to have been called.
151 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
152 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
153 EXPECT_EQ(1U, cswh.sweep_count_);
154
155 // Expect the weak to not be cleared.
156 EXPECT_FALSE(cswh.Get().IsNull());
157 EXPECT_EQ(cswh.Get().Read(), s.Get());
158 }
159
TEST_F(SystemWeakTest,Discard)160 TEST_F(SystemWeakTest, Discard) {
161 CountingSystemWeakHolder cswh;
162 Runtime::Current()->AddSystemWeakHolder(&cswh);
163
164 ScopedObjectAccess soa(Thread::Current());
165
166 cswh.Set(GcRoot<mirror::Object>(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
167
168 // Trigger a GC.
169 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
170
171 // Expect the holder to have been called.
172 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
173 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
174 EXPECT_EQ(1U, cswh.sweep_count_);
175
176 // Expect the weak to be cleared.
177 EXPECT_TRUE(cswh.Get().IsNull());
178 }
179
TEST_F(SystemWeakTest,Remove)180 TEST_F(SystemWeakTest, Remove) {
181 CountingSystemWeakHolder cswh;
182 Runtime::Current()->AddSystemWeakHolder(&cswh);
183
184 ScopedObjectAccess soa(Thread::Current());
185
186 StackHandleScope<1> hs(soa.Self());
187
188 // We use Strings because they are very easy to allocate.
189 Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
190 cswh.Set(GcRoot<mirror::Object>(s.Get()));
191
192 // Trigger a GC.
193 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
194
195 // Expect the holder to have been called.
196 ASSERT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
197 ASSERT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
198 ASSERT_EQ(1U, cswh.sweep_count_);
199
200 // Expect the weak to not be cleared.
201 ASSERT_FALSE(cswh.Get().IsNull());
202 ASSERT_EQ(cswh.Get().Read(), s.Get());
203
204 // Remove the holder.
205 Runtime::Current()->RemoveSystemWeakHolder(&cswh);
206
207 // Trigger another GC.
208 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false);
209
210 // Expectation: no change in the numbers.
211 EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
212 EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
213 EXPECT_EQ(1U, cswh.sweep_count_);
214 }
215
216 } // namespace gc
217 } // namespace art
218