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 <stack>
21 
22 #include "base/enums.h"
23 #include "base/logging.h"
24 #include "base/macros.h"
25 #include "base/mutex.h"
26 #include "handle.h"
27 #include "stack_reference.h"
28 #include "verify_object.h"
29 
30 namespace art {
31 
32 class HandleScope;
33 template<class MirrorType> class ObjPtr;
34 class Thread;
35 class VariableSizedHandleScope;
36 
37 namespace mirror {
38 class Object;
39 }
40 
41 // Basic handle scope, tracked by a list. May be variable sized.
42 class PACKED(4) BaseHandleScope {
43  public:
IsVariableSized()44   bool IsVariableSized() const {
45     return number_of_references_ == kNumReferencesVariableSized;
46   }
47 
48   // Number of references contained within this handle scope.
49   ALWAYS_INLINE uint32_t NumberOfReferences() const;
50 
51   ALWAYS_INLINE bool Contains(StackReference<mirror::Object>* handle_scope_entry) const;
52 
53   template <typename Visitor>
54   ALWAYS_INLINE void VisitRoots(Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_);
55 
56   // Link to previous BaseHandleScope or null.
GetLink()57   BaseHandleScope* GetLink() const {
58     return link_;
59   }
60 
61   ALWAYS_INLINE VariableSizedHandleScope* AsVariableSized();
62   ALWAYS_INLINE HandleScope* AsHandleScope();
63   ALWAYS_INLINE const VariableSizedHandleScope* AsVariableSized() const;
64   ALWAYS_INLINE const HandleScope* AsHandleScope() const;
65 
66  protected:
BaseHandleScope(BaseHandleScope * link,uint32_t num_references)67   BaseHandleScope(BaseHandleScope* link, uint32_t num_references)
68       : link_(link),
69         number_of_references_(num_references) {}
70 
71   // Variable sized constructor.
BaseHandleScope(BaseHandleScope * link)72   explicit BaseHandleScope(BaseHandleScope* link)
73       : link_(link),
74         number_of_references_(kNumReferencesVariableSized) {}
75 
76   static constexpr int32_t kNumReferencesVariableSized = -1;
77 
78   // Link-list of handle scopes. The root is held by a Thread.
79   BaseHandleScope* const link_;
80 
81   // Number of handlerized references. -1 for variable sized handle scopes.
82   const int32_t number_of_references_;
83 
84  private:
85   DISALLOW_COPY_AND_ASSIGN(BaseHandleScope);
86 };
87 
88 // HandleScopes are scoped objects containing a number of Handles. They are used to allocate
89 // handles, for these handles (and the objects contained within them) to be visible/roots for the
90 // GC. It is most common to stack allocate HandleScopes using StackHandleScope.
91 class PACKED(4) HandleScope : public BaseHandleScope {
92  public:
~HandleScope()93   ~HandleScope() {}
94 
95   // We have versions with and without explicit pointer size of the following. The first two are
96   // used at runtime, so OFFSETOF_MEMBER computes the right offsets automatically. The last one
97   // takes the pointer size explicitly so that at compile time we can cross-compile correctly.
98 
99   // Returns the size of a HandleScope containing num_references handles.
100   static size_t SizeOf(uint32_t num_references);
101 
102   // Returns the size of a HandleScope containing num_references handles.
103   static size_t SizeOf(PointerSize pointer_size, uint32_t num_references);
104 
105   ALWAYS_INLINE mirror::Object* GetReference(size_t i) const
106       REQUIRES_SHARED(Locks::mutator_lock_);
107 
108   ALWAYS_INLINE Handle<mirror::Object> GetHandle(size_t i);
109 
110   ALWAYS_INLINE MutableHandle<mirror::Object> GetMutableHandle(size_t i)
111       REQUIRES_SHARED(Locks::mutator_lock_);
112 
113   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
114       REQUIRES_SHARED(Locks::mutator_lock_);
115 
116   ALWAYS_INLINE bool Contains(StackReference<mirror::Object>* handle_scope_entry) const;
117 
118   // Offset of link within HandleScope, used by generated code.
LinkOffset(PointerSize pointer_size ATTRIBUTE_UNUSED)119   static constexpr size_t LinkOffset(PointerSize pointer_size ATTRIBUTE_UNUSED) {
120     return 0;
121   }
122 
123   // Offset of length within handle scope, used by generated code.
NumberOfReferencesOffset(PointerSize pointer_size)124   static constexpr size_t NumberOfReferencesOffset(PointerSize pointer_size) {
125     return static_cast<size_t>(pointer_size);
126   }
127 
128   // Offset of link within handle scope, used by generated code.
ReferencesOffset(PointerSize pointer_size)129   static constexpr size_t ReferencesOffset(PointerSize pointer_size) {
130     return NumberOfReferencesOffset(pointer_size) + sizeof(number_of_references_);
131   }
132 
133   // Placement new creation.
Create(void * storage,BaseHandleScope * link,uint32_t num_references)134   static HandleScope* Create(void* storage, BaseHandleScope* link, uint32_t num_references)
135       WARN_UNUSED {
136     return new (storage) HandleScope(link, num_references);
137   }
138 
139   // Number of references contained within this handle scope.
NumberOfReferences()140   ALWAYS_INLINE uint32_t NumberOfReferences() const {
141     DCHECK_GE(number_of_references_, 0);
142     return static_cast<uint32_t>(number_of_references_);
143   }
144 
145   template <typename Visitor>
VisitRoots(Visitor & visitor)146   void VisitRoots(Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
147     for (size_t i = 0, count = NumberOfReferences(); i < count; ++i) {
148       // GetReference returns a pointer to the stack reference within the handle scope. If this
149       // needs to be updated, it will be done by the root visitor.
150       visitor.VisitRootIfNonNull(GetHandle(i).GetReference());
151     }
152   }
153 
154  protected:
155   // Return backing storage used for references.
GetReferences()156   ALWAYS_INLINE StackReference<mirror::Object>* GetReferences() const {
157     uintptr_t address = reinterpret_cast<uintptr_t>(this) + ReferencesOffset(kRuntimePointerSize);
158     return reinterpret_cast<StackReference<mirror::Object>*>(address);
159   }
160 
HandleScope(size_t number_of_references)161   explicit HandleScope(size_t number_of_references) : HandleScope(nullptr, number_of_references) {}
162 
163   // Semi-hidden constructor. Construction expected by generated code and StackHandleScope.
HandleScope(BaseHandleScope * link,uint32_t num_references)164   HandleScope(BaseHandleScope* link, uint32_t num_references)
165       : BaseHandleScope(link, num_references) {}
166 
167   // Storage for references.
168   // StackReference<mirror::Object> references_[number_of_references_]
169 
170  private:
171   DISALLOW_COPY_AND_ASSIGN(HandleScope);
172 };
173 
174 // A wrapper which wraps around Object** and restores the pointer in the destructor.
175 // TODO: Delete
176 template<class T>
177 class HandleWrapper : public MutableHandle<T> {
178  public:
HandleWrapper(T ** obj,const MutableHandle<T> & handle)179   HandleWrapper(T** obj, const MutableHandle<T>& handle)
180      : MutableHandle<T>(handle), obj_(obj) {
181   }
182 
183   HandleWrapper(const HandleWrapper&) = default;
184 
~HandleWrapper()185   ~HandleWrapper() {
186     *obj_ = MutableHandle<T>::Get();
187   }
188 
189  private:
190   T** const obj_;
191 };
192 
193 
194 // A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
195 // TODO: Add more functionality.
196 template<class T>
197 class HandleWrapperObjPtr : public MutableHandle<T> {
198  public:
HandleWrapperObjPtr(ObjPtr<T> * obj,const MutableHandle<T> & handle)199   HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
200       : MutableHandle<T>(handle), obj_(obj) {}
201 
202   HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
203 
~HandleWrapperObjPtr()204   ~HandleWrapperObjPtr() {
205     *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
206   }
207 
208  private:
209   ObjPtr<T>* const obj_;
210 };
211 
212 // Fixed size handle scope that is not necessarily linked in the thread.
213 template<size_t kNumReferences>
214 class PACKED(4) FixedSizeHandleScope : public HandleScope {
215  public:
216   template<class T>
217   ALWAYS_INLINE MutableHandle<T> NewHandle(T* object) REQUIRES_SHARED(Locks::mutator_lock_);
218 
219   template<class T>
220   ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
221       REQUIRES_SHARED(Locks::mutator_lock_);
222 
223   template<class T>
224   ALWAYS_INLINE HandleWrapperObjPtr<T> NewHandleWrapper(ObjPtr<T>* object)
225       REQUIRES_SHARED(Locks::mutator_lock_);
226 
227   template<class MirrorType>
228   ALWAYS_INLINE MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType> object)
229     REQUIRES_SHARED(Locks::mutator_lock_);
230 
231   ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
232       REQUIRES_SHARED(Locks::mutator_lock_);
233 
RemainingSlots()234   size_t RemainingSlots() const {
235     return kNumReferences - pos_;
236   }
237 
238  private:
239   explicit ALWAYS_INLINE FixedSizeHandleScope(BaseHandleScope* link,
240                                               mirror::Object* fill_value = nullptr);
~FixedSizeHandleScope()241   ALWAYS_INLINE ~FixedSizeHandleScope() {}
242 
243   template<class T>
GetHandle(size_t i)244   ALWAYS_INLINE MutableHandle<T> GetHandle(size_t i) REQUIRES_SHARED(Locks::mutator_lock_) {
245     DCHECK_LT(i, kNumReferences);
246     return MutableHandle<T>(&GetReferences()[i]);
247   }
248 
249   // Reference storage needs to be first as expected by the HandleScope layout.
250   StackReference<mirror::Object> storage_[kNumReferences];
251 
252   // Position new handles will be created.
253   uint32_t pos_ = 0;
254 
255   template<size_t kNumRefs> friend class StackHandleScope;
256   friend class VariableSizedHandleScope;
257 };
258 
259 // Scoped handle storage of a fixed size that is stack allocated.
260 template<size_t kNumReferences>
261 class PACKED(4) StackHandleScope FINAL : public FixedSizeHandleScope<kNumReferences> {
262  public:
263   explicit ALWAYS_INLINE StackHandleScope(Thread* self, mirror::Object* fill_value = nullptr);
264   ALWAYS_INLINE ~StackHandleScope();
265 
Self()266   Thread* Self() const {
267     return self_;
268   }
269 
270  private:
271   // The thread that the stack handle scope is a linked list upon. The stack handle scope will
272   // push and pop itself from this thread.
273   Thread* const self_;
274 };
275 
276 // Utility class to manage a variable sized handle scope by having a list of fixed size handle
277 // scopes.
278 // Calls to NewHandle will create a new handle inside the current FixedSizeHandleScope.
279 // When the current handle scope becomes full a new one is created and put at the front of the
280 // list.
281 class VariableSizedHandleScope : public BaseHandleScope {
282  public:
283   explicit VariableSizedHandleScope(Thread* const self);
284   ~VariableSizedHandleScope();
285 
286   template<class T>
287   MutableHandle<T> NewHandle(T* object) REQUIRES_SHARED(Locks::mutator_lock_);
288 
289   template<class MirrorType>
290   MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType> ptr)
291       REQUIRES_SHARED(Locks::mutator_lock_);
292 
293   // Number of references contained within this handle scope.
294   ALWAYS_INLINE uint32_t NumberOfReferences() const;
295 
296   ALWAYS_INLINE bool Contains(StackReference<mirror::Object>* handle_scope_entry) const;
297 
298   template <typename Visitor>
299   void VisitRoots(Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_);
300 
301  private:
302   static constexpr size_t kLocalScopeSize = 64u;
303   static constexpr size_t kSizeOfReferencesPerScope =
304       kLocalScopeSize
305           - /* BaseHandleScope::link_ */ sizeof(BaseHandleScope*)
306           - /* BaseHandleScope::number_of_references_ */ sizeof(int32_t)
307           - /* FixedSizeHandleScope<>::pos_ */ sizeof(uint32_t);
308   static constexpr size_t kNumReferencesPerScope =
309       kSizeOfReferencesPerScope / sizeof(StackReference<mirror::Object>);
310 
311   Thread* const self_;
312 
313   // Linked list of fixed size handle scopes.
314   using LocalScopeType = FixedSizeHandleScope<kNumReferencesPerScope>;
315   static_assert(sizeof(LocalScopeType) == kLocalScopeSize, "Unexpected size of LocalScopeType");
316   LocalScopeType* current_scope_;
317 
318   DISALLOW_COPY_AND_ASSIGN(VariableSizedHandleScope);
319 };
320 
321 }  // namespace art
322 
323 #endif  // ART_RUNTIME_HANDLE_SCOPE_H_
324