bool ClassTable::Contains(ObjPtr<mirror::Class> klass) {
ReaderMutexLock mu(Thread::Current(), lock_);
+ TableSlot slot(klass);
for (ClassSet& class_set : classes_) {
- auto it = class_set.Find(TableSlot(klass));
+ auto it = class_set.Find(slot);
if (it != class_set.end()) {
return it->Read() == klass;
}
mirror::Class* ClassTable::LookupByDescriptor(ObjPtr<mirror::Class> klass) {
ReaderMutexLock mu(Thread::Current(), lock_);
+ TableSlot slot(klass);
for (ClassSet& class_set : classes_) {
- auto it = class_set.Find(TableSlot(klass));
+ auto it = class_set.Find(slot);
if (it != class_set.end()) {
return it->Read();
}
}
mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) {
- ReaderMutexLock mu(Thread::Current(), lock_);
DescriptorHashPair pair(descriptor, hash);
+ ReaderMutexLock mu(Thread::Current(), lock_);
for (ClassSet& class_set : classes_) {
auto it = class_set.FindWithHash(pair, hash);
if (it != class_set.end()) {
}
void ClassTable::Insert(ObjPtr<mirror::Class> klass) {
+ const uint32_t hash = TableSlot::HashDescriptor(klass);
WriterMutexLock mu(Thread::Current(), lock_);
- classes_.back().Insert(TableSlot(klass));
+ classes_.back().InsertWithHash(TableSlot(klass, hash), hash);
}
void ClassTable::InsertWithoutLocks(ObjPtr<mirror::Class> klass) {
- classes_.back().Insert(TableSlot(klass));
+ const uint32_t hash = TableSlot::HashDescriptor(klass);
+ classes_.back().InsertWithHash(TableSlot(klass, hash), hash);
}
void ClassTable::InsertWithHash(ObjPtr<mirror::Class> klass, size_t hash) {
}
bool ClassTable::Remove(const char* descriptor) {
- WriterMutexLock mu(Thread::Current(), lock_);
DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor));
+ WriterMutexLock mu(Thread::Current(), lock_);
for (ClassSet& class_set : classes_) {
auto it = class_set.Find(pair);
if (it != class_set.end()) {
strong_roots_.clear();
}
-ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass) {
+ClassTable::TableSlot::TableSlot(ObjPtr<mirror::Class> klass)
+ : TableSlot(klass, HashDescriptor(klass)) {}
+
+uint32_t ClassTable::TableSlot::HashDescriptor(ObjPtr<mirror::Class> klass) {
std::string temp;
- data_.StoreRelaxed(Encode(klass.Ptr(),
- MaskHash(ComputeModifiedUtf8Hash(klass->GetDescriptor(&temp)))));
+ return ComputeModifiedUtf8Hash(klass->GetDescriptor(&temp));
}
} // namespace art
--- /dev/null
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_table-inl.h"
+
+#include "art_field-inl.h"
+#include "art_method-inl.h"
+#include "class_linker-inl.h"
+#include "common_runtime_test.h"
+#include "dex_file.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "handle_scope-inl.h"
+#include "mirror/class-inl.h"
+#include "obj_ptr.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+namespace mirror {
+
+class CollectRootVisitor {
+ public:
+ CollectRootVisitor() {}
+
+ template <class MirrorType>
+ ALWAYS_INLINE void VisitRootIfNonNull(GcRoot<MirrorType>& root) const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!root.IsNull()) {
+ VisitRoot(root);
+ }
+ }
+
+ template <class MirrorType>
+ ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<MirrorType>* root) const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!root->IsNull()) {
+ VisitRoot(root);
+ }
+ }
+
+ template <class MirrorType>
+ void VisitRoot(GcRoot<MirrorType>& root) const REQUIRES_SHARED(Locks::mutator_lock_) {
+ VisitRoot(root.AddressWithoutBarrier());
+ }
+
+ template <class MirrorType>
+ void VisitRoot(mirror::CompressedReference<MirrorType>* root) const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ roots_.insert(root->AsMirrorPtr());
+ }
+
+ mutable std::set<mirror::Object*> roots_;
+};
+
+
+class ClassTableTest : public CommonRuntimeTest {};
+
+TEST_F(ClassTableTest, ClassTable) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject jclass_loader = LoadDex("XandY");
+ VariableSizedHandleScope hs(soa.Self());
+ Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
+ const char* descriptor_x = "LX;";
+ const char* descriptor_y = "LY;";
+ Handle<mirror::Class> h_X(
+ hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_x, class_loader)));
+ Handle<mirror::Class> h_Y(
+ hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
+ Handle<mirror::Object> obj_X = hs.NewHandle(h_X->AllocObject(soa.Self()));
+ ASSERT_TRUE(obj_X.Get() != nullptr);
+ ClassTable table;
+ EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
+ EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
+
+ // Add h_X to the class table.
+ table.Insert(h_X.Get());
+ EXPECT_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
+ EXPECT_EQ(table.Lookup(descriptor_x, ComputeModifiedUtf8Hash(descriptor_x)), h_X.Get());
+ EXPECT_EQ(table.Lookup("NOT_THERE", ComputeModifiedUtf8Hash("NOT_THERE")), nullptr);
+ EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 0u);
+ EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
+
+ // Create the zygote snapshot and ensure the accounting is correct.
+ table.FreezeSnapshot();
+ EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
+ EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 0u);
+
+ // Test inserting and related lookup functions.
+ EXPECT_EQ(table.LookupByDescriptor(h_Y.Get()), nullptr);
+ EXPECT_FALSE(table.Contains(h_Y.Get()));
+ table.Insert(h_Y.Get());
+ EXPECT_EQ(table.LookupByDescriptor(h_X.Get()), h_X.Get());
+ EXPECT_EQ(table.LookupByDescriptor(h_Y.Get()), h_Y.Get());
+ EXPECT_TRUE(table.Contains(h_X.Get()));
+ EXPECT_TRUE(table.Contains(h_Y.Get()));
+
+ EXPECT_EQ(table.NumZygoteClasses(class_loader.Get()), 1u);
+ EXPECT_EQ(table.NumNonZygoteClasses(class_loader.Get()), 1u);
+
+ // Test adding / clearing strong roots.
+ EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
+ EXPECT_FALSE(table.InsertStrongRoot(obj_X.Get()));
+ table.ClearStrongRoots();
+ EXPECT_TRUE(table.InsertStrongRoot(obj_X.Get()));
+
+ // Collect all the roots and make sure there is nothing missing.
+ CollectRootVisitor roots;
+ table.VisitRoots(roots);
+ EXPECT_TRUE(roots.roots_.find(h_X.Get()) != roots.roots_.end());
+ EXPECT_TRUE(roots.roots_.find(h_Y.Get()) != roots.roots_.end());
+ EXPECT_TRUE(roots.roots_.find(obj_X.Get()) != roots.roots_.end());
+
+ // Checks that vising only classes works.
+ std::set<mirror::Class*> classes;
+ table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ classes.insert(klass.Ptr());
+ return true;
+ });
+ EXPECT_TRUE(classes.find(h_X.Get()) != classes.end());
+ EXPECT_TRUE(classes.find(h_Y.Get()) != classes.end());
+ EXPECT_EQ(classes.size(), 2u);
+ classes.clear();
+ table.Visit([&classes](ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+ classes.insert(klass.Ptr());
+ // Return false to exit the Visit early.
+ return false;
+ });
+ EXPECT_EQ(classes.size(), 1u);
+
+ // Test remove.
+ table.Remove(descriptor_x);
+ EXPECT_FALSE(table.Contains(h_X.Get()));
+
+ // Test that WriteToMemory and ReadFromMemory work.
+ table.Insert(h_X.Get());
+ const size_t count = table.WriteToMemory(nullptr);
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[count]());
+ ASSERT_EQ(table.WriteToMemory(&buffer[0]), count);
+ ClassTable table2;
+ size_t count2 = table2.ReadFromMemory(&buffer[0]);
+ EXPECT_EQ(count, count2);
+ // Strong roots are not serialized, only classes.
+ EXPECT_TRUE(table2.Contains(h_X.Get()));
+ EXPECT_TRUE(table2.Contains(h_Y.Get()));
+
+ // TODO: Add tests for UpdateClass, InsertOatFile.
+}
+
+} // namespace mirror
+} // namespace art