• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-alloc-inl.h"
28 #include "obj_ptr.h"
29 #include "scoped_thread_state_change-inl.h"
30 
31 namespace art HIDDEN {
32 namespace mirror {
33 
34 class CollectRootVisitor {
35  public:
CollectRootVisitor()36   CollectRootVisitor() {}
37 
38   template <class MirrorType>
VisitRootIfNonNull(GcRoot<MirrorType> & root) const39   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>
VisitRootIfNonNull(mirror::CompressedReference<MirrorType> * root) const47   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>
VisitRoot(GcRoot<MirrorType> & root) const55   void VisitRoot(GcRoot<MirrorType>& root) const REQUIRES_SHARED(Locks::mutator_lock_) {
56     VisitRoot(root.AddressWithoutBarrier());
57   }
58 
59   template <class MirrorType>
VisitRoot(mirror::CompressedReference<MirrorType> * root) const60   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  protected:
ClassTableTest()71   ClassTableTest() {
72     use_boot_image_ = true;  // Make the Runtime creation cheaper.
73   }
74 };
75 
TEST_F(ClassTableTest,ClassTable)76 TEST_F(ClassTableTest, ClassTable) {
77   ScopedObjectAccess soa(Thread::Current());
78   jobject jclass_loader = LoadDex("XandY");
79   VariableSizedHandleScope hs(soa.Self());
80   Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
81   const char* descriptor_x = "LX;";
82   const char* descriptor_y = "LY;";
83   Handle<mirror::Class> h_X(
84       hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_x, class_loader)));
85   Handle<mirror::Class> h_Y(
86       hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
87   Handle<mirror::Object> obj_X = hs.NewHandle(h_X->AllocObject(soa.Self()));
88   ASSERT_TRUE(obj_X != nullptr);
89   ClassTable table;
90   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
91   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
92 
93   // Add h_X to the class table.
94   table.Insert(h_X.Get());
95   EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
96   EXPECT_OBJ_PTR_EQ(table.Lookup(descriptor_x, ComputeModifiedUtf8Hash(descriptor_x)), h_X.Get());
97   EXPECT_TRUE(table.Lookup("NOT_THERE", ComputeModifiedUtf8Hash("NOT_THERE")) == nullptr);
98   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
99   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
100 
101   // Create the zygote snapshot and ensure the accounting is correct.
102   table.FreezeSnapshot();
103   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
104   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
105 
106   // Test inserting and related lookup functions.
107   EXPECT_TRUE(table.LookupByDescriptor(h_Y.Get()) == nullptr);
108   table.Insert(h_Y.Get());
109   EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
110   EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_Y.Get()), h_Y.Get());
111 
112   EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
113   EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
114 
115   // Test adding / clearing strong roots.
116   EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
117   EXPECT_FALSE(table.InsertStrongRoot(obj_X.Get()));
118   table.ClearStrongRoots();
119   EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
120 
121   // Collect all the roots and make sure there is nothing missing.
122   CollectRootVisitor roots;
123   table.VisitRoots(roots);
124   EXPECT_TRUE(roots.roots_.find(h_X.Get()) != roots.roots_.end());
125   EXPECT_TRUE(roots.roots_.find(h_Y.Get()) != roots.roots_.end());
126   EXPECT_TRUE(roots.roots_.find(obj_X.Get()) != roots.roots_.end());
127 
128   // Checks that vising only classes works.
129   std::set<mirror::Class*> classes;
130   table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
131     classes.insert(klass.Ptr());
132     return true;
133   });
134   EXPECT_TRUE(classes.find(h_X.Get()) != classes.end());
135   EXPECT_TRUE(classes.find(h_Y.Get()) != classes.end());
136   EXPECT_EQ(classes.size(), 2u);
137   classes.clear();
138   table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
139     classes.insert(klass.Ptr());
140     // Return false to exit the Visit early.
141     return false;
142   });
143   EXPECT_EQ(classes.size(), 1u);
144 
145   // Test that reading a class set from memory works.
146   ClassTable::ClassSet temp_set;
147   table.Visit([&temp_set](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
148     temp_set.insert(ClassTable::TableSlot(klass));
149     return true;
150   });
151   const size_t count = temp_set.WriteToMemory(nullptr);
152   std::unique_ptr<uint8_t[]> buffer(new uint8_t[count]());
153   ASSERT_EQ(temp_set.WriteToMemory(&buffer[0]), count);
154   ClassTable table2;
155   size_t count2 = table2.ReadFromMemory(&buffer[0]);
156   EXPECT_EQ(count, count2);
157   // Strong roots are not serialized, only classes.
158   EXPECT_OBJ_PTR_EQ(table2.LookupByDescriptor(h_X.Get()), h_X.Get());
159   EXPECT_OBJ_PTR_EQ(table2.LookupByDescriptor(h_Y.Get()), h_Y.Get());
160 
161   // TODO: Add tests for UpdateClass, InsertOatFile.
162 }
163 
164 }  // namespace mirror
165 }  // namespace art
166