Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2016 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 "class_table-inl.h"
     18 
     19 #include "art_field-inl.h"
     20 #include "art_method-inl.h"
     21 #include "class_linker-inl.h"
     22 #include "common_runtime_test.h"
     23 #include "dex/dex_file.h"
     24 #include "gc/accounting/card_table-inl.h"
     25 #include "gc/heap.h"
     26 #include "handle_scope-inl.h"
     27 #include "mirror/class-inl.h"
     28 #include "obj_ptr.h"
     29 #include "scoped_thread_state_change-inl.h"
     30 
     31 namespace art {
     32 namespace mirror {
     33 
     34 class CollectRootVisitor {
     35  public:
     36   CollectRootVisitor() {}
     37 
     38   template <class MirrorType>
     39   ALWAYS_INLINE void VisitRootIfNonNull(GcRoot<MirrorType>& root) const
     40       REQUIRES_SHARED(Locks::mutator_lock_) {
     41     if (!root.IsNull()) {
     42       VisitRoot(root);
     43     }
     44   }
     45 
     46   template <class MirrorType>
     47   ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<MirrorType>* root) const
     48       REQUIRES_SHARED(Locks::mutator_lock_) {
     49     if (!root->IsNull()) {
     50       VisitRoot(root);
     51     }
     52   }
     53 
     54   template <class MirrorType>
     55   void VisitRoot(GcRoot<MirrorType>& root) const REQUIRES_SHARED(Locks::mutator_lock_) {
     56     VisitRoot(root.AddressWithoutBarrier());
     57   }
     58 
     59   template <class MirrorType>
     60   void VisitRoot(mirror::CompressedReference<MirrorType>* root) const
     61       REQUIRES_SHARED(Locks::mutator_lock_) {
     62     roots_.insert(root->AsMirrorPtr());
     63   }
     64 
     65   mutable std::set<mirror::Object*> roots_;
     66 };
     67 
     68 
     69 class ClassTableTest : public CommonRuntimeTest {};
     70 
     71 TEST_F(ClassTableTest, ClassTable) {
     72   ScopedObjectAccess soa(Thread::Current());
     73   jobject jclass_loader = LoadDex("XandY");
     74   VariableSizedHandleScope hs(soa.Self());
     75   Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
     76   const char* descriptor_x = "LX;";
     77   const char* descriptor_y = "LY;";
     78   Handle<mirror::Class> h_X(
     79       hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_x, class_loader)));
     80   Handle<mirror::Class> h_Y(
     81       hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
     82   Handle<mirror::Object> obj_X = hs.NewHandle(h_X->AllocObject(soa.Self()));
     83   ASSERT_TRUE(obj_X != nullptr);
     84   ClassTable table;
     85   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
     86   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
     87 
     88   // Add h_X to the class table.
     89   table.Insert(h_X.Get());
     90   EXPECT_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
     91   EXPECT_EQ(table.Lookup(descriptor_x, ComputeModifiedUtf8Hash(descriptor_x)), h_X.Get());
     92   EXPECT_EQ(table.Lookup("NOT_THERE", ComputeModifiedUtf8Hash("NOT_THERE")), nullptr);
     93   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
     94   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
     95 
     96   // Create the zygote snapshot and ensure the accounting is correct.
     97   table.FreezeSnapshot();
     98   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
     99   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
    100 
    101   // Test inserting and related lookup functions.
    102   EXPECT_EQ(table.LookupByDescriptor(h_Y.Get()), nullptr);
    103   EXPECT_FALSE(table.Contains(h_Y.Get()));
    104   table.Insert(h_Y.Get());
    105   EXPECT_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
    106   EXPECT_EQ(table.LookupByDescriptor(h_Y.Get()), h_Y.Get());
    107   EXPECT_TRUE(table.Contains(h_X.Get()));
    108   EXPECT_TRUE(table.Contains(h_Y.Get()));
    109 
    110   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
    111   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
    112 
    113   // Test adding / clearing strong roots.
    114   EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
    115   EXPECT_FALSE(table.InsertStrongRoot(obj_X.Get()));
    116   table.ClearStrongRoots();
    117   EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
    118 
    119   // Collect all the roots and make sure there is nothing missing.
    120   CollectRootVisitor roots;
    121   table.VisitRoots(roots);
    122   EXPECT_TRUE(roots.roots_.find(h_X.Get()) != roots.roots_.end());
    123   EXPECT_TRUE(roots.roots_.find(h_Y.Get()) != roots.roots_.end());
    124   EXPECT_TRUE(roots.roots_.find(obj_X.Get()) != roots.roots_.end());
    125 
    126   // Checks that vising only classes works.
    127   std::set<mirror::Class*> classes;
    128   table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
    129     classes.insert(klass.Ptr());
    130     return true;
    131   });
    132   EXPECT_TRUE(classes.find(h_X.Get()) != classes.end());
    133   EXPECT_TRUE(classes.find(h_Y.Get()) != classes.end());
    134   EXPECT_EQ(classes.size(), 2u);
    135   classes.clear();
    136   table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
    137     classes.insert(klass.Ptr());
    138     // Return false to exit the Visit early.
    139     return false;
    140   });
    141   EXPECT_EQ(classes.size(), 1u);
    142 
    143   // Test remove.
    144   table.Remove(descriptor_x);
    145   EXPECT_FALSE(table.Contains(h_X.Get()));
    146 
    147   // Test that WriteToMemory and ReadFromMemory work.
    148   table.Insert(h_X.Get());
    149   const size_t count = table.WriteToMemory(nullptr);
    150   std::unique_ptr<uint8_t[]> buffer(new uint8_t[count]());
    151   ASSERT_EQ(table.WriteToMemory(&buffer[0]), count);
    152   ClassTable table2;
    153   size_t count2 = table2.ReadFromMemory(&buffer[0]);
    154   EXPECT_EQ(count, count2);
    155   // Strong roots are not serialized, only classes.
    156   EXPECT_TRUE(table2.Contains(h_X.Get()));
    157   EXPECT_TRUE(table2.Contains(h_Y.Get()));
    158 
    159   // TODO: Add tests for UpdateClass, InsertOatFile.
    160 }
    161 
    162 }  // namespace mirror
    163 }  // namespace art
    164