1 /*
   2  * Copyright (c) 2012, 2018, 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 #include "precompiled.hpp"
  26 #include "classfile/javaClasses.hpp"
  27 #include "classfile/vmSymbols.hpp"
  28 #include "jfr/jfr.hpp"
  29 #include "jfr/dcmd/jfrDcmds.hpp"
  30 #include "jfr/jni/jfrJavaSupport.hpp"
  31 #include "jfr/recorder/jfrRecorder.hpp"
  32 #include "jfr/recorder/service/jfrOptionSet.hpp"
  33 #include "memory/resourceArea.hpp"
  34 #include "oops/oop.inline.hpp"
  35 #include "oops/symbol.hpp"
  36 #include "runtime/handles.inline.hpp"
  37 #include "services/diagnosticArgument.hpp"
  38 #include "services/diagnosticFramework.hpp"
  39 #include "utilities/globalDefinitions.hpp"
  40 
  41 #ifdef _WINDOWS
  42 #define JFR_FILENAME_EXAMPLE "C:\\Users\\user\\My Recording.jfr"
  43 #endif
  44 
  45 #ifdef __APPLE__
  46 #define JFR_FILENAME_EXAMPLE  "/Users/user/My Recording.jfr"
  47 #endif
  48 
  49 #ifndef JFR_FILENAME_EXAMPLE
  50 #define JFR_FILENAME_EXAMPLE "/home/user/My Recording.jfr"
  51 #endif
  52 
  53 // JNIHandle management
  54 
  55 // ------------------------------------------------------------------
  56 // push_jni_handle_block
  57 //
  58 // Push on a new block of JNI handles.
  59 static void push_jni_handle_block(Thread* const thread) {
  60   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
  61 
  62   // Allocate a new block for JNI handles.
  63   // Inlined code from jni_PushLocalFrame()
  64   JNIHandleBlock* prev_handles = thread->active_handles();
  65   JNIHandleBlock* entry_handles = JNIHandleBlock::allocate_block(thread);
  66   assert(entry_handles != NULL && prev_handles != NULL, "should not be NULL");
  67   entry_handles->set_pop_frame_link(prev_handles);  // make sure prev handles get gc'd.
  68   thread->set_active_handles(entry_handles);
  69 }
  70 
  71 // ------------------------------------------------------------------
  72 // pop_jni_handle_block
  73 //
  74 // Pop off the current block of JNI handles.
  75 static void pop_jni_handle_block(Thread* const thread) {
  76   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
  77 
  78   // Release our JNI handle block
  79   JNIHandleBlock* entry_handles = thread->active_handles();
  80   JNIHandleBlock* prev_handles = entry_handles->pop_frame_link();
  81   // restore
  82   thread->set_active_handles(prev_handles);
  83   entry_handles->set_pop_frame_link(NULL);
  84   JNIHandleBlock::release_block(entry_handles, thread); // may block
  85 }
  86 
  87 class JNIHandleBlockManager : public StackObj {
  88  private:
  89   Thread* const _thread;
  90  public:
  91   JNIHandleBlockManager(Thread* thread) : _thread(thread) {
  92     push_jni_handle_block(_thread);
  93   }
  94 
  95   ~JNIHandleBlockManager() {
  96     pop_jni_handle_block(_thread);
  97   }
  98 };
  99 
 100 static bool is_module_available(outputStream* output, TRAPS) {
 101   return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD);
 102 }
 103 
 104 static bool is_disabled(outputStream* output) {
 105   if (Jfr::is_disabled()) {
 106     if (output != NULL) {
 107       output->print_cr("Flight Recorder is disabled.\n");
 108     }
 109     return true;
 110   }
 111   return false;
 112 }
 113 
 114 static bool is_recorder_instance_created(outputStream* output) {
 115   if (!JfrRecorder::is_created()) {
 116     if (output != NULL) {
 117       output->print_cr("No available recordings.\n");
 118       output->print_cr("Use JFR.start to start a recording.\n");
 119     }
 120     return false;
 121   }
 122   return true;
 123 }
 124 
 125 static bool invalid_state(outputStream* out, TRAPS) {
 126   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 127   return is_disabled(out) || !is_module_available(out, THREAD);
 128 }
 129 
 130 static void print_pending_exception(outputStream* output, oop throwable) {
 131   assert(throwable != NULL, "invariant");
 132 
 133   oop msg = java_lang_Throwable::message(throwable);
 134 
 135   if (msg != NULL) {
 136     char* text = java_lang_String::as_utf8_string(msg);
 137     output->print_raw_cr(text);
 138   }
 139 }
 140 
 141 static void print_message(outputStream* output, const char* message) {
 142   if (message != NULL) {
 143     output->print_raw(message);
 144   }
 145 }
 146 
 147 static void handle_dcmd_result(outputStream* output,
 148                                const oop result,
 149                                const DCmdSource source,
 150                                TRAPS) {
 151   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 152   assert(output != NULL, "invariant");
 153   if (HAS_PENDING_EXCEPTION) {
 154     print_pending_exception(output, PENDING_EXCEPTION);
 155     // Don't clear excption on startup, JVM should fail initialization.
 156     if (DCmd_Source_Internal != source) {
 157       CLEAR_PENDING_EXCEPTION;
 158     }
 159     return;
 160   }
 161 
 162   assert(!HAS_PENDING_EXCEPTION, "invariant");
 163 
 164   if (result != NULL) {
 165     const char* result_chars = java_lang_String::as_utf8_string(result);
 166     print_message(output, result_chars);
 167   }
 168 }
 169 
 170 static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) {
 171   assert(args != NULL, "invariant");
 172   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 173   assert(args->klass() != NULL, "invariant");
 174   args->set_name("<init>", CHECK_NULL);
 175   args->set_signature("()V", CHECK_NULL);
 176   JfrJavaSupport::new_object(args, CHECK_NULL);
 177   return (oop)args->result()->get_jobject();
 178 }
 179 
 180 JfrDumpFlightRecordingDCmd::JfrDumpFlightRecordingDCmd(outputStream* output,
 181                                                        bool heap) : DCmdWithParser(output, heap),
 182   _name("name", "Recording name, e.g. \\\"My Recording\\\"", "STRING", false, NULL),
 183   _filename("filename", "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false),
 184   _maxage("maxage", "Maximum duration to dump, in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"),
 185   _maxsize("maxsize", "Maximum amount of bytes to dump, in (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"),
 186   _begin("begin", "Point in time to dump data from, e.g. 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d", "STRING", false),
 187   _end("end", "Point in time to dump data to, e.g. 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d", "STRING", false),
 188   _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
 189   _dcmdparser.add_dcmd_option(&_name);
 190   _dcmdparser.add_dcmd_option(&_filename);
 191   _dcmdparser.add_dcmd_option(&_maxage);
 192   _dcmdparser.add_dcmd_option(&_maxsize);
 193   _dcmdparser.add_dcmd_option(&_begin);
 194   _dcmdparser.add_dcmd_option(&_end);
 195   _dcmdparser.add_dcmd_option(&_path_to_gc_roots);
 196 };
 197 
 198 int JfrDumpFlightRecordingDCmd::num_arguments() {
 199   ResourceMark rm;
 200   JfrDumpFlightRecordingDCmd* dcmd = new JfrDumpFlightRecordingDCmd(NULL, false);
 201   if (dcmd != NULL) {
 202     DCmdMark mark(dcmd);
 203     return dcmd->_dcmdparser.num_arguments();
 204   }
 205   return 0;
 206 }
 207 
 208 void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
 209   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 210 
 211   if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
 212     return;
 213   }
 214 
 215   ResourceMark rm(THREAD);
 216   HandleMark hm(THREAD);
 217   JNIHandleBlockManager jni_handle_management(THREAD);
 218 
 219   JavaValue result(T_OBJECT);
 220   JfrJavaArguments constructor_args(&result);
 221   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdDump", CHECK);
 222   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 223   Handle h_dcmd_instance(THREAD, dcmd);
 224   assert(h_dcmd_instance.not_null(), "invariant");
 225 
 226   jstring name = NULL;
 227   if (_name.is_set() && _name.value()  != NULL) {
 228     name = JfrJavaSupport::new_string(_name.value(), CHECK);
 229   }
 230 
 231   jstring filepath = NULL;
 232   if (_filename.is_set() && _filename.value() != NULL) {
 233     filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
 234   }
 235 
 236   jobject maxage = NULL;
 237   if (_maxage.is_set()) {
 238     maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK);
 239   }
 240 
 241   jobject maxsize = NULL;
 242   if (_maxsize.is_set()) {
 243     maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK);
 244   }
 245 
 246   jstring begin = NULL;
 247   if (_begin.is_set() && _begin.value() != NULL) {
 248     begin = JfrJavaSupport::new_string(_begin.value(), CHECK);
 249   }
 250 
 251   jstring end = NULL;
 252   if (_end.is_set() && _end.value() != NULL) {
 253     end = JfrJavaSupport::new_string(_end.value(), CHECK);
 254   }
 255 
 256   jobject path_to_gc_roots = NULL;
 257   if (_path_to_gc_roots.is_set()) {
 258     path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
 259   }
 260 
 261   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdDump";
 262   static const char method[] = "execute";
 263   static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
 264 
 265   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 266   execute_args.set_receiver(h_dcmd_instance);
 267 
 268   // arguments
 269   execute_args.push_jobject(name);
 270   execute_args.push_jobject(filepath);
 271   execute_args.push_jobject(maxage);
 272   execute_args.push_jobject(maxsize);
 273   execute_args.push_jobject(begin);
 274   execute_args.push_jobject(end);
 275   execute_args.push_jobject(path_to_gc_roots);
 276 
 277   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 278   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 279 }
 280 
 281 JfrCheckFlightRecordingDCmd::JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
 282   _name("name","Recording name, e.g. \\\"My Recording\\\" or omit to see all recordings","STRING",false, NULL),
 283   _verbose("verbose","Print event settings for the recording(s)","BOOLEAN",
 284            false, "false") {
 285   _dcmdparser.add_dcmd_option(&_name);
 286   _dcmdparser.add_dcmd_option(&_verbose);
 287 };
 288 
 289 int JfrCheckFlightRecordingDCmd::num_arguments() {
 290   ResourceMark rm;
 291   JfrCheckFlightRecordingDCmd* dcmd = new JfrCheckFlightRecordingDCmd(NULL, false);
 292   if (dcmd != NULL) {
 293     DCmdMark mark(dcmd);
 294     return dcmd->_dcmdparser.num_arguments();
 295   }
 296   return 0;
 297 }
 298 
 299 void JfrCheckFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
 300   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 301 
 302   if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
 303     return;
 304   }
 305 
 306   ResourceMark rm(THREAD);
 307   HandleMark hm(THREAD);
 308   JNIHandleBlockManager jni_handle_management(THREAD);
 309 
 310   JavaValue result(T_OBJECT);
 311   JfrJavaArguments constructor_args(&result);
 312   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdCheck", CHECK);
 313   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 314   Handle h_dcmd_instance(THREAD, dcmd);
 315   assert(h_dcmd_instance.not_null(), "invariant");
 316 
 317   jstring name = NULL;
 318   if (_name.is_set() && _name.value() != NULL) {
 319     name = JfrJavaSupport::new_string(_name.value(), CHECK);
 320   }
 321 
 322   jobject verbose = NULL;
 323   if (_verbose.is_set()) {
 324     verbose = JfrJavaSupport::new_java_lang_Boolean(_verbose.value(), CHECK);
 325   }
 326 
 327   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdCheck";
 328   static const char method[] = "execute";
 329   static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
 330 
 331   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 332   execute_args.set_receiver(h_dcmd_instance);
 333 
 334   // arguments
 335   execute_args.push_jobject(name);
 336   execute_args.push_jobject(verbose);
 337 
 338   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 339   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 340 }
 341 
 342 JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output,
 343                                                          bool heap) : DCmdWithParser(output, heap),
 344   _name("name", "Name that can be used to identify recording, e.g. \\\"My Recording\\\"", "STRING", false, NULL),
 345   _settings("settings", "Settings file(s), e.g. profile or default. See JRE_HOME/lib/jfr", "STRING SET", false),
 346   _delay("delay", "Delay recording start with (s)econds, (m)inutes), (h)ours), or (d)ays, e.g. 5h.", "NANOTIME", false, "0"),
 347   _duration("duration", "Duration of recording in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 300s.", "NANOTIME", false, "0"),
 348   _disk("disk", "Recording should be persisted to disk", "BOOLEAN", false),
 349   _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false),
 350   _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"),
 351   _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"),
 352   _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false),
 353   _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
 354   _dcmdparser.add_dcmd_option(&_name);
 355   _dcmdparser.add_dcmd_option(&_settings);
 356   _dcmdparser.add_dcmd_option(&_delay);
 357   _dcmdparser.add_dcmd_option(&_duration);
 358   _dcmdparser.add_dcmd_option(&_disk);
 359   _dcmdparser.add_dcmd_option(&_filename);
 360   _dcmdparser.add_dcmd_option(&_maxage);
 361   _dcmdparser.add_dcmd_option(&_maxsize);
 362   _dcmdparser.add_dcmd_option(&_dump_on_exit);
 363   _dcmdparser.add_dcmd_option(&_path_to_gc_roots);
 364 };
 365 
 366 int JfrStartFlightRecordingDCmd::num_arguments() {
 367   ResourceMark rm;
 368   JfrStartFlightRecordingDCmd* dcmd = new JfrStartFlightRecordingDCmd(NULL, false);
 369   if (dcmd != NULL) {
 370     DCmdMark mark(dcmd);
 371     return dcmd->_dcmdparser.num_arguments();
 372   }
 373   return 0;
 374 }
 375 
 376 void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
 377   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 378 
 379   if (invalid_state(output(), THREAD)) {
 380     return;
 381   }
 382 
 383   ResourceMark rm(THREAD);
 384   HandleMark hm(THREAD);
 385   JNIHandleBlockManager jni_handle_management(THREAD);
 386 
 387   JavaValue result(T_OBJECT);
 388   JfrJavaArguments constructor_args(&result);
 389   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStart", THREAD);
 390   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 391   Handle h_dcmd_instance(THREAD, dcmd);
 392   assert(h_dcmd_instance.not_null(), "invariant");
 393 
 394   jstring name = NULL;
 395   if (_name.is_set() && _name.value() != NULL) {
 396     name = JfrJavaSupport::new_string(_name.value(), CHECK);
 397   }
 398 
 399   jstring filename = NULL;
 400   if (_filename.is_set() && _filename.value() != NULL) {
 401     filename = JfrJavaSupport::new_string(_filename.value(), CHECK);
 402   }
 403 
 404   jobject maxage = NULL;
 405   if (_maxage.is_set()) {
 406     maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK);
 407   }
 408 
 409   jobject maxsize = NULL;
 410   if (_maxsize.is_set()) {
 411     maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK);
 412   }
 413 
 414   jobject duration = NULL;
 415   if (_duration.is_set()) {
 416     duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK);
 417   }
 418 
 419   jobject delay = NULL;
 420   if (_delay.is_set()) {
 421     delay = JfrJavaSupport::new_java_lang_Long(_delay.value()._nanotime, CHECK);
 422   }
 423 
 424   jobject disk = NULL;
 425   if (_disk.is_set()) {
 426     disk = JfrJavaSupport::new_java_lang_Boolean(_disk.value(), CHECK);
 427   }
 428 
 429   jobject dump_on_exit = NULL;
 430   if (_dump_on_exit.is_set()) {
 431     dump_on_exit = JfrJavaSupport::new_java_lang_Boolean(_dump_on_exit.value(), CHECK);
 432   }
 433 
 434   jobject path_to_gc_roots = NULL;
 435   if (_path_to_gc_roots.is_set()) {
 436     path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
 437   }
 438 
 439   jobjectArray settings = NULL;
 440   if (_settings.is_set()) {
 441     const int length = _settings.value()->array()->length();
 442     settings = JfrJavaSupport::new_string_array(length, CHECK);
 443     assert(settings != NULL, "invariant");
 444     for (int i = 0; i < length; ++i) {
 445       jobject element = JfrJavaSupport::new_string(_settings.value()->array()->at(i), CHECK);
 446       assert(element != NULL, "invariant");
 447       JfrJavaSupport::set_array_element(settings, element, i, CHECK);
 448     }
 449   }
 450 
 451   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStart";
 452   static const char method[] = "execute";
 453   static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
 454     "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
 455     "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
 456 
 457   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 458   execute_args.set_receiver(h_dcmd_instance);
 459 
 460   // arguments
 461   execute_args.push_jobject(name);
 462   execute_args.push_jobject(settings);
 463   execute_args.push_jobject(delay);
 464   execute_args.push_jobject(duration);
 465   execute_args.push_jobject(disk);
 466   execute_args.push_jobject(filename);
 467   execute_args.push_jobject(maxage);
 468   execute_args.push_jobject(maxsize);
 469   execute_args.push_jobject(dump_on_exit);
 470   execute_args.push_jobject(path_to_gc_roots);
 471 
 472   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 473   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 474 }
 475 
 476 JfrStopFlightRecordingDCmd::JfrStopFlightRecordingDCmd(outputStream* output,
 477                                                        bool heap) : DCmdWithParser(output, heap),
 478   _name("name", "Recording text,.e.g \\\"My Recording\\\"", "STRING", true, NULL),
 479   _filename("filename", "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false, NULL) {
 480   _dcmdparser.add_dcmd_option(&_name);
 481   _dcmdparser.add_dcmd_option(&_filename);
 482 };
 483 
 484 int JfrStopFlightRecordingDCmd::num_arguments() {
 485   ResourceMark rm;
 486   JfrStopFlightRecordingDCmd* dcmd = new JfrStopFlightRecordingDCmd(NULL, false);
 487   if (dcmd != NULL) {
 488     DCmdMark mark(dcmd);
 489     return dcmd->_dcmdparser.num_arguments();
 490   }
 491   return 0;
 492 }
 493 
 494 void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
 495   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 496 
 497   if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
 498     return;
 499   }
 500 
 501   ResourceMark rm(THREAD);
 502   HandleMark hm(THREAD);
 503   JNIHandleBlockManager jni_handle_management(THREAD);
 504 
 505   JavaValue result(T_OBJECT);
 506   JfrJavaArguments constructor_args(&result);
 507   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStop", CHECK);
 508   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 509   Handle h_dcmd_instance(THREAD, dcmd);
 510   assert(h_dcmd_instance.not_null(), "invariant");
 511 
 512   jstring name = NULL;
 513   if (_name.is_set() && _name.value()  != NULL) {
 514     name = JfrJavaSupport::new_string(_name.value(), CHECK);
 515   }
 516 
 517   jstring filepath = NULL;
 518   if (_filename.is_set() && _filename.value() != NULL) {
 519     filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
 520   }
 521 
 522   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop";
 523   static const char method[] = "execute";
 524   static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
 525 
 526   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 527   execute_args.set_receiver(h_dcmd_instance);
 528 
 529   // arguments
 530   execute_args.push_jobject(name);
 531   execute_args.push_jobject(filepath);
 532 
 533   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 534   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 535 }
 536 
 537 JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
 538                                                                bool heap) : DCmdWithParser(output, heap),
 539   _repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
 540   _dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
 541   _stack_depth("stackdepth", "Stack Depth", "JLONG", false, "64"),
 542   _global_buffer_count("globalbuffercount", "Number of global buffers,", "JLONG", false, "32"),
 543   _global_buffer_size("globalbuffersize", "Size of a global buffers,", "JLONG", false, "524288"),
 544   _thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "JLONG", false, "8192"),
 545   _memory_size("memorysize", "Overall memory size, ", "JLONG", false, "16777216"),
 546   _max_chunk_size("maxchunksize", "Size of an individual disk chunk", "JLONG", false, "12582912"),
 547   _sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true") {
 548   _dcmdparser.add_dcmd_option(&_repository_path);
 549   _dcmdparser.add_dcmd_option(&_dump_path);
 550   _dcmdparser.add_dcmd_option(&_stack_depth);
 551   _dcmdparser.add_dcmd_option(&_global_buffer_count);
 552   _dcmdparser.add_dcmd_option(&_global_buffer_size);
 553   _dcmdparser.add_dcmd_option(&_thread_buffer_size);
 554   _dcmdparser.add_dcmd_option(&_memory_size);
 555   _dcmdparser.add_dcmd_option(&_max_chunk_size);
 556   _dcmdparser.add_dcmd_option(&_sample_threads);
 557 };
 558 
 559 int JfrConfigureFlightRecorderDCmd::num_arguments() {
 560   ResourceMark rm;
 561   JfrConfigureFlightRecorderDCmd* dcmd = new JfrConfigureFlightRecorderDCmd(NULL, false);
 562   if (dcmd != NULL) {
 563     DCmdMark mark(dcmd);
 564     return dcmd->_dcmdparser.num_arguments();
 565   }
 566   return 0;
 567 }
 568 
 569 void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
 570   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 571 
 572   if (invalid_state(output(), THREAD)) {
 573     return;
 574   }
 575 
 576   ResourceMark rm(THREAD);
 577   HandleMark hm(THREAD);
 578   JNIHandleBlockManager jni_handle_management(THREAD);
 579 
 580   JavaValue result(T_OBJECT);
 581   JfrJavaArguments constructor_args(&result);
 582   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdConfigure", CHECK);
 583   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 584   Handle h_dcmd_instance(THREAD, dcmd);
 585   assert(h_dcmd_instance.not_null(), "invariant");
 586 
 587   jstring repository_path = NULL;
 588   if (_repository_path.is_set() && _repository_path.value() != NULL) {
 589     repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK);
 590   }
 591 
 592   jstring dump_path = NULL;
 593   if (_dump_path.is_set() && _dump_path.value() != NULL) {
 594     dump_path = JfrJavaSupport::new_string(_dump_path.value(), CHECK);
 595   }
 596 
 597   jobject stack_depth = NULL;
 598   if (_stack_depth.is_set()) {
 599     stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK);
 600   }
 601 
 602   jobject global_buffer_count = NULL;
 603   if (_global_buffer_count.is_set()) {
 604     global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK);
 605   }
 606 
 607   jobject global_buffer_size = NULL;
 608   if (_global_buffer_size.is_set()) {
 609     global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value(), CHECK);
 610   }
 611 
 612   jobject thread_buffer_size = NULL;
 613   if (_thread_buffer_size.is_set()) {
 614     thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value(), CHECK);
 615   }
 616 
 617   jobject max_chunk_size = NULL;
 618   if (_max_chunk_size.is_set()) {
 619     max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value(), CHECK);
 620   }
 621 
 622   jobject memory_size = NULL;
 623   if (_memory_size.is_set()) {
 624     memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value(), CHECK);
 625   }
 626 
 627   jobject sample_threads = NULL;
 628   if (_sample_threads.is_set()) {
 629     sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK);
 630   }
 631 
 632   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
 633   static const char method[] = "execute";
 634   static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
 635     "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
 636     "Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
 637 
 638   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 639   execute_args.set_receiver(h_dcmd_instance);
 640 
 641   // params
 642   execute_args.push_jobject(repository_path);
 643   execute_args.push_jobject(dump_path);
 644   execute_args.push_jobject(stack_depth);
 645   execute_args.push_jobject(global_buffer_count);
 646   execute_args.push_jobject(global_buffer_size);
 647   execute_args.push_jobject(thread_buffer_size);
 648   execute_args.push_jobject(memory_size);
 649   execute_args.push_jobject(max_chunk_size);
 650   execute_args.push_jobject(sample_threads);
 651 
 652   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 653   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 654 }
 655 
 656 bool register_jfr_dcmds() {
 657   uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
 658   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrCheckFlightRecordingDCmd>(full_export, true, false));
 659   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrDumpFlightRecordingDCmd>(full_export, true, false));
 660   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStartFlightRecordingDCmd>(full_export, true, false));
 661   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStopFlightRecordingDCmd>(full_export, true, false));
 662   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrConfigureFlightRecorderDCmd>(full_export, true, false));
 663   return true;
 664 }
 665