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