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