1 /* 2 * Copyright (C) 2014 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 <type_traits> 18 19 #include "base/enums.h" 20 #include "class_linker-inl.h" 21 #include "common_runtime_test.h" 22 #include "gtest/gtest.h" 23 #include "handle.h" 24 #include "handle_scope-inl.h" 25 #include "mirror/class-alloc-inl.h" 26 #include "mirror/class-inl.h" 27 #include "mirror/object.h" 28 #include "scoped_thread_state_change-inl.h" 29 #include "thread.h" 30 31 namespace art { 32 33 // Handles are value objects and should be trivially copyable. 34 static_assert(std::is_trivially_copyable<Handle<mirror::Object>>::value, 35 "Handle should be trivially copyable"); 36 static_assert(std::is_trivially_copyable<MutableHandle<mirror::Object>>::value, 37 "MutableHandle should be trivially copyable"); 38 static_assert(std::is_trivially_copyable<ScopedNullHandle<mirror::Object>>::value, 39 "ScopedNullHandle should be trivially copyable"); 40 41 class HandleScopeTest : public CommonRuntimeTest {}; 42 43 // Test the offsets computed for members of HandleScope. Because of cross-compiling 44 // it is impossible the use OFFSETOF_MEMBER, so we do some reasonable computations ourselves. This 45 // test checks whether we do the right thing. 46 TEST_F(HandleScopeTest, Offsets) { 47 ScopedObjectAccess soa(Thread::Current()); 48 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); 49 // As the members of HandleScope are private, we cannot use OFFSETOF_MEMBER 50 // here. So do the inverse: set some data, and access it through pointers created from the offsets. 51 StackHandleScope<0x1> hs0(soa.Self()); 52 static const size_t kNumReferences = 0x9ABC; 53 StackHandleScope<kNumReferences> test_table(soa.Self()); 54 ObjPtr<mirror::Class> c = class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;"); 55 test_table.SetReference(0, c.Ptr()); 56 57 uint8_t* table_base_ptr = reinterpret_cast<uint8_t*>(&test_table); 58 59 { 60 BaseHandleScope** link_ptr = reinterpret_cast<BaseHandleScope**>(table_base_ptr + 61 HandleScope::LinkOffset(kRuntimePointerSize)); 62 EXPECT_EQ(*link_ptr, &hs0); 63 } 64 65 { 66 uint32_t* num_ptr = reinterpret_cast<uint32_t*>(table_base_ptr + 67 HandleScope::NumberOfReferencesOffset(kRuntimePointerSize)); 68 EXPECT_EQ(*num_ptr, static_cast<size_t>(kNumReferences)); 69 } 70 71 { 72 auto* ref_ptr = reinterpret_cast<StackReference<mirror::Object>*>(table_base_ptr + 73 HandleScope::ReferencesOffset(kRuntimePointerSize)); 74 EXPECT_OBJ_PTR_EQ(ref_ptr->AsMirrorPtr(), c); 75 } 76 } 77 78 class CollectVisitor { 79 public: 80 void VisitRootIfNonNull(StackReference<mirror::Object>* ref) { 81 if (!ref->IsNull()) { 82 visited.insert(ref); 83 } 84 ++total_visited; 85 } 86 87 std::set<StackReference<mirror::Object>*> visited; 88 size_t total_visited = 0; // including null. 89 }; 90 91 // Test functionality of variable sized handle scopes. 92 TEST_F(HandleScopeTest, VariableSized) { 93 ScopedObjectAccess soa(Thread::Current()); 94 VariableSizedHandleScope hs(soa.Self()); 95 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); 96 Handle<mirror::Class> c = 97 hs.NewHandle(class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;")); 98 // Test nested scopes. 99 StackHandleScope<1> inner(soa.Self()); 100 inner.NewHandle(c->AllocObject(soa.Self())); 101 // Add a bunch of handles and make sure callbacks work. 102 static const size_t kNumHandles = 100; 103 std::vector<Handle<mirror::Object>> handles; 104 for (size_t i = 0; i < kNumHandles; ++i) { 105 BaseHandleScope* base = &hs; 106 ObjPtr<mirror::Object> o = c->AllocObject(soa.Self()); 107 handles.push_back(hs.NewHandle(o)); 108 EXPECT_OBJ_PTR_EQ(o, handles.back().Get()); 109 EXPECT_TRUE(hs.Contains(handles.back().GetReference())); 110 EXPECT_TRUE(base->Contains(handles.back().GetReference())); 111 EXPECT_EQ(hs.NumberOfReferences(), base->NumberOfReferences()); 112 } 113 CollectVisitor visitor; 114 BaseHandleScope* base = &hs; 115 base->VisitRoots(visitor); 116 EXPECT_LE(visitor.visited.size(), base->NumberOfReferences()); 117 EXPECT_EQ(visitor.total_visited, base->NumberOfReferences()); 118 for (StackReference<mirror::Object>* ref : visitor.visited) { 119 EXPECT_TRUE(base->Contains(ref)); 120 } 121 } 122 123 } // namespace art 124