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   explicit HandleScope(size_t number_of_references) :
    124       link_(nullptr), number_of_references_(number_of_references) {
    125   }
    126 
    127   HandleScope* link_;
    128   uint32_t number_of_references_;
    129 
    130   // number_of_references_ are available if this is allocated and filled in by jni_compiler.
    131   StackReference<mirror::Object> references_[0];
    132 
    133  private:
    134   template<size_t kNumReferences> friend class StackHandleScope;
    135 
    136   DISALLOW_COPY_AND_ASSIGN(HandleScope);
    137 };
    138 
    139 // A wrapper which wraps around Object** and restores the pointer in the destructor.
    140 // TODO: Add more functionality.
    141 template<class T>
    142 class HandleWrapper : public Handle<T> {
    143  public:
    144   HandleWrapper(T** obj, const Handle<T>& handle)
    145      : Handle<T>(handle), obj_(obj) {
    146   }
    147 
    148   ~HandleWrapper() {
    149     *obj_ = Handle<T>::Get();
    150   }
    151 
    152  private:
    153   T** obj_;
    154 };
    155 
    156 // Scoped handle storage of a fixed size that is usually stack allocated.
    157 template<size_t kNumReferences>
    158 class PACKED(4) StackHandleScope FINAL : public HandleScope {
    159  public:
    160   explicit StackHandleScope(Thread* self);
    161   ~StackHandleScope();
    162 
    163   // Currently unused, using this GetReference instead of the one in HandleScope is preferred to
    164   // avoid compiler optimizations incorrectly optimizing out of bound array accesses.
    165   // TODO: Remove this when it is un-necessary.
    166   mirror::Object* GetReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
    167       ALWAYS_INLINE {
    168     DCHECK_LT(i, number_of_references_);
    169     return references_storage_[i].AsMirrorPtr();
    170   }
    171 
    172   Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
    173       ALWAYS_INLINE {
    174     DCHECK_LT(i, number_of_references_);
    175     return Handle<mirror::Object>(&references_storage_[i]);
    176   }
    177 
    178   void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
    179       ALWAYS_INLINE {
    180     DCHECK_LT(i, number_of_references_);
    181     references_storage_[i].Assign(object);
    182   }
    183 
    184   template<class T>
    185   Handle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    186     SetReference(pos_, object);
    187     Handle<T> h(GetHandle(pos_));
    188     pos_++;
    189     return h;
    190   }
    191 
    192   template<class T>
    193   HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    194     SetReference(pos_, *object);
    195     Handle<T> h(GetHandle(pos_));
    196     pos_++;
    197     return HandleWrapper<T>(object, h);
    198   }
    199 
    200  private:
    201   // References_storage_ needs to be first so that it appears in the same location as
    202   // HandleScope::references_.
    203   StackReference<mirror::Object> references_storage_[kNumReferences];
    204 
    205   // The thread that the stack handle scope is a linked list upon. The stack handle scope will
    206   // push and pop itself from this thread.
    207   Thread* const self_;
    208 
    209   // Position new handles will be created.
    210   size_t pos_;
    211 
    212   template<size_t kNumRefs> friend class StackHandleScope;
    213 };
    214 
    215 }  // namespace art
    216 
    217 #endif  // ART_RUNTIME_HANDLE_SCOPE_H_
    218