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 #include "offsets.h"
25 
26 namespace art {
27 
28 class ArtMethod;
29 class ProfilingInfo;
30 
31 namespace jit {
32 class JitCodeCache;
33 }  // namespace jit
34 
35 namespace mirror {
36 class Class;
37 }  // namespace mirror
38 
39 // Structure to store the classes seen at runtime for a specific instruction.
40 // Once the classes_ array is full, we consider the INVOKE to be megamorphic.
41 class InlineCache {
42  public:
43   // This is hard coded in the assembly stub art_quick_update_inline_cache.
44   static constexpr uint8_t kIndividualCacheSize = 5;
45 
ClassesOffset()46   static constexpr MemberOffset ClassesOffset() {
47     return MemberOffset(OFFSETOF_MEMBER(InlineCache, classes_));
48   }
49 
50  private:
51   uint32_t dex_pc_;
52   GcRoot<mirror::Class> classes_[kIndividualCacheSize];
53 
54   friend class jit::JitCodeCache;
55   friend class ProfilingInfo;
56 
57   DISALLOW_COPY_AND_ASSIGN(InlineCache);
58 };
59 
60 /**
61  * Profiling info for a method, created and filled by the interpreter once the
62  * method is warm, and used by the compiler to drive optimizations.
63  */
64 class ProfilingInfo {
65  public:
66   // Create a ProfilingInfo for 'method'. Return whether it succeeded, or if it is
67   // not needed in case the method does not have virtual/interface invocations.
68   static bool Create(Thread* self, ArtMethod* method, bool retry_allocation)
69       REQUIRES_SHARED(Locks::mutator_lock_);
70 
71   // Add information from an executed INVOKE instruction to the profile.
72   void AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls)
73       // Method should not be interruptible, as it manipulates the ProfilingInfo
74       // which can be concurrently collected.
75       REQUIRES(Roles::uninterruptible_)
76       REQUIRES_SHARED(Locks::mutator_lock_);
77 
GetMethod()78   ArtMethod* GetMethod() const {
79     return method_;
80   }
81 
82   // Mutator lock only required for debugging output.
83   InlineCache* GetInlineCache(uint32_t dex_pc)
84       REQUIRES_SHARED(Locks::mutator_lock_);
85 
IsMethodBeingCompiled(bool osr)86   bool IsMethodBeingCompiled(bool osr) const {
87     return osr
88         ? is_osr_method_being_compiled_
89         : is_method_being_compiled_;
90   }
91 
SetIsMethodBeingCompiled(bool value,bool osr)92   void SetIsMethodBeingCompiled(bool value, bool osr) {
93     if (osr) {
94       is_osr_method_being_compiled_ = value;
95     } else {
96       is_method_being_compiled_ = value;
97     }
98   }
99 
SetSavedEntryPoint(const void * entry_point)100   void SetSavedEntryPoint(const void* entry_point) {
101     saved_entry_point_ = entry_point;
102   }
103 
GetSavedEntryPoint()104   const void* GetSavedEntryPoint() const {
105     return saved_entry_point_;
106   }
107 
108   // Increments the number of times this method is currently being inlined.
109   // Returns whether it was successful, that is it could increment without
110   // overflowing.
IncrementInlineUse()111   bool IncrementInlineUse() {
112     if (current_inline_uses_ == std::numeric_limits<uint16_t>::max()) {
113       return false;
114     }
115     current_inline_uses_++;
116     return true;
117   }
118 
DecrementInlineUse()119   void DecrementInlineUse() {
120     DCHECK_GT(current_inline_uses_, 0);
121     current_inline_uses_--;
122   }
123 
IsInUseByCompiler()124   bool IsInUseByCompiler() const {
125     return IsMethodBeingCompiled(/*osr=*/ true) || IsMethodBeingCompiled(/*osr=*/ false) ||
126         (current_inline_uses_ > 0);
127   }
128 
BaselineHotnessCountOffset()129   static constexpr MemberOffset BaselineHotnessCountOffset() {
130     return MemberOffset(OFFSETOF_MEMBER(ProfilingInfo, baseline_hotness_count_));
131   }
132 
SetBaselineHotnessCount(uint16_t count)133   void SetBaselineHotnessCount(uint16_t count) {
134     baseline_hotness_count_ = count;
135   }
136 
GetBaselineHotnessCount()137   uint16_t GetBaselineHotnessCount() const {
138     return baseline_hotness_count_;
139   }
140 
141  private:
142   ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries);
143 
144   // Hotness count for methods compiled with the JIT baseline compiler. Once
145   // a threshold is hit (currentily the maximum value of uint16_t), we will
146   // JIT compile optimized the method.
147   uint16_t baseline_hotness_count_;
148 
149   // Method this profiling info is for.
150   // Not 'const' as JVMTI introduces obsolete methods that we implement by creating new ArtMethods.
151   // See JitCodeCache::MoveObsoleteMethod.
152   ArtMethod* method_;
153 
154   // Entry point of the corresponding ArtMethod, while the JIT code cache
155   // is poking for the liveness of compiled code.
156   const void* saved_entry_point_;
157 
158   // Number of instructions we are profiling in the ArtMethod.
159   const uint32_t number_of_inline_caches_;
160 
161   // When the compiler inlines the method associated to this ProfilingInfo,
162   // it updates this counter so that the GC does not try to clear the inline caches.
163   uint16_t current_inline_uses_;
164 
165   // Whether the ArtMethod is currently being compiled. This flag
166   // is implicitly guarded by the JIT code cache lock.
167   // TODO: Make the JIT code cache lock global.
168   bool is_method_being_compiled_;
169   bool is_osr_method_being_compiled_;
170 
171   // Dynamically allocated array of size `number_of_inline_caches_`.
172   InlineCache cache_[0];
173 
174   friend class jit::JitCodeCache;
175 
176   DISALLOW_COPY_AND_ASSIGN(ProfilingInfo);
177 };
178 
179 }  // namespace art
180 
181 #endif  // ART_RUNTIME_JIT_PROFILING_INFO_H_
182