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   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