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   EXPECT_TRUE(foo_1->Equals("foo"));
39   EXPECT_TRUE(foo_2->Equals("foo"));
40   EXPECT_TRUE(foo_3->Equals("foo"));
41   EXPECT_TRUE(foo_1.Get() != NULL);
42   EXPECT_TRUE(foo_2.Get() != NULL);
43   EXPECT_EQ(foo_1.Get(), foo_2.Get());
44   EXPECT_NE(foo_1.Get(), bar.Get());
45   EXPECT_NE(foo_2.Get(), bar.Get());
46   EXPECT_NE(foo_3.Get(), bar.Get());
47 }
48 
TEST_F(InternTableTest,Size)49 TEST_F(InternTableTest, Size) {
50   ScopedObjectAccess soa(Thread::Current());
51   InternTable t;
52   EXPECT_EQ(0U, t.Size());
53   t.InternStrong(3, "foo");
54   StackHandleScope<1> hs(soa.Self());
55   Handle<mirror::String> foo(
56       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
57   t.InternWeak(foo.Get());
58   EXPECT_EQ(1U, t.Size());
59   t.InternStrong(3, "bar");
60   EXPECT_EQ(2U, t.Size());
61 }
62 
63 class TestPredicate {
64  public:
IsMarked(const mirror::Object * s) const65   bool IsMarked(const mirror::Object* s) const {
66     bool erased = false;
67     for (auto it = expected_.begin(), end = expected_.end(); it != end; ++it) {
68       if (*it == s) {
69         expected_.erase(it);
70         erased = true;
71         break;
72       }
73     }
74     EXPECT_TRUE(erased);
75     return false;
76   }
77 
Expect(const mirror::String * s)78   void Expect(const mirror::String* s) {
79     expected_.push_back(s);
80   }
81 
~TestPredicate()82   ~TestPredicate() {
83     EXPECT_EQ(0U, expected_.size());
84   }
85 
86  private:
87   mutable std::vector<const mirror::String*> expected_;
88 };
89 
IsMarkedSweepingCallback(mirror::Object * object,void * arg)90 mirror::Object* IsMarkedSweepingCallback(mirror::Object* object, void* arg) {
91   if (reinterpret_cast<TestPredicate*>(arg)->IsMarked(object)) {
92     return object;
93   }
94   return nullptr;
95 }
96 
TEST_F(InternTableTest,SweepInternTableWeaks)97 TEST_F(InternTableTest, SweepInternTableWeaks) {
98   ScopedObjectAccess soa(Thread::Current());
99   InternTable t;
100   t.InternStrong(3, "foo");
101   t.InternStrong(3, "bar");
102   StackHandleScope<5> hs(soa.Self());
103   Handle<mirror::String> hello(
104       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello")));
105   Handle<mirror::String> world(
106       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "world")));
107   Handle<mirror::String> s0(hs.NewHandle(t.InternWeak(hello.Get())));
108   Handle<mirror::String> s1(hs.NewHandle(t.InternWeak(world.Get())));
109 
110   EXPECT_EQ(4U, t.Size());
111 
112   // We should traverse only the weaks...
113   TestPredicate p;
114   p.Expect(s0.Get());
115   p.Expect(s1.Get());
116   {
117     ReaderMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
118     t.SweepInternTableWeaks(IsMarkedSweepingCallback, &p);
119   }
120 
121   EXPECT_EQ(2U, t.Size());
122 
123   // Just check that we didn't corrupt the map.
124   Handle<mirror::String> still_here(
125       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "still here")));
126   t.InternWeak(still_here.Get());
127   EXPECT_EQ(3U, t.Size());
128 }
129 
TEST_F(InternTableTest,ContainsWeak)130 TEST_F(InternTableTest, ContainsWeak) {
131   ScopedObjectAccess soa(Thread::Current());
132   {
133     // Strongs are never weak.
134     InternTable t;
135     StackHandleScope<2> hs(soa.Self());
136     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
137     EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
138     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
139     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
140     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
141   }
142 
143   {
144     // Weaks are always weak.
145     InternTable t;
146     StackHandleScope<4> hs(soa.Self());
147     Handle<mirror::String> foo_1(
148         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
149     Handle<mirror::String> foo_2(
150         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
151     EXPECT_NE(foo_1.Get(), foo_2.Get());
152     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo_1.Get())));
153     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo_2.Get())));
154     EXPECT_TRUE(t.ContainsWeak(interned_foo_2.Get()));
155     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
156   }
157 
158   {
159     // A weak can be promoted to a strong.
160     InternTable t;
161     StackHandleScope<3> hs(soa.Self());
162     Handle<mirror::String> foo(
163         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
164     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo.Get())));
165     EXPECT_TRUE(t.ContainsWeak(interned_foo_1.Get()));
166     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
167     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
168     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
169   }
170 
171   {
172     // Interning a weak after a strong gets you the strong.
173     InternTable t;
174     StackHandleScope<3> hs(soa.Self());
175     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
176     EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
177     Handle<mirror::String> foo(
178         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
179     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo.Get())));
180     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
181     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
182   }
183 }
184 
185 }  // namespace art
186