1 /* 2 * Copyright (C) 2015 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_JIT_PROFILING_INFO_H_ 18 #define ART_RUNTIME_JIT_PROFILING_INFO_H_ 19 20 #include <vector> 21 22 #include "base/macros.h" 23 #include "gc_root.h" 24 25 namespace art { 26 27 class ArtMethod; 28 class ProfilingInfo; 29 30 namespace jit { 31 class JitCodeCache; 32 } 33 34 namespace mirror { 35 class Class; 36 } 37 38 // Structure to store the classes seen at runtime for a specific instruction. 39 // Once the classes_ array is full, we consider the INVOKE to be megamorphic. 40 class InlineCache { 41 public: IsMonomorphic()42 bool IsMonomorphic() const { 43 DCHECK_GE(kIndividualCacheSize, 2); 44 return !classes_[0].IsNull() && classes_[1].IsNull(); 45 } 46 IsMegamorphic()47 bool IsMegamorphic() const { 48 for (size_t i = 0; i < kIndividualCacheSize; ++i) { 49 if (classes_[i].IsNull()) { 50 return false; 51 } 52 } 53 return true; 54 } 55 GetMonomorphicType()56 mirror::Class* GetMonomorphicType() const SHARED_REQUIRES(Locks::mutator_lock_) { 57 // Note that we cannot ensure the inline cache is actually monomorphic 58 // at this point, as other threads may have updated it. 59 DCHECK(!classes_[0].IsNull()); 60 return classes_[0].Read(); 61 } 62 IsUninitialized()63 bool IsUninitialized() const { 64 return classes_[0].IsNull(); 65 } 66 IsPolymorphic()67 bool IsPolymorphic() const { 68 DCHECK_GE(kIndividualCacheSize, 3); 69 return !classes_[1].IsNull() && classes_[kIndividualCacheSize - 1].IsNull(); 70 } 71 GetTypeAt(size_t i)72 mirror::Class* GetTypeAt(size_t i) const SHARED_REQUIRES(Locks::mutator_lock_) { 73 return classes_[i].Read(); 74 } 75 76 static constexpr uint16_t kIndividualCacheSize = 5; 77 78 private: 79 uint32_t dex_pc_; 80 GcRoot<mirror::Class> classes_[kIndividualCacheSize]; 81 82 friend class ProfilingInfo; 83 84 DISALLOW_COPY_AND_ASSIGN(InlineCache); 85 }; 86 87 /** 88 * Profiling info for a method, created and filled by the interpreter once the 89 * method is warm, and used by the compiler to drive optimizations. 90 */ 91 class ProfilingInfo { 92 public: 93 // Create a ProfilingInfo for 'method'. Return whether it succeeded, or if it is 94 // not needed in case the method does not have virtual/interface invocations. 95 static bool Create(Thread* self, ArtMethod* method, bool retry_allocation) 96 SHARED_REQUIRES(Locks::mutator_lock_); 97 98 // Add information from an executed INVOKE instruction to the profile. 99 void AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) 100 // Method should not be interruptible, as it manipulates the ProfilingInfo 101 // which can be concurrently collected. 102 REQUIRES(Roles::uninterruptible_) 103 SHARED_REQUIRES(Locks::mutator_lock_); 104 105 // NO_THREAD_SAFETY_ANALYSIS since we don't know what the callback requires. 106 template<typename RootVisitorType> VisitRoots(RootVisitorType & visitor)107 void VisitRoots(RootVisitorType& visitor) NO_THREAD_SAFETY_ANALYSIS { 108 visitor.VisitRootIfNonNull(holding_class_.AddressWithoutBarrier()); 109 for (size_t i = 0; i < number_of_inline_caches_; ++i) { 110 InlineCache* cache = &cache_[i]; 111 for (size_t j = 0; j < InlineCache::kIndividualCacheSize; ++j) { 112 visitor.VisitRootIfNonNull(cache->classes_[j].AddressWithoutBarrier()); 113 } 114 } 115 } 116 GetMethod()117 ArtMethod* GetMethod() const { 118 return method_; 119 } 120 121 InlineCache* GetInlineCache(uint32_t dex_pc); 122 IsMethodBeingCompiled(bool osr)123 bool IsMethodBeingCompiled(bool osr) const { 124 return osr 125 ? is_osr_method_being_compiled_ 126 : is_method_being_compiled_; 127 } 128 SetIsMethodBeingCompiled(bool value,bool osr)129 void SetIsMethodBeingCompiled(bool value, bool osr) { 130 if (osr) { 131 is_osr_method_being_compiled_ = value; 132 } else { 133 is_method_being_compiled_ = value; 134 } 135 } 136 SetSavedEntryPoint(const void * entry_point)137 void SetSavedEntryPoint(const void* entry_point) { 138 saved_entry_point_ = entry_point; 139 } 140 GetSavedEntryPoint()141 const void* GetSavedEntryPoint() const { 142 return saved_entry_point_; 143 } 144 ClearGcRootsInInlineCaches()145 void ClearGcRootsInInlineCaches() { 146 for (size_t i = 0; i < number_of_inline_caches_; ++i) { 147 InlineCache* cache = &cache_[i]; 148 memset(&cache->classes_[0], 149 0, 150 InlineCache::kIndividualCacheSize * sizeof(GcRoot<mirror::Class>)); 151 } 152 } 153 IncrementInlineUse()154 void IncrementInlineUse() { 155 DCHECK_NE(current_inline_uses_, std::numeric_limits<uint16_t>::max()); 156 current_inline_uses_++; 157 } 158 DecrementInlineUse()159 void DecrementInlineUse() { 160 DCHECK_GT(current_inline_uses_, 0); 161 current_inline_uses_--; 162 } 163 IsInUseByCompiler()164 bool IsInUseByCompiler() const { 165 return IsMethodBeingCompiled(/*osr*/ true) || IsMethodBeingCompiled(/*osr*/ false) || 166 (current_inline_uses_ > 0); 167 } 168 169 private: 170 ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries); 171 172 // Number of instructions we are profiling in the ArtMethod. 173 const uint32_t number_of_inline_caches_; 174 175 // Method this profiling info is for. 176 ArtMethod* const method_; 177 178 // Holding class for the method in case method is a copied method. 179 GcRoot<mirror::Class> holding_class_; 180 181 // Whether the ArtMethod is currently being compiled. This flag 182 // is implicitly guarded by the JIT code cache lock. 183 // TODO: Make the JIT code cache lock global. 184 bool is_method_being_compiled_; 185 bool is_osr_method_being_compiled_; 186 187 // When the compiler inlines the method associated to this ProfilingInfo, 188 // it updates this counter so that the GC does not try to clear the inline caches. 189 uint16_t current_inline_uses_; 190 191 // Entry point of the corresponding ArtMethod, while the JIT code cache 192 // is poking for the liveness of compiled code. 193 const void* saved_entry_point_; 194 195 // Dynamically allocated array of size `number_of_inline_caches_`. 196 InlineCache cache_[0]; 197 198 friend class jit::JitCodeCache; 199 200 DISALLOW_COPY_AND_ASSIGN(ProfilingInfo); 201 }; 202 203 } // namespace art 204 205 #endif // ART_RUNTIME_JIT_PROFILING_INFO_H_ 206