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 
SetSavedEntryPoint(const void * entry_point)86   void SetSavedEntryPoint(const void* entry_point) {
87     saved_entry_point_ = entry_point;
88   }
89 
GetSavedEntryPoint()90   const void* GetSavedEntryPoint() const {
91     return saved_entry_point_;
92   }
93 
94   // Increments the number of times this method is currently being inlined.
95   // Returns whether it was successful, that is it could increment without
96   // overflowing.
IncrementInlineUse()97   bool IncrementInlineUse() {
98     if (current_inline_uses_ == std::numeric_limits<uint16_t>::max()) {
99       return false;
100     }
101     current_inline_uses_++;
102     return true;
103   }
104 
DecrementInlineUse()105   void DecrementInlineUse() {
106     DCHECK_GT(current_inline_uses_, 0);
107     current_inline_uses_--;
108   }
109 
IsInUseByCompiler()110   bool IsInUseByCompiler() const {
111     return current_inline_uses_ > 0;
112   }
113 
BaselineHotnessCountOffset()114   static constexpr MemberOffset BaselineHotnessCountOffset() {
115     return MemberOffset(OFFSETOF_MEMBER(ProfilingInfo, baseline_hotness_count_));
116   }
117 
SetBaselineHotnessCount(uint16_t count)118   void SetBaselineHotnessCount(uint16_t count) {
119     baseline_hotness_count_ = count;
120   }
121 
GetBaselineHotnessCount()122   uint16_t GetBaselineHotnessCount() const {
123     return baseline_hotness_count_;
124   }
125 
126  private:
127   ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& entries);
128 
129   // Hotness count for methods compiled with the JIT baseline compiler. Once
130   // a threshold is hit (currentily the maximum value of uint16_t), we will
131   // JIT compile optimized the method.
132   uint16_t baseline_hotness_count_;
133 
134   // Method this profiling info is for.
135   // Not 'const' as JVMTI introduces obsolete methods that we implement by creating new ArtMethods.
136   // See JitCodeCache::MoveObsoleteMethod.
137   ArtMethod* method_;
138 
139   // Entry point of the corresponding ArtMethod, while the JIT code cache
140   // is poking for the liveness of compiled code.
141   const void* saved_entry_point_;
142 
143   // Number of instructions we are profiling in the ArtMethod.
144   const uint32_t number_of_inline_caches_;
145 
146   // When the compiler inlines the method associated to this ProfilingInfo,
147   // it updates this counter so that the GC does not try to clear the inline caches.
148   uint16_t current_inline_uses_;
149 
150   // Dynamically allocated array of size `number_of_inline_caches_`.
151   InlineCache cache_[0];
152 
153   friend class jit::JitCodeCache;
154 
155   DISALLOW_COPY_AND_ASSIGN(ProfilingInfo);
156 };
157 
158 }  // namespace art
159 
160 #endif  // ART_RUNTIME_JIT_PROFILING_INFO_H_
161