Home | History | Annotate | Download | only in runtime
      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   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() != nullptr);
     42   EXPECT_TRUE(foo_2.Get() != nullptr);
     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 
     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:
     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 
     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 
     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 
    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