1 /*
  2  * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_RUNTIME_VMOPERATIONS_HPP
 26 #define SHARE_RUNTIME_VMOPERATIONS_HPP
 27 
 28 #include "oops/oop.hpp"
 29 #include "runtime/javaThread.hpp"
 30 #include "runtime/vmOperation.hpp"
 31 #include "runtime/threadSMR.hpp"
 32 
 33 class ObjectMonitorsView;
 34 
 35 // A hodge podge of commonly used VM Operations
 36 
 37 class VM_EmptyOperation : public VM_Operation {
 38 public:
 39   virtual void doit() final {}
 40   virtual bool skip_thread_oop_barriers() const final {
 41     // Neither the doit function nor the safepoint
 42     // cleanup tasks read oops in the Java threads.
 43     return true;
 44   }
 45 };
 46 
 47 class VM_Halt: public VM_EmptyOperation {
 48  public:
 49   VMOp_Type type() const { return VMOp_Halt; }
 50 };
 51 
 52 class VM_SafepointALot: public VM_EmptyOperation {
 53  public:
 54   VMOp_Type type() const { return VMOp_SafepointALot; }
 55 };
 56 
 57 class VM_Cleanup: public VM_EmptyOperation {
 58  public:
 59   VMOp_Type type() const { return VMOp_Cleanup; }
 60 };
 61 
 62 // empty vm op, evaluated just to force a safepoint
 63 class VM_ForceSafepoint: public VM_EmptyOperation {
 64  public:
 65   VMOp_Type type() const { return VMOp_ForceSafepoint; }
 66 };
 67 
 68 // empty vm op, when forcing a safepoint due to inline cache buffers being full
 69 class VM_ICBufferFull: public VM_EmptyOperation {
 70  public:
 71   VMOp_Type type() const { return VMOp_ICBufferFull; }
 72 };
 73 
 74 class VM_ClearICs: public VM_Operation {
 75  private:
 76   bool _preserve_static_stubs;
 77  public:
 78   VM_ClearICs(bool preserve_static_stubs) { _preserve_static_stubs = preserve_static_stubs; }
 79   void doit();
 80   VMOp_Type type() const { return VMOp_ClearICs; }
 81 };
 82 
 83 // Base class for invoking parts of a gtest in a safepoint.
 84 // Derived classes provide the doit method.
 85 // Typically also need to transition the gtest thread from native to VM.
 86 class VM_GTestExecuteAtSafepoint: public VM_Operation {
 87  public:
 88   VMOp_Type type() const                         { return VMOp_GTestExecuteAtSafepoint; }
 89 
 90  protected:
 91   VM_GTestExecuteAtSafepoint() {}
 92 };
 93 
 94 class VM_CleanClassLoaderDataMetaspaces : public VM_Operation {
 95  public:
 96   VM_CleanClassLoaderDataMetaspaces() {}
 97   VMOp_Type type() const                         { return VMOp_CleanClassLoaderDataMetaspaces; }
 98   void doit();
 99 };
100 
101 // Deopt helper that can deoptimize frames in threads other than the
102 // current thread.  Only used through Deoptimization::deoptimize_frame.
103 class VM_DeoptimizeFrame: public VM_Operation {
104   friend class Deoptimization;
105 
106  private:
107   JavaThread* _thread;
108   intptr_t*   _id;
109   int _reason;
110   VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason);
111 
112  public:
113   VMOp_Type type() const                         { return VMOp_DeoptimizeFrame; }
114   void doit();
115   bool allow_nested_vm_operations() const        { return true;  }
116 };
117 
118 #ifndef PRODUCT
119 class VM_DeoptimizeAll: public VM_Operation {
120  public:
121   VM_DeoptimizeAll() {}
122   VMOp_Type type() const                         { return VMOp_DeoptimizeAll; }
123   void doit();
124   bool allow_nested_vm_operations() const        { return true; }
125 };
126 
127 
128 class VM_ZombieAll: public VM_Operation {
129  public:
130   VM_ZombieAll() {}
131   VMOp_Type type() const                         { return VMOp_ZombieAll; }
132   void doit();
133   bool allow_nested_vm_operations() const        { return true; }
134 };
135 #endif // PRODUCT
136 
137 class VM_PrintThreads: public VM_Operation {
138  private:
139   outputStream* _out;
140   bool _print_concurrent_locks;
141   bool _print_extended_info;
142   bool _print_jni_handle_info;
143  public:
144   VM_PrintThreads()
145     : _out(tty), _print_concurrent_locks(PrintConcurrentLocks), _print_extended_info(false), _print_jni_handle_info(false)
146   {}
147   VM_PrintThreads(outputStream* out, bool print_concurrent_locks, bool print_extended_info, bool print_jni_handle_info)
148     : _out(out), _print_concurrent_locks(print_concurrent_locks), _print_extended_info(print_extended_info),
149       _print_jni_handle_info(print_jni_handle_info)
150   {}
151   VMOp_Type type() const {
152     return VMOp_PrintThreads;
153   }
154   void doit();
155   bool doit_prologue();
156   void doit_epilogue();
157 };
158 
159 class VM_PrintMetadata : public VM_Operation {
160  private:
161   outputStream* const _out;
162   const size_t        _scale;
163   const int           _flags;
164 
165  public:
166   VM_PrintMetadata(outputStream* out, size_t scale, int flags)
167     : _out(out), _scale(scale), _flags(flags)
168   {};
169 
170   VMOp_Type type() const  { return VMOp_PrintMetadata; }
171   void doit();
172 };
173 
174 class DeadlockCycle;
175 class VM_FindDeadlocks: public VM_Operation {
176  private:
177   bool              _concurrent_locks;
178   DeadlockCycle*    _deadlocks;
179   outputStream*     _out;
180   ThreadsListSetter _setter;  // Helper to set hazard ptr in the originating thread
181                               // which protects the JavaThreads in _deadlocks.
182 
183  public:
184   VM_FindDeadlocks(bool concurrent_locks) :  _concurrent_locks(concurrent_locks), _deadlocks(nullptr), _out(nullptr), _setter() {};
185   VM_FindDeadlocks(outputStream* st) : _concurrent_locks(true), _deadlocks(nullptr), _out(st) {};
186   ~VM_FindDeadlocks();
187 
188   DeadlockCycle* result()      { return _deadlocks; };
189   VMOp_Type type() const       { return VMOp_FindDeadlocks; }
190   void doit();
191 };
192 
193 class ThreadDumpResult;
194 class ThreadSnapshot;
195 class ThreadConcurrentLocks;
196 
197 class VM_ThreadDump : public VM_Operation {
198  private:
199   ThreadDumpResult*              _result;
200   int                            _num_threads;
201   GrowableArray<instanceHandle>* _threads;
202   int                            _max_depth;
203   bool                           _with_locked_monitors;
204   bool                           _with_locked_synchronizers;
205 
206   void snapshot_thread(JavaThread* java_thread, ThreadConcurrentLocks* tcl,
207                        ObjectMonitorsView* monitors);
208 
209  public:
210   VM_ThreadDump(ThreadDumpResult* result,
211                 int max_depth,  // -1 indicates entire stack
212                 bool with_locked_monitors,
213                 bool with_locked_synchronizers);
214 
215   VM_ThreadDump(ThreadDumpResult* result,
216                 GrowableArray<instanceHandle>* threads,
217                 int num_threads, // -1 indicates entire stack
218                 int max_depth,
219                 bool with_locked_monitors,
220                 bool with_locked_synchronizers);
221 
222   VMOp_Type type() const { return VMOp_ThreadDump; }
223   void doit();
224   bool doit_prologue();
225   void doit_epilogue();
226 };
227 
228 
229 class VM_Exit: public VM_Operation {
230  private:
231   int  _exit_code;
232   static volatile bool _vm_exited;
233   static Thread * volatile _shutdown_thread;
234   static void wait_if_vm_exited();
235  public:
236   VM_Exit(int exit_code) {
237     _exit_code = exit_code;
238   }
239   static int wait_for_threads_in_native_to_block();
240   static int set_vm_exited();
241   static bool vm_exited()                      { return _vm_exited; }
242   static Thread * shutdown_thread()            { return _shutdown_thread; }
243   static void block_if_vm_exited() {
244     if (_vm_exited) {
245       wait_if_vm_exited();
246     }
247   }
248   VMOp_Type type() const { return VMOp_Exit; }
249   void doit();
250 };
251 
252 class VM_PrintCompileQueue: public VM_Operation {
253  private:
254   outputStream* _out;
255 
256  public:
257   VM_PrintCompileQueue(outputStream* st) : _out(st) {}
258   VMOp_Type type() const { return VMOp_PrintCompileQueue; }
259   void doit();
260 };
261 
262 #if INCLUDE_SERVICES
263 class VM_PrintClassHierarchy: public VM_Operation {
264  private:
265   outputStream* _out;
266   bool _print_interfaces;
267   bool _print_subclasses;
268   char* _classname;
269 
270  public:
271   VM_PrintClassHierarchy(outputStream* st, bool print_interfaces, bool print_subclasses, char* classname) :
272     _out(st), _print_interfaces(print_interfaces), _print_subclasses(print_subclasses),
273     _classname(classname) {}
274   VMOp_Type type() const { return VMOp_PrintClassHierarchy; }
275   void doit();
276 };
277 #endif // INCLUDE_SERVICES
278 
279 #endif // SHARE_RUNTIME_VMOPERATIONS_HPP