1 /*
   2  * Copyright (c) 2012, 2019, 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>");
 175   args->set_signature("()V");
 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     int length = _settings.value()->array()->length();
 442     if (length == 1) {
 443       const char* c_str = _settings.value()->array()->at(0);
 444       if (strcmp(c_str, "none") == 0) {
 445         length = 0;
 446       }
 447     }
 448     settings = JfrJavaSupport::new_string_array(length, CHECK);
 449     assert(settings != NULL, "invariant");
 450     for (int i = 0; i < length; ++i) {
 451       jobject element = JfrJavaSupport::new_string(_settings.value()->array()->at(i), CHECK);
 452       assert(element != NULL, "invariant");
 453       JfrJavaSupport::set_array_element(settings, element, i, CHECK);
 454     }
 455   } else {
 456     settings = JfrJavaSupport::new_string_array(1, CHECK);
 457     assert(settings != NULL, "invariant");
 458     jobject element = JfrJavaSupport::new_string("default", CHECK);
 459     assert(element != NULL, "invariant");
 460     JfrJavaSupport::set_array_element(settings, element, 0, CHECK);
 461   }
 462 
 463   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStart";
 464   static const char method[] = "execute";
 465   static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
 466     "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
 467     "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
 468 
 469   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 470   execute_args.set_receiver(h_dcmd_instance);
 471 
 472   // arguments
 473   execute_args.push_jobject(name);
 474   execute_args.push_jobject(settings);
 475   execute_args.push_jobject(delay);
 476   execute_args.push_jobject(duration);
 477   execute_args.push_jobject(disk);
 478   execute_args.push_jobject(filename);
 479   execute_args.push_jobject(maxage);
 480   execute_args.push_jobject(maxsize);
 481   execute_args.push_jobject(dump_on_exit);
 482   execute_args.push_jobject(path_to_gc_roots);
 483 
 484   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 485   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 486 }
 487 
 488 JfrStopFlightRecordingDCmd::JfrStopFlightRecordingDCmd(outputStream* output,
 489                                                        bool heap) : DCmdWithParser(output, heap),
 490   _name("name", "Recording text,.e.g \\\"My Recording\\\"", "STRING", true, NULL),
 491   _filename("filename", "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false, NULL) {
 492   _dcmdparser.add_dcmd_option(&_name);
 493   _dcmdparser.add_dcmd_option(&_filename);
 494 };
 495 
 496 int JfrStopFlightRecordingDCmd::num_arguments() {
 497   ResourceMark rm;
 498   JfrStopFlightRecordingDCmd* dcmd = new JfrStopFlightRecordingDCmd(NULL, false);
 499   if (dcmd != NULL) {
 500     DCmdMark mark(dcmd);
 501     return dcmd->_dcmdparser.num_arguments();
 502   }
 503   return 0;
 504 }
 505 
 506 void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
 507   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 508 
 509   if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
 510     return;
 511   }
 512 
 513   ResourceMark rm(THREAD);
 514   HandleMark hm(THREAD);
 515   JNIHandleBlockManager jni_handle_management(THREAD);
 516 
 517   JavaValue result(T_OBJECT);
 518   JfrJavaArguments constructor_args(&result);
 519   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStop", CHECK);
 520   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 521   Handle h_dcmd_instance(THREAD, dcmd);
 522   assert(h_dcmd_instance.not_null(), "invariant");
 523 
 524   jstring name = NULL;
 525   if (_name.is_set() && _name.value()  != NULL) {
 526     name = JfrJavaSupport::new_string(_name.value(), CHECK);
 527   }
 528 
 529   jstring filepath = NULL;
 530   if (_filename.is_set() && _filename.value() != NULL) {
 531     filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
 532   }
 533 
 534   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop";
 535   static const char method[] = "execute";
 536   static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
 537 
 538   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 539   execute_args.set_receiver(h_dcmd_instance);
 540 
 541   // arguments
 542   execute_args.push_jobject(name);
 543   execute_args.push_jobject(filepath);
 544 
 545   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 546   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 547 }
 548 
 549 JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
 550                                                                bool heap) : DCmdWithParser(output, heap),
 551   _repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
 552   _dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
 553   _stack_depth("stackdepth", "Stack Depth", "JULONG", false, "64"),
 554   _global_buffer_count("globalbuffercount", "Number of global buffers,", "JULONG", false, "20"),
 555   _global_buffer_size("globalbuffersize", "Size of a global buffers,", "MEMORY SIZE", false, "512k"),
 556   _thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "MEMORY SIZE", false, "8k"),
 557   _memory_size("memorysize", "Overall memory size, ", "MEMORY SIZE", false, "10m"),
 558   _max_chunk_size("maxchunksize", "Size of an individual disk chunk", "MEMORY SIZE", false, "12m"),
 559   _sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true") {
 560   _dcmdparser.add_dcmd_option(&_repository_path);
 561   _dcmdparser.add_dcmd_option(&_dump_path);
 562   _dcmdparser.add_dcmd_option(&_stack_depth);
 563   _dcmdparser.add_dcmd_option(&_global_buffer_count);
 564   _dcmdparser.add_dcmd_option(&_global_buffer_size);
 565   _dcmdparser.add_dcmd_option(&_thread_buffer_size);
 566   _dcmdparser.add_dcmd_option(&_memory_size);
 567   _dcmdparser.add_dcmd_option(&_max_chunk_size);
 568   _dcmdparser.add_dcmd_option(&_sample_threads);
 569 };
 570 
 571 int JfrConfigureFlightRecorderDCmd::num_arguments() {
 572   ResourceMark rm;
 573   JfrConfigureFlightRecorderDCmd* dcmd = new JfrConfigureFlightRecorderDCmd(NULL, false);
 574   if (dcmd != NULL) {
 575     DCmdMark mark(dcmd);
 576     return dcmd->_dcmdparser.num_arguments();
 577   }
 578   return 0;
 579 }
 580 
 581 void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
 582   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
 583 
 584   if (invalid_state(output(), THREAD)) {
 585     return;
 586   }
 587 
 588   ResourceMark rm(THREAD);
 589   HandleMark hm(THREAD);
 590   JNIHandleBlockManager jni_handle_management(THREAD);
 591 
 592   JavaValue result(T_OBJECT);
 593   JfrJavaArguments constructor_args(&result);
 594   constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdConfigure", CHECK);
 595   const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
 596   Handle h_dcmd_instance(THREAD, dcmd);
 597   assert(h_dcmd_instance.not_null(), "invariant");
 598 
 599   jstring repository_path = NULL;
 600   if (_repository_path.is_set() && _repository_path.value() != NULL) {
 601     repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK);
 602   }
 603 
 604   jstring dump_path = NULL;
 605   if (_dump_path.is_set() && _dump_path.value() != NULL) {
 606     dump_path = JfrJavaSupport::new_string(_dump_path.value(), CHECK);
 607   }
 608 
 609   jobject stack_depth = NULL;
 610   if (_stack_depth.is_set()) {
 611     stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK);
 612   }
 613 
 614   jobject global_buffer_count = NULL;
 615   if (_global_buffer_count.is_set()) {
 616     global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK);
 617   }
 618 
 619   jobject global_buffer_size = NULL;
 620   if (_global_buffer_size.is_set()) {
 621     global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value()._size, CHECK);
 622   }
 623 
 624   jobject thread_buffer_size = NULL;
 625   if (_thread_buffer_size.is_set()) {
 626     thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value()._size, CHECK);
 627   }
 628 
 629   jobject max_chunk_size = NULL;
 630   if (_max_chunk_size.is_set()) {
 631     max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value()._size, CHECK);
 632   }
 633 
 634   jobject memory_size = NULL;
 635   if (_memory_size.is_set()) {
 636     memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value()._size, CHECK);
 637   }
 638 
 639   jobject sample_threads = NULL;
 640   if (_sample_threads.is_set()) {
 641     sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK);
 642   }
 643 
 644   static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
 645   static const char method[] = "execute";
 646   static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
 647     "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
 648     "Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
 649 
 650   JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
 651   execute_args.set_receiver(h_dcmd_instance);
 652 
 653   // params
 654   execute_args.push_jobject(repository_path);
 655   execute_args.push_jobject(dump_path);
 656   execute_args.push_jobject(stack_depth);
 657   execute_args.push_jobject(global_buffer_count);
 658   execute_args.push_jobject(global_buffer_size);
 659   execute_args.push_jobject(thread_buffer_size);
 660   execute_args.push_jobject(memory_size);
 661   execute_args.push_jobject(max_chunk_size);
 662   execute_args.push_jobject(sample_threads);
 663 
 664   JfrJavaSupport::call_virtual(&execute_args, THREAD);
 665   handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
 666 }
 667 
 668 bool register_jfr_dcmds() {
 669   uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
 670   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrCheckFlightRecordingDCmd>(full_export, true, false));
 671   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrDumpFlightRecordingDCmd>(full_export, true, false));
 672   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStartFlightRecordingDCmd>(full_export, true, false));
 673   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStopFlightRecordingDCmd>(full_export, true, false));
 674   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrConfigureFlightRecorderDCmd>(full_export, true, false));
 675   return true;
 676 }
 677