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 #ifndef ART_RUNTIME_HANDLE_SCOPE_H_
18 #define ART_RUNTIME_HANDLE_SCOPE_H_
19 
20 #include "base/logging.h"
21 #include "base/macros.h"
22 #include "handle.h"
23 #include "stack.h"
24 #include "utils.h"
25 
26 namespace art {
27 namespace mirror {
28 class Object;
29 }
30 
31 class Thread;
32 
33 // HandleScopes are scoped objects containing a number of Handles. They are used to allocate
34 // handles, for these handles (and the objects contained within them) to be visible/roots for the
35 // GC. It is most common to stack allocate HandleScopes using StackHandleScope.
36 class PACKED(4) HandleScope {
37  public:
~HandleScope()38   ~HandleScope() {}
39 
40   // Number of references contained within this handle scope.
NumberOfReferences()41   uint32_t NumberOfReferences() const {
42     return number_of_references_;
43   }
44 
45   // We have versions with and without explicit pointer size of the following. The first two are
46   // used at runtime, so OFFSETOF_MEMBER computes the right offsets automatically. The last one
47   // takes the pointer size explicitly so that at compile time we can cross-compile correctly.
48 
49   // Returns the size of a HandleScope containing num_references handles.
SizeOf(uint32_t num_references)50   static size_t SizeOf(uint32_t num_references) {
51     size_t header_size = sizeof(HandleScope);
52     size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
53     return header_size + data_size;
54   }
55 
56   // Returns the size of a HandleScope containing num_references handles.
SizeOf(size_t pointer_size,uint32_t num_references)57   static size_t SizeOf(size_t pointer_size, uint32_t num_references) {
58     // Assume that the layout is packed.
59     size_t header_size = pointer_size + sizeof(number_of_references_);
60     size_t data_size = sizeof(StackReference<mirror::Object>) * num_references;
61     return header_size + data_size;
62   }
63 
64   // Link to previous HandleScope or null.
GetLink()65   HandleScope* GetLink() const {
66     return link_;
67   }
68 
SetLink(HandleScope * link)69   void SetLink(HandleScope* link) {
70     DCHECK_NE(this, link);
71     link_ = link;
72   }
73 
74   // Sets the number_of_references_ field for constructing tables out of raw memory. Warning: will
75   // not resize anything.
SetNumberOfReferences(uint32_t num_references)76   void SetNumberOfReferences(uint32_t num_references) {
77     number_of_references_ = num_references;
78   }
79 
GetReference(size_t i)80   mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
81       ALWAYS_INLINE {
82     DCHECK_LT(i, number_of_references_);
83     return references_[i].AsMirrorPtr();
84   }
85 
GetHandle(size_t i)86   Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
87       ALWAYS_INLINE {
88     DCHECK_LT(i, number_of_references_);
89     return Handle<mirror::Object>(&references_[i]);
90   }
91 
SetReference(size_t i,mirror::Object * object)92   void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
93       ALWAYS_INLINE {
94     DCHECK_LT(i, number_of_references_);
95     references_[i].Assign(object);
96   }
97 
Contains(StackReference<mirror::Object> * handle_scope_entry)98   bool Contains(StackReference<mirror::Object>* handle_scope_entry) const {
99     // A HandleScope should always contain something. One created by the
100     // jni_compiler should have a jobject/jclass as a native method is
101     // passed in a this pointer or a class
102     DCHECK_GT(number_of_references_, 0U);
103     return &references_[0] <= handle_scope_entry &&
104         handle_scope_entry <= &references_[number_of_references_ - 1];
105   }
106 
107   // Offset of link within HandleScope, used by generated code
LinkOffset(size_t pointer_size)108   static size_t LinkOffset(size_t pointer_size) {
109     return 0;
110   }
111 
112   // Offset of length within handle scope, used by generated code
NumberOfReferencesOffset(size_t pointer_size)113   static size_t NumberOfReferencesOffset(size_t pointer_size) {
114     return pointer_size;
115   }
116 
117   // Offset of link within handle scope, used by generated code
ReferencesOffset(size_t pointer_size)118   static size_t ReferencesOffset(size_t pointer_size) {
119     return pointer_size + sizeof(number_of_references_);
120   }
121 
122  protected:
123   // Return backing storage used for references.
GetReferences()124   ALWAYS_INLINE StackReference<mirror::Object>* GetReferences() const {
125     uintptr_t address = reinterpret_cast<uintptr_t>(this) + ReferencesOffset(sizeof(void*));
126     return reinterpret_cast<StackReference<mirror::Object>*>(address);
127   }
128 
HandleScope(size_t number_of_references)129   explicit HandleScope(size_t number_of_references) :
130       link_(nullptr), number_of_references_(number_of_references) {
131   }
132 
133   HandleScope* link_;
134   uint32_t number_of_references_;
135 
136   // number_of_references_ are available if this is allocated and filled in by jni_compiler.
137   StackReference<mirror::Object> references_[0];
138 
139  private:
140   template<size_t kNumReferences> friend class StackHandleScope;
141 
142   DISALLOW_COPY_AND_ASSIGN(HandleScope);
143 };
144 
145 // A wrapper which wraps around Object** and restores the pointer in the destructor.
146 // TODO: Add more functionality.
147 template<class T>
148 class HandleWrapper : public Handle<T> {
149  public:
HandleWrapper(T ** obj,const Handle<T> & handle)150   HandleWrapper(T** obj, const Handle<T>& handle)
151      : Handle<T>(handle), obj_(obj) {
152   }
153 
~HandleWrapper()154   ~HandleWrapper() {
155     *obj_ = Handle<T>::Get();
156   }
157 
158  private:
159   T** const obj_;
160 };
161 
162 // Scoped handle storage of a fixed size that is usually stack allocated.
163 template<size_t kNumReferences>
164 class PACKED(4) StackHandleScope FINAL : public HandleScope {
165  public:
166   explicit ALWAYS_INLINE StackHandleScope(Thread* self, mirror::Object* fill_value = nullptr);
167   ALWAYS_INLINE ~StackHandleScope();
168 
169   template<class T>
NewHandle(T * object)170   ALWAYS_INLINE Handle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
171     SetReference(pos_, object);
172     Handle<T> h(GetHandle<T>(pos_));
173     pos_++;
174     return h;
175   }
176 
177   template<class T>
NewHandleWrapper(T ** object)178   ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
179       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
180     SetReference(pos_, *object);
181     Handle<T> h(GetHandle<T>(pos_));
182     pos_++;
183     return HandleWrapper<T>(object, h);
184   }
185 
SetReference(size_t i,mirror::Object * object)186   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
187       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
188     DCHECK_LT(i, kNumReferences);
189     GetReferences()[i].Assign(object);
190   }
191 
192  private:
193   template<class T>
GetHandle(size_t i)194   ALWAYS_INLINE Handle<T> GetHandle(size_t i)
195       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
196     DCHECK_LT(i, kNumReferences);
197     return Handle<T>(&GetReferences()[i]);
198   }
199 
200   // Reference storage needs to be first as expected by the HandleScope layout.
201   StackReference<mirror::Object> references_storage_[kNumReferences];
202 
203   // The thread that the stack handle scope is a linked list upon. The stack handle scope will
204   // push and pop itself from this thread.
205   Thread* const self_;
206 
207   // Position new handles will be created.
208   size_t pos_;
209 
210   template<size_t kNumRefs> friend class StackHandleScope;
211 };
212 
213 }  // namespace art
214 
215 #endif  // ART_RUNTIME_HANDLE_SCOPE_H_
216