• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 "indirect_reference_table-inl.h"
18 
19 #include "android-base/stringprintf.h"
20 
21 #include "class_linker-inl.h"
22 #include "common_runtime_test.h"
23 #include "mirror/class-alloc-inl.h"
24 #include "mirror/object-inl.h"
25 #include "scoped_thread_state_change-inl.h"
26 
27 namespace art HIDDEN {
28 
29 using android::base::StringPrintf;
30 
31 class IndirectReferenceTableTest : public CommonRuntimeTest {
32  protected:
IndirectReferenceTableTest()33   IndirectReferenceTableTest() {
34     use_boot_image_ = true;  // Make the Runtime creation cheaper.
35   }
36 };
37 
CheckDump(IndirectReferenceTable * irt,size_t num_objects,size_t num_unique)38 static void CheckDump(IndirectReferenceTable* irt, size_t num_objects, size_t num_unique)
39     REQUIRES_SHARED(Locks::mutator_lock_) {
40   std::ostringstream oss;
41   irt->Dump(oss);
42   if (num_objects == 0) {
43     EXPECT_EQ(oss.str().find("java.lang.Object"), std::string::npos) << oss.str();
44   } else if (num_objects == 1) {
45     EXPECT_NE(oss.str().find("1 of java.lang.Object"), std::string::npos) << oss.str();
46   } else {
47     EXPECT_NE(oss.str().find(StringPrintf("%zd of java.lang.Object (%zd unique instances)",
48                                           num_objects, num_unique)),
49               std::string::npos)
50                   << "\n Expected number of objects: " << num_objects
51                   << "\n Expected unique objects: " << num_unique << "\n"
52                   << oss.str();
53   }
54 }
55 
TEST_F(IndirectReferenceTableTest,BasicTest)56 TEST_F(IndirectReferenceTableTest, BasicTest) {
57   // This will lead to error messages in the log.
58   ScopedLogSeverity sls(LogSeverity::FATAL);
59 
60   ScopedObjectAccess soa(Thread::Current());
61   static const size_t kTableMax = 20;
62   IndirectReferenceTable irt(kGlobal);
63   std::string error_msg;
64   bool success = irt.Initialize(kTableMax, &error_msg);
65   ASSERT_TRUE(success) << error_msg;
66 
67   StackHandleScope<5> hs(soa.Self());
68   Handle<mirror::Class> c =
69       hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;"));
70   ASSERT_TRUE(c != nullptr);
71   Handle<mirror::Object> obj0 = hs.NewHandle(c->AllocObject(soa.Self()));
72   ASSERT_TRUE(obj0 != nullptr);
73   Handle<mirror::Object> obj1 = hs.NewHandle(c->AllocObject(soa.Self()));
74   ASSERT_TRUE(obj1 != nullptr);
75   Handle<mirror::Object> obj2 = hs.NewHandle(c->AllocObject(soa.Self()));
76   ASSERT_TRUE(obj2 != nullptr);
77   Handle<mirror::Object> obj3 = hs.NewHandle(c->AllocObject(soa.Self()));
78   ASSERT_TRUE(obj3 != nullptr);
79 
80   CheckDump(&irt, 0, 0);
81 
82   IndirectRef iref0 = (IndirectRef) 0x11110;
83   EXPECT_FALSE(irt.Remove(iref0)) << "unexpectedly successful removal";
84 
85   // Add three, check, remove in the order in which they were added.
86   iref0 = irt.Add(obj0.Get(), &error_msg);
87   EXPECT_TRUE(iref0 != nullptr);
88   CheckDump(&irt, 1, 1);
89   IndirectRef iref1 = irt.Add(obj1.Get(), &error_msg);
90   EXPECT_TRUE(iref1 != nullptr);
91   CheckDump(&irt, 2, 2);
92   IndirectRef iref2 = irt.Add(obj2.Get(), &error_msg);
93   EXPECT_TRUE(iref2 != nullptr);
94   CheckDump(&irt, 3, 3);
95 
96   EXPECT_OBJ_PTR_EQ(obj0.Get(), irt.Get(iref0));
97   EXPECT_OBJ_PTR_EQ(obj1.Get(), irt.Get(iref1));
98   EXPECT_OBJ_PTR_EQ(obj2.Get(), irt.Get(iref2));
99 
100   EXPECT_TRUE(irt.Remove(iref0));
101   CheckDump(&irt, 2, 2);
102   EXPECT_TRUE(irt.Remove(iref1));
103   CheckDump(&irt, 1, 1);
104   EXPECT_TRUE(irt.Remove(iref2));
105   CheckDump(&irt, 0, 0);
106 
107   // Table should be empty now.
108   EXPECT_EQ(0U, irt.Capacity());
109 
110   // Check that the entry off the end of the list is not valid.
111   // (CheckJNI shall abort for such entries.)
112   EXPECT_FALSE(irt.IsValidReference(iref0, &error_msg));
113 
114   // Add three, remove in the opposite order.
115   iref0 = irt.Add(obj0.Get(), &error_msg);
116   EXPECT_TRUE(iref0 != nullptr);
117   iref1 = irt.Add(obj1.Get(), &error_msg);
118   EXPECT_TRUE(iref1 != nullptr);
119   iref2 = irt.Add(obj2.Get(), &error_msg);
120   EXPECT_TRUE(iref2 != nullptr);
121   CheckDump(&irt, 3, 3);
122 
123   ASSERT_TRUE(irt.Remove(iref2));
124   CheckDump(&irt, 2, 2);
125   ASSERT_TRUE(irt.Remove(iref1));
126   CheckDump(&irt, 1, 1);
127   ASSERT_TRUE(irt.Remove(iref0));
128   CheckDump(&irt, 0, 0);
129 
130   // Table should be empty now.
131   ASSERT_EQ(0U, irt.Capacity());
132 
133   // Add three, remove middle / middle / bottom / top.  (Second attempt
134   // to remove middle should fail.)
135   iref0 = irt.Add(obj0.Get(), &error_msg);
136   EXPECT_TRUE(iref0 != nullptr);
137   iref1 = irt.Add(obj1.Get(), &error_msg);
138   EXPECT_TRUE(iref1 != nullptr);
139   iref2 = irt.Add(obj2.Get(), &error_msg);
140   EXPECT_TRUE(iref2 != nullptr);
141   CheckDump(&irt, 3, 3);
142 
143   ASSERT_EQ(3U, irt.Capacity());
144 
145   ASSERT_TRUE(irt.Remove(iref1));
146   CheckDump(&irt, 2, 2);
147   ASSERT_FALSE(irt.Remove(iref1));
148   CheckDump(&irt, 2, 2);
149 
150   // Check that the reference to the hole is not valid.
151   EXPECT_FALSE(irt.IsValidReference(iref1, &error_msg));
152 
153   ASSERT_TRUE(irt.Remove(iref2));
154   CheckDump(&irt, 1, 1);
155   ASSERT_TRUE(irt.Remove(iref0));
156   CheckDump(&irt, 0, 0);
157 
158   // Table should be empty now.
159   ASSERT_EQ(0U, irt.Capacity());
160 
161   // Add four entries.  Remove #1, add new entry, verify that table size
162   // is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
163   // that we delete one and don't hole-compact the other.
164   iref0 = irt.Add(obj0.Get(), &error_msg);
165   EXPECT_TRUE(iref0 != nullptr);
166   iref1 = irt.Add(obj1.Get(), &error_msg);
167   EXPECT_TRUE(iref1 != nullptr);
168   iref2 = irt.Add(obj2.Get(), &error_msg);
169   EXPECT_TRUE(iref2 != nullptr);
170   IndirectRef iref3 = irt.Add(obj3.Get(), &error_msg);
171   EXPECT_TRUE(iref3 != nullptr);
172   CheckDump(&irt, 4, 4);
173 
174   ASSERT_TRUE(irt.Remove(iref1));
175   CheckDump(&irt, 3, 3);
176 
177   iref1 = irt.Add(obj1.Get(), &error_msg);
178   EXPECT_TRUE(iref1 != nullptr);
179 
180   ASSERT_EQ(4U, irt.Capacity()) << "hole not filled";
181   CheckDump(&irt, 4, 4);
182 
183   ASSERT_TRUE(irt.Remove(iref1));
184   CheckDump(&irt, 3, 3);
185   ASSERT_TRUE(irt.Remove(iref3));
186   CheckDump(&irt, 2, 2);
187 
188   ASSERT_EQ(3U, irt.Capacity()) << "should be 3 after two deletions";
189 
190   ASSERT_TRUE(irt.Remove(iref2));
191   CheckDump(&irt, 1, 1);
192   ASSERT_TRUE(irt.Remove(iref0));
193   CheckDump(&irt, 0, 0);
194 
195   ASSERT_EQ(0U, irt.Capacity()) << "not empty after split remove";
196 
197   // Add an entry, remove it, add a new entry, and try to use the original
198   // iref.  They have the same slot number but are for different objects.
199   // With the extended checks in place, this should fail.
200   iref0 = irt.Add(obj0.Get(), &error_msg);
201   EXPECT_TRUE(iref0 != nullptr);
202   CheckDump(&irt, 1, 1);
203   ASSERT_TRUE(irt.Remove(iref0));
204   CheckDump(&irt, 0, 0);
205   iref1 = irt.Add(obj1.Get(), &error_msg);
206   EXPECT_TRUE(iref1 != nullptr);
207   CheckDump(&irt, 1, 1);
208   ASSERT_FALSE(irt.Remove(iref0)) << "mismatched del succeeded";
209   CheckDump(&irt, 1, 1);
210   ASSERT_TRUE(irt.Remove(iref1)) << "switched del failed";
211   ASSERT_EQ(0U, irt.Capacity()) << "switching del not empty";
212   CheckDump(&irt, 0, 0);
213 
214   // Same as above, but with the same object.  A more rigorous checker
215   // (e.g. with slot serialization) will catch this.
216   iref0 = irt.Add(obj0.Get(), &error_msg);
217   EXPECT_TRUE(iref0 != nullptr);
218   CheckDump(&irt, 1, 1);
219   ASSERT_TRUE(irt.Remove(iref0));
220   CheckDump(&irt, 0, 0);
221   iref1 = irt.Add(obj0.Get(), &error_msg);
222   EXPECT_TRUE(iref1 != nullptr);
223   CheckDump(&irt, 1, 1);
224   if (iref0 != iref1) {
225     // Try 0, should not work.
226     ASSERT_FALSE(irt.Remove(iref0)) << "temporal del succeeded";
227   }
228   ASSERT_TRUE(irt.Remove(iref1)) << "temporal cleanup failed";
229   ASSERT_EQ(0U, irt.Capacity()) << "temporal del not empty";
230   CheckDump(&irt, 0, 0);
231 
232   // Stale reference is not valid.
233   iref0 = irt.Add(obj0.Get(), &error_msg);
234   EXPECT_TRUE(iref0 != nullptr);
235   CheckDump(&irt, 1, 1);
236   ASSERT_TRUE(irt.Remove(iref0));
237   EXPECT_FALSE(irt.IsValidReference(iref0, &error_msg)) << "stale lookup succeeded";
238   CheckDump(&irt, 0, 0);
239 
240   // Test deleting all but the last entry.
241   // We shall delete these.
242   static const size_t kTableInitial = kTableMax / 2;
243   IndirectRef manyRefs[kTableInitial];
244   for (size_t i = 0; i < kTableInitial; i++) {
245     manyRefs[i] = irt.Add(obj0.Get(), &error_msg);
246     ASSERT_TRUE(manyRefs[i] != nullptr) << "Failed adding " << i;
247     CheckDump(&irt, i + 1, 1);
248   }
249   // We shall keep this one.
250   iref0 = irt.Add(obj0.Get(), &error_msg);
251   ASSERT_TRUE(iref0 != nullptr);
252   ASSERT_EQ(kTableInitial + 1, irt.Capacity());
253   CheckDump(&irt, kTableInitial + 1, 1);
254   // Delete all but the last entry.
255   for (size_t i = 0; i < kTableInitial; i++) {
256     ASSERT_TRUE(irt.Remove(manyRefs[i])) << "failed removing " << i;
257     CheckDump(&irt, kTableInitial - i, 1);
258   }
259   // Because of removal order, should have 11 entries, 10 of them holes.
260   ASSERT_EQ(kTableInitial + 1, irt.Capacity());
261 
262   ASSERT_TRUE(irt.Remove(iref0)) << "multi-remove final failed";
263 
264   ASSERT_EQ(0U, irt.Capacity()) << "multi-del not empty";
265   CheckDump(&irt, 0, 0);
266 }
267 
268 }  // namespace art
269