blob: d9f53ed6a21bc0bbba74e6c11748ab37139481d5 [file] [log] [blame]
Mathieu Chartierdb70ce52016-12-12 11:06:59 -08001/*
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"
David Sehr9e734c72018-01-04 17:56:19 -080023#include "dex/dex_file.h"
Mathieu Chartierdb70ce52016-12-12 11:06:59 -080024#include "gc/accounting/card_table-inl.h"
25#include "gc/heap.h"
26#include "handle_scope-inl.h"
Andreas Gampe70f5fd02018-10-24 19:58:37 -070027#include "mirror/class-alloc-inl.h"
Mathieu Chartierdb70ce52016-12-12 11:06:59 -080028#include "obj_ptr.h"
29#include "scoped_thread_state_change-inl.h"
30
31namespace art {
32namespace mirror {
33
34class 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
69class ClassTableTest : public CommonRuntimeTest {};
70
71TEST_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()));
Andreas Gampefa4333d2017-02-14 11:10:34 -080083 ASSERT_TRUE(obj_X != nullptr);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -080084 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());
Vladimir Marko1fe58392019-04-10 16:14:56 +010090 EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
91 EXPECT_OBJ_PTR_EQ(table.Lookup(descriptor_x, ComputeModifiedUtf8Hash(descriptor_x)), h_X.Get());
92 EXPECT_TRUE(table.Lookup("NOT_THERE", ComputeModifiedUtf8Hash("NOT_THERE")) == nullptr);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -080093 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.
Vladimir Marko1fe58392019-04-10 16:14:56 +0100102 EXPECT_TRUE(table.LookupByDescriptor(h_Y.Get()) == nullptr);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800103 table.Insert(h_Y.Get());
Vladimir Marko1fe58392019-04-10 16:14:56 +0100104 EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
105 EXPECT_OBJ_PTR_EQ(table.LookupByDescriptor(h_Y.Get()), h_Y.Get());
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800106
107 EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
108 EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
109
110 // Test adding / clearing strong roots.
111 EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
112 EXPECT_FALSE(table.InsertStrongRoot(obj_X.Get()));
113 table.ClearStrongRoots();
114 EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
115
116 // Collect all the roots and make sure there is nothing missing.
117 CollectRootVisitor roots;
118 table.VisitRoots(roots);
119 EXPECT_TRUE(roots.roots_.find(h_X.Get()) != roots.roots_.end());
120 EXPECT_TRUE(roots.roots_.find(h_Y.Get()) != roots.roots_.end());
121 EXPECT_TRUE(roots.roots_.find(obj_X.Get()) != roots.roots_.end());
122
123 // Checks that vising only classes works.
124 std::set<mirror::Class*> classes;
125 table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
126 classes.insert(klass.Ptr());
127 return true;
128 });
129 EXPECT_TRUE(classes.find(h_X.Get()) != classes.end());
130 EXPECT_TRUE(classes.find(h_Y.Get()) != classes.end());
131 EXPECT_EQ(classes.size(), 2u);
132 classes.clear();
133 table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
134 classes.insert(klass.Ptr());
135 // Return false to exit the Visit early.
136 return false;
137 });
138 EXPECT_EQ(classes.size(), 1u);
139
140 // Test remove.
141 table.Remove(descriptor_x);
Vladimir Marko1dab5752021-02-25 15:41:33 +0000142 EXPECT_TRUE(table.LookupByDescriptor(h_X.Get()) == nullptr);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800143
Vladimir Marko4c796aa2021-01-15 10:04:45 +0000144 // Test that reading a class set from memory works.
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800145 table.Insert(h_X.Get());
Vladimir Marko4c796aa2021-01-15 10:04:45 +0000146 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);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800152 std::unique_ptr<uint8_t[]> buffer(new uint8_t[count]());
Vladimir Marko4c796aa2021-01-15 10:04:45 +0000153 ASSERT_EQ(temp_set.WriteToMemory(&buffer[0]), count);
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800154 ClassTable table2;
155 size_t count2 = table2.ReadFromMemory(&buffer[0]);
156 EXPECT_EQ(count, count2);
157 // Strong roots are not serialized, only classes.
Vladimir Marko1dab5752021-02-25 15:41:33 +0000158 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());
Mathieu Chartierdb70ce52016-12-12 11:06:59 -0800160
161 // TODO: Add tests for UpdateClass, InsertOatFile.
162}
163
164} // namespace mirror
165} // namespace art