blob: be675a82c8e1bcb1429b4509a08fca0c947c602b [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#include "cha.h"
18
19#include "jit/jit.h"
20#include "jit/jit_code_cache.h"
21#include "runtime.h"
22#include "scoped_thread_state_change-inl.h"
23#include "stack.h"
24#include "thread.h"
25#include "thread_list.h"
26#include "thread_pool.h"
27
28namespace art {
29
30void ClassHierarchyAnalysis::AddDependency(ArtMethod* method,
31 ArtMethod* dependent_method,
32 OatQuickMethodHeader* dependent_header) {
33 auto it = cha_dependency_map_.find(method);
34 if (it == cha_dependency_map_.end()) {
35 cha_dependency_map_[method] =
36 new std::vector<std::pair<art::ArtMethod*, art::OatQuickMethodHeader*>>();
37 it = cha_dependency_map_.find(method);
38 } else {
39 DCHECK(it->second != nullptr);
40 }
41 it->second->push_back(std::make_pair(dependent_method, dependent_header));
42}
43
44std::vector<std::pair<ArtMethod*, OatQuickMethodHeader*>>*
45 ClassHierarchyAnalysis::GetDependents(ArtMethod* method) {
46 auto it = cha_dependency_map_.find(method);
47 if (it != cha_dependency_map_.end()) {
48 DCHECK(it->second != nullptr);
49 return it->second;
50 }
51 return nullptr;
52}
53
54void ClassHierarchyAnalysis::RemoveDependencyFor(ArtMethod* method) {
55 auto it = cha_dependency_map_.find(method);
56 if (it != cha_dependency_map_.end()) {
57 auto dependents = it->second;
58 cha_dependency_map_.erase(it);
59 delete dependents;
60 }
61}
62
63void ClassHierarchyAnalysis::RemoveDependentsWithMethodHeaders(
64 const std::unordered_set<OatQuickMethodHeader*>& method_headers) {
65 // Iterate through all entries in the dependency map and remove any entry that
66 // contains one of those in method_headers.
67 for (auto map_it = cha_dependency_map_.begin(); map_it != cha_dependency_map_.end(); ) {
68 auto dependents = map_it->second;
69 for (auto vec_it = dependents->begin(); vec_it != dependents->end(); ) {
70 OatQuickMethodHeader* method_header = vec_it->second;
71 auto it = std::find(method_headers.begin(), method_headers.end(), method_header);
72 if (it != method_headers.end()) {
73 vec_it = dependents->erase(vec_it);
74 } else {
75 vec_it++;
76 }
77 }
78 // Remove the map entry if there are no more dependents.
79 if (dependents->empty()) {
80 map_it = cha_dependency_map_.erase(map_it);
81 delete dependents;
82 } else {
83 map_it++;
84 }
85 }
86}
87
88// This stack visitor walks the stack and for compiled code with certain method
89// headers, sets the should_deoptimize flag on stack to 1.
90// TODO: also set the register value to 1 when should_deoptimize is allocated in
91// a register.
92class CHAStackVisitor FINAL : public StackVisitor {
93 public:
94 CHAStackVisitor(Thread* thread_in,
95 Context* context,
96 const std::unordered_set<OatQuickMethodHeader*>& method_headers)
97 : StackVisitor(thread_in, context, StackVisitor::StackWalkKind::kSkipInlinedFrames),
98 method_headers_(method_headers) {
99 }
100
101 bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
102 ArtMethod* method = GetMethod();
103 if (method == nullptr || method->IsRuntimeMethod() || method->IsNative()) {
104 return true;
105 }
106 if (GetCurrentQuickFrame() == nullptr) {
107 // Not compiled code.
108 return true;
109 }
110 // Method may have multiple versions of compiled code. Check
111 // the method header to see if it has should_deoptimize flag.
112 const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
113 if (!method_header->HasShouldDeoptimizeFlag()) {
114 // This compiled version doesn't have should_deoptimize flag. Skip.
115 return true;
116 }
117 auto it = std::find(method_headers_.begin(), method_headers_.end(), method_header);
118 if (it == method_headers_.end()) {
119 // Not in the list of method headers that should be deoptimized.
120 return true;
121 }
122
123 // The compiled code on stack is not valid anymore. Need to deoptimize.
124 SetShouldDeoptimizeFlag();
125
126 return true;
127 }
128
129 private:
130 void SetShouldDeoptimizeFlag() REQUIRES_SHARED(Locks::mutator_lock_) {
131 QuickMethodFrameInfo frame_info = GetCurrentQuickFrameInfo();
132 size_t frame_size = frame_info.FrameSizeInBytes();
133 uint8_t* sp = reinterpret_cast<uint8_t*>(GetCurrentQuickFrame());
134 size_t core_spill_size = POPCOUNT(frame_info.CoreSpillMask()) *
135 GetBytesPerGprSpillLocation(kRuntimeISA);
136 size_t fpu_spill_size = POPCOUNT(frame_info.FpSpillMask()) *
137 GetBytesPerFprSpillLocation(kRuntimeISA);
138 size_t offset = frame_size - core_spill_size - fpu_spill_size - kShouldDeoptimizeFlagSize;
139 uint8_t* should_deoptimize_addr = sp + offset;
140 // Set deoptimization flag to 1.
141 DCHECK(*should_deoptimize_addr == 0 || *should_deoptimize_addr == 1);
142 *should_deoptimize_addr = 1;
143 }
144
145 // Set of method headers for compiled code that should be deoptimized.
146 const std::unordered_set<OatQuickMethodHeader*>& method_headers_;
147
148 DISALLOW_COPY_AND_ASSIGN(CHAStackVisitor);
149};
150
151class CHACheckpoint FINAL : public Closure {
152 public:
153 explicit CHACheckpoint(const std::unordered_set<OatQuickMethodHeader*>& method_headers)
154 : barrier_(0),
155 method_headers_(method_headers) {}
156
157 void Run(Thread* thread) OVERRIDE {
158 // Note thread and self may not be equal if thread was already suspended at
159 // the point of the request.
160 Thread* self = Thread::Current();
161 ScopedObjectAccess soa(self);
162 CHAStackVisitor visitor(thread, nullptr, method_headers_);
163 visitor.WalkStack();
164 barrier_.Pass(self);
165 }
166
167 void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
168 Thread* self = Thread::Current();
169 ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
170 barrier_.Increment(self, threads_running_checkpoint);
171 }
172
173 private:
174 // The barrier to be passed through and for the requestor to wait upon.
175 Barrier barrier_;
176 // List of method headers for invalidated compiled code.
177 const std::unordered_set<OatQuickMethodHeader*>& method_headers_;
178
179 DISALLOW_COPY_AND_ASSIGN(CHACheckpoint);
180};
181
182void ClassHierarchyAnalysis::VerifyNonSingleImplementation(mirror::Class* verify_class,
183 uint16_t verify_index) {
184 // Grab cha_lock_ to make sure all single-implementation updates are seen.
185 PointerSize image_pointer_size =
186 Runtime::Current()->GetClassLinker()->GetImagePointerSize();
187 MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
188 while (verify_class != nullptr) {
189 if (verify_index >= verify_class->GetVTableLength()) {
190 return;
191 }
192 ArtMethod* verify_method = verify_class->GetVTableEntry(verify_index, image_pointer_size);
193 DCHECK(!verify_method->HasSingleImplementation())
194 << "class: " << verify_class->PrettyClass()
195 << " verify_method: " << verify_method->PrettyMethod(true);
196 verify_class = verify_class->GetSuperClass();
197 }
198}
199
200void ClassHierarchyAnalysis::CheckSingleImplementationInfo(
201 Handle<mirror::Class> klass,
202 ArtMethod* virtual_method,
203 ArtMethod* method_in_super,
204 std::unordered_set<ArtMethod*>& invalidated_single_impl_methods) {
205 // TODO: if klass is not instantiable, virtual_method isn't invocable yet so
206 // even if it overrides, it doesn't invalidate single-implementation
207 // assumption.
208
209 DCHECK_NE(virtual_method, method_in_super);
210 DCHECK(method_in_super->GetDeclaringClass()->IsResolved()) << "class isn't resolved";
211 // If virtual_method doesn't come from a default interface method, it should
212 // be supplied by klass.
213 DCHECK(virtual_method->IsCopied() ||
214 virtual_method->GetDeclaringClass() == klass.Get());
215
216 // A new virtual_method should set method_in_super to
217 // non-single-implementation (if not set already).
218 // We don't grab cha_lock_. Single-implementation flag won't be set to true
219 // again once it's set to false.
220 if (!method_in_super->HasSingleImplementation()) {
221 // method_in_super already has multiple implementations. All methods in the
222 // same vtable slots in its super classes should have
223 // non-single-implementation already.
224 if (kIsDebugBuild) {
225 VerifyNonSingleImplementation(klass->GetSuperClass()->GetSuperClass(),
226 method_in_super->GetMethodIndex());
227 }
228 return;
229 }
230
231 // Native methods don't have single-implementation flag set.
232 DCHECK(!method_in_super->IsNative());
233 // Invalidate method_in_super's single-implementation status.
234 invalidated_single_impl_methods.insert(method_in_super);
235}
236
237void ClassHierarchyAnalysis::InitSingleImplementationFlag(Handle<mirror::Class> klass,
238 ArtMethod* method) {
239 DCHECK(method->IsCopied() || method->GetDeclaringClass() == klass.Get());
240 if (klass->IsFinal() || method->IsFinal()) {
241 // Final classes or methods do not need CHA for devirtualization.
242 // This frees up modifier bits for intrinsics which currently are only
243 // used for static methods or methods of final classes.
244 return;
245 }
246 if (method->IsNative()) {
247 // Native method's invocation overhead is already high and it
248 // cannot be inlined. It's not worthwhile to devirtualize the
249 // call which can add a deoptimization point.
250 DCHECK(!method->HasSingleImplementation());
251 } else {
252 method->SetHasSingleImplementation(true);
253 if (method->IsAbstract()) {
254 // There is no real implementation yet.
255 // TODO: implement single-implementation logic for abstract methods.
256 DCHECK(method->GetSingleImplementation() == nullptr);
257 } else {
258 // Single implementation of non-abstract method is itself.
259 DCHECK_EQ(method->GetSingleImplementation(), method);
260 }
261 }
262}
263
264void ClassHierarchyAnalysis::UpdateAfterLoadingOf(Handle<mirror::Class> klass) {
265 if (klass->IsInterface()) {
266 return;
267 }
268 mirror::Class* super_class = klass->GetSuperClass();
269 if (super_class == nullptr) {
270 return;
271 }
272
273 // Keeps track of all methods whose single-implementation assumption
274 // is invalidated by linking `klass`.
275 std::unordered_set<ArtMethod*> invalidated_single_impl_methods;
276
277 PointerSize image_pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
278 // Do an entry-by-entry comparison of vtable contents with super's vtable.
279 for (int32_t i = 0; i < super_class->GetVTableLength(); ++i) {
280 ArtMethod* method = klass->GetVTableEntry(i, image_pointer_size);
281 ArtMethod* method_in_super = super_class->GetVTableEntry(i, image_pointer_size);
282 if (method == method_in_super) {
283 // vtable slot entry is inherited from super class.
284 continue;
285 }
286 InitSingleImplementationFlag(klass, method);
287 CheckSingleImplementationInfo(klass,
288 method,
289 method_in_super,
290 invalidated_single_impl_methods);
291 }
292
293 // For new virtual methods that don't override.
294 for (int32_t i = super_class->GetVTableLength(); i < klass->GetVTableLength(); ++i) {
295 ArtMethod* method = klass->GetVTableEntry(i, image_pointer_size);
296 InitSingleImplementationFlag(klass, method);
297 }
298
299 Runtime* const runtime = Runtime::Current();
300 if (!invalidated_single_impl_methods.empty()) {
301 Thread *self = Thread::Current();
302 // Method headers for compiled code to be invalidated.
303 std::unordered_set<OatQuickMethodHeader*> dependent_method_headers;
304
305 {
306 // We do this under cha_lock_. Committing code also grabs this lock to
307 // make sure the code is only committed when all single-implementation
308 // assumptions are still true.
309 MutexLock cha_mu(self, *Locks::cha_lock_);
310 // Invalidate compiled methods that assume some virtual calls have only
311 // single implementations.
312 for (ArtMethod* invalidated : invalidated_single_impl_methods) {
313 if (!invalidated->HasSingleImplementation()) {
314 // It might have been invalidated already when other class linking is
315 // going on.
316 continue;
317 }
318 invalidated->SetHasSingleImplementation(false);
319
320 if (runtime->IsAotCompiler()) {
321 // No need to invalidate any compiled code as the AotCompiler doesn't
322 // run any code.
323 continue;
324 }
325
326 // Invalidate all dependents.
327 auto dependents = GetDependents(invalidated);
328 if (dependents == nullptr) {
329 continue;
330 }
331 for (const auto& dependent : *dependents) {
332 ArtMethod* method = dependent.first;;
333 OatQuickMethodHeader* method_header = dependent.second;
334 VLOG(class_linker) << "CHA invalidated compiled code for " << method->PrettyMethod();
335 DCHECK(runtime->UseJitCompilation());
336 runtime->GetJit()->GetCodeCache()->InvalidateCompiledCodeFor(
337 method, method_header);
338 dependent_method_headers.insert(method_header);
339 }
340 RemoveDependencyFor(invalidated);
341 }
342 }
343
344 if (dependent_method_headers.empty()) {
345 return;
346 }
347 // Deoptimze compiled code on stack that should have been invalidated.
348 CHACheckpoint checkpoint(dependent_method_headers);
349 size_t threads_running_checkpoint = runtime->GetThreadList()->RunCheckpoint(&checkpoint);
350 if (threads_running_checkpoint != 0) {
351 checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint);
352 }
353 }
354}
355
356} // namespace art