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 "base/hash_set.h"
     20 #include "common_runtime_test.h"
     21 #include "gc_root-inl.h"
     22 #include "mirror/object.h"
     23 #include "handle_scope-inl.h"
     24 #include "mirror/string.h"
     25 #include "scoped_thread_state_change-inl.h"
     26 
     27 namespace art {
     28 
     29 class InternTableTest : public CommonRuntimeTest {};
     30 
     31 TEST_F(InternTableTest, Intern) {
     32   ScopedObjectAccess soa(Thread::Current());
     33   InternTable intern_table;
     34   StackHandleScope<4> hs(soa.Self());
     35   Handle<mirror::String> foo_1(hs.NewHandle(intern_table.InternStrong(3, "foo")));
     36   Handle<mirror::String> foo_2(hs.NewHandle(intern_table.InternStrong(3, "foo")));
     37   Handle<mirror::String> foo_3(
     38       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
     39   Handle<mirror::String> bar(hs.NewHandle(intern_table.InternStrong(3, "bar")));
     40   ASSERT_TRUE(foo_1 != nullptr);
     41   ASSERT_TRUE(foo_2 != nullptr);
     42   ASSERT_TRUE(foo_3 != nullptr);
     43   ASSERT_TRUE(bar != nullptr);
     44   EXPECT_EQ(foo_1.Get(), foo_2.Get());
     45   EXPECT_TRUE(foo_1->Equals("foo"));
     46   EXPECT_TRUE(foo_2->Equals("foo"));
     47   EXPECT_TRUE(foo_3->Equals("foo"));
     48   EXPECT_NE(foo_1.Get(), bar.Get());
     49   EXPECT_NE(foo_2.Get(), bar.Get());
     50   EXPECT_NE(foo_3.Get(), bar.Get());
     51 }
     52 
     53 TEST_F(InternTableTest, Size) {
     54   ScopedObjectAccess soa(Thread::Current());
     55   InternTable t;
     56   EXPECT_EQ(0U, t.Size());
     57   t.InternStrong(3, "foo");
     58   StackHandleScope<1> hs(soa.Self());
     59   Handle<mirror::String> foo(
     60       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
     61   t.InternWeak(foo.Get());
     62   EXPECT_EQ(1U, t.Size());
     63   t.InternStrong(3, "bar");
     64   EXPECT_EQ(2U, t.Size());
     65 }
     66 
     67 // Check if table indexes match on 64 and 32 bit machines.
     68 // This is done by ensuring hash values are the same on every machine and limited to 32-bit wide.
     69 // Otherwise cross compilation can cause a table to be filled on host using one indexing algorithm
     70 // and later on a device with different sizeof(size_t) can use another indexing algorithm.
     71 // Thus the table may provide wrong data.
     72 TEST_F(InternTableTest, CrossHash) {
     73   ScopedObjectAccess soa(Thread::Current());
     74   InternTable t;
     75 
     76   // A string that has a negative hash value.
     77   GcRoot<mirror::String> str(mirror::String::AllocFromModifiedUtf8(soa.Self(), "00000000"));
     78 
     79   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
     80   for (InternTable::Table::UnorderedSet& table : t.strong_interns_.tables_) {
     81     // The negative hash value shall be 32-bit wide on every host.
     82     ASSERT_TRUE(IsUint<32>(table.hashfn_(str)));
     83   }
     84 }
     85 
     86 class TestPredicate : public IsMarkedVisitor {
     87  public:
     88   mirror::Object* IsMarked(mirror::Object* s) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     89     bool erased = false;
     90     for (auto it = expected_.begin(), end = expected_.end(); it != end; ++it) {
     91       if (*it == s) {
     92         expected_.erase(it);
     93         erased = true;
     94         break;
     95       }
     96     }
     97     EXPECT_TRUE(erased);
     98     return nullptr;
     99   }
    100 
    101   void Expect(const mirror::String* s) {
    102     expected_.push_back(s);
    103   }
    104 
    105   ~TestPredicate() {
    106     EXPECT_EQ(0U, expected_.size());
    107   }
    108 
    109  private:
    110   mutable std::vector<const mirror::String*> expected_;
    111 };
    112 
    113 TEST_F(InternTableTest, SweepInternTableWeaks) {
    114   ScopedObjectAccess soa(Thread::Current());
    115   InternTable t;
    116   t.InternStrong(3, "foo");
    117   t.InternStrong(3, "bar");
    118   StackHandleScope<5> hs(soa.Self());
    119   Handle<mirror::String> hello(
    120       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello")));
    121   Handle<mirror::String> world(
    122       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "world")));
    123   Handle<mirror::String> s0(hs.NewHandle(t.InternWeak(hello.Get())));
    124   Handle<mirror::String> s1(hs.NewHandle(t.InternWeak(world.Get())));
    125 
    126   EXPECT_EQ(4U, t.Size());
    127 
    128   // We should traverse only the weaks...
    129   TestPredicate p;
    130   p.Expect(s0.Get());
    131   p.Expect(s1.Get());
    132   {
    133     ReaderMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
    134     t.SweepInternTableWeaks(&p);
    135   }
    136 
    137   EXPECT_EQ(2U, t.Size());
    138 
    139   // Just check that we didn't corrupt the map.
    140   Handle<mirror::String> still_here(
    141       hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "still here")));
    142   t.InternWeak(still_here.Get());
    143   EXPECT_EQ(3U, t.Size());
    144 }
    145 
    146 TEST_F(InternTableTest, ContainsWeak) {
    147   ScopedObjectAccess soa(Thread::Current());
    148   {
    149     // Strongs are never weak.
    150     InternTable t;
    151     StackHandleScope<2> hs(soa.Self());
    152     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
    153     EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
    154     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
    155     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
    156     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
    157   }
    158 
    159   {
    160     // Weaks are always weak.
    161     InternTable t;
    162     StackHandleScope<4> hs(soa.Self());
    163     Handle<mirror::String> foo_1(
    164         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
    165     Handle<mirror::String> foo_2(
    166         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
    167     EXPECT_NE(foo_1.Get(), foo_2.Get());
    168     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo_1.Get())));
    169     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo_2.Get())));
    170     EXPECT_TRUE(t.ContainsWeak(interned_foo_2.Get()));
    171     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
    172   }
    173 
    174   {
    175     // A weak can be promoted to a strong.
    176     InternTable t;
    177     StackHandleScope<3> hs(soa.Self());
    178     Handle<mirror::String> foo(
    179         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
    180     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternWeak(foo.Get())));
    181     EXPECT_TRUE(t.ContainsWeak(interned_foo_1.Get()));
    182     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternStrong(3, "foo")));
    183     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
    184     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
    185   }
    186 
    187   {
    188     // Interning a weak after a strong gets you the strong.
    189     InternTable t;
    190     StackHandleScope<3> hs(soa.Self());
    191     Handle<mirror::String> interned_foo_1(hs.NewHandle(t.InternStrong(3, "foo")));
    192     EXPECT_FALSE(t.ContainsWeak(interned_foo_1.Get()));
    193     Handle<mirror::String> foo(
    194         hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "foo")));
    195     Handle<mirror::String> interned_foo_2(hs.NewHandle(t.InternWeak(foo.Get())));
    196     EXPECT_FALSE(t.ContainsWeak(interned_foo_2.Get()));
    197     EXPECT_EQ(interned_foo_1.Get(), interned_foo_2.Get());
    198   }
    199 }
    200 
    201 TEST_F(InternTableTest, LookupStrong) {
    202   ScopedObjectAccess soa(Thread::Current());
    203   InternTable intern_table;
    204   StackHandleScope<3> hs(soa.Self());
    205   Handle<mirror::String> foo(hs.NewHandle(intern_table.InternStrong(3, "foo")));
    206   Handle<mirror::String> bar(hs.NewHandle(intern_table.InternStrong(3, "bar")));
    207   Handle<mirror::String> foobar(hs.NewHandle(intern_table.InternStrong(6, "foobar")));
    208   ASSERT_TRUE(foo != nullptr);
    209   ASSERT_TRUE(bar != nullptr);
    210   ASSERT_TRUE(foobar != nullptr);
    211   ASSERT_TRUE(foo->Equals("foo"));
    212   ASSERT_TRUE(bar->Equals("bar"));
    213   ASSERT_TRUE(foobar->Equals("foobar"));
    214   ASSERT_NE(foo.Get(), bar.Get());
    215   ASSERT_NE(foo.Get(), foobar.Get());
    216   ASSERT_NE(bar.Get(), foobar.Get());
    217   ObjPtr<mirror::String> lookup_foo = intern_table.LookupStrong(soa.Self(), 3, "foo");
    218   EXPECT_OBJ_PTR_EQ(lookup_foo, foo.Get());
    219   ObjPtr<mirror::String> lookup_bar = intern_table.LookupStrong(soa.Self(), 3, "bar");
    220   EXPECT_OBJ_PTR_EQ(lookup_bar, bar.Get());
    221   ObjPtr<mirror::String> lookup_foobar = intern_table.LookupStrong(soa.Self(), 6, "foobar");
    222   EXPECT_OBJ_PTR_EQ(lookup_foobar, foobar.Get());
    223   ObjPtr<mirror::String> lookup_foox = intern_table.LookupStrong(soa.Self(), 4, "foox");
    224   EXPECT_TRUE(lookup_foox == nullptr);
    225   ObjPtr<mirror::String> lookup_fooba = intern_table.LookupStrong(soa.Self(), 5, "fooba");
    226   EXPECT_TRUE(lookup_fooba == nullptr);
    227   ObjPtr<mirror::String> lookup_foobaR = intern_table.LookupStrong(soa.Self(), 6, "foobaR");
    228   EXPECT_TRUE(lookup_foobaR == nullptr);
    229   // Try a hash conflict.
    230   ASSERT_EQ(ComputeUtf16HashFromModifiedUtf8("foobar", 6),
    231             ComputeUtf16HashFromModifiedUtf8("foobbS", 6));
    232   ObjPtr<mirror::String> lookup_foobbS = intern_table.LookupStrong(soa.Self(), 6, "foobbS");
    233   EXPECT_TRUE(lookup_foobbS == nullptr);
    234 }
    235 
    236 }  // namespace art
    237