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 
TEST_F(InternTableTest,Intern)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 
TEST_F(InternTableTest,Size)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:
IsMarked(mirror::Object * s)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 
Expect(const mirror::String * s)80   void Expect(const mirror::String* s) {
81     expected_.push_back(s);
82   }
83 
~TestPredicate()84   ~TestPredicate() {
85     EXPECT_EQ(0U, expected_.size());
86   }
87 
88  private:
89   mutable std::vector<const mirror::String*> expected_;
90 };
91 
TEST_F(InternTableTest,SweepInternTableWeaks)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 
TEST_F(InternTableTest,ContainsWeak)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 
TEST_F(InternTableTest,LookupStrong)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