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 "intern_table.h" 18 19 #include "common_runtime_test.h" 20 #include "mirror/object.h" 21 #include "handle_scope-inl.h" 22 #include "mirror/string.h" 23 #include "scoped_thread_state_change.h" 24 25 namespace art { 26 27 class InternTableTest : public CommonRuntimeTest {}; 28 29 TEST_F(InternTableTest, Intern) { 30 ScopedObjectAccess soa(Thread::Current()); 31 InternTable intern_table; 32 StackHandleScope<4> hs(soa.Self()); 33 Handle<mirror::String> foo_1(hs.NewHandle(intern_table.InternStrong(3, "foo"))); 34 Handle<mirror::String> foo_2(hs.NewHandle(intern_table.InternStrong(3, "foo"))); 35 Handle<mirror::String> foo_3( 36 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 37 Handle<mirror::String> bar(hs.NewHandle(intern_table.InternStrong(3, "bar"))); 38 ASSERT_TRUE(foo_1.Get() != nullptr); 39 ASSERT_TRUE(foo_2.Get() != nullptr); 40 ASSERT_TRUE(foo_3.Get() != nullptr); 41 ASSERT_TRUE(bar.Get() != nullptr); 42 EXPECT_EQ(foo_1.Get(), foo_2.Get()); 43 EXPECT_TRUE(foo_1->Equals("foo")); 44 EXPECT_TRUE(foo_2->Equals("foo")); 45 EXPECT_TRUE(foo_3->Equals("foo")); 46 EXPECT_NE(foo_1.Get(), bar.Get()); 47 EXPECT_NE(foo_2.Get(), bar.Get()); 48 EXPECT_NE(foo_3.Get(), bar.Get()); 49 } 50 51 TEST_F(InternTableTest, Size) { 52 ScopedObjectAccess soa(Thread::Current()); 53 InternTable t; 54 EXPECT_EQ(0U, t.Size()); 55 t.InternStrong(3, "foo"); 56 StackHandleScope<1> hs(soa.Self()); 57 Handle<mirror::String> foo( 58 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 59 t.InternWeak(foo.Get()); 60 EXPECT_EQ(1U, t.Size()); 61 t.InternStrong(3, "bar"); 62 EXPECT_EQ(2U, t.Size()); 63 } 64 65 class TestPredicate : public IsMarkedVisitor { 66 public: 67 mirror::Object* IsMarked(mirror::Object* s) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { 68 bool erased = false; 69 for (auto it = expected_.begin(), end = expected_.end(); it != end; ++it) { 70 if (*it == s) { 71 expected_.erase(it); 72 erased = true; 73 break; 74 } 75 } 76 EXPECT_TRUE(erased); 77 return nullptr; 78 } 79 80 void Expect(const mirror::String* s) { 81 expected_.push_back(s); 82 } 83 84 ~TestPredicate() { 85 EXPECT_EQ(0U, expected_.size()); 86 } 87 88 private: 89 mutable std::vector<const mirror::String*> expected_; 90 }; 91 92 TEST_F(InternTableTest, SweepInternTableWeaks) { 93 ScopedObjectAccess soa(Thread::Current()); 94 InternTable t; 95 t.InternStrong(3, "foo"); 96 t.InternStrong(3, "bar"); 97 StackHandleScope<5> hs(soa.Self()); 98 Handle<mirror::String> hello( 99 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"))); 100 Handle<mirror::String> world( 101 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "world"))); 102 Handle<mirror::String> s0(hs.NewHandle(t.InternWeak(hello.Get()))); 103 Handle<mirror::String> s1(hs.NewHandle(t.InternWeak(world.Get()))); 104 105 EXPECT_EQ(4U, t.Size()); 106 107 // We should traverse only the weaks... 108 TestPredicate p; 109 p.Expect(s0.Get()); 110 p.Expect(s1.Get()); 111 { 112 ReaderMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_); 113 t.SweepInternTableWeaks(&p); 114 } 115 116 EXPECT_EQ(2U, t.Size()); 117 118 // Just check that we didn't corrupt the map. 119 Handle<mirror::String> still_here( 120 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "still here"))); 121 t.InternWeak(still_here.Get()); 122 EXPECT_EQ(3U, t.Size()); 123 } 124 125 TEST_F(InternTableTest, ContainsWeak) { 126 ScopedObjectAccess soa(Thread::Current()); 127 { 128 // Strongs are never weak. 129 InternTable t; 130 StackHandleScope<2> hs(soa.Self()); 131 Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo"))); 132 EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get())); 133 Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo"))); 134 EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get())); 135 EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get()); 136 } 137 138 { 139 // Weaks are always weak. 140 InternTable t; 141 StackHandleScope<4> hs(soa.Self()); 142 Handle<mirror::String> foo_1( 143 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 144 Handle<mirror::String> foo_2( 145 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 146 EXPECT_NE(foo_1.Get(), foo_2.Get()); 147 Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo_1.Get()))); 148 Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo_2.Get()))); 149 EXPECT_TRUE(t.ContainsWeak(interned_foo_2.Get())); 150 EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get()); 151 } 152 153 { 154 // A weak can be promoted to a strong. 155 InternTable t; 156 StackHandleScope<3> hs(soa.Self()); 157 Handle<mirror::String> foo( 158 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 159 Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo.Get()))); 160 EXPECT_TRUE(t.ContainsWeak(interned_foo_1.Get())); 161 Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo"))); 162 EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get())); 163 EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get()); 164 } 165 166 { 167 // Interning a weak after a strong gets you the strong. 168 InternTable t; 169 StackHandleScope<3> hs(soa.Self()); 170 Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo"))); 171 EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get())); 172 Handle<mirror::String> foo( 173 hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo"))); 174 Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo.Get()))); 175 EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get())); 176 EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get()); 177 } 178 } 179 180 TEST_F(InternTableTest, LookupStrong) { 181 ScopedObjectAccess soa(Thread::Current()); 182 InternTable intern_table; 183 StackHandleScope<3> hs(soa.Self()); 184 Handle<mirror::String> foo(hs.NewHandle(intern_table.InternStrong(3, "foo"))); 185 Handle<mirror::String> bar(hs.NewHandle(intern_table.InternStrong(3, "bar"))); 186 Handle<mirror::String> foobar(hs.NewHandle(intern_table.InternStrong(6, "foobar"))); 187 ASSERT_TRUE(foo.Get() != nullptr); 188 ASSERT_TRUE(bar.Get() != nullptr); 189 ASSERT_TRUE(foobar.Get() != nullptr); 190 ASSERT_TRUE(foo->Equals("foo")); 191 ASSERT_TRUE(bar->Equals("bar")); 192 ASSERT_TRUE(foobar->Equals("foobar")); 193 ASSERT_NE(foo.Get(), bar.Get()); 194 ASSERT_NE(foo.Get(), foobar.Get()); 195 ASSERT_NE(bar.Get(), foobar.Get()); 196 mirror::String* lookup_foo = intern_table.LookupStrong(soa.Self(), 3, "foo"); 197 EXPECT_EQ(lookup_foo, foo.Get()); 198 mirror::String* lookup_bar = intern_table.LookupStrong(soa.Self(), 3, "bar"); 199 EXPECT_EQ(lookup_bar, bar.Get()); 200 mirror::String* lookup_foobar = intern_table.LookupStrong(soa.Self(), 6, "foobar"); 201 EXPECT_EQ(lookup_foobar, foobar.Get()); 202 mirror::String* lookup_foox = intern_table.LookupStrong(soa.Self(), 4, "foox"); 203 EXPECT_TRUE(lookup_foox == nullptr); 204 mirror::String* lookup_fooba = intern_table.LookupStrong(soa.Self(), 5, "fooba"); 205 EXPECT_TRUE(lookup_fooba == nullptr); 206 mirror::String* lookup_foobaR = intern_table.LookupStrong(soa.Self(), 6, "foobaR"); 207 EXPECT_TRUE(lookup_foobaR == nullptr); 208 // Try a hash conflict. 209 ASSERT_EQ(ComputeUtf16HashFromModifiedUtf8("foobar", 6), 210 ComputeUtf16HashFromModifiedUtf8("foobbS", 6)); 211 mirror::String* lookup_foobbS = intern_table.LookupStrong(soa.Self(), 6, "foobbS"); 212 EXPECT_TRUE(lookup_foobbS == nullptr); 213 } 214 215 } // namespace art 216