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
25namespace art {
26
27class InternTableTest : public CommonRuntimeTest {};
28
29TEST_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
49TEST_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
63class TestPredicate {
64 public:
65  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
78  void Expect(const mirror::String* s) {
79    expected_.push_back(s);
80  }
81
82  ~TestPredicate() {
83    EXPECT_EQ(0U, expected_.size());
84  }
85
86 private:
87  mutable std::vector<const mirror::String*> expected_;
88};
89
90mirror::Object* IsMarkedSweepingCallback(mirror::Object* object, void* arg) {
91  if (reinterpret_cast<TestPredicate*>(arg)->IsMarked(object)) {
92    return object;
93  }
94  return nullptr;
95}
96
97TEST_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
130TEST_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