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