1 /* Copyright (C) 2017 The Android Open Source Project
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This file implements interfaces from the file jvmti.h. This implementation
5  * is licensed under the same terms as the file jvmti.h.  The
6  * copyright and license information for the file jvmti.h follows.
7  *
8  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
9  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
10  *
11  * This code is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License version 2 only, as
13  * published by the Free Software Foundation.  Oracle designates this
14  * particular file as subject to the "Classpath" exception as provided
15  * by Oracle in the LICENSE file that accompanied this code.
16  *
17  * This code is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * version 2 for more details (a copy is included in the LICENSE file that
21  * accompanied this code).
22  *
23  * You should have received a copy of the GNU General Public License version
24  * 2 along with this work; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26  *
27  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
28  * or visit www.oracle.com if you need additional information or have any
29  * questions.
30  */
31 
32 #ifndef ART_OPENJDKJVMTI_DEOPT_MANAGER_H_
33 #define ART_OPENJDKJVMTI_DEOPT_MANAGER_H_
34 
35 #include <atomic>
36 #include <iosfwd>
37 #include <unordered_map>
38 
39 #include "base/mutex.h"
40 #include "runtime_callbacks.h"
41 
42 #include <jvmti.h>
43 
44 namespace art {
45 class ArtMethod;
46 class ScopedObjectAccessUnchecked;
47 namespace mirror {
48 class Class;
49 }  // namespace mirror
50 }  // namespace art
51 
52 namespace openjdkjvmti {
53 
54 class DeoptManager;
55 
56 struct JvmtiMethodInspectionCallback : public art::MethodInspectionCallback {
57  public:
JvmtiMethodInspectionCallbackJvmtiMethodInspectionCallback58   explicit JvmtiMethodInspectionCallback(DeoptManager* manager) : manager_(manager) {}
59 
60   bool IsMethodBeingInspected(art::ArtMethod* method)
61       override REQUIRES_SHARED(art::Locks::mutator_lock_);
62 
63   bool IsMethodSafeToJit(art::ArtMethod* method)
64       override REQUIRES_SHARED(art::Locks::mutator_lock_);
65 
66   bool MethodNeedsDebugVersion(art::ArtMethod* method)
67       override REQUIRES_SHARED(art::Locks::mutator_lock_);
68 
69  private:
70   DeoptManager* manager_;
71 };
72 
73 class ScopedDeoptimizationContext;
74 
75 class DeoptManager {
76  public:
77   DeoptManager();
78 
79   void Setup();
80   void Shutdown();
81 
82   void DumpDeoptInfo(art::Thread* self, std::ostream& stream);
83 
84   void RemoveDeoptimizationRequester() REQUIRES(!deoptimization_status_lock_,
85                                                 !art::Roles::uninterruptible_);
86   void AddDeoptimizationRequester() REQUIRES(!deoptimization_status_lock_,
87                                              !art::Roles::uninterruptible_);
88   bool MethodHasBreakpoints(art::ArtMethod* method)
89       REQUIRES(!deoptimization_status_lock_);
90 
91   void RemoveMethodBreakpoint(art::ArtMethod* method)
92       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
93       REQUIRES_SHARED(art::Locks::mutator_lock_);
94 
95   void AddMethodBreakpoint(art::ArtMethod* method)
96       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
97       REQUIRES_SHARED(art::Locks::mutator_lock_);
98 
99   void AddDeoptimizeAllMethods()
100       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
101       REQUIRES_SHARED(art::Locks::mutator_lock_);
102 
103   void RemoveDeoptimizeAllMethods()
104       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
105       REQUIRES_SHARED(art::Locks::mutator_lock_);
106 
107   jvmtiError AddDeoptimizeThreadMethods(art::ScopedObjectAccessUnchecked& soa, jthread thread)
108       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
109       REQUIRES_SHARED(art::Locks::mutator_lock_);
110 
111   jvmtiError RemoveDeoptimizeThreadMethods(art::ScopedObjectAccessUnchecked& soa, jthread thread)
112       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
113       REQUIRES_SHARED(art::Locks::mutator_lock_);
114 
115   void DeoptimizeThread(art::Thread* target)
116       REQUIRES(!art::Locks::thread_list_lock_)
117       REQUIRES_SHARED(art::Locks::mutator_lock_);
118   void DeoptimizeAllThreads() REQUIRES_SHARED(art::Locks::mutator_lock_);
119 
120   void FinishSetup()
121       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
122       REQUIRES(art::Locks::mutator_lock_);
123 
124   static DeoptManager* Get();
125 
HaveLocalsChanged()126   bool HaveLocalsChanged() const {
127     return set_local_variable_called_.load();
128   }
129 
SetLocalsUpdated()130   void SetLocalsUpdated() {
131     set_local_variable_called_.store(true);
132   }
133 
134  private:
135   bool MethodHasBreakpointsLocked(art::ArtMethod* method)
136       REQUIRES(breakpoint_status_lock_);
137 
138   // Wait until nothing is currently in the middle of deoptimizing/undeoptimizing something. This is
139   // needed to ensure that everything is synchronized since threads need to drop the
140   // deoptimization_status_lock_ while deoptimizing methods.
141   void WaitForDeoptimizationToFinish(art::Thread* self)
142       RELEASE(deoptimization_status_lock_) REQUIRES(!art::Locks::mutator_lock_);
143 
144   void WaitForDeoptimizationToFinishLocked(art::Thread* self)
145       REQUIRES(deoptimization_status_lock_, !art::Locks::mutator_lock_);
146 
147   void AddDeoptimizeAllMethodsLocked(art::Thread* self)
148       RELEASE(deoptimization_status_lock_)
149       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
150 
151   void RemoveDeoptimizeAllMethodsLocked(art::Thread* self)
152       RELEASE(deoptimization_status_lock_)
153       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
154 
155   void PerformGlobalDeoptimization(art::Thread* self)
156       RELEASE(deoptimization_status_lock_)
157       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
158 
159   void PerformGlobalUndeoptimization(art::Thread* self)
160       RELEASE(deoptimization_status_lock_)
161       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
162 
163   void PerformLimitedDeoptimization(art::Thread* self, art::ArtMethod* method)
164       RELEASE(deoptimization_status_lock_)
165       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
166 
167   void PerformLimitedUndeoptimization(art::Thread* self, art::ArtMethod* method)
168       RELEASE(deoptimization_status_lock_)
169       REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_);
170 
171   static constexpr const char* kDeoptManagerInstrumentationKey = "JVMTI_DeoptManager";
172 
173   art::Mutex deoptimization_status_lock_ ACQUIRED_BEFORE(art::Locks::classlinker_classes_lock_);
174   art::ConditionVariable deoptimization_condition_ GUARDED_BY(deoptimization_status_lock_);
175   bool performing_deoptimization_ GUARDED_BY(deoptimization_status_lock_);
176 
177   // Number of times we have gotten requests to deopt everything.
178   uint32_t global_deopt_count_ GUARDED_BY(deoptimization_status_lock_);
179 
180   // Number of users of deoptimization there currently are.
181   uint32_t deopter_count_ GUARDED_BY(deoptimization_status_lock_);
182 
183   // A mutex that just protects the breakpoint-status map. This mutex should always be at the
184   // bottom of the lock hierarchy. Nothing more should be locked if we hold this.
185   art::Mutex breakpoint_status_lock_ ACQUIRED_BEFORE(art::Locks::abort_lock_);
186   // A map from methods to the number of breakpoints in them from all envs.
187   std::unordered_map<art::ArtMethod*, uint32_t> breakpoint_status_
188       GUARDED_BY(breakpoint_status_lock_);
189 
190   // The MethodInspectionCallback we use to tell the runtime if we care about particular methods.
191   JvmtiMethodInspectionCallback inspection_callback_;
192 
193   // Set to true if anything calls SetLocalVariables on any thread since we need to be careful about
194   // OSR after this.
195   std::atomic<bool> set_local_variable_called_;
196 
197   // Helper for setting up/tearing-down for deoptimization.
198   friend class ScopedDeoptimizationContext;
199 };
200 
201 }  // namespace openjdkjvmti
202 #endif  // ART_OPENJDKJVMTI_DEOPT_MANAGER_H_
203