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