blob: ffdf00a4113fc90928383440654dc4c5e0c0312a [file] [log] [blame]
Mingyao Yang063fc772016-08-02 11:02:54 -07001/*
2 * Copyright (C) 2016 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_CHA_H_
18#define ART_RUNTIME_CHA_H_
19
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070020#include <unordered_map>
21#include <unordered_set>
22
Mingyao Yang063fc772016-08-02 11:02:54 -070023#include "base/enums.h"
Andreas Gampe7fbc4a52018-11-28 08:26:47 -080024#include "base/locks.h"
Dmitrii Ishcheikinf63924e2024-01-17 14:53:20 +000025#include "base/macros.h"
Mingyao Yang063fc772016-08-02 11:02:54 -070026#include "handle.h"
27#include "mirror/class.h"
Dmitrii Ishcheikin06d94bd2024-01-17 15:54:51 +000028#include "oat/oat_quick_method_header.h"
Mingyao Yang063fc772016-08-02 11:02:54 -070029
Dmitrii Ishcheikinf63924e2024-01-17 14:53:20 +000030namespace art HIDDEN {
Mingyao Yang063fc772016-08-02 11:02:54 -070031
Andreas Gamped4901292017-05-30 18:41:34 -070032class ArtMethod;
Mathieu Chartiercf79cf52017-07-21 11:17:57 -070033class LinearAlloc;
Andreas Gamped4901292017-05-30 18:41:34 -070034
Mingyao Yang063fc772016-08-02 11:02:54 -070035/**
36 * Class Hierarchy Analysis (CHA) tries to devirtualize virtual calls into
37 * direct calls based on the info generated by analyzing class hierarchies.
38 * If a class is not subclassed, or even if it's subclassed but one of its
39 * virtual methods isn't overridden, a virtual call for that method can be
40 * changed into a direct call.
41 *
42 * Each virtual method carries a single-implementation status. The status is
43 * incrementally maintained at the end of class linking time when method
44 * overriding takes effect.
45 *
46 * Compiler takes advantage of the single-implementation info of a
47 * method. If a method A has the single-implementation flag set, the compiler
48 * devirtualizes the virtual call for method A into a direct call, and
49 * further try to inline the direct call as a result. The compiler will
50 * also register a dependency that the compiled code depends on the
51 * assumption that method A has single-implementation status.
52 *
53 * When single-implementation info is updated at the end of class linking,
54 * and if method A's single-implementation status is invalidated, all compiled
55 * code that depends on the assumption that method A has single-implementation
56 * status need to be invalidated. Method entrypoints that have this dependency
57 * will be updated as a result. Method A can later be recompiled with less
58 * aggressive assumptions.
59 *
60 * For live compiled code that's on stack, deoptmization will be initiated
61 * to force the invalidated compiled code into interpreter mode to guarantee
62 * correctness. The deoptimization mechanism used is a hybrid of
63 * synchronous and asynchronous deoptimization. The synchronous deoptimization
64 * part checks a hidden local variable flag for the method, and if true,
65 * initiates deoptimization. The asynchronous deoptimization part issues a
66 * checkpoint that walks the stack and for any compiled code on the stack
67 * that should be deoptimized, set the hidden local variable value to be true.
68 *
69 * A cha_lock_ needs to be held for updating single-implementation status,
70 * and registering/unregistering CHA dependencies. Registering CHA dependency
71 * and making compiled code visible also need to be atomic. Otherwise, we
72 * may miss invalidating CHA dependents or making compiled code visible even
73 * after it is invalidated. Care needs to be taken between cha_lock_ and
74 * JitCodeCache::lock_ to guarantee the atomicity.
75 *
76 * We base our CHA on dynamically linked class profiles instead of doing static
77 * analysis. Static analysis can be too aggressive due to dynamic class loading
78 * at runtime, and too conservative since some classes may not be really loaded
79 * at runtime.
80 */
81class ClassHierarchyAnalysis {
82 public:
83 // Types for recording CHA dependencies.
84 // For invalidating CHA dependency, we need to know both the ArtMethod and
85 // the method header. If the ArtMethod has compiled code with the method header
86 // as the entrypoint, we update the entrypoint to the interpreter bridge.
87 // We will also deoptimize frames that are currently executing the code of
88 // the method header.
Vladimir Marko4f990712021-07-14 12:45:13 +010089 using MethodAndMethodHeaderPair = std::pair<ArtMethod*, OatQuickMethodHeader*>;
90 using ListOfDependentPairs = std::vector<MethodAndMethodHeaderPair>;
Mingyao Yang063fc772016-08-02 11:02:54 -070091
92 ClassHierarchyAnalysis() {}
93
94 // Add a dependency that compiled code with `dependent_header` for `dependent_method`
95 // assumes that virtual `method` has single-implementation.
96 void AddDependency(ArtMethod* method,
97 ArtMethod* dependent_method,
98 OatQuickMethodHeader* dependent_header) REQUIRES(Locks::cha_lock_);
99
100 // Return compiled code that assumes that `method` has single-implementation.
Mingyao Yangcc104502017-05-24 17:13:03 -0700101 const ListOfDependentPairs& GetDependents(ArtMethod* method) REQUIRES(Locks::cha_lock_);
Mingyao Yang063fc772016-08-02 11:02:54 -0700102
103 // Remove dependency tracking for compiled code that assumes that
104 // `method` has single-implementation.
Mingyao Yangcc104502017-05-24 17:13:03 -0700105 void RemoveAllDependenciesFor(ArtMethod* method) REQUIRES(Locks::cha_lock_);
Mingyao Yang063fc772016-08-02 11:02:54 -0700106
107 // Remove from cha_dependency_map_ all entries that contain OatQuickMethodHeader from
108 // the given `method_headers` set.
109 // This is used when some compiled code is freed.
110 void RemoveDependentsWithMethodHeaders(
111 const std::unordered_set<OatQuickMethodHeader*>& method_headers)
112 REQUIRES(Locks::cha_lock_);
113
Alexey Grebenkinbe4c2bd2018-02-01 19:09:59 +0300114 // If a given class belongs to a linear allocation that is about to be deleted, in all its
115 // superclasses and superinterfaces reset SingleImplementation fields of their methods
116 // that might be affected by the deletion.
117 // The method is intended to be called during GC before ReclaimPhase, since it gets info from
118 // Java objects that are going to be collected.
119 // For the same reason it's important to access objects without read barrier to not revive them.
120 void ResetSingleImplementationInHierarchy(ObjPtr<mirror::Class> klass,
121 const LinearAlloc* alloc,
122 PointerSize pointer_size)
123 const REQUIRES_SHARED(Locks::mutator_lock_);
124
Mingyao Yang063fc772016-08-02 11:02:54 -0700125 // Update CHA info for methods that `klass` overrides, after loading `klass`.
126 void UpdateAfterLoadingOf(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
127
Mathieu Chartiercf79cf52017-07-21 11:17:57 -0700128 // Remove all of the dependencies for a linear allocator. This is called when dex cache unloading
129 // occurs.
Vladimir Marko8e94a6f2022-12-13 16:46:22 +0000130 void RemoveDependenciesForLinearAlloc(Thread* self, const LinearAlloc* linear_alloc)
Mathieu Chartiercf79cf52017-07-21 11:17:57 -0700131 REQUIRES(!Locks::cha_lock_);
132
Mingyao Yang063fc772016-08-02 11:02:54 -0700133 private:
Mingyao Yange8fcd012017-01-20 10:43:30 -0800134 void InitSingleImplementationFlag(Handle<mirror::Class> klass,
135 ArtMethod* method,
136 PointerSize pointer_size)
Mingyao Yang063fc772016-08-02 11:02:54 -0700137 REQUIRES_SHARED(Locks::mutator_lock_);
138
Nicolas Geoffray18ea1c92017-03-27 08:00:18 +0000139 // Check/update single-implementation info when one virtual method
140 // overrides another.
Mingyao Yang063fc772016-08-02 11:02:54 -0700141 // `virtual_method` in `klass` overrides `method_in_super`.
Nicolas Geoffray18ea1c92017-03-27 08:00:18 +0000142 // This may invalidate some assumptions on single-implementation.
Mingyao Yang063fc772016-08-02 11:02:54 -0700143 // Append methods that should have their single-implementation flag invalidated
144 // to `invalidated_single_impl_methods`.
Nicolas Geoffray18ea1c92017-03-27 08:00:18 +0000145 void CheckVirtualMethodSingleImplementationInfo(
Mingyao Yang063fc772016-08-02 11:02:54 -0700146 Handle<mirror::Class> klass,
147 ArtMethod* virtual_method,
148 ArtMethod* method_in_super,
Mingyao Yange8fcd012017-01-20 10:43:30 -0800149 std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
150 PointerSize pointer_size)
Mingyao Yang063fc772016-08-02 11:02:54 -0700151 REQUIRES_SHARED(Locks::mutator_lock_);
152
Nicolas Geoffray18ea1c92017-03-27 08:00:18 +0000153 // Check/update single-implementation info when one method
154 // implements an interface method.
155 // `implementation_method` in `klass` implements `interface_method`.
156 // Append `interface_method` to `invalidated_single_impl_methods`
157 // if `interface_method` gets a new implementation.
158 void CheckInterfaceMethodSingleImplementationInfo(
159 Handle<mirror::Class> klass,
160 ArtMethod* interface_method,
161 ArtMethod* implementation_method,
162 std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
163 PointerSize pointer_size)
164 REQUIRES_SHARED(Locks::mutator_lock_);
165
166 void InvalidateSingleImplementationMethods(
167 std::unordered_set<ArtMethod*>& invalidated_single_impl_methods)
168 REQUIRES_SHARED(Locks::mutator_lock_);
169
Mingyao Yang063fc772016-08-02 11:02:54 -0700170 // A map that maps a method to a set of compiled code that assumes that method has a
171 // single implementation, which is used to do CHA-based devirtualization.
Mingyao Yangcc104502017-05-24 17:13:03 -0700172 std::unordered_map<ArtMethod*, ListOfDependentPairs> cha_dependency_map_
Mingyao Yang063fc772016-08-02 11:02:54 -0700173 GUARDED_BY(Locks::cha_lock_);
174
175 DISALLOW_COPY_AND_ASSIGN(ClassHierarchyAnalysis);
176};
177
178} // namespace art
179
180#endif // ART_RUNTIME_CHA_H_