• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_GC_ROOT_H_
18 #define ART_RUNTIME_GC_ROOT_H_
19 
20 #include "base/macros.h"
21 #include "base/mutex.h"       // For Locks::mutator_lock_.
22 #include "mirror/object_reference.h"
23 
24 namespace art {
25 class ArtField;
26 class ArtMethod;
27 
28 namespace mirror {
29 class Object;
30 }  // namespace mirror
31 
32 template <size_t kBufferSize>
33 class BufferedRootVisitor;
34 
35 // Dependent on pointer size so that we don't have frames that are too big on 64 bit.
36 static const size_t kDefaultBufferedRootCount = 1024 / sizeof(void*);
37 
38 enum RootType {
39   kRootUnknown = 0,
40   kRootJNIGlobal,
41   kRootJNILocal,
42   kRootJavaFrame,
43   kRootNativeStack,
44   kRootStickyClass,
45   kRootThreadBlock,
46   kRootMonitorUsed,
47   kRootThreadObject,
48   kRootInternedString,
49   kRootFinalizing,  // used for HPROF's conversion to HprofHeapTag
50   kRootDebugger,
51   kRootReferenceCleanup,  // used for HPROF's conversion to HprofHeapTag
52   kRootVMInternal,
53   kRootJNIMonitor,
54 };
55 std::ostream& operator<<(std::ostream& os, const RootType& root_type);
56 
57 // Only used by hprof. thread_id_ and type_ are only used by hprof.
58 class RootInfo {
59  public:
60   // Thread id 0 is for non thread roots.
61   explicit RootInfo(RootType type, uint32_t thread_id = 0)
type_(type)62      : type_(type), thread_id_(thread_id) {
63   }
64   RootInfo(const RootInfo&) = default;
~RootInfo()65   virtual ~RootInfo() {
66   }
GetType()67   RootType GetType() const {
68     return type_;
69   }
GetThreadId()70   uint32_t GetThreadId() const {
71     return thread_id_;
72   }
Describe(std::ostream & os)73   virtual void Describe(std::ostream& os) const {
74     os << "Type=" << type_ << " thread_id=" << thread_id_;
75   }
76   std::string ToString() const;
77 
78  private:
79   const RootType type_;
80   const uint32_t thread_id_;
81 };
82 
83 inline std::ostream& operator<<(std::ostream& os, const RootInfo& root_info) {
84   root_info.Describe(os);
85   return os;
86 }
87 
88 class RootVisitor {
89  public:
~RootVisitor()90   virtual ~RootVisitor() { }
91 
92   // Single root version, not overridable.
VisitRoot(mirror::Object ** root,const RootInfo & info)93   ALWAYS_INLINE void VisitRoot(mirror::Object** root, const RootInfo& info)
94       SHARED_REQUIRES(Locks::mutator_lock_) {
95     VisitRoots(&root, 1, info);
96   }
97 
98   // Single root version, not overridable.
VisitRootIfNonNull(mirror::Object ** root,const RootInfo & info)99   ALWAYS_INLINE void VisitRootIfNonNull(mirror::Object** root, const RootInfo& info)
100       SHARED_REQUIRES(Locks::mutator_lock_) {
101     if (*root != nullptr) {
102       VisitRoot(root, info);
103     }
104   }
105 
106   virtual void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info)
107       SHARED_REQUIRES(Locks::mutator_lock_) = 0;
108 
109   virtual void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count,
110                           const RootInfo& info)
111       SHARED_REQUIRES(Locks::mutator_lock_) = 0;
112 };
113 
114 // Only visits roots one at a time, doesn't handle updating roots. Used when performance isn't
115 // critical.
116 class SingleRootVisitor : public RootVisitor {
117  private:
VisitRoots(mirror::Object *** roots,size_t count,const RootInfo & info)118   void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info) OVERRIDE
119       SHARED_REQUIRES(Locks::mutator_lock_) {
120     for (size_t i = 0; i < count; ++i) {
121       VisitRoot(*roots[i], info);
122     }
123   }
124 
VisitRoots(mirror::CompressedReference<mirror::Object> ** roots,size_t count,const RootInfo & info)125   void VisitRoots(mirror::CompressedReference<mirror::Object>** roots, size_t count,
126                           const RootInfo& info) OVERRIDE
127       SHARED_REQUIRES(Locks::mutator_lock_) {
128     for (size_t i = 0; i < count; ++i) {
129       VisitRoot(roots[i]->AsMirrorPtr(), info);
130     }
131   }
132 
133   virtual void VisitRoot(mirror::Object* root, const RootInfo& info) = 0;
134 };
135 
136 class GcRootSource {
137  public:
GcRootSource()138   GcRootSource()
139       : field_(nullptr), method_(nullptr) {
140   }
GcRootSource(ArtField * field)141   explicit GcRootSource(ArtField* field)
142       : field_(field), method_(nullptr) {
143   }
GcRootSource(ArtMethod * method)144   explicit GcRootSource(ArtMethod* method)
145       : field_(nullptr), method_(method) {
146   }
GetArtField()147   ArtField* GetArtField() const {
148     return field_;
149   }
GetArtMethod()150   ArtMethod* GetArtMethod() const {
151     return method_;
152   }
HasArtField()153   bool HasArtField() const {
154     return field_ != nullptr;
155   }
HasArtMethod()156   bool HasArtMethod() const {
157     return method_ != nullptr;
158   }
159 
160  private:
161   ArtField* const field_;
162   ArtMethod* const method_;
163 
164   DISALLOW_COPY_AND_ASSIGN(GcRootSource);
165 };
166 
167 template<class MirrorType>
168 class GcRoot {
169  public:
170   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
171   ALWAYS_INLINE MirrorType* Read(GcRootSource* gc_root_source = nullptr) const
172       SHARED_REQUIRES(Locks::mutator_lock_);
173 
VisitRoot(RootVisitor * visitor,const RootInfo & info)174   void VisitRoot(RootVisitor* visitor, const RootInfo& info) const
175       SHARED_REQUIRES(Locks::mutator_lock_) {
176     DCHECK(!IsNull());
177     mirror::CompressedReference<mirror::Object>* roots[1] = { &root_ };
178     visitor->VisitRoots(roots, 1u, info);
179     DCHECK(!IsNull());
180   }
181 
VisitRootIfNonNull(RootVisitor * visitor,const RootInfo & info)182   void VisitRootIfNonNull(RootVisitor* visitor, const RootInfo& info) const
183       SHARED_REQUIRES(Locks::mutator_lock_) {
184     if (!IsNull()) {
185       VisitRoot(visitor, info);
186     }
187   }
188 
AddressWithoutBarrier()189   ALWAYS_INLINE mirror::CompressedReference<mirror::Object>* AddressWithoutBarrier() {
190     return &root_;
191   }
192 
IsNull()193   ALWAYS_INLINE bool IsNull() const {
194     // It's safe to null-check it without a read barrier.
195     return root_.IsNull();
196   }
197 
198   ALWAYS_INLINE GcRoot(MirrorType* ref = nullptr) SHARED_REQUIRES(Locks::mutator_lock_);
199 
200  private:
201   // Root visitors take pointers to root_ and place them in CompressedReference** arrays. We use a
202   // CompressedReference<mirror::Object> here since it violates strict aliasing requirements to
203   // cast CompressedReference<MirrorType>* to CompressedReference<mirror::Object>*.
204   mutable mirror::CompressedReference<mirror::Object> root_;
205 
206   template <size_t kBufferSize> friend class BufferedRootVisitor;
207 };
208 
209 // Simple data structure for buffered root visiting to avoid virtual dispatch overhead. Currently
210 // only for CompressedReferences since these are more common than the Object** roots which are only
211 // for thread local roots.
212 template <size_t kBufferSize>
213 class BufferedRootVisitor {
214  public:
BufferedRootVisitor(RootVisitor * visitor,const RootInfo & root_info)215   BufferedRootVisitor(RootVisitor* visitor, const RootInfo& root_info)
216       : visitor_(visitor), root_info_(root_info), buffer_pos_(0) {
217   }
218 
~BufferedRootVisitor()219   ~BufferedRootVisitor() {
220     Flush();
221   }
222 
223   template <class MirrorType>
VisitRootIfNonNull(GcRoot<MirrorType> & root)224   ALWAYS_INLINE void VisitRootIfNonNull(GcRoot<MirrorType>& root)
225       SHARED_REQUIRES(Locks::mutator_lock_) {
226     if (!root.IsNull()) {
227       VisitRoot(root);
228     }
229   }
230 
231   template <class MirrorType>
VisitRootIfNonNull(mirror::CompressedReference<MirrorType> * root)232   ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<MirrorType>* root)
233       SHARED_REQUIRES(Locks::mutator_lock_) {
234     if (!root->IsNull()) {
235       VisitRoot(root);
236     }
237   }
238 
239   template <class MirrorType>
VisitRoot(GcRoot<MirrorType> & root)240   void VisitRoot(GcRoot<MirrorType>& root) SHARED_REQUIRES(Locks::mutator_lock_) {
241     VisitRoot(root.AddressWithoutBarrier());
242   }
243 
244   template <class MirrorType>
VisitRoot(mirror::CompressedReference<MirrorType> * root)245   void VisitRoot(mirror::CompressedReference<MirrorType>* root)
246       SHARED_REQUIRES(Locks::mutator_lock_) {
247     if (UNLIKELY(buffer_pos_ >= kBufferSize)) {
248       Flush();
249     }
250     roots_[buffer_pos_++] = root;
251   }
252 
Flush()253   void Flush() SHARED_REQUIRES(Locks::mutator_lock_) {
254     visitor_->VisitRoots(roots_, buffer_pos_, root_info_);
255     buffer_pos_ = 0;
256   }
257 
258  private:
259   RootVisitor* const visitor_;
260   RootInfo root_info_;
261   mirror::CompressedReference<mirror::Object>* roots_[kBufferSize];
262   size_t buffer_pos_;
263 };
264 
265 }  // namespace art
266 
267 #endif  // ART_RUNTIME_GC_ROOT_H_
268