1 /* 2 * Copyright (C) 2011 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 "reference_table.h" 18 19 #include "android-base/stringprintf.h" 20 21 #include "art_method-inl.h" 22 #include "class_linker.h" 23 #include "common_runtime_test.h" 24 #include "handle_scope-inl.h" 25 #include "mirror/array-inl.h" 26 #include "mirror/class-inl.h" 27 #include "mirror/class_loader.h" 28 #include "mirror/string.h" 29 #include "primitive.h" 30 #include "runtime.h" 31 #include "scoped_thread_state_change-inl.h" 32 #include "thread-inl.h" 33 34 namespace art { 35 36 using android::base::StringPrintf; 37 38 class ReferenceTableTest : public CommonRuntimeTest {}; 39 40 static mirror::Object* CreateWeakReference(mirror::Object* referent) 41 REQUIRES_SHARED(Locks::mutator_lock_) { 42 Thread* self = Thread::Current(); 43 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 44 45 StackHandleScope<3> scope(self); 46 Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent)); 47 48 Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>( 49 class_linker->FindClass(self, 50 "Ljava/lang/ref/WeakReference;", 51 ScopedNullHandle<mirror::ClassLoader>()))); 52 CHECK(h_ref_class != nullptr); 53 CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true)); 54 55 Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>( 56 h_ref_class->AllocObject(self))); 57 CHECK(h_ref_instance != nullptr); 58 59 ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod( 60 "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize()); 61 CHECK(constructor != nullptr); 62 63 uint32_t args[2]; 64 args[0] = PointerToLowMemUInt32(h_ref_instance.Get()); 65 args[1] = PointerToLowMemUInt32(h_referent.Get()); 66 JValue result; 67 constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty()); 68 CHECK(!self->IsExceptionPending()); 69 70 return h_ref_instance.Get(); 71 } 72 73 TEST_F(ReferenceTableTest, Basics) { 74 ScopedObjectAccess soa(Thread::Current()); 75 mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); 76 77 ReferenceTable rt("test", 0, 11); 78 79 // Check dumping the empty table. 80 { 81 std::ostringstream oss; 82 rt.Dump(oss); 83 EXPECT_NE(oss.str().find("(empty)"), std::string::npos) << oss.str(); 84 EXPECT_EQ(0U, rt.Size()); 85 } 86 87 // Check removal of all nullss in a empty table is a no-op. 88 rt.Remove(nullptr); 89 EXPECT_EQ(0U, rt.Size()); 90 91 // Check removal of all o1 in a empty table is a no-op. 92 rt.Remove(o1); 93 EXPECT_EQ(0U, rt.Size()); 94 95 // Add o1 and check we have 1 element and can dump. 96 { 97 rt.Add(o1); 98 EXPECT_EQ(1U, rt.Size()); 99 std::ostringstream oss; 100 rt.Dump(oss); 101 EXPECT_NE(oss.str().find("1 of java.lang.String"), std::string::npos) << oss.str(); 102 EXPECT_EQ(oss.str().find("short[]"), std::string::npos) << oss.str(); 103 } 104 105 // Add a second object 10 times and check dumping is sane. 106 mirror::Object* o2 = mirror::ShortArray::Alloc(soa.Self(), 0); 107 for (size_t i = 0; i < 10; ++i) { 108 rt.Add(o2); 109 EXPECT_EQ(i + 2, rt.Size()); 110 std::ostringstream oss; 111 rt.Dump(oss); 112 EXPECT_NE(oss.str().find(StringPrintf("Last %zd entries (of %zd):", 113 i + 2 > 10 ? 10 : i + 2, 114 i + 2)), 115 std::string::npos) << oss.str(); 116 EXPECT_NE(oss.str().find("1 of java.lang.String"), std::string::npos) << oss.str(); 117 if (i == 0) { 118 EXPECT_NE(oss.str().find("1 of short[]"), std::string::npos) << oss.str(); 119 } else { 120 EXPECT_NE(oss.str().find(StringPrintf("%zd of short[] (1 unique instances)", i + 1)), 121 std::string::npos) << oss.str(); 122 } 123 } 124 125 // Remove o1 (first element). 126 { 127 rt.Remove(o1); 128 EXPECT_EQ(10U, rt.Size()); 129 std::ostringstream oss; 130 rt.Dump(oss); 131 EXPECT_EQ(oss.str().find("java.lang.String"), std::string::npos) << oss.str(); 132 } 133 134 // Remove o2 ten times. 135 for (size_t i = 0; i < 10; ++i) { 136 rt.Remove(o2); 137 EXPECT_EQ(9 - i, rt.Size()); 138 std::ostringstream oss; 139 rt.Dump(oss); 140 if (i == 9) { 141 EXPECT_EQ(oss.str().find("short[]"), std::string::npos) << oss.str(); 142 } else if (i == 8) { 143 EXPECT_NE(oss.str().find("1 of short[]"), std::string::npos) << oss.str(); 144 } else { 145 EXPECT_NE(oss.str().find(StringPrintf("%zd of short[] (1 unique instances)", 10 - i - 1)), 146 std::string::npos) << oss.str(); 147 } 148 } 149 150 // Add a reference and check that the type of the referent is dumped. 151 { 152 mirror::Object* empty_reference = CreateWeakReference(nullptr); 153 ASSERT_TRUE(empty_reference->IsReferenceInstance()); 154 rt.Add(empty_reference); 155 std::ostringstream oss; 156 rt.Dump(oss); 157 EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos) 158 << oss.str(); 159 } 160 161 { 162 mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A"); 163 mirror::Object* non_empty_reference = CreateWeakReference(string_referent); 164 ASSERT_TRUE(non_empty_reference->IsReferenceInstance()); 165 rt.Add(non_empty_reference); 166 std::ostringstream oss; 167 rt.Dump(oss); 168 EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"), 169 std::string::npos) 170 << oss.str(); 171 } 172 } 173 174 static std::vector<size_t> FindAll(const std::string& haystack, const char* needle) { 175 std::vector<size_t> res; 176 size_t start = 0; 177 do { 178 size_t pos = haystack.find(needle, start); 179 if (pos == std::string::npos) { 180 break; 181 } 182 res.push_back(pos); 183 start = pos + 1; 184 } while (start < haystack.size()); 185 return res; 186 } 187 188 TEST_F(ReferenceTableTest, SummaryOrder) { 189 // Check that the summary statistics are sorted. 190 ScopedObjectAccess soa(Thread::Current()); 191 192 ReferenceTable rt("test", 0, 20); 193 194 { 195 mirror::Object* s1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"); 196 mirror::Object* s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"); 197 198 // 3 copies of s1, 2 copies of s2, interleaved. 199 for (size_t i = 0; i != 2; ++i) { 200 rt.Add(s1); 201 rt.Add(s2); 202 } 203 rt.Add(s1); 204 } 205 206 { 207 // Differently sized byte arrays. Should be sorted by identical (non-unique cound). 208 mirror::Object* b1_1 = mirror::ByteArray::Alloc(soa.Self(), 1); 209 rt.Add(b1_1); 210 rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 211 rt.Add(b1_1); 212 rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 213 rt.Add(mirror::ByteArray::Alloc(soa.Self(), 1)); 214 rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2)); 215 } 216 217 rt.Add(mirror::CharArray::Alloc(soa.Self(), 0)); 218 219 // Now dump, and ensure order. 220 std::ostringstream oss; 221 rt.Dump(oss); 222 223 // Only do this on the part after Summary. 224 std::string base = oss.str(); 225 size_t summary_pos = base.find("Summary:"); 226 ASSERT_NE(summary_pos, std::string::npos); 227 228 std::string haystack = base.substr(summary_pos); 229 230 std::vector<size_t> strCounts = FindAll(haystack, "java.lang.String"); 231 std::vector<size_t> b1Counts = FindAll(haystack, "byte[] (1 elements)"); 232 std::vector<size_t> b2Counts = FindAll(haystack, "byte[] (2 elements)"); 233 std::vector<size_t> cCounts = FindAll(haystack, "char[]"); 234 235 // Only one each. 236 EXPECT_EQ(1u, strCounts.size()); 237 EXPECT_EQ(1u, b1Counts.size()); 238 EXPECT_EQ(1u, b2Counts.size()); 239 EXPECT_EQ(1u, cCounts.size()); 240 241 // Expect them to be in order. 242 EXPECT_LT(strCounts[0], b1Counts[0]); 243 EXPECT_LT(b1Counts[0], b2Counts[0]); 244 EXPECT_LT(b2Counts[0], cCounts[0]); 245 } 246 247 } // namespace art 248