Home | History | Annotate | Download | only in runtime
      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:
     38   ~HandleScope() {}
     39 
     40   // Number of references contained within this handle scope.
     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.
     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.
     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.
     65   HandleScope* GetLink() const {
     66     return link_;
     67   }
     68 
     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.
     76   void SetNumberOfReferences(uint32_t num_references) {
     77     number_of_references_ = num_references;
     78   }
     79 
     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 
     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 
     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 
     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
    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
    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
    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.
    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 
    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:
    150   HandleWrapper(T** obj, const Handle<T>& handle)
    151      : Handle<T>(handle), obj_(obj) {
    152   }
    153 
    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>
    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>
    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 
    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>
    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