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