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
30namespace art {
31
32// Handles are value objects and should be trivially copyable.
33static_assert(std::is_trivially_copyable<Handle<mirror::Object>>::value,
34              "Handle should be trivially copyable");
35static_assert(std::is_trivially_copyable<MutableHandle<mirror::Object>>::value,
36              "MutableHandle should be trivially copyable");
37static_assert(std::is_trivially_copyable<ScopedNullHandle<mirror::Object>>::value,
38              "ScopedNullHandle should be trivially copyable");
39
40class 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.
45TEST_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
77class 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.
91TEST_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