ssssssss81

C:\hotspot-69087d08d473\src\share\vm/services/allocationSite.hpp
#ifndef SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
#define SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
#include "memory/allocation.hpp"
#include "utilities/nativeCallStack.hpp"
template <class E> class AllocationSite VALUE_OBJ_CLASS_SPEC {
 private:
  NativeCallStack  _call_stack;
  E                e;
  MEMFLAGS         _flag;
 public:
  AllocationSite(const NativeCallStack& stack, MEMFLAGS flag) : _call_stack(stack), _flag(flag) { }
  int hash() const { return _call_stack.hash(); }
  bool equals(const NativeCallStack& stack) const {
    return _call_stack.equals(stack);
  }
  bool equals(const AllocationSite<E>& other) const {
    return other.equals(_call_stack);
  }
  const NativeCallStack* call_stack() const {
    return &_call_stack;
  }
  E* data()             { return &e; }
  const E* peek() const { return &e; }
  MEMFLAGS flag() const { return _flag; }
};
#endif  // SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/attachListener.cpp
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/attachListener.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/heapDumper.hpp"
volatile bool AttachListener::_initialized;
static Klass* load_and_initialize_klass(Symbol* sh, TRAPS) {
  Klass* k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
  instanceKlassHandle ik (THREAD, k);
  if (ik->should_be_initialized()) {
    ik->initialize(CHECK_NULL);
  }
  return ik();
}
static jint get_properties(AttachOperation* op, outputStream* out, Symbol* serializePropertiesMethod) {
  Thread* THREAD = Thread::current();
  HandleMark hm;
  Symbol* klass = vmSymbols::sun_misc_VMSupport();
  Klass* k = load_and_initialize_klass(klass, THREAD);
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, out);
    CLEAR_PENDING_EXCEPTION;
    return JNI_ERR;
  }
  instanceKlassHandle ik(THREAD, k);
  JavaValue result(T_OBJECT);
  JavaCallArguments args;
  Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
  JavaCalls::call_static(&result,
                           ik,
                           serializePropertiesMethod,
                           signature,
                           &args,
                           THREAD);
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, out);
    CLEAR_PENDING_EXCEPTION;
    return JNI_ERR;
  }
  oop res = (oop)result.get_jobject();
  assert(res->is_typeArray(), "just checking");
  assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
  typeArrayOop ba = typeArrayOop(res);
  jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
  out->print_raw((const char*)addr, ba->length());
  return JNI_OK;
}
static jint get_system_properties(AttachOperation* op, outputStream* out) {
  return get_properties(op, out, vmSymbols::serializePropertiesToByteArray_name());
}
static jint get_agent_properties(AttachOperation* op, outputStream* out) {
  return get_properties(op, out, vmSymbols::serializeAgentPropertiesToByteArray_name());
}
static jint data_dump(AttachOperation* op, outputStream* out) {
  if (!ReduceSignalUsage) {
    AttachListener::pd_data_dump();
  } else {
    if (JvmtiExport::should_post_data_dump()) {
      JvmtiExport::post_data_dump();
    }
  }
  return JNI_OK;
}
static jint thread_dump(AttachOperation* op, outputStream* out) {
  bool print_concurrent_locks = false;
  if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
    print_concurrent_locks = true;
  }
  VM_PrintThreads op1(out, print_concurrent_locks);
  VMThread::execute(&op1);
  VM_PrintJNI op2(out);
  VMThread::execute(&op2);
  VM_FindDeadlocks op3(out);
  VMThread::execute(&op3);
  return JNI_OK;
}
static jint jcmd(AttachOperation* op, outputStream* out) {
  Thread* THREAD = Thread::current();
  DCmd::parse_and_execute(DCmd_Source_AttachAPI, out, op->arg(0), ' ', THREAD);
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, out);
    out->cr();
    CLEAR_PENDING_EXCEPTION;
    return JNI_ERR;
  }
  return JNI_OK;
}
jint dump_heap(AttachOperation* op, outputStream* out) {
  const char* path = op->arg(0);
  if (path == NULL || path[0] == '\0') {
    out->print_cr("No dump file specified");
  } else {
    bool live_objects_only = true;   // default is true to retain the behavior before this change is made
    const char* arg1 = op->arg(1);
    if (arg1 != NULL && (strlen(arg1) > 0)) {
      if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
        out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
        return JNI_ERR;
      }
      live_objects_only = strcmp(arg1, "-live") == 0;
    }
    HeapDumper dumper(live_objects_only /* request GC */);
    int res = dumper.dump(op->arg(0));
    if (res == 0) {
      out->print_cr("Heap dump file created");
    } else {
      ResourceMark rm;
      char* error = dumper.error_as_C_string();
      if (error == NULL) {
        out->print_cr("Dump failed - reason unknown");
      } else {
        out->print_cr("%s", error);
      }
    }
  }
  return JNI_OK;
}
static jint heap_inspection(AttachOperation* op, outputStream* out) {
  bool live_objects_only = true;   // default is true to retain the behavior before this change is made
  const char* arg0 = op->arg(0);
  if (arg0 != NULL && (strlen(arg0) > 0)) {
    if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
      out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
      return JNI_ERR;
    }
    live_objects_only = strcmp(arg0, "-live") == 0;
  }
  VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */);
  VMThread::execute(&heapop);
  return JNI_OK;
}
static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
  bool value = true;
  const char* arg1;
  if ((arg1 = op->arg(1)) != NULL) {
    int tmp;
    int n = sscanf(arg1, "%d", &tmp);
    if (n != 1) {
      out->print_cr("flag value must be a boolean (1 or 0)");
      return JNI_ERR;
    }
    value = (tmp != 0);
  }
  bool res = CommandLineFlags::boolAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
  if (! res) {
    out->print_cr("setting flag %s failed", name);
  }
  return res? JNI_OK : JNI_ERR;
}
static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
  intx value;
  const char* arg1;
  if ((arg1 = op->arg(1)) != NULL) {
    int n = sscanf(arg1, INTX_FORMAT, &value);
    if (n != 1) {
      out->print_cr("flag value must be an integer");
      return JNI_ERR;
    }
  }
  bool res = CommandLineFlags::intxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
  if (! res) {
    out->print_cr("setting flag %s failed", name);
  }
  return res? JNI_OK : JNI_ERR;
}
static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
  uintx value;
  const char* arg1 = op->arg(1);
  if (arg1 == NULL) {
    out->print_cr("flag value must be specified");
    return JNI_ERR;
  }
  int n = sscanf(arg1, UINTX_FORMAT, &value);
  if (n != 1) {
    out->print_cr("flag value must be an unsigned integer");
    return JNI_ERR;
  }
  if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
    FormatBuffer<80> err_msg("%s", "");
    if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) {
      out->print_cr("%s", err_msg.buffer());
      return JNI_ERR;
    }
  } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) {
    FormatBuffer<80> err_msg("%s", "");
    if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) {
      out->print_cr("%s", err_msg.buffer());
      return JNI_ERR;
    }
  }
  bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
  if (! res) {
    out->print_cr("setting flag %s failed", name);
  }
  return res? JNI_OK : JNI_ERR;
}
static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
  uint64_t value;
  const char* arg1;
  if ((arg1 = op->arg(1)) != NULL) {
    int n = sscanf(arg1, UINT64_FORMAT, &value);
    if (n != 1) {
      out->print_cr("flag value must be an unsigned 64-bit integer");
      return JNI_ERR;
    }
  }
  bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
  if (! res) {
    out->print_cr("setting flag %s failed", name);
  }
  return res? JNI_OK : JNI_ERR;
}
static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
  const char* value;
  if ((value = op->arg(1)) == NULL) {
    out->print_cr("flag value must be a string");
    return JNI_ERR;
  }
  bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
  if (res) {
    FREE_C_HEAP_ARRAY(char, value, mtInternal);
  } else {
    out->print_cr("setting flag %s failed", name);
  }
  return res? JNI_OK : JNI_ERR;
}
static jint set_flag(AttachOperation* op, outputStream* out) {
  const char* name = NULL;
  if ((name = op->arg(0)) == NULL) {
    out->print_cr("flag name is missing");
    return JNI_ERR;
  }
  Flag* f = Flag::find_flag((char*)name, strlen(name));
  if (f && f->is_external() && f->is_writeable()) {
    if (f->is_bool()) {
      return set_bool_flag(name, op, out);
    } else if (f->is_intx()) {
      return set_intx_flag(name, op, out);
    } else if (f->is_uintx()) {
      return set_uintx_flag(name, op, out);
    } else if (f->is_uint64_t()) {
      return set_uint64_t_flag(name, op, out);
    } else if (f->is_ccstr()) {
      return set_ccstr_flag(name, op, out);
    } else {
      ShouldNotReachHere();
      return JNI_ERR;
    }
  } else {
    return AttachListener::pd_set_flag(op, out);
  }
}
static jint print_flag(AttachOperation* op, outputStream* out) {
  const char* name = NULL;
  if ((name = op->arg(0)) == NULL) {
    out->print_cr("flag name is missing");
    return JNI_ERR;
  }
  Flag* f = Flag::find_flag((char*)name, strlen(name));
  if (f) {
    f->print_as_flag(out);
    out->cr();
  } else {
    out->print_cr("no such flag '%s'", name);
  }
  return JNI_OK;
}
static AttachOperationFunctionInfo funcs[] = {
  { "agentProperties",  get_agent_properties },
  { "datadump",         data_dump },
  { "dumpheap",         dump_heap },
  { "load",             JvmtiExport::load_agent_library },
  { "properties",       get_system_properties },
  { "threaddump",       thread_dump },
  { "inspectheap",      heap_inspection },
  { "setflag",          set_flag },
  { "printflag",        print_flag },
  { "jcmd",             jcmd },
  { NULL,               NULL }
};
static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
  os::set_priority(thread, NearMaxPriority);
  thread->record_stack_base_and_size();
  if (AttachListener::pd_init() != 0) {
    return;
  }
  AttachListener::set_initialized();
  for (;;) {
    AttachOperation* op = AttachListener::dequeue();
    if (op == NULL) {
      return;   // dequeue failed or shutdown
    }
    ResourceMark rm;
    bufferedStream st;
    jint res = JNI_OK;
    if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
      AttachListener::detachall();
    } else {
      AttachOperationFunctionInfo* info = NULL;
      for (int i=0; funcs[i].name != NULL; i++) {
        const char* name = funcs[i].name;
        assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
        if (strcmp(op->name(), name) == 0) {
          info = &(funcs[i]);
          break;
        }
      }
      if (info == NULL) {
        info = AttachListener::pd_find_operation(op->name());
      }
      if (info != NULL) {
        res = (info->func)(op, &st);
      } else {
        st.print("Operation %s not recognized!", op->name());
        res = JNI_ERR;
      }
    }
    op->complete(res, &st);
  }
}
bool AttachListener::has_init_error(TRAPS) {
  if (HAS_PENDING_EXCEPTION) {
    tty->print_cr("Exception in VM (AttachListener::init) : ");
    java_lang_Throwable::print(PENDING_EXCEPTION, tty);
    tty->cr();
    CLEAR_PENDING_EXCEPTION;
    return true;
  } else {
    return false;
  }
}
void AttachListener::init() {
  EXCEPTION_MARK;
  Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, THREAD);
  if (has_init_error(THREAD)) {
    return;
  }
  instanceKlassHandle klass (THREAD, k);
  instanceHandle thread_oop = klass->allocate_instance_handle(THREAD);
  if (has_init_error(THREAD)) {
    return;
  }
  const char thread_name[] = "Attach Listener";
  Handle string = java_lang_String::create_from_str(thread_name, THREAD);
  if (has_init_error(THREAD)) {
    return;
  }
  Handle thread_group (THREAD, Universe::system_thread_group());
  JavaValue result(T_VOID);
  JavaCalls::call_special(&result, thread_oop,
                       klass,
                       vmSymbols::object_initializer_name(),
                       vmSymbols::threadgroup_string_void_signature(),
                       thread_group,
                       string,
                       THREAD);
  if (has_init_error(THREAD)) {
    return;
  }
  KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
  JavaCalls::call_special(&result,
                        thread_group,
                        group,
                        vmSymbols::add_method_name(),
                        vmSymbols::thread_void_signature(),
                        thread_oop,             // ARG 1
                        THREAD);
  if (has_init_error(THREAD)) {
    return;
  }
  { MutexLocker mu(Threads_lock);
    JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
    if (listener_thread == NULL || listener_thread->osthread() == NULL) {
      vm_exit_during_initialization("java.lang.OutOfMemoryError",
                                    "unable to create new native thread");
    }
    java_lang_Thread::set_thread(thread_oop(), listener_thread);
    java_lang_Thread::set_daemon(thread_oop());
    listener_thread->set_threadObj(thread_oop());
    Threads::add(listener_thread);
    Thread::start(listener_thread);
  }
}
void AttachListener::detachall() {
  pd_detachall();
}
C:\hotspot-69087d08d473\src\share\vm/services/attachListener.hpp
#ifndef SHARE_VM_SERVICES_ATTACHLISTENER_HPP
#define SHARE_VM_SERVICES_ATTACHLISTENER_HPP
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
class AttachOperation;
typedef jint (*AttachOperationFunction)(AttachOperation* op, outputStream* out);
struct AttachOperationFunctionInfo {
  const char* name;
  AttachOperationFunction func;
};
class AttachListener: AllStatic {
 public:
  static void vm_start() NOT_SERVICES_RETURN;
  static void init()  NOT_SERVICES_RETURN;
  static void abort() NOT_SERVICES_RETURN;
  static void detachall() NOT_SERVICES_RETURN;
  static bool init_at_startup() NOT_SERVICES_RETURN_(false);
  static bool is_init_trigger() NOT_SERVICES_RETURN_(false);
#if !INCLUDE_SERVICES
  static bool is_attach_supported()             { return false; }
#else
 private:
  static volatile bool _initialized;
 public:
  static bool is_initialized()                  { return _initialized; }
  static void set_initialized()                 { _initialized = true; }
  static bool is_attach_supported()             { return !DisableAttachMechanism; }
  static int pd_init();
  static AttachOperationFunctionInfo* pd_find_operation(const char* name);
  static jint pd_set_flag(AttachOperation* op, outputStream* out);
  static void pd_detachall();
  static void pd_data_dump();
  static AttachOperation* dequeue();
#endif // !INCLUDE_SERVICES
 private:
  static bool has_init_error(TRAPS);
};
#if INCLUDE_SERVICES
class AttachOperation: public CHeapObj<mtInternal> {
 public:
  enum {
    name_length_max = 16,       // maximum length of  name
    arg_length_max = 1024,      // maximum length of argument
    arg_count_max = 3           // maximum number of arguments
  };
  static char* detachall_operation_name() { return (char*)"detachall"; }
 private:
  char _name[name_length_max+1];
  char _arg[arg_count_max][arg_length_max+1];
 public:
  const char* name() const                      { return _name; }
  void set_name(char* name) {
    assert(strlen(name) <= name_length_max, "exceeds maximum name length");
    strcpy(_name, name);
  }
  const char* arg(int i) const {
    assert(i>=0 && i<arg_count_max, "invalid argument index");
    return _arg[i];
  }
  void set_arg(int i, char* arg) {
    assert(i>=0 && i<arg_count_max, "invalid argument index");
    if (arg == NULL) {
      _arg[i][0] = '\0';
    } else {
      assert(strlen(arg) <= arg_length_max, "exceeds maximum argument length");
      strcpy(_arg[i], arg);
    }
  }
  AttachOperation(char* name) {
    set_name(name);
    for (int i=0; i<arg_count_max; i++) {
      set_arg(i, NULL);
    }
  }
  virtual void complete(jint result, bufferedStream* result_stream) = 0;
};
#endif // INCLUDE_SERVICES
#endif // SHARE_VM_SERVICES_ATTACHLISTENER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/classLoadingService.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/allocation.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/classLoadingService.hpp"
#include "services/memoryService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#ifdef DTRACE_ENABLED
#ifndef USDT2
HS_DTRACE_PROBE_DECL4(hotspot, class__loaded, char*, int, oop, bool);
HS_DTRACE_PROBE_DECL4(hotspot, class__unloaded, char*, int, oop, bool);
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared)  \
  {                                                 \
    char* data = NULL;                              \
    int len = 0;                                    \
    Symbol* name = (clss)->name();                  \
    if (name != NULL) {                             \
      data = (char*)name->bytes();                  \
      len = name->utf8_length();                    \
    }                                               \
    HS_DTRACE_PROBE4(hotspot, class__##type,        \
      data, len, (void *)(clss)->class_loader(), (shared)); \
  }
#else /* USDT2 */
#define HOTSPOT_CLASS_unloaded HOTSPOT_CLASS_UNLOADED
#define HOTSPOT_CLASS_loaded HOTSPOT_CLASS_LOADED
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared)  \
  {                                                 \
    char* data = NULL;                              \
    int len = 0;                                    \
    Symbol* name = (clss)->name();                  \
    if (name != NULL) {                             \
      data = (char*)name->bytes();                  \
      len = name->utf8_length();                    \
    }                                               \
    HOTSPOT_CLASS_##type( /* type = unloaded, loaded */ \
      data, len, (void *)(clss)->class_loader(), (shared)); \
  }
#endif /* USDT2 */
#else //  ndef DTRACE_ENABLED
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared)
#endif
#if INCLUDE_MANAGEMENT
PerfCounter*    ClassLoadingService::_classes_loaded_count = NULL;
PerfCounter*    ClassLoadingService::_classes_unloaded_count = NULL;
PerfCounter*    ClassLoadingService::_classbytes_loaded = NULL;
PerfCounter*    ClassLoadingService::_classbytes_unloaded = NULL;
PerfCounter*    ClassLoadingService::_shared_classes_loaded_count = NULL;
PerfCounter*    ClassLoadingService::_shared_classes_unloaded_count = NULL;
PerfCounter*    ClassLoadingService::_shared_classbytes_loaded = NULL;
PerfCounter*    ClassLoadingService::_shared_classbytes_unloaded = NULL;
PerfVariable*   ClassLoadingService::_class_methods_size = NULL;
void ClassLoadingService::init() {
  EXCEPTION_MARK;
  _classes_loaded_count =
                 PerfDataManager::create_counter(JAVA_CLS, "loadedClasses",
                                                 PerfData::U_Events, CHECK);
  _classes_unloaded_count =
                 PerfDataManager::create_counter(JAVA_CLS, "unloadedClasses",
                                                 PerfData::U_Events, CHECK);
  _shared_classes_loaded_count =
                 PerfDataManager::create_counter(JAVA_CLS, "sharedLoadedClasses",
                                                 PerfData::U_Events, CHECK);
  _shared_classes_unloaded_count =
                 PerfDataManager::create_counter(JAVA_CLS, "sharedUnloadedClasses",
                                                 PerfData::U_Events, CHECK);
  if (UsePerfData) {
    _classbytes_loaded =
                 PerfDataManager::create_counter(SUN_CLS, "loadedBytes",
                                                 PerfData::U_Bytes, CHECK);
    _classbytes_unloaded =
                 PerfDataManager::create_counter(SUN_CLS, "unloadedBytes",
                                                 PerfData::U_Bytes, CHECK);
    _shared_classbytes_loaded =
                 PerfDataManager::create_counter(SUN_CLS, "sharedLoadedBytes",
                                                 PerfData::U_Bytes, CHECK);
    _shared_classbytes_unloaded =
                 PerfDataManager::create_counter(SUN_CLS, "sharedUnloadedBytes",
                                                 PerfData::U_Bytes, CHECK);
    _class_methods_size =
                 PerfDataManager::create_variable(SUN_CLS, "methodBytes",
                                                  PerfData::U_Bytes, CHECK);
  }
}
void ClassLoadingService::notify_class_unloaded(InstanceKlass* k) {
  DTRACE_CLASSLOAD_PROBE(unloaded, k, false);
  _classes_unloaded_count->inc();
  if (UsePerfData) {
    size_t size = compute_class_size(k);
    _classbytes_unloaded->inc(size);
    Array<Method*>* methods = k->methods();
    for (int i = 0; i < methods->length(); i++) {
      _class_methods_size->inc(-methods->at(i)->size());
    }
  }
  if (TraceClassUnloading) {
    ResourceMark rm;
    tty->print_cr("[Unloading class %s " INTPTR_FORMAT "]", k->external_name(), p2i(k));
  }
}
void ClassLoadingService::notify_class_loaded(InstanceKlass* k, bool shared_class) {
  DTRACE_CLASSLOAD_PROBE(loaded, k, shared_class);
  PerfCounter* classes_counter = (shared_class ? _shared_classes_loaded_count
                                               : _classes_loaded_count);
  classes_counter->inc();
  if (UsePerfData) {
    PerfCounter* classbytes_counter = (shared_class ? _shared_classbytes_loaded
                                                    : _classbytes_loaded);
    size_t size = compute_class_size(k);
    classbytes_counter->inc(size);
  }
}
size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
  size_t class_size = 0;
  class_size += k->size();
  if (k->oop_is_instance()) {
    class_size += k->methods()->size();
    class_size += k->constants()->size();
    class_size += k->local_interfaces()->size();
    class_size += k->transitive_interfaces()->size();
  }
  return class_size * oopSize;
}
bool ClassLoadingService::set_verbose(bool verbose) {
  MutexLocker m(Management_lock);
  bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, Flag::MANAGEMENT);
  assert(succeed, "Setting TraceClassLoading flag fails");
  reset_trace_class_unloading();
  return verbose;
}
void ClassLoadingService::reset_trace_class_unloading() {
  assert(Management_lock->owned_by_self(), "Must own the Management_lock");
  bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
  bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, Flag::MANAGEMENT);
  assert(succeed, "Setting TraceClassUnLoading flag fails");
}
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
Thread* LoadedClassesEnumerator::_current_thread = NULL;
LoadedClassesEnumerator::LoadedClassesEnumerator(Thread* cur_thread) {
  assert(cur_thread == Thread::current(), "Check current thread");
  int init_size = ClassLoadingService::loaded_class_count();
  _klass_handle_array = new GrowableArray<KlassHandle>(init_size);
  MutexLocker sd_mutex(SystemDictionary_lock);
  _loaded_classes = _klass_handle_array;
  _current_thread = cur_thread;
  SystemDictionary::classes_do(&add_loaded_class);
}
#endif // INCLUDE_MANAGEMENT
C:\hotspot-69087d08d473\src\share\vm/services/classLoadingService.hpp
#ifndef SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
#define SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
#include "runtime/handles.hpp"
#include "runtime/perfData.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
class InstanceKlass;
class ClassLoadingService : public AllStatic {
private:
  static PerfCounter*  _classes_loaded_count;
  static PerfCounter*  _classes_unloaded_count;
  static PerfCounter*  _classbytes_loaded;
  static PerfCounter*  _classbytes_unloaded;
  static PerfCounter*  _shared_classes_loaded_count;
  static PerfCounter*  _shared_classes_unloaded_count;
  static PerfCounter*  _shared_classbytes_loaded;
  static PerfCounter*  _shared_classbytes_unloaded;
  static PerfVariable* _class_methods_size;
  static size_t compute_class_size(InstanceKlass* k);
public:
  static void init();
  static bool get_verbose() { return TraceClassLoading; }
  static bool set_verbose(bool verbose);
  static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
  static jlong loaded_class_count() {
    return _classes_loaded_count->get_value() + _shared_classes_loaded_count->get_value();
  }
  static jlong unloaded_class_count() {
    return _classes_unloaded_count->get_value() + _shared_classes_unloaded_count->get_value();
  }
  static jlong loaded_class_bytes() {
    if (UsePerfData) {
      return _classbytes_loaded->get_value() + _shared_classbytes_loaded->get_value();
    } else {
      return -1;
    }
  }
  static jlong unloaded_class_bytes() {
    if (UsePerfData) {
      return _classbytes_unloaded->get_value() + _shared_classbytes_unloaded->get_value();
    } else {
      return -1;
    }
  }
  static jlong loaded_shared_class_count() {
    return _shared_classes_loaded_count->get_value();
  }
  static jlong unloaded_shared_class_count() {
    return _shared_classes_unloaded_count->get_value();
  }
  static jlong loaded_shared_class_bytes() {
    if (UsePerfData) {
      return _shared_classbytes_loaded->get_value();
    } else {
      return -1;
    }
  }
  static jlong unloaded_shared_class_bytes() {
    if (UsePerfData) {
      return _shared_classbytes_unloaded->get_value();
    } else {
      return -1;
    }
  }
  static jlong class_method_data_size() {
    return (UsePerfData ? _class_methods_size->get_value() : -1);
  }
  static void notify_class_loaded(InstanceKlass* k, bool shared_class)
      NOT_MANAGEMENT_RETURN;
  static void notify_class_unloaded(InstanceKlass* k) NOT_MANAGEMENT_RETURN;
  static void add_class_method_size(int size) {
#if INCLUDE_MANAGEMENT
    if (UsePerfData) {
      _class_methods_size->inc(size);
    }
#endif // INCLUDE_MANAGEMENT
  }
};
class LoadedClassesEnumerator : public StackObj {
private:
  static GrowableArray<KlassHandle>* _loaded_classes;
  static Thread*                     _current_thread;
  GrowableArray<KlassHandle>* _klass_handle_array;
public:
  LoadedClassesEnumerator(Thread* cur_thread);
  int num_loaded_classes()         { return _klass_handle_array->length(); }
  KlassHandle get_klass(int index) { return _klass_handle_array->at(index); }
  static void add_loaded_class(Klass* k) {
    KlassHandle h(_current_thread, k);
    _loaded_classes->append(h);
  }
};
#endif // SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticArgument.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/thread.hpp"
#include "services/diagnosticArgument.hpp"
void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) {
  if (is_set() && !allow_multiple()) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
            "Duplicates in diagnostic command arguments\n");
  }
  parse_value(str, len, CHECK);
  set_is_set(true);
}
void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) {
  jio_snprintf(buf, len, INT64_FORMAT, l);
}
void GenDCmdArgument::to_string(bool b, char* buf, size_t len) {
  jio_snprintf(buf, len, b ? "true" : "false");
}
void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) {
  jio_snprintf(buf, len, INT64_FORMAT, n._nanotime);
}
void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) {
  jio_snprintf(buf, len, INT64_FORMAT, m._size);
}
void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
  jio_snprintf(buf, len, "%s", (c != NULL) ? c : "");
}
void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
  int length = f->array()->length();
  size_t written = 0;
  buf[0] = 0;
  for (int i = 0; i < length; i++) {
    char* next_str = f->array()->at(i);
    size_t next_size = strlen(next_str);
    if (written + next_size > len) {
      return;
    }
    strcat(buf, next_str);
    written += next_size;
    if (i < length-1 && len - written > 0) {
      strcat(buf, ",");
    }
  }
}
template <> void DCmdArgument<jlong>::parse_value(const char* str,
                                                  size_t len, TRAPS) {
  int scanned = -1;
  if (str == NULL
      || sscanf(str, JLONG_FORMAT "%n", &_value, &scanned) != 1
      || (size_t)scanned != len)
  {
    ResourceMark rm;
    char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
    strncpy(buf, str, len);
    buf[len] = '\0';
    Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
      "Integer parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
  }
}
template <> void DCmdArgument<jlong>::init_value(TRAPS) {
  if (has_default()) {
    this->parse_value(_default_string, strlen(_default_string), THREAD);
    if (HAS_PENDING_EXCEPTION) {
      fatal("Default string must be parseable");
    }
  } else {
    set_value(0);
  }
}
template <> void DCmdArgument<jlong>::destroy_value() { }
template <> void DCmdArgument<bool>::parse_value(const char* str,
                                                 size_t len, TRAPS) {
  if (len == 0) {
    set_value(true);
  } else {
    if (len == strlen("true") && strncasecmp(str, "true", len) == 0) {
       set_value(true);
    } else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) {
       set_value(false);
    } else {
      ResourceMark rm;
      char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
      strncpy(buf, str, len);
      buf[len] = '\0';
      Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
        "Boolean parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
    }
  }
}
template <> void DCmdArgument<bool>::init_value(TRAPS) {
  if (has_default()) {
    this->parse_value(_default_string, strlen(_default_string), THREAD);
    if (HAS_PENDING_EXCEPTION) {
      fatal("Default string must be parsable");
    }
  } else {
    set_value(false);
  }
}
template <> void DCmdArgument<bool>::destroy_value() { }
template <> void DCmdArgument<char*>::parse_value(const char* str,
                                                  size_t len, TRAPS) {
  if (str == NULL) {
    _value = NULL;
  } else {
    _value = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
    strncpy(_value, str, len);
    _value[len] = 0;
  }
}
template <> void DCmdArgument<char*>::init_value(TRAPS) {
  if (has_default() && _default_string != NULL) {
    this->parse_value(_default_string, strlen(_default_string), THREAD);
    if (HAS_PENDING_EXCEPTION) {
     fatal("Default string must be parsable");
    }
  } else {
    set_value(NULL);
  }
}
template <> void DCmdArgument<char*>::destroy_value() {
  if (_value != NULL) {
    FREE_C_HEAP_ARRAY(char, _value, mtInternal);
    set_value(NULL);
  }
}
template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str,
                                                 size_t len, TRAPS) {
  if (str == NULL) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
              "Integer parsing error nanotime value: syntax error, value is null");
  }
  int argc = sscanf(str, JLONG_FORMAT, &_value._time);
  if (argc != 1) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
              "Integer parsing error nanotime value: syntax error");
  }
  size_t idx = 0;
  while(idx < len && isdigit(str[idx])) {
    idx++;
  }
  if (idx == len) {
    if (_value._time != 0) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                "Integer parsing error nanotime value: unit required");
    } else {
      _value._nanotime = 0;
      strcpy(_value._unit, "ns");
      return;
    }
  } else if(len - idx > 2) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
              "Integer parsing error nanotime value: illegal unit");
  } else {
    strncpy(_value._unit, &str[idx], len - idx);
    _value._unit[len-idx] = '\0';
  }
  if (strcmp(_value._unit, "ns") == 0) {
    _value._nanotime = _value._time;
  } else if (strcmp(_value._unit, "us") == 0) {
    _value._nanotime = _value._time * 1000;
  } else if (strcmp(_value._unit, "ms") == 0) {
    _value._nanotime = _value._time * 1000 * 1000;
  } else if (strcmp(_value._unit, "s") == 0) {
    _value._nanotime = _value._time * 1000 * 1000 * 1000;
  } else if (strcmp(_value._unit, "m") == 0) {
    _value._nanotime = _value._time * 60 * 1000 * 1000 * 1000;
  } else if (strcmp(_value._unit, "h") == 0) {
    _value._nanotime = _value._time * 60 * 60 * 1000 * 1000 * 1000;
  } else if (strcmp(_value._unit, "d") == 0) {
    _value._nanotime = _value._time * 24 * 60 * 60 * 1000 * 1000 * 1000;
  } else {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "Integer parsing error nanotime value: illegal unit");
  }
}
template <> void DCmdArgument<NanoTimeArgument>::init_value(TRAPS) {
  if (has_default()) {
    this->parse_value(_default_string, strlen(_default_string), THREAD);
    if (HAS_PENDING_EXCEPTION) {
      fatal("Default string must be parsable");
    }
  } else {
    _value._time = 0;
    _value._nanotime = 0;
    strcpy(_value._unit, "ns");
  }
}
template <> void DCmdArgument<NanoTimeArgument>::destroy_value() { }
template <> void DCmdArgument<StringArrayArgument*>::parse_value(const char* str,
                                                  size_t len, TRAPS) {
  _value->add(str,len);
}
template <> void DCmdArgument<StringArrayArgument*>::init_value(TRAPS) {
  _value = new StringArrayArgument();
  _allow_multiple = true;
  if (has_default()) {
    fatal("StringArrayArgument cannot have default value");
  }
}
template <> void DCmdArgument<StringArrayArgument*>::destroy_value() {
  if (_value != NULL) {
    delete _value;
    set_value(NULL);
  }
}
template <> void DCmdArgument<MemorySizeArgument>::parse_value(const char* str,
                                                  size_t len, TRAPS) {
  if (str == NULL) {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "Parsing error memory size value: syntax error, value is null\n");
  }
  if (*str == '-') {
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "Parsing error memory size value: negative values not allowed");
  }
  int res = sscanf(str, UINT64_FORMAT "%c", &_value._val, &_value._multiplier);
  if (res == 2) {
     switch (_value._multiplier) {
      case 'k': case 'K':
         _value._size = _value._val * 1024;
         break;
      case 'm': case 'M':
         _value._size = _value._val * 1024 * 1024;
         break;
      case 'g': case 'G':
         _value._size = _value._val * 1024 * 1024 * 1024;
         break;
       default:
         _value._size = _value._val;
         _value._multiplier = ' ';
         break;
     }
   } else if (res == 1) {
     _value._size = _value._val;
   } else {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "Parsing error memory size value: invalid value");
   }
}
template <> void DCmdArgument<MemorySizeArgument>::init_value(TRAPS) {
  if (has_default()) {
    this->parse_value(_default_string, strlen(_default_string), THREAD);
    if (HAS_PENDING_EXCEPTION) {
      fatal("Default string must be parsable");
    }
  } else {
    _value._size = 0;
    _value._val = 0;
    _value._multiplier = ' ';
  }
}
template <> void DCmdArgument<MemorySizeArgument>::destroy_value() { }
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticArgument.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.hpp"
#include "utilities/exceptions.hpp"
class StringArrayArgument : public CHeapObj<mtInternal> {
private:
  GrowableArray<char*>* _array;
public:
  StringArrayArgument() {
    _array = new(ResourceObj::C_HEAP, mtInternal)GrowableArray<char *>(32, true);
    assert(_array != NULL, "Sanity check");
  }
  void add(const char* str, size_t len) {
    if (str != NULL) {
      char* ptr = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
      strncpy(ptr, str, len);
      ptr[len] = 0;
      _array->append(ptr);
    }
  }
  GrowableArray<char*>* array() {
    return _array;
  }
  ~StringArrayArgument() {
    for (int i=0; i<_array->length(); i++) {
      if(_array->at(i) != NULL) { // Safety check
        FREE_C_HEAP_ARRAY(char, _array->at(i), mtInternal);
      }
    }
    delete _array;
  }
};
class NanoTimeArgument {
public:
  jlong _nanotime;
  jlong _time;
  char _unit[3];
};
class MemorySizeArgument {
public:
  u8 _size;
  u8 _val;
  char _multiplier;
};
class GenDCmdArgument : public ResourceObj {
protected:
  GenDCmdArgument* _next;
  const char*      _name;
  const char*      _description;
  const char*      _type;
  const char*      _default_string;
  bool             _is_set;
  bool             _is_mandatory;
  bool             _allow_multiple;
  GenDCmdArgument(const char* name, const char* description, const char* type,
                  const char* default_string, bool mandatory) {
    _name = name;
    _description = description;
    _type = type;
    _default_string = default_string;
    _is_mandatory = mandatory;
    _is_set = false;
    _allow_multiple = false;
  };
public:
  const char* name() { return _name; }
  const char* description() { return _description; }
  const char* type() { return _type; }
  const char* default_string() { return _default_string; }
  bool is_set() { return _is_set; }
  void set_is_set(bool b) { _is_set = b; }
  bool allow_multiple() { return _allow_multiple; }
  bool is_mandatory() { return _is_mandatory; }
  bool has_value() { return _is_set || _default_string != NULL; }
  bool has_default() { return _default_string != NULL; }
  void read_value(const char* str, size_t len, TRAPS);
  virtual void parse_value(const char* str, size_t len, TRAPS) = 0;
  virtual void init_value(TRAPS) = 0;
  virtual void reset(TRAPS) = 0;
  virtual void cleanup() = 0;
  virtual void value_as_str(char* buf, size_t len) = 0;
  void set_next(GenDCmdArgument* arg) {
    _next = arg;
  }
  GenDCmdArgument* next() {
    return _next;
  }
  void to_string(jlong l, char* buf, size_t len);
  void to_string(bool b, char* buf, size_t len);
  void to_string(char* c, char* buf, size_t len);
  void to_string(NanoTimeArgument n, char* buf, size_t len);
  void to_string(MemorySizeArgument f, char* buf, size_t len);
  void to_string(StringArrayArgument* s, char* buf, size_t len);
};
template <class ArgType> class DCmdArgument: public GenDCmdArgument {
private:
  ArgType _value;
public:
  DCmdArgument(const char* name, const char* description, const char* type,
               bool mandatory) :
               GenDCmdArgument(name, description, type, NULL, mandatory) { }
  DCmdArgument(const char* name, const char* description, const char* type,
               bool mandatory, const char* defaultvalue) :
               GenDCmdArgument(name, description, type, defaultvalue, mandatory)
               { }
  ~DCmdArgument() { destroy_value(); }
  ArgType value() { return _value;}
  void set_value(ArgType v) { _value = v; }
  void reset(TRAPS) {
    destroy_value();
    init_value(CHECK);
    _is_set = false;
  }
  void cleanup() {
    destroy_value();
  }
  void parse_value(const char* str, size_t len, TRAPS);
  void init_value(TRAPS);
  void destroy_value();
  void value_as_str(char *buf, size_t len) { return to_string(_value, buf, len);}
};
#endif  /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand.cpp
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/heapDumper.hpp"
#include "services/management.hpp"
#include "utilities/macros.hpp"
#include "oops/objArrayOop.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
void DCmdRegistrant::register_dcmds(){
  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
                         | DCmd_Source_MBean;
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false));
#if INCLUDE_SERVICES // Heap dumping/inspection supported
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
  uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
}
#ifndef HAVE_EXTRA_DCMD
void DCmdRegistrant::register_dcmds_ext(){
}
#endif
HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
  _all("-all", "Show help for all commands", "BOOLEAN", false, "false"),
  _cmd("command name", "The name of the command for which we want help",
        "STRING", false) {
  _dcmdparser.add_dcmd_option(&_all);
  _dcmdparser.add_dcmd_argument(&_cmd);
};
void HelpDCmd::execute(DCmdSource source, TRAPS) {
  if (_all.value()) {
    GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
    for (int i = 0; i < cmd_list->length(); i++) {
      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                  strlen(cmd_list->at(i)));
      output()->print_cr("%s%s", factory->name(),
                         factory->is_enabled() ? "" : " [disabled]");
      output()->print_cr("\t%s", factory->description());
      output()->cr();
      factory = factory->next();
    }
  } else if (_cmd.has_value()) {
    DCmd* cmd = NULL;
    DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
                                                strlen(_cmd.value()));
    if (factory != NULL) {
      output()->print_cr("%s%s", factory->name(),
                         factory->is_enabled() ? "" : " [disabled]");
      output()->print_cr("%s", factory->description());
      output()->print_cr("\nImpact: %s", factory->impact());
      JavaPermission p = factory->permission();
      if(p._class != NULL) {
        if(p._action != NULL) {
          output()->print_cr("\nPermission: %s(%s, %s)",
                  p._class, p._name == NULL ? "null" : p._name, p._action);
        } else {
          output()->print_cr("\nPermission: %s(%s)",
                  p._class, p._name == NULL ? "null" : p._name);
        }
      }
      output()->cr();
      cmd = factory->create_resource_instance(output());
      if (cmd != NULL) {
        DCmdMark mark(cmd);
        cmd->print_help(factory->name());
      }
    } else {
      output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value());
    }
  } else {
    output()->print_cr("The following commands are available:");
    GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
    for (int i = 0; i < cmd_list->length(); i++) {
      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                  strlen(cmd_list->at(i)));
      output()->print_cr("%s%s", factory->name(),
                         factory->is_enabled() ? "" : " [disabled]");
      factory = factory->_next;
    }
    output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
  }
}
int HelpDCmd::num_arguments() {
  ResourceMark rm;
  HelpDCmd* dcmd = new HelpDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
void VersionDCmd::execute(DCmdSource source, TRAPS) {
  output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(),
          Abstract_VM_Version::vm_release());
  JDK_Version jdk_version = JDK_Version::current();
  if (jdk_version.update_version() > 0) {
    output()->print_cr("JDK %d.%d_%02d", jdk_version.major_version(),
            jdk_version.minor_version(), jdk_version.update_version());
  } else {
    output()->print_cr("JDK %d.%d", jdk_version.major_version(),
            jdk_version.minor_version());
  }
}
PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) :
                                   DCmdWithParser(output, heap),
  _all("-all", "Print all flags supported by the VM", "BOOLEAN", false, "false") {
  _dcmdparser.add_dcmd_option(&_all);
}
void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
  if (_all.value()) {
    CommandLineFlags::printFlags(output(), true);
  } else {
    CommandLineFlags::printSetFlags(output());
  }
}
int PrintVMFlagsDCmd::num_arguments() {
    ResourceMark rm;
    PrintVMFlagsDCmd* dcmd = new PrintVMFlagsDCmd(NULL, false);
    if (dcmd != NULL) {
      DCmdMark mark(dcmd);
      return dcmd->_dcmdparser.num_arguments();
    } else {
      return 0;
    }
}
void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
  Symbol* klass = vmSymbols::sun_misc_VMSupport();
  Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
  instanceKlassHandle ik (THREAD, k);
  if (ik->should_be_initialized()) {
    ik->initialize(THREAD);
  }
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, output());
    output()->cr();
    CLEAR_PENDING_EXCEPTION;
    return;
  }
  JavaValue result(T_OBJECT);
  JavaCallArguments args;
  Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
  JavaCalls::call_static(&result,
                         ik,
                         vmSymbols::serializePropertiesToByteArray_name(),
                         signature,
                         &args,
                         THREAD);
  if (HAS_PENDING_EXCEPTION) {
    java_lang_Throwable::print(PENDING_EXCEPTION, output());
    output()->cr();
    CLEAR_PENDING_EXCEPTION;
    return;
  }
  oop res = (oop)result.get_jobject();
  assert(res->is_typeArray(), "just checking");
  assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
  typeArrayOop ba = typeArrayOop(res);
  jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
  output()->print_raw((const char*)addr, ba->length());
}
VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) :
                           DCmdWithParser(output, heap),
  _date("-date", "Add a prefix with current date", "BOOLEAN", false, "false") {
  _dcmdparser.add_dcmd_option(&_date);
}
void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
  if (_date.value()) {
    output()->date_stamp(true, "", ": ");
  }
  output()->time_stamp().update_to(tty->time_stamp().ticks());
  output()->stamp();
  output()->print_cr(" s");
}
int VMUptimeDCmd::num_arguments() {
  ResourceMark rm;
  VMUptimeDCmd* dcmd = new VMUptimeDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
  if (!DisableExplicitGC) {
    Universe::heap()->collect(GCCause::_java_lang_system_gc);
  } else {
    output()->print_cr("Explicit GC is disabled, no GC has been performed.");
  }
}
void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
  Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(),
                                                 true, CHECK);
  instanceKlassHandle klass(THREAD, k);
  JavaValue result(T_VOID);
  JavaCalls::call_static(&result, klass,
                         vmSymbols::run_finalization_name(),
                         vmSymbols::void_method_signature(), CHECK);
}
void HeapInfoDCmd::execute(DCmdSource source, TRAPS) {
  Universe::heap()->print_on(output());
}
void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) {
  ResourceMark rm;
  Klass* k = SystemDictionary::resolve_or_null(
    vmSymbols::finalizer_histogram_klass(), THREAD);
  assert(k != NULL, "FinalizerHistogram class is not accessible");
  instanceKlassHandle klass(THREAD, k);
  JavaValue result(T_ARRAY);
  JavaCalls::call_static(&result, klass,
                         vmSymbols::get_finalizer_histogram_name(),
                         vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK);
  objArrayOop result_oop = (objArrayOop) result.get_jobject();
  if (result_oop->length() == 0) {
    output()->print_cr("No instances waiting for finalization found");
    return;
  }
  oop foop = result_oop->obj_at(0);
  InstanceKlass* ik = InstanceKlass::cast(foop->klass());
  fieldDescriptor count_fd, name_fd;
  Klass* count_res = ik->find_field(
    vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd);
  Klass* name_res = ik->find_field(
    vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd);
  assert(count_res != NULL && name_res != NULL, "Unexpected layout of FinalizerHistogramEntry");
  output()->print_cr("Unreachable instances waiting for finalization");
  output()->print_cr("#instances  class name");
  output()->print_cr("-----------------------");
  for (int i = 0; i < result_oop->length(); ++i) {
    oop element_oop = result_oop->obj_at(i);
    oop str_oop = element_oop->obj_field(name_fd.offset());
    char *name = java_lang_String::as_utf8_string(str_oop);
    int count = element_oop->int_field(count_fd.offset());
    output()->print_cr("%10d  %s", count, name);
  }
}
#if INCLUDE_SERVICES // Heap dumping/inspection supported
HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
                           DCmdWithParser(output, heap),
  _filename("filename","Name of the dump file", "STRING",true),
  _all("-all", "Dump all objects, including unreachable objects",
       "BOOLEAN", false, "false") {
  _dcmdparser.add_dcmd_option(&_all);
  _dcmdparser.add_dcmd_argument(&_filename);
}
void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
  HeapDumper dumper(!_all.value() /* request GC if _all is false*/);
  int res = dumper.dump(_filename.value());
  if (res == 0) {
    output()->print_cr("Heap dump file created");
  } else {
    ResourceMark rm;
    char* error = dumper.error_as_C_string();
    if (error == NULL) {
      output()->print_cr("Dump failed - reason unknown");
    } else {
      output()->print_cr("%s", error);
    }
  }
}
int HeapDumpDCmd::num_arguments() {
  ResourceMark rm;
  HeapDumpDCmd* dcmd = new HeapDumpDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
                                       DCmdWithParser(output, heap),
  _all("-all", "Inspect all objects, including unreachable objects",
       "BOOLEAN", false, "false") {
  _dcmdparser.add_dcmd_option(&_all);
}
void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
  VM_GC_HeapInspection heapop(output(),
                              !_all.value() /* request full gc if false */);
  VMThread::execute(&heapop);
}
int ClassHistogramDCmd::num_arguments() {
  ResourceMark rm;
  ClassHistogramDCmd* dcmd = new ClassHistogramDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total"
ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) :
                                       DCmdWithParser(output, heap),
  _csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets",
       "BOOLEAN", false, "false"),
  _all("-all", "Show all columns",
       "BOOLEAN", false, "false"),
  _help("-help", "Show meaning of all the columns",
       "BOOLEAN", false, "false"),
  _columns("columns", "Comma-separated list of all the columns to show. "
           "If not specified, the following columns are shown: " DEFAULT_COLUMNS,
           "STRING", false) {
  _dcmdparser.add_dcmd_option(&_all);
  _dcmdparser.add_dcmd_option(&_csv);
  _dcmdparser.add_dcmd_option(&_help);
  _dcmdparser.add_dcmd_argument(&_columns);
}
void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
  if (!UnlockDiagnosticVMOptions) {
    output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions");
    return;
  }
  VM_GC_HeapInspection heapop(output(),
                              true /* request_full_gc */);
  heapop.set_csv_format(_csv.value());
  heapop.set_print_help(_help.value());
  heapop.set_print_class_stats(true);
  if (_all.value()) {
    if (_columns.has_value()) {
      output()->print_cr("Cannot specify -all and individual columns at the same time");
      return;
    } else {
      heapop.set_columns(NULL);
    }
  } else {
    if (_columns.has_value()) {
      heapop.set_columns(_columns.value());
    } else {
      heapop.set_columns(DEFAULT_COLUMNS);
    }
  }
  VMThread::execute(&heapop);
}
int ClassStatsDCmd::num_arguments() {
  ResourceMark rm;
  ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
#endif // INCLUDE_SERVICES
ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) :
                               DCmdWithParser(output, heap),
  _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") {
  _dcmdparser.add_dcmd_option(&_locks);
}
void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
  VM_PrintThreads op1(output(), _locks.value());
  VMThread::execute(&op1);
  VM_PrintJNI op2(output());
  VMThread::execute(&op2);
  VM_FindDeadlocks op3(output());
  VMThread::execute(&op3);
}
int ThreadDumpDCmd::num_arguments() {
  ResourceMark rm;
  ThreadDumpDCmd* dcmd = new ThreadDumpDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated) :
  DCmdWithParser(output, heap_allocated),
  _config_file
  ("config.file",
   "set com.sun.management.config.file", "STRING", false),
  _jmxremote_host
  ("jmxremote.host",
   "set com.sun.management.jmxremote.host", "STRING", false),
  _jmxremote_port
  ("jmxremote.port",
   "set com.sun.management.jmxremote.port", "STRING", false),
  _jmxremote_rmi_port
  ("jmxremote.rmi.port",
   "set com.sun.management.jmxremote.rmi.port", "STRING", false),
  _jmxremote_ssl
  ("jmxremote.ssl",
   "set com.sun.management.jmxremote.ssl", "STRING", false),
  _jmxremote_registry_ssl
  ("jmxremote.registry.ssl",
   "set com.sun.management.jmxremote.registry.ssl", "STRING", false),
  _jmxremote_authenticate
  ("jmxremote.authenticate",
   "set com.sun.management.jmxremote.authenticate", "STRING", false),
  _jmxremote_password_file
  ("jmxremote.password.file",
   "set com.sun.management.jmxremote.password.file", "STRING", false),
  _jmxremote_access_file
  ("jmxremote.access.file",
   "set com.sun.management.jmxremote.access.file", "STRING", false),
  _jmxremote_login_config
  ("jmxremote.login.config",
   "set com.sun.management.jmxremote.login.config", "STRING", false),
  _jmxremote_ssl_enabled_cipher_suites
  ("jmxremote.ssl.enabled.cipher.suites",
   "set com.sun.management.jmxremote.ssl.enabled.cipher.suite", "STRING", false),
  _jmxremote_ssl_enabled_protocols
  ("jmxremote.ssl.enabled.protocols",
   "set com.sun.management.jmxremote.ssl.enabled.protocols", "STRING", false),
  _jmxremote_ssl_need_client_auth
  ("jmxremote.ssl.need.client.auth",
   "set com.sun.management.jmxremote.need.client.auth", "STRING", false),
  _jmxremote_ssl_config_file
  ("jmxremote.ssl.config.file",
   "set com.sun.management.jmxremote.ssl_config_file", "STRING", false),
  _jmxremote_autodiscovery
  ("jmxremote.autodiscovery",
   "set com.sun.management.jmxremote.autodiscovery", "STRING", false),
   _jdp_port
  ("jdp.port",
   "set com.sun.management.jdp.port", "INT", false),
   _jdp_address
  ("jdp.address",
   "set com.sun.management.jdp.address", "STRING", false),
   _jdp_source_addr
  ("jdp.source_addr",
   "set com.sun.management.jdp.source_addr", "STRING", false),
   _jdp_ttl
  ("jdp.ttl",
   "set com.sun.management.jdp.ttl", "INT", false),
   _jdp_pause
  ("jdp.pause",
   "set com.sun.management.jdp.pause", "INT", false),
   _jdp_name
  ("jdp.name",
   "set com.sun.management.jdp.name", "STRING", false)
  {
    _dcmdparser.add_dcmd_option(&_config_file);
    _dcmdparser.add_dcmd_option(&_jmxremote_host);
    _dcmdparser.add_dcmd_option(&_jmxremote_port);
    _dcmdparser.add_dcmd_option(&_jmxremote_rmi_port);
    _dcmdparser.add_dcmd_option(&_jmxremote_ssl);
    _dcmdparser.add_dcmd_option(&_jmxremote_registry_ssl);
    _dcmdparser.add_dcmd_option(&_jmxremote_authenticate);
    _dcmdparser.add_dcmd_option(&_jmxremote_password_file);
    _dcmdparser.add_dcmd_option(&_jmxremote_access_file);
    _dcmdparser.add_dcmd_option(&_jmxremote_login_config);
    _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_cipher_suites);
    _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols);
    _dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth);
    _dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file);
    _dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery);
    _dcmdparser.add_dcmd_option(&_jdp_port);
    _dcmdparser.add_dcmd_option(&_jdp_address);
    _dcmdparser.add_dcmd_option(&_jdp_source_addr);
    _dcmdparser.add_dcmd_option(&_jdp_ttl);
    _dcmdparser.add_dcmd_option(&_jdp_pause);
    _dcmdparser.add_dcmd_option(&_jdp_name);
}
int JMXStartRemoteDCmd::num_arguments() {
  ResourceMark rm;
  JMXStartRemoteDCmd* dcmd = new JMXStartRemoteDCmd(NULL, false);
  if (dcmd != NULL) {
    DCmdMark mark(dcmd);
    return dcmd->_dcmdparser.num_arguments();
  } else {
    return 0;
  }
}
void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
    Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
    Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
    instanceKlassHandle ik (THREAD, k);
    JavaValue result(T_VOID);
    int len = 0;
    stringStream options;
    char comma[2] = {0,0};
#define PUT_OPTION(a) \
    if ( (a).is_set() ){ \
        options.print(\
               ( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\
                comma, (a).name(), (a).value()); \
        comma[0] = ','; \
    }
    PUT_OPTION(_config_file);
    PUT_OPTION(_jmxremote_host);
    PUT_OPTION(_jmxremote_port);
    PUT_OPTION(_jmxremote_rmi_port);
    PUT_OPTION(_jmxremote_ssl);
    PUT_OPTION(_jmxremote_registry_ssl);
    PUT_OPTION(_jmxremote_authenticate);
    PUT_OPTION(_jmxremote_password_file);
    PUT_OPTION(_jmxremote_access_file);
    PUT_OPTION(_jmxremote_login_config);
    PUT_OPTION(_jmxremote_ssl_enabled_cipher_suites);
    PUT_OPTION(_jmxremote_ssl_enabled_protocols);
    PUT_OPTION(_jmxremote_ssl_need_client_auth);
    PUT_OPTION(_jmxremote_ssl_config_file);
    PUT_OPTION(_jmxremote_autodiscovery);
    PUT_OPTION(_jdp_port);
    PUT_OPTION(_jdp_address);
    PUT_OPTION(_jdp_source_addr);
    PUT_OPTION(_jdp_ttl);
    PUT_OPTION(_jdp_pause);
    PUT_OPTION(_jdp_name);
#undef PUT_OPTION
    Handle str = java_lang_String::create_from_str(options.as_string(), CHECK);
    JavaCalls::call_static(&result, ik, vmSymbols::startRemoteAgent_name(), vmSymbols::string_void_signature(), str, CHECK);
}
JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) :
  DCmd(output, heap_allocated) {
}
void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
    Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
    Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
    instanceKlassHandle ik (THREAD, k);
    JavaValue result(T_VOID);
    JavaCalls::call_static(&result, ik, vmSymbols::startLocalAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
    ResourceMark rm(THREAD);
    HandleMark hm(THREAD);
    Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
    Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
    instanceKlassHandle ik (THREAD, k);
    JavaValue result(T_VOID);
    JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) :
  DCmd(output, heap_allocated) {
}
void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) {
  os::print_dll_info(output());
  output()->cr();
}
void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
  if (UseGCLogFileRotation) {
    VM_RotateGCLog rotateop(output());
    VMThread::execute(&rotateop);
  } else {
    output()->print_cr("Target VM does not support GC log file rotation.");
  }
}
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
#include "runtime/arguments.hpp"
#include "classfile/vmSymbols.hpp"
#include "utilities/ostream.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/os.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/diagnosticCommand_ext.hpp"
#include "utilities/macros.hpp"
class HelpDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _all;
  DCmdArgument<char*> _cmd;
public:
  HelpDCmd(outputStream* output, bool heap);
  static const char* name() { return "help"; }
  static const char* description() {
    return "For more information about a specific command use 'help <command>'. "
           "With no argument this will show a list of available commands. "
           "'help all' will show help for all commands.";
  }
  static const char* impact() { return "Low"; }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class VersionDCmd : public DCmd {
public:
  VersionDCmd(outputStream* output, bool heap) : DCmd(output,heap) { }
  static const char* name() { return "VM.version"; }
  static const char* description() {
    return "Print JVM version information.";
  }
  static const char* impact() { return "Low"; }
  static const JavaPermission permission() {
    JavaPermission p = {"java.util.PropertyPermission",
                        "java.vm.version", "read"};
    return p;
  }
  static int num_arguments() { return 0; }
  virtual void execute(DCmdSource source, TRAPS);
};
class CommandLineDCmd : public DCmd {
public:
  CommandLineDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
  static const char* name() { return "VM.command_line"; }
  static const char* description() {
    return "Print the command line used to start this VM instance.";
  }
  static const char* impact() { return "Low"; }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments() { return 0; }
  virtual void execute(DCmdSource source, TRAPS) {
    Arguments::print_on(_output);
  }
};
class PrintSystemPropertiesDCmd : public DCmd {
public:
  PrintSystemPropertiesDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
    static const char* name() { return "VM.system_properties"; }
    static const char* description() {
      return "Print system properties.";
    }
    static const char* impact() {
      return "Low";
    }
    static const JavaPermission permission() {
      JavaPermission p = {"java.util.PropertyPermission",
                          "*", "read"};
      return p;
    }
    static int num_arguments() { return 0; }
    virtual void execute(DCmdSource source, TRAPS);
};
class PrintVMFlagsDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _all;
public:
  PrintVMFlagsDCmd(outputStream* output, bool heap);
  static const char* name() { return "VM.flags"; }
  static const char* description() {
    return "Print VM flag options and their current values.";
  }
  static const char* impact() {
    return "Low";
  }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class VMDynamicLibrariesDCmd : public DCmd {
public:
  VMDynamicLibrariesDCmd(outputStream* output, bool heap);
  static const char* name() {
    return "VM.dynlibs";
  }
  static const char* description() {
    return "Print loaded dynamic libraries.";
  }
  static const char* impact() {
    return "Low";
  }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments() {
    return 0;
  };
  virtual void execute(DCmdSource source, TRAPS);
};
class VMUptimeDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _date;
public:
  VMUptimeDCmd(outputStream* output, bool heap);
  static const char* name() { return "VM.uptime"; }
  static const char* description() {
    return "Print VM uptime.";
  }
  static const char* impact() {
    return "Low";
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class SystemGCDCmd : public DCmd {
public:
  SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
    static const char* name() { return "GC.run"; }
    static const char* description() {
      return "Call java.lang.System.gc().";
    }
    static const char* impact() {
      return "Medium: Depends on Java heap size and content.";
    }
    static int num_arguments() { return 0; }
    virtual void execute(DCmdSource source, TRAPS);
};
class RunFinalizationDCmd : public DCmd {
public:
  RunFinalizationDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
    static const char* name() { return "GC.run_finalization"; }
    static const char* description() {
      return "Call java.lang.System.runFinalization().";
    }
    static const char* impact() {
      return "Medium: Depends on Java content.";
    }
    static int num_arguments() { return 0; }
    virtual void execute(DCmdSource source, TRAPS);
};
class HeapInfoDCmd : public DCmd {
public:
  HeapInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
  static const char* name() { return "GC.heap_info"; }
  static const char* description() {
    return "Provide generic Java heap information.";
  }
  static const char* impact() {
    return "Medium";
  }
  static int num_arguments() { return 0; }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
      "monitor", NULL};
      return p;
  }
  virtual void execute(DCmdSource source, TRAPS);
};
class FinalizerInfoDCmd : public DCmd {
public:
  FinalizerInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
  static const char* name() { return "GC.finalizer_info"; }
  static const char* description() {
    return "Provide information about Java finalization queue.";
  }
  static const char* impact() {
    return "Medium";
  }
  static int num_arguments() { return 0; }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
      "monitor", NULL};
      return p;
  }
  virtual void execute(DCmdSource source, TRAPS);
};
#if INCLUDE_SERVICES   // Heap dumping supported
class HeapDumpDCmd : public DCmdWithParser {
protected:
  DCmdArgument<char*> _filename;
  DCmdArgument<bool>  _all;
public:
  HeapDumpDCmd(outputStream* output, bool heap);
  static const char* name() {
    return "GC.heap_dump";
  }
  static const char* description() {
    return "Generate a HPROF format dump of the Java heap.";
  }
  static const char* impact() {
    return "High: Depends on Java heap size and content. "
           "Request a full GC unless the '-all' option is specified.";
  }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
#endif // INCLUDE_SERVICES
class ClassHistogramDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _all;
public:
  ClassHistogramDCmd(outputStream* output, bool heap);
  static const char* name() {
    return "GC.class_histogram";
  }
  static const char* description() {
    return "Provide statistics about the Java heap usage.";
  }
  static const char* impact() {
    return "High: Depends on Java heap size and content.";
  }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class ClassStatsDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _all;
  DCmdArgument<bool> _csv;
  DCmdArgument<bool> _help;
  DCmdArgument<char*> _columns;
public:
  ClassStatsDCmd(outputStream* output, bool heap);
  static const char* name() {
    return "GC.class_stats";
  }
  static const char* description() {
    return "Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions.";
  }
  static const char* impact() {
    return "High: Depends on Java heap size and content.";
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class ThreadDumpDCmd : public DCmdWithParser {
protected:
  DCmdArgument<bool> _locks;
public:
  ThreadDumpDCmd(outputStream* output, bool heap);
  static const char* name() { return "Thread.print"; }
  static const char* description() {
    return "Print all threads with stacktraces.";
  }
  static const char* impact() {
    return "Medium: Depends on the number of threads.";
  }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "monitor", NULL};
    return p;
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class JMXStartRemoteDCmd : public DCmdWithParser {
  DCmdArgument<char *> _config_file;
  DCmdArgument<char *> _jmxremote_host;
  DCmdArgument<char *> _jmxremote_port;
  DCmdArgument<char *> _jmxremote_rmi_port;
  DCmdArgument<char *> _jmxremote_ssl;
  DCmdArgument<char *> _jmxremote_registry_ssl;
  DCmdArgument<char *> _jmxremote_authenticate;
  DCmdArgument<char *> _jmxremote_password_file;
  DCmdArgument<char *> _jmxremote_access_file;
  DCmdArgument<char *> _jmxremote_login_config;
  DCmdArgument<char *> _jmxremote_ssl_enabled_cipher_suites;
  DCmdArgument<char *> _jmxremote_ssl_enabled_protocols;
  DCmdArgument<char *> _jmxremote_ssl_need_client_auth;
  DCmdArgument<char *> _jmxremote_ssl_config_file;
  DCmdArgument<char *> _jmxremote_autodiscovery;
  DCmdArgument<jlong>  _jdp_port;
  DCmdArgument<char *> _jdp_address;
  DCmdArgument<char *> _jdp_source_addr;
  DCmdArgument<jlong>  _jdp_ttl;
  DCmdArgument<jlong>  _jdp_pause;
  DCmdArgument<char *> _jdp_name;
public:
  JMXStartRemoteDCmd(outputStream *output, bool heap_allocated);
  static const char *name() {
    return "ManagementAgent.start";
  }
  static const char *description() {
    return "Start remote management agent.";
  }
  static int num_arguments();
  virtual void execute(DCmdSource source, TRAPS);
};
class JMXStartLocalDCmd : public DCmd {
public:
  JMXStartLocalDCmd(outputStream *output, bool heap_allocated);
  static const char *name() {
    return "ManagementAgent.start_local";
  }
  static const char *description() {
    return "Start local management agent.";
  }
  virtual void execute(DCmdSource source, TRAPS);
};
class JMXStopRemoteDCmd : public DCmd {
public:
  JMXStopRemoteDCmd(outputStream *output, bool heap_allocated) :
  DCmd(output, heap_allocated) {
  }
  static const char *name() {
    return "ManagementAgent.stop";
  }
  static const char *description() {
    return "Stop remote management agent.";
  }
  virtual void execute(DCmdSource source, TRAPS);
};
class RotateGCLogDCmd : public DCmd {
public:
  RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
  static const char* name() { return "GC.rotate_log"; }
  static const char* description() {
    return "Force the GC log file to be rotated.";
  }
  static const char* impact() { return "Low"; }
  virtual void execute(DCmdSource source, TRAPS);
  static int num_arguments() { return 0; }
  static const JavaPermission permission() {
    JavaPermission p = {"java.lang.management.ManagementPermission",
                        "control", NULL};
    return p;
  }
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand_ext.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_EXT_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_EXT_HPP
#undef HAVE_EXTRA_DCMD
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticFramework.cpp
#include "precompiled.hpp"
#include "memory/oopFactory.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/management.hpp"
CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) {
  assert(line != NULL, "Command line string should not be NULL");
  const char* line_end;
  const char* cmd_end;
  _cmd = line;
  line_end = &line[len];
  while (_cmd < line_end && isspace((int) _cmd[0])) {
    _cmd++;
  }
  cmd_end = _cmd;
  if (no_command_name) {
    _cmd = NULL;
    _cmd_len = 0;
  } else {
    while (cmd_end < line_end && !isspace((int) cmd_end[0])) {
      cmd_end++;
    }
    _cmd_len = cmd_end - _cmd;
  }
  _args = cmd_end;
  _args_len = line_end - _args;
}
bool DCmdArgIter::next(TRAPS) {
  if (_len == 0) return false;
  while (_cursor < _len - 1 && _buffer[_cursor] == _delim) {
    _cursor++;
  }
  if (_cursor >= _len - 1) {
    _cursor = _len - 1;
    _key_addr = &_buffer[_len - 1];
    _key_len = 0;
    _value_addr = &_buffer[_len - 1];
    _value_len = 0;
    return false;
  }
  _key_addr = &_buffer[_cursor];
  bool arg_had_quotes = false;
  while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) {
    if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
      _key_addr++;
      char quote = _buffer[_cursor];
      arg_had_quotes = true;
      while (_cursor < _len - 1) {
        _cursor++;
        if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
          break;
        }
      }
      if (_buffer[_cursor] != quote) {
        THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
                "Format error in diagnostic command arguments", false);
      }
      break;
    }
    _cursor++;
  }
  _key_len = &_buffer[_cursor] - _key_addr;
  if (arg_had_quotes) {
    _cursor++;
  }
  if (_cursor <= _len -1 && _buffer[_cursor] == '=') {
    _cursor++;
    _value_addr = &_buffer[_cursor];
    bool value_had_quotes = false;
    while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) {
      if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
        _value_addr++;
        char quote = _buffer[_cursor];
        value_had_quotes = true;
        while (_cursor < _len - 1) {
          _cursor++;
          if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
            break;
          }
        }
        if (_buffer[_cursor] != quote) {
          THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
                  "Format error in diagnostic command arguments", false);
        }
        break;
      }
      _cursor++;
    }
    _value_len = &_buffer[_cursor] - _value_addr;
    if (value_had_quotes) {
      _cursor++;
    }
  } else {
    _value_addr = NULL;
    _value_len = 0;
  }
  return _key_len != 0;
}
bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) {
  if (info == NULL) return false;
  return strcmp((const char*)cmd_name, info->name()) == 0;
}
void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) {
  assert(arg != NULL, "Sanity");
  if (_options == NULL) {
    _options = arg;
  } else {
    GenDCmdArgument* o = _options;
    while (o->next() != NULL) {
      o = o->next();
    }
    o->set_next(arg);
  }
  arg->set_next(NULL);
  Thread* THREAD = Thread::current();
  arg->init_value(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    fatal("Initialization must be successful");
  }
}
void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) {
  assert(arg != NULL, "Sanity");
  if (_arguments_list == NULL) {
    _arguments_list = arg;
  } else {
    GenDCmdArgument* a = _arguments_list;
    while (a->next() != NULL) {
      a = a->next();
    }
    a->set_next(arg);
  }
  arg->set_next(NULL);
  Thread* THREAD = Thread::current();
  arg->init_value(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    fatal("Initialization must be successful");
  }
}
void DCmdParser::parse(CmdLine* line, char delim, TRAPS) {
  GenDCmdArgument* next_argument = _arguments_list;
  DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
  bool cont = iter.next(CHECK);
  while (cont) {
    GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(),
            iter.key_length());
    if (arg != NULL) {
      arg->read_value(iter.value_addr(), iter.value_length(), CHECK);
    } else {
      if (next_argument != NULL) {
        arg = next_argument;
        arg->read_value(iter.key_addr(), iter.key_length(), CHECK);
        next_argument = next_argument->next();
      } else {
        const size_t buflen    = 120;
        const size_t argbuflen = 30;
        char buf[buflen];
        char argbuf[argbuflen];
        size_t len = MIN2<size_t>(iter.key_length(), argbuflen - 1);
        strncpy(argbuf, iter.key_addr(), len);
        argbuf[len] = '\0';
        jio_snprintf(buf, buflen - 1, "Unknown argument '%s' in diagnostic command.", argbuf);
        THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
      }
    }
    cont = iter.next(CHECK);
  }
  check(CHECK);
}
GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) {
  GenDCmdArgument* arg = _options;
  while (arg != NULL) {
    if (strlen(arg->name()) == len &&
      strncmp(name, arg->name(), len) == 0) {
      return arg;
    }
    arg = arg->next();
  }
  return NULL;
}
void DCmdParser::check(TRAPS) {
  const size_t buflen = 256;
  char buf[buflen];
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    if (arg->is_mandatory() && !arg->has_value()) {
      jio_snprintf(buf, buflen - 1, "The argument '%s' is mandatory.", arg->name());
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
    }
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    if (arg->is_mandatory() && !arg->has_value()) {
      jio_snprintf(buf, buflen - 1, "The option '%s' is mandatory.", arg->name());
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
    }
    arg = arg->next();
  }
}
void DCmdParser::print_help(outputStream* out, const char* cmd_name) {
  out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]");
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    if (arg->is_mandatory()) {
      out->print(" <%s>", arg->name());
    } else {
      out->print(" [<%s>]", arg->name());
    }
    arg = arg->next();
  }
  out->cr();
  if (_arguments_list != NULL) {
    out->print_cr("\nArguments:");
    arg = _arguments_list;
    while (arg != NULL) {
      out->print("\t%s : %s %s (%s, ", arg->name(),
                 arg->is_mandatory() ? "" : "[optional]",
                 arg->description(), arg->type());
      if (arg->has_default()) {
        out->print("%s", arg->default_string());
      } else {
        out->print("no default value");
      }
      out->print_cr(")");
      arg = arg->next();
    }
  }
  if (_options != NULL) {
    out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)");
    arg = _options;
    while (arg != NULL) {
      out->print("\t%s : %s %s (%s, ", arg->name(),
                 arg->is_mandatory() ? "" : "[optional]",
                 arg->description(), arg->type());
      if (arg->has_default()) {
        out->print("%s", arg->default_string());
      } else {
        out->print("no default value");
      }
      out->print_cr(")");
      arg = arg->next();
    }
  }
}
void DCmdParser::reset(TRAPS) {
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    arg->reset(CHECK);
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    arg->reset(CHECK);
    arg = arg->next();
  }
}
void DCmdParser::cleanup() {
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    arg->cleanup();
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    arg->cleanup();
    arg = arg->next();
  }
}
int DCmdParser::num_arguments() {
  GenDCmdArgument* arg = _arguments_list;
  int count = 0;
  while (arg != NULL) {
    count++;
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    count++;
    arg = arg->next();
  }
  return count;
}
GrowableArray<const char *>* DCmdParser::argument_name_array() {
  int count = num_arguments();
  GrowableArray<const char *>* array = new GrowableArray<const char *>(count);
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    array->append(arg->name());
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    array->append(arg->name());
    arg = arg->next();
  }
  return array;
}
GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() {
  int count = num_arguments();
  GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count);
  int idx = 0;
  GenDCmdArgument* arg = _arguments_list;
  while (arg != NULL) {
    array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                  arg->type(), arg->default_string(), arg->is_mandatory(),
                  false, arg->allow_multiple(), idx));
    idx++;
    arg = arg->next();
  }
  arg = _options;
  while (arg != NULL) {
    array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                  arg->type(), arg->default_string(), arg->is_mandatory(),
                  true, arg->allow_multiple()));
    arg = arg->next();
  }
  return array;
}
DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;
bool DCmdFactory::_has_pending_jmx_notification = false;
void DCmd::parse_and_execute(DCmdSource source, outputStream* out,
                             const char* cmdline, char delim, TRAPS) {
  if (cmdline == NULL) return; // Nothing to do!
  DCmdIter iter(cmdline, '\n');
  int count = 0;
  while (iter.has_next()) {
    if(source == DCmd_Source_MBean && count > 0) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
              "Invalid syntax");
    }
    CmdLine line = iter.next();
    if (line.is_stop()) {
      break;
    }
    if (line.is_executable()) {
      DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);
      assert(command != NULL, "command error must be handled before this line");
      DCmdMark mark(command);
      command->parse(&line, delim, CHECK);
      command->execute(source, CHECK);
    }
    count++;
  }
}
void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) {
  _dcmdparser.parse(line, delim, CHECK);
}
void DCmdWithParser::print_help(const char* name) {
  _dcmdparser.print_help(output(), name);
}
void DCmdWithParser::reset(TRAPS) {
  _dcmdparser.reset(CHECK);
}
void DCmdWithParser::cleanup() {
  _dcmdparser.cleanup();
}
GrowableArray<const char*>* DCmdWithParser::argument_name_array() {
  return _dcmdparser.argument_name_array();
}
GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() {
  return _dcmdparser.argument_info_array();
}
void DCmdFactory::push_jmx_notification_request() {
  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
  _has_pending_jmx_notification = true;
  Service_lock->notify_all();
}
void DCmdFactory::send_notification(TRAPS) {
  DCmdFactory::send_notification_internal(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    CLEAR_PENDING_EXCEPTION;
  }
}
void DCmdFactory::send_notification_internal(TRAPS) {
  ResourceMark rm(THREAD);
  HandleMark hm(THREAD);
  bool notif = false;
  {
    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
    notif = _has_pending_jmx_notification;
    _has_pending_jmx_notification = false;
  }
  if (notif) {
    Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK);
    instanceKlassHandle mgmt_factory_helper_klass(THREAD, k);
    JavaValue result(T_OBJECT);
    JavaCalls::call_static(&result,
            mgmt_factory_helper_klass,
            vmSymbols::getDiagnosticCommandMBean_name(),
            vmSymbols::getDiagnosticCommandMBean_signature(),
            CHECK);
    instanceOop m = (instanceOop) result.get_jobject();
    instanceHandle dcmd_mbean_h(THREAD, m);
    Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK);
    instanceKlassHandle dcmd_mbean_klass(THREAD, k2);
    if (!dcmd_mbean_h->is_a(k2)) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
              "ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");
    }
    JavaValue result2(T_VOID);
    JavaCallArguments args2(dcmd_mbean_h);
    JavaCalls::call_virtual(&result2,
            dcmd_mbean_klass,
            vmSymbols::createDiagnosticFrameworkNotification_name(),
            vmSymbols::void_method_signature(),
            &args2,
            CHECK);
  }
}
Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
bool DCmdFactory::_send_jmx_notification = false;
DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {
  MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
  DCmdFactory* factory = _DCmdFactoryList;
  while (factory != NULL) {
    if (strlen(factory->name()) == len &&
        strncmp(name, factory->name(), len) == 0) {
      if(factory->export_flags() & source) {
        return factory;
      } else {
        return NULL;
      }
    }
    factory = factory->_next;
  }
  return NULL;
}
int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) {
  MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
  factory->_next = _DCmdFactoryList;
  _DCmdFactoryList = factory;
  if (_send_jmx_notification && !factory->_hidden
      && (factory->_export_flags & DCmd_Source_MBean)) {
    DCmdFactory::push_jmx_notification_request();
  }
  return 0; // Actually, there's no checks for duplicates
}
DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line,
                                      outputStream* out, TRAPS) {
  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
  if (f != NULL) {
    if (f->is_enabled()) {
      THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
                     f->disabled_message());
    }
    return f->create_Cheap_instance(out);
  }
  THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
             "Unknown diagnostic command");
}
DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,
                                     outputStream* out, TRAPS) {
  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
  if (f != NULL) {
    if (!f->is_enabled()) {
      THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
                     f->disabled_message());
    }
    return f->create_resource_instance(out);
  }
  THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
             "Unknown diagnostic command");
}
GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {
  MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
  GrowableArray<const char*>* array = new GrowableArray<const char*>();
  DCmdFactory* factory = _DCmdFactoryList;
  while (factory != NULL) {
    if (!factory->is_hidden() && (factory->export_flags() & source)) {
      array->append(factory->name());
    }
    factory = factory->next();
  }
  return array;
}
GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {
  MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
  GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();
  DCmdFactory* factory = _DCmdFactoryList;
  while (factory != NULL) {
    if (!factory->is_hidden() && (factory->export_flags() & source)) {
      array->append(new DCmdInfo(factory->name(),
                    factory->description(), factory->impact(),
                    factory->permission(), factory->num_arguments(),
                    factory->is_enabled()));
    }
    factory = factory->next();
  }
  return array;
}
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticFramework.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/ostream.hpp"
enum DCmdSource {
  DCmd_Source_Internal  = 0x01U,  // invocation from the JVM
  DCmd_Source_AttachAPI = 0x02U,  // invocation via the attachAPI
  DCmd_Source_MBean     = 0x04U   // invocation via a MBean
};
struct JavaPermission {
  const char* _class;
  const char* _name;
  const char* _action;
};
class CmdLine : public StackObj {
private:
  const char* _cmd;
  size_t      _cmd_len;
  const char* _args;
  size_t      _args_len;
public:
  CmdLine(const char* line, size_t len, bool no_command_name);
  const char* args_addr() const { return _args; }
  size_t args_len() const { return _args_len; }
  const char* cmd_addr() const { return _cmd; }
  size_t cmd_len() const { return _cmd_len; }
  bool is_empty() { return _cmd_len == 0; }
  bool is_executable() { return is_empty() || _cmd[0] != '#'; }
  bool is_stop() { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; }
};
class DCmdIter : public StackObj {
  friend class DCmd;
private:
  const char* _str;
  char        _delim;
  size_t      _len;
  size_t      _cursor;
public:
  DCmdIter(const char* str, char delim) {
    _str = str;
    _delim = delim;
    _len = strlen(str);
    _cursor = 0;
  }
  bool has_next() { return _cursor < _len; }
  CmdLine next() {
    assert(_cursor <= _len, "Cannot iterate more");
    size_t n = _cursor;
    while (n < _len && _str[n] != _delim) n++;
    CmdLine line(&(_str[_cursor]), n - _cursor, false);
    _cursor = n + 1;
    return line;
  }
};
class DCmdArgIter : public ResourceObj {
  const char* _buffer;
  size_t      _len;
  size_t      _cursor;
  const char* _key_addr;
  size_t      _key_len;
  const char* _value_addr;
  size_t      _value_len;
  char        _delim;
public:
  DCmdArgIter(const char* buf, size_t len, char delim) {
    _buffer = buf;
    _len = len;
    _delim = delim;
    _cursor = 0;
  }
  bool next(TRAPS);
  const char* key_addr() { return _key_addr; }
  size_t key_length() { return _key_len; }
  const char* value_addr() { return _value_addr; }
  size_t value_length() { return _value_len; }
};
class DCmdInfo : public ResourceObj {
protected:
  const char* _name;           /* Name of the diagnostic command */
  const char* _description;    /* Short description */
  const char* _impact;         /* Impact on the JVM */
  JavaPermission _permission;  /* Java Permission required to execute this command if any */
  int         _num_arguments;  /* Number of supported options or arguments */
  bool        _is_enabled;     /* True if the diagnostic command can be invoked, false otherwise */
public:
  DCmdInfo(const char* name,
          const char* description,
          const char* impact,
          JavaPermission permission,
          int num_arguments,
          bool enabled) {
    this->_name = name;
    this->_description = description;
    this->_impact = impact;
    this->_permission = permission;
    this->_num_arguments = num_arguments;
    this->_is_enabled = enabled;
  }
  const char* name() const { return _name; }
  const char* description() const { return _description; }
  const char* impact() const { return _impact; }
  JavaPermission permission() const { return _permission; }
  int num_arguments() const { return _num_arguments; }
  bool is_enabled() const { return _is_enabled; }
  static bool by_name(void* name, DCmdInfo* info);
};
class DCmdArgumentInfo : public ResourceObj {
protected:
  const char* _name;            /* Option/Argument name*/
  const char* _description;     /* Short description */
  const char* _type;            /* Type: STRING, BOOLEAN, etc. */
  const char* _default_string;  /* Default value in a parsable string */
  bool        _mandatory;       /* True if the option/argument is mandatory */
  bool        _option;          /* True if it is an option, false if it is an argument */
  bool        _multiple;        /* True is the option can be specified several time */
  int         _position;        /* Expected position for this argument (this field is */
public:
  DCmdArgumentInfo(const char* name, const char* description, const char* type,
                   const char* default_string, bool mandatory, bool option,
                   bool multiple) {
    this->_name = name;
    this->_description = description;
    this->_type = type;
    this->_default_string = default_string;
    this->_option = option;
    this->_mandatory = mandatory;
    this->_option = option;
    this->_multiple = multiple;
    this->_position = -1;
  }
  DCmdArgumentInfo(const char* name, const char* description, const char* type,
                   const char* default_string, bool mandatory, bool option,
                   bool multiple, int position) {
    this->_name = name;
    this->_description = description;
    this->_type = type;
    this->_default_string = default_string;
    this->_option = option;
    this->_mandatory = mandatory;
    this->_option = option;
    this->_multiple = multiple;
    this->_position = position;
  }
  const char* name() const { return _name; }
  const char* description() const { return _description; }
  const char* type() const { return _type; }
  const char* default_string() const { return _default_string; }
  bool is_mandatory() const { return _mandatory; }
  bool is_option() const { return _option; }
  bool is_multiple() const { return _multiple; }
  int position() const { return _position; }
};
class DCmdParser {
private:
  GenDCmdArgument* _options;
  GenDCmdArgument* _arguments_list;
  char             _delim;
public:
  DCmdParser() {
    _options = NULL;
    _arguments_list = NULL;
    _delim = ' ';
  }
  void add_dcmd_option(GenDCmdArgument* arg);
  void add_dcmd_argument(GenDCmdArgument* arg);
  GenDCmdArgument* lookup_dcmd_option(const char* name, size_t len);
  GenDCmdArgument* arguments_list() { return _arguments_list; };
  void check(TRAPS);
  void parse(CmdLine* line, char delim, TRAPS);
  void print_help(outputStream* out, const char* cmd_name);
  void reset(TRAPS);
  void cleanup();
  int num_arguments();
  GrowableArray<const char*>* argument_name_array();
  GrowableArray<DCmdArgumentInfo*>* argument_info_array();
};
class DCmd : public ResourceObj {
protected:
  outputStream* _output;
  bool          _is_heap_allocated;
public:
  DCmd(outputStream* output, bool heap_allocated) {
    _output = output;
    _is_heap_allocated = heap_allocated;
  }
  static const char* name() { return "No Name";}
  static const char* description() { return "No Help";}
  static const char* disabled_message() { return "Diagnostic command currently disabled"; }
  static const char* impact() { return "Low: No impact"; }
  static const JavaPermission permission() {
    JavaPermission p = {NULL, NULL, NULL};
    return p;
  }
  static int num_arguments() { return 0; }
  outputStream* output() { return _output; }
  bool is_heap_allocated()  { return _is_heap_allocated; }
  virtual void print_help(const char* name) {
    output()->print_cr("Syntax: %s", name);
  }
  virtual void parse(CmdLine* line, char delim, TRAPS) {
    DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
    bool has_arg = iter.next(CHECK);
    if (has_arg) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                "The argument list of this diagnostic command should be empty.");
    }
  }
  virtual void execute(DCmdSource source, TRAPS) { }
  virtual void reset(TRAPS) { }
  virtual void cleanup() { }
  virtual GrowableArray<const char*>* argument_name_array() {
    GrowableArray<const char*>* array = new GrowableArray<const char*>(0);
    return array;
  }
  virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() {
    GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo*>(0);
    return array;
  }
  static void parse_and_execute(DCmdSource source, outputStream* out, const char* cmdline,
                                char delim, TRAPS);
};
class DCmdWithParser : public DCmd {
protected:
  DCmdParser _dcmdparser;
public:
  DCmdWithParser (outputStream *output, bool heap=false) : DCmd(output, heap) { }
  static const char* name() { return "No Name";}
  static const char* description() { return "No Help";}
  static const char* disabled_message() { return "Diagnostic command currently disabled"; }
  static const char* impact() { return "Low: No impact"; }
  static const JavaPermission permission() {JavaPermission p = {NULL, NULL, NULL}; return p; }
  static int num_arguments() { return 0; }
  virtual void parse(CmdLine *line, char delim, TRAPS);
  virtual void execute(DCmdSource source, TRAPS) { }
  virtual void reset(TRAPS);
  virtual void cleanup();
  virtual void print_help(const char* name);
  virtual GrowableArray<const char*>* argument_name_array();
  virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array();
};
class DCmdMark : public StackObj {
  DCmd* _ref;
public:
  DCmdMark(DCmd* cmd) { _ref = cmd; }
  ~DCmdMark() {
    if (_ref != NULL) {
      _ref->cleanup();
      if (_ref->is_heap_allocated()) {
        delete _ref;
      }
    }
  }
};
class DCmdFactory: public CHeapObj<mtInternal> {
private:
  static Mutex*       _dcmdFactory_lock;
  static bool         _send_jmx_notification;
  static bool         _has_pending_jmx_notification;
  DCmdFactory*        _next;
  bool                _enabled;
  bool                _hidden;
  uint32_t            _export_flags;
  int                 _num_arguments;
  static DCmdFactory* _DCmdFactoryList;
public:
  DCmdFactory(int num_arguments, uint32_t flags, bool enabled, bool hidden) {
    _next = NULL;
    _enabled = enabled;
    _hidden = hidden;
    _export_flags = flags;
    _num_arguments = num_arguments;
  }
  bool is_enabled() const { return _enabled; }
  void set_enabled(bool b) { _enabled = b; }
  bool is_hidden() const { return _hidden; }
  void set_hidden(bool b) { _hidden = b; }
  uint32_t export_flags() { return _export_flags; }
  void set_export_flags(uint32_t f) { _export_flags = f; }
  int num_arguments() { return _num_arguments; }
  DCmdFactory* next() { return _next; }
  virtual DCmd* create_Cheap_instance(outputStream* output) = 0;
  virtual DCmd* create_resource_instance(outputStream* output) = 0;
  virtual const char* name() const = 0;
  virtual const char* description() const = 0;
  virtual const char* impact() const = 0;
  virtual const JavaPermission permission() const = 0;
  virtual const char* disabled_message() const = 0;
  static int register_DCmdFactory(DCmdFactory* factory);
  static DCmdFactory* factory(DCmdSource source, const char* cmd, size_t len);
  static DCmd* create_global_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
  static DCmd* create_local_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
  static GrowableArray<const char*>* DCmd_list(DCmdSource source);
  static GrowableArray<DCmdInfo*>* DCmdInfo_list(DCmdSource source);
  static void set_jmx_notification_enabled(bool enabled) {
    _send_jmx_notification = enabled;
  }
  static void push_jmx_notification_request();
  static bool has_pending_jmx_notification() { return _has_pending_jmx_notification; }
  static void send_notification(TRAPS);
private:
  static void send_notification_internal(TRAPS);
  friend class HelpDCmd;
};
template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory {
public:
  DCmdFactoryImpl(uint32_t flags, bool enabled, bool hidden) :
    DCmdFactory(DCmdClass::num_arguments(), flags, enabled, hidden) { }
  virtual DCmd* create_Cheap_instance(outputStream* output) {
    return new (ResourceObj::C_HEAP, mtInternal) DCmdClass(output, true);
  }
  virtual DCmd* create_resource_instance(outputStream* output) {
    return new DCmdClass(output, false);
  }
  virtual const char* name() const {
    return DCmdClass::name();
  }
  virtual const char* description() const {
    return DCmdClass::description();
  }
  virtual const char* impact() const {
    return DCmdClass::impact();
  }
  virtual const JavaPermission permission() const {
    return DCmdClass::permission();
  }
  virtual const char* disabled_message() const {
     return DCmdClass::disabled_message();
  }
};
class DCmdRegistrant : public AllStatic {
private:
    static void register_dcmds();
    static void register_dcmds_ext();
    friend class Management;
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
C:\hotspot-69087d08d473\src\share\vm/services/dtraceAttacher.cpp
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/dtraceAttacher.hpp"
#ifdef SOLARIS
class VM_DeoptimizeTheWorld : public VM_Operation {
 public:
  VMOp_Type type() const {
    return VMOp_DeoptimizeTheWorld;
  }
  void doit() {
    CodeCache::mark_all_nmethods_for_deoptimization();
    ResourceMark rm;
    DeoptimizationMarker dm;
    Deoptimization::deoptimize_dependents();
    CodeCache::make_marked_nmethods_not_entrant();
  }
};
static void set_bool_flag(const char* flag, bool value) {
  CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value,
                              Flag::ATTACH_ON_DEMAND);
}
void DTrace::enable_dprobes(int probes) {
  bool changed = false;
  if (!DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
    set_bool_flag("DTraceAllocProbes", true);
    changed = true;
  }
  if (!DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
    set_bool_flag("DTraceMethodProbes", true);
    changed = true;
  }
  if (!DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
    set_bool_flag("DTraceMonitorProbes", true);
    changed = true;
  }
  if (changed) {
    VM_DeoptimizeTheWorld op;
    VMThread::execute(&op);
  }
}
void DTrace::disable_dprobes(int probes) {
  bool changed = false;
  if (DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
    set_bool_flag("DTraceAllocProbes", false);
    changed = true;
  }
  if (DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
    set_bool_flag("DTraceMethodProbes", false);
    changed = true;
  }
  if (DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
    set_bool_flag("DTraceMonitorProbes", false);
    changed = true;
  }
  if (changed) {
    VM_DeoptimizeTheWorld op;
    VMThread::execute(&op);
  }
}
void DTrace::detach_all_clients() {
  if (ExtendedDTraceProbes) {
    enable_dprobes(DTRACE_ALL_PROBES);
  } else {
    disable_dprobes(DTRACE_ALL_PROBES);
  }
}
void DTrace::set_extended_dprobes(bool flag) {
  set_bool_flag("ExtendedDTraceProbes", flag);
  if (flag) {
    enable_dprobes(DTRACE_ALL_PROBES);
  } else {
    disable_dprobes(DTRACE_ALL_PROBES);
  }
}
void DTrace::set_monitor_dprobes(bool flag) {
  set_bool_flag("DTraceMonitorProbes", flag);
}
#endif /* SOLARIS */
C:\hotspot-69087d08d473\src\share\vm/services/dtraceAttacher.hpp
#ifndef SHARE_VM_SERVICES_DTRACEATTACHER_HPP
#define SHARE_VM_SERVICES_DTRACEATTACHER_HPP
#define DTRACE_ALLOC_PROBES    0x1
#define DTRACE_METHOD_PROBES   0x2
#define DTRACE_MONITOR_PROBES  0x4
#define DTRACE_ALL_PROBES      (DTRACE_ALLOC_PROBES  | \
                                DTRACE_METHOD_PROBES | \
                                DTRACE_MONITOR_PROBES)
class DTrace : public AllStatic {
 private:
  static void disable_dprobes(int probe_types);
 public:
  static void enable_dprobes(int probe_types);
  static void detach_all_clients();
  static void set_extended_dprobes(bool value);
  static void set_monitor_dprobes(bool value);
};
#endif // SHARE_VM_SERVICES_DTRACEATTACHER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/g1MemoryPool.cpp
#include "precompiled.hpp"
#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#include "services/g1MemoryPool.hpp"
G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h,
                                     const char* name,
                                     size_t init_size,
                                     size_t max_size,
                                     bool support_usage_threshold) :
  _g1mm(g1h->g1mm()), CollectedMemoryPool(name,
                                          MemoryPool::Heap,
                                          init_size,
                                          max_size,
                                          support_usage_threshold) {
  assert(UseG1GC, "sanity");
}
G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) :
  G1MemoryPoolSuper(g1h,
                    "G1 Eden Space",
                    g1h->g1mm()->eden_space_committed(), /* init_size */
                    _undefined_max,
                    false /* support_usage_threshold */) { }
MemoryUsage G1EdenPool::get_memory_usage() {
  size_t initial_sz = initial_size();
  size_t max_sz     = max_size();
  size_t used       = used_in_bytes();
  size_t committed  = _g1mm->eden_space_committed();
  return MemoryUsage(initial_sz, used, committed, max_sz);
}
G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) :
  G1MemoryPoolSuper(g1h,
                    "G1 Survivor Space",
                    g1h->g1mm()->survivor_space_committed(), /* init_size */
                    _undefined_max,
                    false /* support_usage_threshold */) { }
MemoryUsage G1SurvivorPool::get_memory_usage() {
  size_t initial_sz = initial_size();
  size_t max_sz     = max_size();
  size_t used       = used_in_bytes();
  size_t committed  = _g1mm->survivor_space_committed();
  return MemoryUsage(initial_sz, used, committed, max_sz);
}
G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) :
  G1MemoryPoolSuper(g1h,
                    "G1 Old Gen",
                    g1h->g1mm()->old_space_committed(), /* init_size */
                    g1h->g1mm()->old_gen_max(),
                    true /* support_usage_threshold */) { }
MemoryUsage G1OldGenPool::get_memory_usage() {
  size_t initial_sz = initial_size();
  size_t max_sz     = max_size();
  size_t used       = used_in_bytes();
  size_t committed  = _g1mm->old_space_committed();
  return MemoryUsage(initial_sz, used, committed, max_sz);
}
C:\hotspot-69087d08d473\src\share\vm/services/g1MemoryPool.hpp
#ifndef SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryUsage.hpp"
#endif // INCLUDE_ALL_GCS
class G1MemoryPoolSuper : public CollectedMemoryPool {
protected:
  const static size_t _undefined_max = (size_t) -1;
  G1MonitoringSupport* _g1mm;
  G1MemoryPoolSuper(G1CollectedHeap* g1h,
                    const char* name,
                    size_t init_size,
                    size_t max_size,
                    bool support_usage_threshold);
};
class G1EdenPool : public G1MemoryPoolSuper {
public:
  G1EdenPool(G1CollectedHeap* g1h);
  size_t used_in_bytes() {
    return _g1mm->eden_space_used();
  }
  size_t max_size() const {
    return _undefined_max;
  }
  MemoryUsage get_memory_usage();
};
class G1SurvivorPool : public G1MemoryPoolSuper {
public:
  G1SurvivorPool(G1CollectedHeap* g1h);
  size_t used_in_bytes() {
    return _g1mm->survivor_space_used();
  }
  size_t max_size() const {
    return _undefined_max;
  }
  MemoryUsage get_memory_usage();
};
class G1OldGenPool : public G1MemoryPoolSuper {
public:
  G1OldGenPool(G1CollectedHeap* g1h);
  size_t used_in_bytes() {
    return _g1mm->old_space_used();
  }
  size_t max_size() const {
    return _g1mm->old_gen_max();
  }
  MemoryUsage get_memory_usage();
};
#endif // SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
C:\hotspot-69087d08d473\src\share\vm/services/gcNotifier.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/gcNotifier.hpp"
#include "services/management.hpp"
#include "services/memoryService.hpp"
#include "memoryManager.hpp"
#include "memory/oopFactory.hpp"
GCNotificationRequest *GCNotifier::first_request = NULL;
GCNotificationRequest *GCNotifier::last_request = NULL;
void GCNotifier::pushNotification(GCMemoryManager *mgr, const char *action, const char *cause) {
  int num_pools = MemoryService::num_memory_pools();
  GCStatInfo* stat = new(ResourceObj::C_HEAP, mtGC) GCStatInfo(num_pools);
  mgr->get_last_gc_stat(stat);
  GCNotificationRequest *request = new GCNotificationRequest(os::javaTimeMillis(),mgr,action,cause,stat);
  addRequest(request);
 }
void GCNotifier::addRequest(GCNotificationRequest *request) {
  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
  if(first_request == NULL) {
    first_request = request;
  } else {
    last_request->next = request;
  }
  last_request = request;
  Service_lock->notify_all();
}
GCNotificationRequest *GCNotifier::getRequest() {
  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
  GCNotificationRequest *request = first_request;
  if(first_request != NULL) {
    first_request = first_request->next;
  }
  return request;
}
bool GCNotifier::has_event() {
  return first_request != NULL;
}
static Handle getGcInfoBuilder(GCMemoryManager *gcManager,TRAPS) {
  Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK_NH);
  instanceKlassHandle gcMBeanKlass (THREAD, k);
  instanceOop i = gcManager->get_memory_manager_instance(THREAD);
  instanceHandle ih(THREAD, i);
  JavaValue result(T_OBJECT);
  JavaCallArguments args(ih);
  JavaCalls::call_virtual(&result,
                          gcMBeanKlass,
                          vmSymbols::getGcInfoBuilder_name(),
                          vmSymbols::getGcInfoBuilder_signature(),
                          &args,
                          CHECK_NH);
  return Handle(THREAD,(oop)result.get_jobject());
}
static Handle createGcInfo(GCMemoryManager *gcManager, GCStatInfo *gcStatInfo,TRAPS) {
  Klass* mu_klass = Management::java_lang_management_MemoryUsage_klass(CHECK_NH);
  instanceKlassHandle mu_kh(THREAD, mu_klass);
  objArrayOop bu = oopFactory::new_objArray(mu_kh(), MemoryService::num_memory_pools(), CHECK_NH);
  objArrayHandle usage_before_gc_ah(THREAD, bu);
  objArrayOop au = oopFactory::new_objArray(mu_kh(), MemoryService::num_memory_pools(), CHECK_NH);
  objArrayHandle usage_after_gc_ah(THREAD, au);
  for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
    Handle before_usage = MemoryService::create_MemoryUsage_obj(gcStatInfo->before_gc_usage_for_pool(i), CHECK_NH);
    Handle after_usage;
    MemoryUsage u = gcStatInfo->after_gc_usage_for_pool(i);
    if (u.max_size() == 0 && u.used() > 0) {
      MemoryUsage usage(u.init_size(), u.used(), u.committed(), (size_t)-1);
      after_usage = MemoryService::create_MemoryUsage_obj(usage, CHECK_NH);
    } else {
        after_usage = MemoryService::create_MemoryUsage_obj(u, CHECK_NH);
    }
    usage_before_gc_ah->obj_at_put(i, before_usage());
    usage_after_gc_ah->obj_at_put(i, after_usage());
  }
  objArrayOop extra_args_array = oopFactory::new_objArray(SystemDictionary::Integer_klass(), 1, CHECK_NH);
  objArrayHandle extra_array (THREAD, extra_args_array);
  Klass* itKlass = SystemDictionary::Integer_klass();
  instanceKlassHandle intK(THREAD, itKlass);
  instanceHandle extra_arg_val = intK->allocate_instance_handle(CHECK_NH);
  {
    JavaValue res(T_VOID);
    JavaCallArguments argsInt;
    argsInt.push_oop(extra_arg_val);
    argsInt.push_int(gcManager->num_gc_threads());
    JavaCalls::call_special(&res,
                            intK,
                            vmSymbols::object_initializer_name(),
                            vmSymbols::int_void_signature(),
                            &argsInt,
                            CHECK_NH);
  }
  extra_array->obj_at_put(0,extra_arg_val());
  Klass* gcInfoklass = Management::com_sun_management_GcInfo_klass(CHECK_NH);
  instanceKlassHandle ik(THREAD, gcInfoklass);
  Handle gcInfo_instance = ik->allocate_instance_handle(CHECK_NH);
  JavaValue constructor_result(T_VOID);
  JavaCallArguments constructor_args(16);
  constructor_args.push_oop(gcInfo_instance);
  constructor_args.push_oop(getGcInfoBuilder(gcManager,THREAD));
  constructor_args.push_long(gcStatInfo->gc_index());
  constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->start_time()));
  constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->end_time()));
  constructor_args.push_oop(usage_before_gc_ah);
  constructor_args.push_oop(usage_after_gc_ah);
  constructor_args.push_oop(extra_array);
  JavaCalls::call_special(&constructor_result,
                          ik,
                          vmSymbols::object_initializer_name(),
                          vmSymbols::com_sun_management_GcInfo_constructor_signature(),
                          &constructor_args,
                          CHECK_NH);
  return Handle(gcInfo_instance());
}
void GCNotifier::sendNotification(TRAPS) {
  GCNotifier::sendNotificationInternal(THREAD);
  if (HAS_PENDING_EXCEPTION) {
    CLEAR_PENDING_EXCEPTION;
  }
}
class NotificationMark : public StackObj {
  GCNotificationRequest* _request;
public:
  NotificationMark(GCNotificationRequest* r) {
    _request = r;
  }
  ~NotificationMark() {
    assert(_request != NULL, "Sanity check");
    delete _request;
  }
};
void GCNotifier::sendNotificationInternal(TRAPS) {
  ResourceMark rm(THREAD);
  HandleMark hm(THREAD);
  GCNotificationRequest *request = getRequest();
  if (request != NULL) {
    NotificationMark nm(request);
    Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, CHECK);
    Handle objName = java_lang_String::create_from_str(request->gcManager->name(), CHECK);
    Handle objAction = java_lang_String::create_from_str(request->gcAction, CHECK);
    Handle objCause = java_lang_String::create_from_str(request->gcCause, CHECK);
    Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK);
    instanceKlassHandle gc_mbean_klass(THREAD, k);
    instanceOop gc_mbean = request->gcManager->get_memory_manager_instance(THREAD);
    instanceHandle gc_mbean_h(THREAD, gc_mbean);
    if (!gc_mbean_h->is_a(k)) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
                "This GCMemoryManager doesn't have a GarbageCollectorMXBean");
    }
    JavaValue result(T_VOID);
    JavaCallArguments args(gc_mbean_h);
    args.push_long(request->timestamp);
    args.push_oop(objName);
    args.push_oop(objAction);
    args.push_oop(objCause);
    args.push_oop(objGcInfo);
    JavaCalls::call_virtual(&result,
                            gc_mbean_klass,
                            vmSymbols::createGCNotification_name(),
                            vmSymbols::createGCNotification_signature(),
                            &args,
                            CHECK);
  }
}
C:\hotspot-69087d08d473\src\share\vm/services/gcNotifier.hpp
#ifndef SHARE_VM_SERVICES_GCNOTIFIER_HPP
#define SHARE_VM_SERVICES_GCNOTIFIER_HPP
#include "memory/allocation.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
#include "services/memoryManager.hpp"
class GCNotificationRequest : public CHeapObj<mtInternal> {
  friend class GCNotifier;
  GCNotificationRequest *next;
  jlong timestamp;
  GCMemoryManager *gcManager;
  const char *gcAction;
  const char *gcCause;
  GCStatInfo *gcStatInfo;
public:
  GCNotificationRequest(jlong ts, GCMemoryManager *manager, const char*action, const char *cause,GCStatInfo *info) {
    next = NULL;
    timestamp = ts;
    gcManager = manager;
    gcAction = action;
    gcCause = cause;
    gcStatInfo = info;
  }
  ~GCNotificationRequest() {
    delete gcStatInfo;
  }
};
class GCNotifier : public AllStatic {
  friend class ServiceThread;
private:
  static GCNotificationRequest *first_request;
  static GCNotificationRequest *last_request;
  static void addRequest(GCNotificationRequest *request);
  static GCNotificationRequest *getRequest();
  static void sendNotificationInternal(TRAPS);
public:
  static void pushNotification(GCMemoryManager *manager, const char *action, const char *cause);
  static bool has_event();
  static void sendNotification(TRAPS);
};
#endif // SHARE_VM_SERVICES_GCNOTIFIER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/heapDumper.cpp
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/heapDumper.hpp"
#include "services/threadService.hpp"
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
#endif // INCLUDE_ALL_GCS
typedef enum {
  HPROF_UTF8                    = 0x01,
  HPROF_LOAD_CLASS              = 0x02,
  HPROF_UNLOAD_CLASS            = 0x03,
  HPROF_FRAME                   = 0x04,
  HPROF_TRACE                   = 0x05,
  HPROF_ALLOC_SITES             = 0x06,
  HPROF_HEAP_SUMMARY            = 0x07,
  HPROF_START_THREAD            = 0x0A,
  HPROF_END_THREAD              = 0x0B,
  HPROF_HEAP_DUMP               = 0x0C,
  HPROF_CPU_SAMPLES             = 0x0D,
  HPROF_CONTROL_SETTINGS        = 0x0E,
  HPROF_HEAP_DUMP_SEGMENT       = 0x1C,
  HPROF_HEAP_DUMP_END           = 0x2C,
  HPROF_ARRAY_OBJECT            = 0x01,
  HPROF_NORMAL_OBJECT           = 0x02,
  HPROF_BOOLEAN                 = 0x04,
  HPROF_CHAR                    = 0x05,
  HPROF_FLOAT                   = 0x06,
  HPROF_DOUBLE                  = 0x07,
  HPROF_BYTE                    = 0x08,
  HPROF_SHORT                   = 0x09,
  HPROF_INT                     = 0x0A,
  HPROF_LONG                    = 0x0B,
  HPROF_GC_ROOT_UNKNOWN         = 0xFF,
  HPROF_GC_ROOT_JNI_GLOBAL      = 0x01,
  HPROF_GC_ROOT_JNI_LOCAL       = 0x02,
  HPROF_GC_ROOT_JAVA_FRAME      = 0x03,
  HPROF_GC_ROOT_NATIVE_STACK    = 0x04,
  HPROF_GC_ROOT_STICKY_CLASS    = 0x05,
  HPROF_GC_ROOT_THREAD_BLOCK    = 0x06,
  HPROF_GC_ROOT_MONITOR_USED    = 0x07,
  HPROF_GC_ROOT_THREAD_OBJ      = 0x08,
  HPROF_GC_CLASS_DUMP           = 0x20,
  HPROF_GC_INSTANCE_DUMP        = 0x21,
  HPROF_GC_OBJ_ARRAY_DUMP       = 0x22,
  HPROF_GC_PRIM_ARRAY_DUMP      = 0x23
} hprofTag;
enum {
  STACK_TRACE_ID = 1,
  INITIAL_CLASS_COUNT = 200
};
class DumpWriter : public StackObj {
 private:
  enum {
    io_buffer_size  = 8*M
  };
  int _fd;              // file descriptor (-1 if dump file not open)
  julong _bytes_written; // number of byte written to dump file
  char* _buffer;    // internal buffer
  size_t _size;
  size_t _pos;
  jlong _dump_start;
  char* _error;   // error message when I/O fails
  void set_file_descriptor(int fd)              { _fd = fd; }
  int file_descriptor() const                   { return _fd; }
  char* buffer() const                          { return _buffer; }
  size_t buffer_size() const                    { return _size; }
  size_t position() const                       { return _pos; }
  void set_position(size_t pos)                 { _pos = pos; }
  void set_error(const char* error)             { _error = (char*)os::strdup(error); }
  void write_internal(void* s, size_t len);
 public:
  DumpWriter(const char* path);
  ~DumpWriter();
  void close();
  bool is_open() const                  { return file_descriptor() >= 0; }
  void flush();
  jlong dump_start() const                      { return _dump_start; }
  void set_dump_start(jlong pos);
  julong current_record_length();
  julong bytes_written() const          { return _bytes_written; }
  void adjust_bytes_written(jlong n)    { _bytes_written += n; }
  size_t bytes_unwritten() const        { return position(); }
  char* error() const                   { return _error; }
  jlong current_offset();
  void seek_to_offset(jlong pos);
  void write_raw(void* s, size_t len);
  void write_u1(u1 x)                   { write_raw((void*)&x, 1); }
  void write_u2(u2 x);
  void write_u4(u4 x);
  void write_u8(u8 x);
  void write_objectID(oop o);
  void write_symbolID(Symbol* o);
  void write_classID(Klass* k);
  void write_id(u4 x);
};
DumpWriter::DumpWriter(const char* path) {
  _size = io_buffer_size;
  do {
    _buffer = (char*)os::malloc(_size, mtInternal);
    if (_buffer == NULL) {
      _size = _size >> 1;
    }
  } while (_buffer == NULL && _size > 0);
  assert((_size > 0 && _buffer != NULL) || (_size == 0 && _buffer == NULL), "sanity check");
  _pos = 0;
  _error = NULL;
  _bytes_written = 0L;
  _dump_start = (jlong)-1;
  _fd = os::create_binary_file(path, false);    // don't replace existing file
  if (_fd < 0) {
    _error = (char*)os::strdup(strerror(errno));
  }
}
DumpWriter::~DumpWriter() {
  if (is_open()) {
    close();
  }
  if (_buffer != NULL) os::free(_buffer);
  if (_error != NULL) os::free(_error);
}
void DumpWriter::close() {
  if (is_open()) {
    flush();
    ::close(file_descriptor());
    set_file_descriptor(-1);
  }
}
void DumpWriter::set_dump_start(jlong pos) {
  _dump_start = pos;
}
julong DumpWriter::current_record_length() {
  if (is_open()) {
    julong dump_end = bytes_written() + bytes_unwritten();
    assert(dump_end == (size_t)current_offset(), "checking");
    julong dump_len = dump_end - dump_start() - 4;
    return dump_len;
  }
  return 0;
}
void DumpWriter::write_internal(void* s, size_t len) {
  if (is_open()) {
    const char* pos = (char*)s;
    ssize_t n = 0;
    while (len > 0) {
      uint tmp = (uint)MIN2(len, (size_t)UINT_MAX);
      n = ::write(file_descriptor(), pos, tmp);
      if (n < 0) {
        set_error(strerror(errno));
        ::close(file_descriptor());
        set_file_descriptor(-1);
        return;
      }
      _bytes_written += n;
      pos += n;
      len -= n;
    }
  }
}
void DumpWriter::write_raw(void* s, size_t len) {
  if (is_open()) {
    if ((position() + len) >= buffer_size()) {
      flush();
    }
    if ((buffer() == NULL) || (len >= buffer_size())) {
      write_internal(s, len);
    } else {
      memcpy(buffer() + position(), s, len);
      set_position(position() + len);
    }
  }
}
void DumpWriter::flush() {
  if (is_open() && position() > 0) {
    write_internal(buffer(), position());
    set_position(0);
  }
}
jlong DumpWriter::current_offset() {
  if (is_open()) {
    jlong offset = os::current_file_offset(file_descriptor());
    assert(offset >= 0, "lseek failed");
    return offset + position();
  } else {
    return (jlong)-1;
  }
}
void DumpWriter::seek_to_offset(jlong off) {
  assert(off >= 0, "bad offset");
  flush();
  if (is_open()) {
    jlong n = os::seek_to_file_offset(file_descriptor(), off);
    assert(n >= 0, "lseek failed");
  }
}
void DumpWriter::write_u2(u2 x) {
  u2 v;
  Bytes::put_Java_u2((address)&v, x);
  write_raw((void*)&v, 2);
}
void DumpWriter::write_u4(u4 x) {
  u4 v;
  Bytes::put_Java_u4((address)&v, x);
  write_raw((void*)&v, 4);
}
void DumpWriter::write_u8(u8 x) {
  u8 v;
  Bytes::put_Java_u8((address)&v, x);
  write_raw((void*)&v, 8);
}
void DumpWriter::write_objectID(oop o) {
  address a = (address)o;
#ifdef _LP64
  write_u8((u8)a);
#else
  write_u4((u4)a);
#endif
}
void DumpWriter::write_symbolID(Symbol* s) {
  address a = (address)((uintptr_t)s);
#ifdef _LP64
  write_u8((u8)a);
#else
  write_u4((u4)a);
#endif
}
void DumpWriter::write_id(u4 x) {
#ifdef _LP64
  write_u8((u8) x);
#else
  write_u4(x);
#endif
}
void DumpWriter::write_classID(Klass* k) {
  write_objectID(k->java_mirror());
}
class DumperSupport : AllStatic {
 public:
  static void write_header(DumpWriter* writer, hprofTag tag, u4 len);
  static hprofTag sig2tag(Symbol* sig);
  static hprofTag type2tag(BasicType type);
  static u4 instance_size(Klass* k);
  static void dump_float(DumpWriter* writer, jfloat f);
  static void dump_double(DumpWriter* writer, jdouble d);
  static void dump_field_value(DumpWriter* writer, char type, address addr);
  static void dump_static_fields(DumpWriter* writer, Klass* k);
  static void dump_instance_fields(DumpWriter* writer, oop o);
  static void dump_instance_field_descriptors(DumpWriter* writer, Klass* k);
  static void dump_instance(DumpWriter* writer, oop o);
  static void dump_class_and_array_classes(DumpWriter* writer, Klass* k);
  static void dump_basic_type_array_class(DumpWriter* writer, Klass* k);
  static void dump_object_array(DumpWriter* writer, objArrayOop array);
  static void dump_prim_array(DumpWriter* writer, typeArrayOop array);
  static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
  static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size);
  static void write_dump_header(DumpWriter* writer);
  static void write_current_dump_record_length(DumpWriter* writer);
  static void end_of_dump(DumpWriter* writer);
};
void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) {
  writer->write_u1((u1)tag);
  writer->write_u4(0);                  // current ticks
  writer->write_u4(len);
}
hprofTag DumperSupport::sig2tag(Symbol* sig) {
  switch (sig->byte_at(0)) {
    case JVM_SIGNATURE_CLASS    : return HPROF_NORMAL_OBJECT;
    case JVM_SIGNATURE_ARRAY    : return HPROF_NORMAL_OBJECT;
    case JVM_SIGNATURE_BYTE     : return HPROF_BYTE;
    case JVM_SIGNATURE_CHAR     : return HPROF_CHAR;
    case JVM_SIGNATURE_FLOAT    : return HPROF_FLOAT;
    case JVM_SIGNATURE_DOUBLE   : return HPROF_DOUBLE;
    case JVM_SIGNATURE_INT      : return HPROF_INT;
    case JVM_SIGNATURE_LONG     : return HPROF_LONG;
    case JVM_SIGNATURE_SHORT    : return HPROF_SHORT;
    case JVM_SIGNATURE_BOOLEAN  : return HPROF_BOOLEAN;
    default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE;
  }
}
hprofTag DumperSupport::type2tag(BasicType type) {
  switch (type) {
    case T_BYTE     : return HPROF_BYTE;
    case T_CHAR     : return HPROF_CHAR;
    case T_FLOAT    : return HPROF_FLOAT;
    case T_DOUBLE   : return HPROF_DOUBLE;
    case T_INT      : return HPROF_INT;
    case T_LONG     : return HPROF_LONG;
    case T_SHORT    : return HPROF_SHORT;
    case T_BOOLEAN  : return HPROF_BOOLEAN;
    default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE;
  }
}
void DumperSupport::dump_float(DumpWriter* writer, jfloat f) {
  if (g_isnan(f)) {
    writer->write_u4(0x7fc00000);    // collapsing NaNs
  } else {
    union {
      int i;
      float f;
    } u;
    u.f = (float)f;
    writer->write_u4((u4)u.i);
  }
}
void DumperSupport::dump_double(DumpWriter* writer, jdouble d) {
  union {
    jlong l;
    double d;
  } u;
  if (g_isnan(d)) {                 // collapsing NaNs
    u.l = (jlong)(0x7ff80000);
    u.l = (u.l << 32);
  } else {
    u.d = (double)d;
  }
  writer->write_u8((u8)u.l);
}
void DumperSupport::dump_field_value(DumpWriter* writer, char type, address addr) {
  switch (type) {
    case JVM_SIGNATURE_CLASS :
    case JVM_SIGNATURE_ARRAY : {
      oop o;
      if (UseCompressedOops) {
        o = oopDesc::load_decode_heap_oop((narrowOop*)addr);
      } else {
        o = oopDesc::load_decode_heap_oop((oop*)addr);
      }
      assert(o->is_oop_or_null(), "should always be an oop");
      writer->write_objectID(o);
      break;
    }
    case JVM_SIGNATURE_BYTE     : {
      jbyte* b = (jbyte*)addr;
      writer->write_u1((u1)*b);
      break;
    }
    case JVM_SIGNATURE_CHAR     : {
      jchar* c = (jchar*)addr;
      writer->write_u2((u2)*c);
      break;
    }
    case JVM_SIGNATURE_SHORT : {
      jshort* s = (jshort*)addr;
      writer->write_u2((u2)*s);
      break;
    }
    case JVM_SIGNATURE_FLOAT : {
      jfloat* f = (jfloat*)addr;
      dump_float(writer, *f);
      break;
    }
    case JVM_SIGNATURE_DOUBLE : {
      jdouble* f = (jdouble*)addr;
      dump_double(writer, *f);
      break;
    }
    case JVM_SIGNATURE_INT : {
      jint* i = (jint*)addr;
      writer->write_u4((u4)*i);
      break;
    }
    case JVM_SIGNATURE_LONG     : {
      jlong* l = (jlong*)addr;
      writer->write_u8((u8)*l);
      break;
    }
    case JVM_SIGNATURE_BOOLEAN : {
      jboolean* b = (jboolean*)addr;
      writer->write_u1((u1)*b);
      break;
    }
    default : ShouldNotReachHere();
  }
}
u4 DumperSupport::instance_size(Klass* k) {
  HandleMark hm;
  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
  u4 size = 0;
  for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) {
    if (!fld.access_flags().is_static()) {
      Symbol* sig = fld.signature();
      switch (sig->byte_at(0)) {
        case JVM_SIGNATURE_CLASS   :
        case JVM_SIGNATURE_ARRAY   : size += oopSize; break;
        case JVM_SIGNATURE_BYTE    :
        case JVM_SIGNATURE_BOOLEAN : size += 1; break;
        case JVM_SIGNATURE_CHAR    :
        case JVM_SIGNATURE_SHORT   : size += 2; break;
        case JVM_SIGNATURE_INT     :
        case JVM_SIGNATURE_FLOAT   : size += 4; break;
        case JVM_SIGNATURE_LONG    :
        case JVM_SIGNATURE_DOUBLE  : size += 8; break;
        default : ShouldNotReachHere();
      }
    }
  }
  return size;
}
void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) {
  HandleMark hm;
  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
  u2 field_count = 0;
  for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) {
    if (fldc.access_flags().is_static()) field_count++;
  }
  oop resolved_references = ikh->constants()->resolved_references_or_null();
  if (resolved_references != NULL) {
    field_count++;
    InstanceKlass* prev = ikh->previous_versions();
    while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) {
      field_count++;
      prev = prev->previous_versions();
    }
  }
  oop init_lock = ikh->init_lock();
  if (init_lock != NULL) {
    field_count++;
  }
  writer->write_u2(field_count);
  for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) {
    if (fld.access_flags().is_static()) {
      Symbol* sig = fld.signature();
      writer->write_symbolID(fld.name());   // name
      writer->write_u1(sig2tag(sig));       // type
      int offset = fld.offset();
      address addr = (address)ikh->java_mirror() + offset;
      dump_field_value(writer, sig->byte_at(0), addr);
    }
  }
  if (resolved_references != NULL) {
    writer->write_symbolID(vmSymbols::resolved_references_name());  // name
    writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
    writer->write_objectID(resolved_references);
    InstanceKlass* prev = ikh->previous_versions();
    while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) {
      writer->write_symbolID(vmSymbols::resolved_references_name());  // name
      writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
      writer->write_objectID(prev->constants()->resolved_references());
      prev = prev->previous_versions();
    }
  }
  if (init_lock != NULL) {
    writer->write_symbolID(vmSymbols::init_lock_name());         // name
    writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type
    writer->write_objectID(init_lock);
  }
}
void DumperSupport::dump_instance_fields(DumpWriter* writer, oop o) {
  HandleMark hm;
  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), o->klass());
  for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) {
    if (!fld.access_flags().is_static()) {
      Symbol* sig = fld.signature();
      address addr = (address)o + fld.offset();
      dump_field_value(writer, sig->byte_at(0), addr);
    }
  }
}
void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k) {
  HandleMark hm;
  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
  u2 field_count = 0;
  for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) {
    if (!fldc.access_flags().is_static()) field_count++;
  }
  writer->write_u2(field_count);
  for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) {
    if (!fld.access_flags().is_static()) {
      Symbol* sig = fld.signature();
      writer->write_symbolID(fld.name());   // name
      writer->write_u1(sig2tag(sig));       // type
    }
  }
}
void DumperSupport::dump_instance(DumpWriter* writer, oop o) {
  Klass* k = o->klass();
  writer->write_u1(HPROF_GC_INSTANCE_DUMP);
  writer->write_objectID(o);
  writer->write_u4(STACK_TRACE_ID);
  writer->write_classID(k);
  writer->write_u4(instance_size(k) );
  dump_instance_fields(writer, o);
}
void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) {
  Klass* klass = k;
  InstanceKlass* ik = InstanceKlass::cast(k);
  if (!ik->is_loaded()) {
    return;
  }
  writer->write_u1(HPROF_GC_CLASS_DUMP);
  writer->write_classID(ik);
  writer->write_u4(STACK_TRACE_ID);
  Klass* java_super = ik->java_super();
  if (java_super == NULL) {
    writer->write_objectID(oop(NULL));
  } else {
    writer->write_classID(java_super);
  }
  writer->write_objectID(ik->class_loader());
  writer->write_objectID(ik->signers());
  writer->write_objectID(ik->protection_domain());
  writer->write_objectID(oop(NULL));
  writer->write_objectID(oop(NULL));
  writer->write_u4(DumperSupport::instance_size(k));
  writer->write_u2(0);
  dump_static_fields(writer, k);
  dump_instance_field_descriptors(writer, k);
  k = klass->array_klass_or_null();
  while (k != NULL) {
    Klass* klass = k;
    assert(klass->oop_is_objArray(), "not an ObjArrayKlass");
    writer->write_u1(HPROF_GC_CLASS_DUMP);
    writer->write_classID(klass);
    writer->write_u4(STACK_TRACE_ID);
    java_super = klass->java_super();
    assert(java_super != NULL, "checking");
    writer->write_classID(java_super);
    writer->write_objectID(ik->class_loader());
    writer->write_objectID(ik->signers());
    writer->write_objectID(ik->protection_domain());
    writer->write_objectID(oop(NULL));    // reserved
    writer->write_objectID(oop(NULL));
    writer->write_u4(0);             // instance size
    writer->write_u2(0);             // constant pool
    writer->write_u2(0);             // static fields
    writer->write_u2(0);             // instance fields
    k = klass->array_klass_or_null();
  }
}
void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) {
 while (k != NULL) {
    Klass* klass = k;
    writer->write_u1(HPROF_GC_CLASS_DUMP);
    writer->write_classID(klass);
    writer->write_u4(STACK_TRACE_ID);
    Klass* java_super = klass->java_super();
    assert(java_super != NULL, "checking");
    writer->write_classID(java_super);
    writer->write_objectID(oop(NULL));    // loader
    writer->write_objectID(oop(NULL));    // signers
    writer->write_objectID(oop(NULL));    // protection domain
    writer->write_objectID(oop(NULL));    // reserved
    writer->write_objectID(oop(NULL));
    writer->write_u4(0);             // instance size
    writer->write_u2(0);             // constant pool
    writer->write_u2(0);             // static fields
    writer->write_u2(0);             // instance fields
    k = klass->array_klass_or_null();
  }
}
int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) {
  BasicType type = ArrayKlass::cast(array->klass())->element_type();
  assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type");
  int length = array->length();
  int type_size;
  if (type == T_OBJECT) {
    type_size = sizeof(address);
  } else {
    type_size = type2aelembytes(type);
  }
  size_t length_in_bytes = (size_t)length * type_size;
  julong current_record_length = writer->current_record_length();
  if (current_record_length > 0 &&
      (current_record_length + header_size + length_in_bytes) > max_juint) {
    write_current_dump_record_length(writer);
    write_dump_header(writer);
    current_record_length = 0;
  }
  uint max_bytes = max_juint - (header_size + current_record_length);
  if (length_in_bytes > max_bytes) {
    length = max_bytes / type_size;
    length_in_bytes = (size_t)length * type_size;
    warning("cannot dump array of type %s[] with length %d; truncating to length %d",
            type2name_tab[type], array->length(), length);
  }
  return length;
}
void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) {
  short header_size = 1 + 2 * 4 + 2 * sizeof(address);
  int length = calculate_array_max_length(writer, array, header_size);
  writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP);
  writer->write_objectID(array);
  writer->write_u4(STACK_TRACE_ID);
  writer->write_u4(length);
  writer->write_classID(array->klass());
  for (int index = 0; index < length; index++) {
    oop o = array->obj_at(index);
    writer->write_objectID(o);
  }
}
#define WRITE_ARRAY(Array, Type, Size, Length) \
  for (int i = 0; i < Length; i++) { writer->write_##Size((Size)array->Type##_at(i)); }
void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) {
  BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
  short header_size = 2 * 1 + 2 * 4 + sizeof(address);
  int length = calculate_array_max_length(writer, array, header_size);
  int type_size = type2aelembytes(type);
  u4 length_in_bytes = (u4)length * type_size;
  writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP);
  writer->write_objectID(array);
  writer->write_u4(STACK_TRACE_ID);
  writer->write_u4(length);
  writer->write_u1(type2tag(type));
  if (length == 0) {
    return;
  }
  switch (type) {
    case T_INT : {
      if (Bytes::is_Java_byte_ordering_different()) {
        WRITE_ARRAY(array, int, u4, length);
      } else {
        writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes);
      }
      break;
    }
    case T_BYTE : {
      writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
      break;
    }
    case T_CHAR : {
      if (Bytes::is_Java_byte_ordering_different()) {
        WRITE_ARRAY(array, char, u2, length);
      } else {
        writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes);
      }
      break;
    }
    case T_SHORT : {
      if (Bytes::is_Java_byte_ordering_different()) {
        WRITE_ARRAY(array, short, u2, length);
      } else {
        writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
      }
      break;
    }
    case T_BOOLEAN : {
      if (Bytes::is_Java_byte_ordering_different()) {
        WRITE_ARRAY(array, bool, u1, length);
      } else {
        writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
      }
      break;
    }
    case T_LONG : {
      if (Bytes::is_Java_byte_ordering_different()) {
        WRITE_ARRAY(array, long, u8, length);
      } else {
        writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
      }
      break;
    }
    case T_FLOAT : {
      for (int i = 0; i < length; i++) {
        dump_float(writer, array->float_at(i));
      }
      break;
    }
    case T_DOUBLE : {
      for (int i = 0; i < length; i++) {
        dump_double(writer, array->double_at(i));
      }
      break;
    }
    default : ShouldNotReachHere();
  }
}
void DumperSupport::dump_stack_frame(DumpWriter* writer,
                                     int frame_serial_num,
                                     int class_serial_num,
                                     Method* m,
                                     int bci) {
  int line_number;
  if (m->is_native()) {
    line_number = -3;  // native frame
  } else {
    line_number = m->line_number_from_bci(bci);
  }
  write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4));
  writer->write_id(frame_serial_num);               // frame serial number
  writer->write_symbolID(m->name());                // method's name
  writer->write_symbolID(m->signature());           // method's signature
  assert(m->method_holder()->oop_is_instance(), "not InstanceKlass");
  writer->write_symbolID(m->method_holder()->source_file_name());  // source file name
  writer->write_u4(class_serial_num);               // class serial number
  writer->write_u4((u4) line_number);               // line number
}
class SymbolTableDumper : public SymbolClosure {
 private:
  DumpWriter* _writer;
  DumpWriter* writer() const                { return _writer; }
 public:
  SymbolTableDumper(DumpWriter* writer)     { _writer = writer; }
  void do_symbol(Symbol** p);
};
void SymbolTableDumper::do_symbol(Symbol** p) {
  ResourceMark rm;
  Symbol* sym = load_symbol(p);
  int len = sym->utf8_length();
  if (len > 0) {
    char* s = sym->as_utf8();
    DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len);
    writer()->write_symbolID(sym);
    writer()->write_raw(s, len);
  }
}
class JNILocalsDumper : public OopClosure {
 private:
  DumpWriter* _writer;
  u4 _thread_serial_num;
  int _frame_num;
  DumpWriter* writer() const                { return _writer; }
 public:
  JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) {
    _writer = writer;
    _thread_serial_num = thread_serial_num;
    _frame_num = -1;  // default - empty stack
  }
  void set_frame_number(int n) { _frame_num = n; }
  void do_oop(oop* obj_p);
  void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
void JNILocalsDumper::do_oop(oop* obj_p) {
  oop o = *obj_p;
  if (o != NULL && o != JNIHandles::deleted_handle()) {
    writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL);
    writer()->write_objectID(o);
    writer()->write_u4(_thread_serial_num);
    writer()->write_u4((u4)_frame_num);
  }
}
class JNIGlobalsDumper : public OopClosure {
 private:
  DumpWriter* _writer;
  DumpWriter* writer() const                { return _writer; }
 public:
  JNIGlobalsDumper(DumpWriter* writer) {
    _writer = writer;
  }
  void do_oop(oop* obj_p);
  void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
void JNIGlobalsDumper::do_oop(oop* obj_p) {
  oop o = *obj_p;
  if (o == NULL || o == JNIHandles::deleted_handle()) return;
  if (o->is_instance() || o->is_objArray() || o->is_typeArray()) {
    writer()->write_u1(HPROF_GC_ROOT_JNI_GLOBAL);
    writer()->write_objectID(o);
    writer()->write_objectID((oopDesc*)obj_p);      // global ref ID
  }
};
class MonitorUsedDumper : public OopClosure {
 private:
  DumpWriter* _writer;
  DumpWriter* writer() const                { return _writer; }
 public:
  MonitorUsedDumper(DumpWriter* writer) {
    _writer = writer;
  }
  void do_oop(oop* obj_p) {
    writer()->write_u1(HPROF_GC_ROOT_MONITOR_USED);
    writer()->write_objectID(*obj_p);
  }
  void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
class StickyClassDumper : public KlassClosure {
 private:
  DumpWriter* _writer;
  DumpWriter* writer() const                { return _writer; }
 public:
  StickyClassDumper(DumpWriter* writer) {
    _writer = writer;
  }
  void do_klass(Klass* k) {
    if (k->oop_is_instance()) {
      InstanceKlass* ik = InstanceKlass::cast(k);
        writer()->write_u1(HPROF_GC_ROOT_STICKY_CLASS);
        writer()->write_classID(ik);
      }
    }
};
class VM_HeapDumper;
class HeapObjectDumper : public ObjectClosure {
 private:
  VM_HeapDumper* _dumper;
  DumpWriter* _writer;
  VM_HeapDumper* dumper()               { return _dumper; }
  DumpWriter* writer()                  { return _writer; }
  void mark_end_of_record();
 public:
  HeapObjectDumper(VM_HeapDumper* dumper, DumpWriter* writer) {
    _dumper = dumper;
    _writer = writer;
  }
  void do_object(oop o);
};
void HeapObjectDumper::do_object(oop o) {
  if (o == JNIHandles::deleted_handle()) return;
  if (o->klass() == SystemDictionary::Class_klass()) {
    if (!java_lang_Class::is_primitive(o)) {
      return;
    }
  }
  if (o->is_instance()) {
    DumperSupport::dump_instance(writer(), o);
    mark_end_of_record();
  } else if (o->is_objArray()) {
    DumperSupport::dump_object_array(writer(), objArrayOop(o));
    mark_end_of_record();
  } else if (o->is_typeArray()) {
    DumperSupport::dump_prim_array(writer(), typeArrayOop(o));
    mark_end_of_record();
  }
}
class VM_HeapDumper : public VM_GC_Operation {
 private:
  static VM_HeapDumper* _global_dumper;
  static DumpWriter*    _global_writer;
  DumpWriter*           _local_writer;
  JavaThread*           _oome_thread;
  Method*               _oome_constructor;
  bool _gc_before_heap_dump;
  GrowableArray<Klass*>* _klass_map;
  ThreadStackTrace** _stack_traces;
  int _num_threads;
  static VM_HeapDumper* dumper()         {  assert(_global_dumper != NULL, "Error"); return _global_dumper; }
  static DumpWriter* writer()            {  assert(_global_writer != NULL, "Error"); return _global_writer; }
  void set_global_dumper() {
    assert(_global_dumper == NULL, "Error");
    _global_dumper = this;
  }
  void set_global_writer() {
    assert(_global_writer == NULL, "Error");
    _global_writer = _local_writer;
  }
  void clear_global_dumper() { _global_dumper = NULL; }
  void clear_global_writer() { _global_writer = NULL; }
  bool skip_operation() const;
  static void do_load_class(Klass* k);
  static void do_class_dump(Klass* k);
  static void do_basic_type_array_class_dump(Klass* k);
  int do_thread(JavaThread* thread, u4 thread_serial_num);
  void do_threads();
  void add_class_serial_number(Klass* k, int serial_num) {
    _klass_map->at_put_grow(serial_num, k);
  }
  void dump_stack_traces();
 public:
  VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) :
    VM_GC_Operation(0 /* total collections,      dummy, ignored */,
                    GCCause::_heap_dump /* GC Cause */,
                    0 /* total full collections, dummy, ignored */,
                    gc_before_heap_dump) {
    _local_writer = writer;
    _gc_before_heap_dump = gc_before_heap_dump;
    _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
    _stack_traces = NULL;
    _num_threads = 0;
    if (oome) {
      assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread");
      InstanceKlass* oome_ik = InstanceKlass::cast(SystemDictionary::OutOfMemoryError_klass());
      _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(),
                                                          vmSymbols::void_method_signature());
      _oome_thread = JavaThread::current();
    } else {
      _oome_thread = NULL;
      _oome_constructor = NULL;
    }
  }
  ~VM_HeapDumper() {
    if (_stack_traces != NULL) {
      for (int i=0; i < _num_threads; i++) {
        delete _stack_traces[i];
      }
      FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces, mtInternal);
    }
    delete _klass_map;
  }
  VMOp_Type type() const { return VMOp_HeapDumper; }
  void check_segment_length();
  void doit();
};
VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL;
DumpWriter*    VM_HeapDumper::_global_writer = NULL;
bool VM_HeapDumper::skip_operation() const {
  return false;
}
void DumperSupport::write_dump_header(DumpWriter* writer) {
  if (writer->is_open()) {
    writer->write_u1(HPROF_HEAP_DUMP_SEGMENT);
    writer->write_u4(0); // current ticks
    writer->set_dump_start(writer->current_offset());
    writer->write_u4(0);
  }
}
void DumperSupport::write_current_dump_record_length(DumpWriter* writer) {
  if (writer->is_open()) {
    julong dump_end = writer->bytes_written() + writer->bytes_unwritten();
    julong dump_len = writer->current_record_length();
    if (dump_len > max_juint) {
      warning("record is too large");
    }
    assert(writer->dump_start() >= 0, "no dump start recorded");
    writer->seek_to_offset(writer->dump_start());
    writer->write_u4((u4)dump_len);
    writer->adjust_bytes_written(-((jlong) sizeof(u4)));
    writer->seek_to_offset(dump_end);
    writer->set_dump_start((jlong)-1);
  }
}
void VM_HeapDumper::check_segment_length() {
  if (writer()->is_open()) {
    julong dump_len = writer()->current_record_length();
    if (dump_len > 2UL*G) {
      DumperSupport::write_current_dump_record_length(writer());
      DumperSupport::write_dump_header(writer());
    }
  }
}
void DumperSupport::end_of_dump(DumpWriter* writer) {
  if (writer->is_open()) {
    write_current_dump_record_length(writer);
    writer->write_u1(HPROF_HEAP_DUMP_END);
    writer->write_u4(0);
    writer->write_u4(0);
  }
}
void HeapObjectDumper::mark_end_of_record() {
  dumper()->check_segment_length();
}
void VM_HeapDumper::do_load_class(Klass* k) {
  static u4 class_serial_num = 0;
  u4 remaining = 2*oopSize + 2*sizeof(u4);
  do {
    DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
    writer()->write_u4(++class_serial_num);
    Klass* klass = k;
    writer()->write_classID(klass);
    dumper()->add_class_serial_number(klass, class_serial_num);
    writer()->write_u4(STACK_TRACE_ID);
    Symbol* name = klass->name();
    writer()->write_symbolID(name);
    k = klass->array_klass_or_null();
  } while (k != NULL);
}
void VM_HeapDumper::do_class_dump(Klass* k) {
  if (k->oop_is_instance()) {
    DumperSupport::dump_class_and_array_classes(writer(), k);
  }
}
void VM_HeapDumper::do_basic_type_array_class_dump(Klass* k) {
  DumperSupport::dump_basic_type_array_class(writer(), k);
}
int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
  JNILocalsDumper blk(writer(), thread_serial_num);
  oop threadObj = java_thread->threadObj();
  assert(threadObj != NULL, "sanity check");
  int stack_depth = 0;
  if (java_thread->has_last_Java_frame()) {
    Thread* current_thread = Thread::current();
    ResourceMark rm(current_thread);
    HandleMark hm(current_thread);
    RegisterMap reg_map(java_thread);
    frame f = java_thread->last_frame();
    vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread);
    frame* last_entry_frame = NULL;
    int extra_frames = 0;
    if (java_thread == _oome_thread && _oome_constructor != NULL) {
      extra_frames++;
    }
    while (vf != NULL) {
      blk.set_frame_number(stack_depth);
      if (vf->is_java_frame()) {
        javaVFrame *jvf = javaVFrame::cast(vf);
        if (!(jvf->method()->is_native())) {
          StackValueCollection* locals = jvf->locals();
          for (int slot=0; slot<locals->size(); slot++) {
            if (locals->at(slot)->type() == T_OBJECT) {
              oop o = locals->obj_at(slot)();
              if (o != NULL) {
                writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME);
                writer()->write_objectID(o);
                writer()->write_u4(thread_serial_num);
                writer()->write_u4((u4) (stack_depth + extra_frames));
              }
            }
          }
        } else {
          if (stack_depth == 0) {
            java_thread->active_handles()->oops_do(&blk);
          } else {
            if (last_entry_frame != NULL) {
              assert(last_entry_frame->is_entry_frame(), "checking");
              last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk);
            }
          }
        }
        stack_depth++;
        last_entry_frame = NULL;
      } else {
        frame* fr = vf->frame_pointer();
        assert(fr != NULL, "sanity check");
        if (fr->is_entry_frame()) {
          last_entry_frame = fr;
        }
      }
      vf = vf->sender();
    }
  } else {
    java_thread->active_handles()->oops_do(&blk);
  }
  return stack_depth;
}
void VM_HeapDumper::do_threads() {
  for (int i=0; i < _num_threads; i++) {
    JavaThread* thread = _stack_traces[i]->thread();
    oop threadObj = thread->threadObj();
    u4 thread_serial_num = i+1;
    u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID;
    writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ);
    writer()->write_objectID(threadObj);
    writer()->write_u4(thread_serial_num);  // thread number
    writer()->write_u4(stack_serial_num);   // stack trace serial number
    int num_frames = do_thread(thread, thread_serial_num);
    assert(num_frames == _stack_traces[i]->get_stack_depth(),
           "total number of Java frames not matched");
  }
}
void VM_HeapDumper::doit() {
  HandleMark hm;
  CollectedHeap* ch = Universe::heap();
  ch->ensure_parsability(false); // must happen, even if collection does
  if (_gc_before_heap_dump) {
    if (GC_locker::is_active()) {
      warning("GC locker is held; pre-heapdump GC was skipped");
    } else {
      ch->collect_as_vm_thread(GCCause::_heap_dump);
    }
  }
  set_global_dumper();
  set_global_writer();
  size_t used = ch->used();
  const char* header = "JAVA PROFILE 1.0.2";
  writer()->write_raw((void*)header, (int)strlen(header));
  writer()->write_u1(0); // terminator
  writer()->write_u4(oopSize);
  writer()->write_u8(os::javaTimeMillis());
  SymbolTableDumper sym_dumper(writer());
  SymbolTable::symbols_do(&sym_dumper);
  ClassLoaderDataGraph::classes_do(&do_load_class);
  Universe::basic_type_classes_do(&do_load_class);
  dump_stack_traces();
  DumperSupport::write_dump_header(writer());
  ClassLoaderDataGraph::classes_do(&do_class_dump);
  Universe::basic_type_classes_do(&do_basic_type_array_class_dump);
  check_segment_length();
  HeapObjectDumper obj_dumper(this, writer());
  Universe::heap()->safe_object_iterate(&obj_dumper);
  do_threads();
  check_segment_length();
  MonitorUsedDumper mon_dumper(writer());
  ObjectSynchronizer::oops_do(&mon_dumper);
  check_segment_length();
  JNIGlobalsDumper jni_dumper(writer());
  JNIHandles::oops_do(&jni_dumper);
  Universe::oops_do(&jni_dumper);  // technically not jni roots, but global roots
  check_segment_length();
  StickyClassDumper class_dumper(writer());
  SystemDictionary::always_strong_classes_do(&class_dumper);
  DumperSupport::end_of_dump(writer());
  clear_global_dumper();
  clear_global_writer();
}
void VM_HeapDumper::dump_stack_traces() {
  DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
  writer()->write_u4((u4) STACK_TRACE_ID);
  writer()->write_u4(0);                    // thread number
  writer()->write_u4(0);                    // frame count
  _stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads(), mtInternal);
  int frame_serial_num = 0;
  for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
    oop threadObj = thread->threadObj();
    if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
      ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false);
      stack_trace->dump_stack_at_safepoint(-1);
      _stack_traces[_num_threads++] = stack_trace;
      int depth = stack_trace->get_stack_depth();
      int thread_frame_start = frame_serial_num;
      int extra_frames = 0;
      if (thread == _oome_thread && _oome_constructor != NULL) {
        int oome_serial_num = _klass_map->find(_oome_constructor->method_holder());
        assert(oome_serial_num > 0, "OutOfMemoryError class not found");
        DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num,
                                        _oome_constructor, 0);
        extra_frames++;
      }
      for (int j=0; j < depth; j++) {
        StackFrameInfo* frame = stack_trace->stack_frame_at(j);
        Method* m = frame->method();
        int class_serial_num = _klass_map->find(m->method_holder());
        assert(class_serial_num > 0, "class not found");
        DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci());
      }
      depth += extra_frames;
      DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize);
      int stack_serial_num = _num_threads + STACK_TRACE_ID;
      writer()->write_u4(stack_serial_num);      // stack trace serial number
      writer()->write_u4((u4) _num_threads);     // thread serial number
      writer()->write_u4(depth);                 // frame count
      for (int j=1; j <= depth; j++) {
        writer()->write_id(thread_frame_start + j);
      }
    }
  }
}
PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL
int HeapDumper::dump(const char* path) {
  assert(path != NULL && strlen(path) > 0, "path missing");
  if (print_to_tty()) {
    tty->print_cr("Dumping heap to %s ...", path);
    timer()->start();
  }
  DumpWriter writer(path);
  if (!writer.is_open()) {
    set_error(writer.error());
    if (print_to_tty()) {
      tty->print_cr("Unable to create %s: %s", path,
        (error() != NULL) ? error() : "reason unknown");
    }
    return -1;
  }
  VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome);
  if (Thread::current()->is_VM_thread()) {
    assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
    dumper.doit();
  } else {
    VMThread::execute(&dumper);
  }
  writer.close();
  set_error(writer.error());
  if (print_to_tty()) {
    timer()->stop();
    if (error() == NULL) {
      tty->print_cr("Heap dump file created [" JULONG_FORMAT " bytes in %3.3f secs]",
                    writer.bytes_written(), timer()->seconds());
    } else {
      tty->print_cr("Dump file is incomplete: %s", writer.error());
    }
  }
  return (writer.error() == NULL) ? 0 : -1;
}
HeapDumper::~HeapDumper() {
  if (timer()->is_active()) {
    timer()->stop();
  }
  set_error(NULL);
}
char* HeapDumper::error_as_C_string() const {
  if (error() != NULL) {
    char* str = NEW_RESOURCE_ARRAY(char, strlen(error())+1);
    strcpy(str, error());
    return str;
  } else {
    return NULL;
  }
}
void HeapDumper::set_error(char* error) {
  if (_error != NULL) {
    os::free(_error);
  }
  if (error == NULL) {
    _error = NULL;
  } else {
    _error = os::strdup(error);
    assert(_error != NULL, "allocation failure");
  }
}
void HeapDumper::dump_heap_from_oome() {
  HeapDumper::dump_heap(true);
}
void HeapDumper::dump_heap() {
  HeapDumper::dump_heap(false);
}
void HeapDumper::dump_heap(bool oome) {
  static char base_path[JVM_MAXPATHLEN] = {'\0'};
  static uint dump_file_seq = 0;
  char* my_path;
  const int max_digit_chars = 20;
  const char* dump_file_name = "java_pid";
  const char* dump_file_ext  = ".hprof";
  if (dump_file_seq == 0) { // first time in, we initialize base_path
    const size_t total_length =
                      (HeapDumpPath == NULL ? 0 : strlen(HeapDumpPath)) +
                      strlen(os::file_separator()) + max_digit_chars +
                      strlen(dump_file_name) + strlen(dump_file_ext) + 1;
    if (total_length > sizeof(base_path)) {
      warning("Cannot create heap dump file.  HeapDumpPath is too long.");
      return;
    }
    bool use_default_filename = true;
    if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
    } else {
      strncpy(base_path, HeapDumpPath, sizeof(base_path));
      DIR* dir = os::opendir(base_path);
      if (dir == NULL) {
        use_default_filename = false;
      } else {
        os::closedir(dir);
        size_t fs_len = strlen(os::file_separator());
        if (strlen(base_path) >= fs_len) {
          char* end = base_path;
          end += (strlen(base_path) - fs_len);
          if (strcmp(end, os::file_separator()) != 0) {
            strcat(base_path, os::file_separator());
          }
        }
      }
    }
    if (use_default_filename) {
      const size_t dlen = strlen(base_path);  // if heap dump dir specified
      jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s",
                   dump_file_name, os::current_process_id(), dump_file_ext);
    }
    const size_t len = strlen(base_path) + 1;
    my_path = (char*)os::malloc(len, mtInternal);
    if (my_path == NULL) {
      warning("Cannot create heap dump file.  Out of system memory.");
      return;
    }
    strncpy(my_path, base_path, len);
  } else {
    const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0
    my_path = (char*)os::malloc(len, mtInternal);
    if (my_path == NULL) {
      warning("Cannot create heap dump file.  Out of system memory.");
      return;
    }
    jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq);
  }
  dump_file_seq++;   // increment seq number for next time we dump
  HeapDumper dumper(false /* no GC before heap dump */,
                    true  /* send to tty */,
                    oome  /* pass along out-of-memory-error flag */);
  dumper.dump(my_path);
  os::free(my_path);
}
C:\hotspot-69087d08d473\src\share\vm/services/heapDumper.hpp
#ifndef SHARE_VM_SERVICES_HEAPDUMPER_HPP
#define SHARE_VM_SERVICES_HEAPDUMPER_HPP
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
#include "runtime/os.hpp"
class HeapDumper : public StackObj {
 private:
  char* _error;
  bool _print_to_tty;
  bool _gc_before_heap_dump;
  bool _oome;
  elapsedTimer _t;
  HeapDumper(bool gc_before_heap_dump, bool print_to_tty, bool oome) :
    _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty), _oome(oome) { }
  char* error() const                   { return _error; }
  void set_error(char* error);
  bool print_to_tty() const             { return _print_to_tty; }
  elapsedTimer* timer()                 { return &_t; }
  static void dump_heap(bool oome);
 public:
  HeapDumper(bool gc_before_heap_dump) :
    _gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false), _oome(false) { }
  ~HeapDumper();
  int dump(const char* path);
  char* error_as_C_string() const;
  static void dump_heap()    NOT_SERVICES_RETURN;
  static void dump_heap_from_oome()    NOT_SERVICES_RETURN;
};
#endif // SHARE_VM_SERVICES_HEAPDUMPER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/jmm.h
#ifndef _JAVA_JMM_H_
#define _JAVA_JMM_H_
#include "jni.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
  JMM_VERSION_1   = 0x20010000,
  JMM_VERSION_1_0 = 0x20010000,
  JMM_VERSION_1_1 = 0x20010100, // JDK 6
  JMM_VERSION_1_2 = 0x20010200, // JDK 7
  JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
  JMM_VERSION_1_2_2 = 0x20010202,
  JMM_VERSION     = 0x20010203
};
typedef struct {
  unsigned int isLowMemoryDetectionSupported : 1;
  unsigned int isCompilationTimeMonitoringSupported : 1;
  unsigned int isThreadContentionMonitoringSupported : 1;
  unsigned int isCurrentThreadCpuTimeSupported : 1;
  unsigned int isOtherThreadCpuTimeSupported : 1;
  unsigned int isBootClassPathSupported : 1;
  unsigned int isObjectMonitorUsageSupported : 1;
  unsigned int isSynchronizerUsageSupported : 1;
  unsigned int isThreadAllocatedMemorySupported : 1;
  unsigned int isRemoteDiagnosticCommandsSupported : 1;
  unsigned int : 22;
} jmmOptionalSupport;
typedef enum {
  JMM_CLASS_LOADED_COUNT             = 1,    /* Total number of loaded classes */
  JMM_CLASS_UNLOADED_COUNT           = 2,    /* Total number of unloaded classes */
  JMM_THREAD_TOTAL_COUNT             = 3,    /* Total number of threads that have been started */
  JMM_THREAD_LIVE_COUNT              = 4,    /* Current number of live threads */
  JMM_THREAD_PEAK_COUNT              = 5,    /* Peak number of live threads */
  JMM_THREAD_DAEMON_COUNT            = 6,    /* Current number of daemon threads */
  JMM_JVM_INIT_DONE_TIME_MS          = 7,    /* Time when the JVM finished initialization */
  JMM_COMPILE_TOTAL_TIME_MS          = 8,    /* Total accumulated time spent in compilation */
  JMM_GC_TIME_MS                     = 9,    /* Total accumulated time spent in collection */
  JMM_GC_COUNT                       = 10,   /* Total number of collections */
  JMM_JVM_UPTIME_MS                  = 11,   /* The JVM uptime in milliseconds */
  JMM_INTERNAL_ATTRIBUTE_INDEX       = 100,
  JMM_CLASS_LOADED_BYTES             = 101,  /* Number of bytes loaded instance classes */
  JMM_CLASS_UNLOADED_BYTES           = 102,  /* Number of bytes unloaded instance classes */
  JMM_TOTAL_CLASSLOAD_TIME_MS        = 103,  /* Accumulated VM class loader time (TraceClassLoadingTime) */
  JMM_VM_GLOBAL_COUNT                = 104,  /* Number of VM internal flags */
  JMM_SAFEPOINT_COUNT                = 105,  /* Total number of safepoints */
  JMM_TOTAL_SAFEPOINTSYNC_TIME_MS    = 106,  /* Accumulated time spent getting to safepoints */
  JMM_TOTAL_STOPPED_TIME_MS          = 107,  /* Accumulated time spent at safepoints */
  JMM_TOTAL_APP_TIME_MS              = 108,  /* Accumulated time spent in Java application */
  JMM_VM_THREAD_COUNT                = 109,  /* Current number of VM internal threads */
  JMM_CLASS_INIT_TOTAL_COUNT         = 110,  /* Number of classes for which initializers were run */
  JMM_CLASS_INIT_TOTAL_TIME_MS       = 111,  /* Accumulated time spent in class initializers */
  JMM_METHOD_DATA_SIZE_BYTES         = 112,  /* Size of method data in memory */
  JMM_CLASS_VERIFY_TOTAL_TIME_MS     = 113,  /* Accumulated time spent in class verifier */
  JMM_SHARED_CLASS_LOADED_COUNT      = 114,  /* Number of shared classes loaded */
  JMM_SHARED_CLASS_UNLOADED_COUNT    = 115,  /* Number of shared classes unloaded */
  JMM_SHARED_CLASS_LOADED_BYTES      = 116,  /* Number of bytes loaded shared classes */
  JMM_SHARED_CLASS_UNLOADED_BYTES    = 117,  /* Number of bytes unloaded shared classes */
  JMM_OS_ATTRIBUTE_INDEX             = 200,
  JMM_OS_PROCESS_ID                  = 201,  /* Process id of the JVM */
  JMM_OS_MEM_TOTAL_PHYSICAL_BYTES    = 202,  /* Physical memory size */
  JMM_GC_EXT_ATTRIBUTE_INFO_SIZE     = 401   /* the size of the GC specific attributes for a given GC memory manager */
} jmmLongAttribute;
typedef enum {
  JMM_VERBOSE_GC                     = 21,
  JMM_VERBOSE_CLASS                  = 22,
  JMM_THREAD_CONTENTION_MONITORING   = 23,
  JMM_THREAD_CPU_TIME                = 24,
  JMM_THREAD_ALLOCATED_MEMORY        = 25
} jmmBoolAttribute;
enum {
  JMM_THREAD_STATE_FLAG_SUSPENDED = 0x00100000,
  JMM_THREAD_STATE_FLAG_NATIVE    = 0x00400000
};
#define JMM_THREAD_STATE_FLAG_MASK  0xFFF00000
typedef enum {
  JMM_STAT_PEAK_THREAD_COUNT         = 801,
  JMM_STAT_THREAD_CONTENTION_COUNT   = 802,
  JMM_STAT_THREAD_CONTENTION_TIME    = 803,
  JMM_STAT_THREAD_CONTENTION_STAT    = 804,
  JMM_STAT_PEAK_POOL_USAGE           = 805,
  JMM_STAT_GC_STAT                   = 806
} jmmStatisticType;
typedef enum {
  JMM_USAGE_THRESHOLD_HIGH            = 901,
  JMM_USAGE_THRESHOLD_LOW             = 902,
  JMM_COLLECTION_USAGE_THRESHOLD_HIGH = 903,
  JMM_COLLECTION_USAGE_THRESHOLD_LOW  = 904
} jmmThresholdType;
typedef enum {
  JMM_VMGLOBAL_TYPE_UNKNOWN  = 0,
  JMM_VMGLOBAL_TYPE_JBOOLEAN = 1,
  JMM_VMGLOBAL_TYPE_JSTRING  = 2,
  JMM_VMGLOBAL_TYPE_JLONG    = 3,
  JMM_VMGLOBAL_TYPE_JDOUBLE  = 4
} jmmVMGlobalType;
typedef enum {
  JMM_VMGLOBAL_ORIGIN_DEFAULT      = 1,   /* Default value */
  JMM_VMGLOBAL_ORIGIN_COMMAND_LINE = 2,   /* Set at command line (or JNI invocation) */
  JMM_VMGLOBAL_ORIGIN_MANAGEMENT   = 3,   /* Set via management interface */
  JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR  = 4,   /* Set via environment variables */
  JMM_VMGLOBAL_ORIGIN_CONFIG_FILE  = 5,   /* Set via config file (such as .hotspotrc) */
  JMM_VMGLOBAL_ORIGIN_ERGONOMIC    = 6,   /* Set via ergonomic */
  JMM_VMGLOBAL_ORIGIN_OTHER        = 99   /* Set via some other mechanism */
} jmmVMGlobalOrigin;
typedef struct {
  jstring           name;
  jvalue            value;
  jmmVMGlobalType   type;           /* Data type */
  jmmVMGlobalOrigin origin;         /* Default or non-default value */
  unsigned int      writeable : 1;  /* dynamically writeable */
  unsigned int      external  : 1;  /* external supported interface */
  unsigned int      reserved  : 30;
  void *reserved1;
  void *reserved2;
} jmmVMGlobal;
typedef struct {
  const char*  name;
  char         type;
  const char*  description;
} jmmExtAttributeInfo;
typedef struct {
  jlong        gc_index;                       /* Index of the collections */
  jlong        start_time;                     /* Start time of the GC */
  jlong        end_time;                       /* End time of the GC */
  jobjectArray usage_before_gc;                /* Memory usage array before GC */
  jobjectArray usage_after_gc;                 /* Memory usage array after GC */
  jint         gc_ext_attribute_values_size;   /* set by the caller of GetGCStat */
  jvalue*      gc_ext_attribute_values;        /* Array of jvalue for GC extension attributes */
  jint         num_gc_ext_attributes;          /* number of GC extension attribute values s are filled */
} jmmGCStat;
typedef struct {
  const char* name;                /* Name of the diagnostic command */
  const char* description;         /* Short description */
  const char* impact;              /* Impact on the JVM */
  const char* permission_class;    /* Class name of the required permission if any */
  const char* permission_name;     /* Permission name of the required permission if any */
  const char* permission_action;   /* Action name of the required permission if any*/
  int         num_arguments;       /* Number of supported options or arguments */
  jboolean    enabled;             /* True if the diagnostic command can be invoked, false otherwise */
} dcmdInfo;
typedef struct {
  const char* name;                /* Option/Argument name*/
  const char* description;         /* Short description */
  const char* type;                /* Type: STRING, BOOLEAN, etc. */
  const char* default_string;      /* Default value in a parsable string */
  jboolean    mandatory;           /* True if the option/argument is mandatory */
  jboolean    option;              /* True if it is an option, false if it is an argument */
  jboolean    multiple;            /* True if the option can be specified several time */
  int         position;            /* Expected position for this argument (this field is */
} dcmdArgInfo;
typedef struct jmmInterface_1_ {
  void*        reserved1;
  jlong        (JNICALL *GetOneThreadAllocatedMemory)
                                                 (JNIEnv *env,
                                                  jlong thread_id);
  jint         (JNICALL *GetVersion)             (JNIEnv *env);
  jint         (JNICALL *GetOptionalSupport)     (JNIEnv *env,
                                                  jmmOptionalSupport* support_ptr);
  jobject      (JNICALL *GetInputArguments)      (JNIEnv *env);
  jint         (JNICALL *GetThreadInfo)          (JNIEnv *env,
                                                  jlongArray ids,
                                                  jint maxDepth,
                                                  jobjectArray infoArray);
  jobjectArray (JNICALL *GetInputArgumentArray)  (JNIEnv *env);
  jobjectArray (JNICALL *GetMemoryPools)         (JNIEnv* env, jobject mgr);
  jobjectArray (JNICALL *GetMemoryManagers)      (JNIEnv* env, jobject pool);
  jobject      (JNICALL *GetMemoryPoolUsage)     (JNIEnv* env, jobject pool);
  jobject      (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv* env, jobject pool);
  void         (JNICALL *GetThreadAllocatedMemory)
                                                 (JNIEnv *env,
                                                  jlongArray ids,
                                                  jlongArray sizeArray);
  jobject      (JNICALL *GetMemoryUsage)         (JNIEnv* env, jboolean heap);
  jlong        (JNICALL *GetLongAttribute)       (JNIEnv *env, jobject obj, jmmLongAttribute att);
  jboolean     (JNICALL *GetBoolAttribute)       (JNIEnv *env, jmmBoolAttribute att);
  jboolean     (JNICALL *SetBoolAttribute)       (JNIEnv *env, jmmBoolAttribute att, jboolean flag);
  jint         (JNICALL *GetLongAttributes)      (JNIEnv *env,
                                                  jobject obj,
                                                  jmmLongAttribute* atts,
                                                  jint count,
                                                  jlong* result);
  jobjectArray (JNICALL *FindCircularBlockedThreads) (JNIEnv *env);
  jlong        (JNICALL *GetThreadCpuTime)       (JNIEnv *env, jlong thread_id);
  jobjectArray (JNICALL *GetVMGlobalNames)       (JNIEnv *env);
  jint         (JNICALL *GetVMGlobals)           (JNIEnv *env,
                                                  jobjectArray names,
                                                  jmmVMGlobal *globals,
                                                  jint count);
  jint         (JNICALL *GetInternalThreadTimes) (JNIEnv *env,
                                                  jobjectArray names,
                                                  jlongArray times);
  jboolean     (JNICALL *ResetStatistic)         (JNIEnv *env,
                                                  jvalue obj,
                                                  jmmStatisticType type);
  void         (JNICALL *SetPoolSensor)          (JNIEnv *env,
                                                  jobject pool,
                                                  jmmThresholdType type,
                                                  jobject sensor);
  jlong        (JNICALL *SetPoolThreshold)       (JNIEnv *env,
                                                  jobject pool,
                                                  jmmThresholdType type,
                                                  jlong threshold);
  jobject      (JNICALL *GetPoolCollectionUsage) (JNIEnv* env, jobject pool);
  jint         (JNICALL *GetGCExtAttributeInfo)  (JNIEnv *env,
                                                  jobject mgr,
                                                  jmmExtAttributeInfo *ext_info,
                                                  jint count);
  void         (JNICALL *GetLastGCStat)          (JNIEnv *env,
                                                  jobject mgr,
                                                  jmmGCStat *gc_stat);
  jlong        (JNICALL *GetThreadCpuTimeWithKind)
                                                 (JNIEnv *env,
                                                  jlong thread_id,
                                                  jboolean user_sys_cpu_time);
  void         (JNICALL *GetThreadCpuTimesWithKind)
                                                 (JNIEnv *env,
                                                  jlongArray ids,
                                                  jlongArray timeArray,
                                                  jboolean user_sys_cpu_time);
  jint         (JNICALL *DumpHeap0)              (JNIEnv *env,
                                                  jstring outputfile,
                                                  jboolean live);
  jobjectArray (JNICALL *FindDeadlocks)          (JNIEnv *env,
                                                  jboolean object_monitors_only);
  void         (JNICALL *SetVMGlobal)            (JNIEnv *env,
                                                  jstring flag_name,
                                                  jvalue  new_value);
  jobjectArray (JNICALL *DumpThreadsMaxDepth)    (JNIEnv *env,
                                                  jlongArray ids,
                                                  jboolean lockedMonitors,
                                                  jboolean lockedSynchronizers,
                                                  jint maxDepth);
  jobjectArray (JNICALL *DumpThreads)            (JNIEnv *env,
                                                  jlongArray ids,
                                                  jboolean lockedMonitors,
                                                  jboolean lockedSynchronizers);
  void         (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
                                                    jobject mgr,
                                                    jboolean enabled);
  jobjectArray (JNICALL *GetDiagnosticCommands)  (JNIEnv *env);
  void         (JNICALL *GetDiagnosticCommandInfo)
                                                 (JNIEnv *env,
                                                  jobjectArray cmds,
                                                  dcmdInfo *infoArray);
  void         (JNICALL *GetDiagnosticCommandArgumentsInfo)
                                                 (JNIEnv *env,
                                                  jstring commandName,
                                                  dcmdArgInfo *infoArray);
  jstring      (JNICALL *ExecuteDiagnosticCommand)
                                                 (JNIEnv *env,
                                                  jstring command);
  void         (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
                                                 (JNIEnv *env,
                                                  jboolean enabled);
} JmmInterface;
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* !_JAVA_JMM_H_ */
C:\hotspot-69087d08d473\src\share\vm/services/lowMemoryDetector.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/lowMemoryDetector.hpp"
#include "services/management.hpp"
volatile bool LowMemoryDetector::_enabled_for_collected_pools = false;
volatile jint LowMemoryDetector::_disabled_count = 0;
bool LowMemoryDetector::has_pending_requests() {
  assert(Service_lock->owned_by_self(), "Must own Service_lock");
  bool has_requests = false;
  int num_memory_pools = MemoryService::num_memory_pools();
  for (int i = 0; i < num_memory_pools; i++) {
    MemoryPool* pool = MemoryService::get_memory_pool(i);
    SensorInfo* sensor = pool->usage_sensor();
    if (sensor != NULL) {
      has_requests = has_requests || sensor->has_pending_requests();
    }
    SensorInfo* gc_sensor = pool->gc_usage_sensor();
    if (gc_sensor != NULL) {
      has_requests = has_requests || gc_sensor->has_pending_requests();
    }
  }
  return has_requests;
}
void LowMemoryDetector::process_sensor_changes(TRAPS) {
  ResourceMark rm(THREAD);
  HandleMark hm(THREAD);
  int num_memory_pools = MemoryService::num_memory_pools();
  for (int i = 0; i < num_memory_pools; i++) {
    MemoryPool* pool = MemoryService::get_memory_pool(i);
    SensorInfo* sensor = pool->usage_sensor();
    SensorInfo* gc_sensor = pool->gc_usage_sensor();
    if (sensor != NULL && sensor->has_pending_requests()) {
      sensor->process_pending_requests(CHECK);
    }
    if (gc_sensor != NULL && gc_sensor->has_pending_requests()) {
      gc_sensor->process_pending_requests(CHECK);
    }
  }
}
void LowMemoryDetector::detect_low_memory() {
  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
  bool has_pending_requests = false;
  int num_memory_pools = MemoryService::num_memory_pools();
  for (int i = 0; i < num_memory_pools; i++) {
    MemoryPool* pool = MemoryService::get_memory_pool(i);
    SensorInfo* sensor = pool->usage_sensor();
    if (sensor != NULL &&
        pool->usage_threshold()->is_high_threshold_supported() &&
        pool->usage_threshold()->high_threshold() != 0) {
      MemoryUsage usage = pool->get_memory_usage();
      sensor->set_gauge_sensor_level(usage,
                                     pool->usage_threshold());
      has_pending_requests = has_pending_requests || sensor->has_pending_requests();
    }
  }
  if (has_pending_requests) {
    Service_lock->notify_all();
  }
}
void LowMemoryDetector::detect_low_memory(MemoryPool* pool) {
  SensorInfo* sensor = pool->usage_sensor();
  if (sensor == NULL ||
      !pool->usage_threshold()->is_high_threshold_supported() ||
      pool->usage_threshold()->high_threshold() == 0) {
    return;
  }
  {
    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
    MemoryUsage usage = pool->get_memory_usage();
    sensor->set_gauge_sensor_level(usage,
                                   pool->usage_threshold());
    if (sensor->has_pending_requests()) {
      Service_lock->notify_all();
    }
  }
}
void LowMemoryDetector::detect_after_gc_memory(MemoryPool* pool) {
  SensorInfo* sensor = pool->gc_usage_sensor();
  if (sensor == NULL ||
      !pool->gc_usage_threshold()->is_high_threshold_supported() ||
      pool->gc_usage_threshold()->high_threshold() == 0) {
    return;
  }
  {
    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
    MemoryUsage usage = pool->get_last_collection_usage();
    sensor->set_counter_sensor_level(usage, pool->gc_usage_threshold());
    if (sensor->has_pending_requests()) {
      Service_lock->notify_all();
    }
  }
}
void LowMemoryDetector::recompute_enabled_for_collected_pools() {
  bool enabled = false;
  int num_memory_pools = MemoryService::num_memory_pools();
  for (int i=0; i<num_memory_pools; i++) {
    MemoryPool* pool = MemoryService::get_memory_pool(i);
    if (pool->is_collected_pool() && is_enabled(pool)) {
      enabled = true;
      break;
    }
  }
  _enabled_for_collected_pools = enabled;
}
SensorInfo::SensorInfo() {
  _sensor_obj = NULL;
  _sensor_on = false;
  _sensor_count = 0;
  _pending_trigger_count = 0;
  _pending_clear_count = 0;
}
void SensorInfo::set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold) {
  assert(high_low_threshold->is_high_threshold_supported(), "just checking");
  bool is_over_high = high_low_threshold->is_high_threshold_crossed(usage);
  bool is_below_low = high_low_threshold->is_low_threshold_crossed(usage);
  assert(!(is_over_high && is_below_low), "Can't be both true");
  if (is_over_high &&
        ((!_sensor_on && _pending_trigger_count == 0) ||
         _pending_clear_count > 0)) {
    _pending_trigger_count++;
    _usage = usage;
    if (_pending_clear_count > 0) {
      _pending_clear_count = 0;
    }
  } else if (is_below_low &&
               ((_sensor_on && _pending_clear_count == 0) ||
                (_pending_trigger_count > 0 && _pending_clear_count == 0))) {
    _pending_clear_count++;
  }
}
void SensorInfo::set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold) {
  assert(counter_threshold->is_high_threshold_supported(), "just checking");
  bool is_over_high = counter_threshold->is_high_threshold_crossed(usage);
  bool is_below_low = counter_threshold->is_low_threshold_crossed(usage);
  assert(!(is_over_high && is_below_low), "Can't be both true");
  if (is_over_high) {
    _pending_trigger_count++;
    _usage = usage;
    _pending_clear_count = 0;
  } else if (is_below_low && (_sensor_on || _pending_trigger_count > 0)) {
    _pending_clear_count++;
  }
}
void SensorInfo::oops_do(OopClosure* f) {
  f->do_oop((oop*) &_sensor_obj);
}
void SensorInfo::process_pending_requests(TRAPS) {
  if (!has_pending_requests()) {
    return;
  }
  int pending_count = pending_trigger_count();
  if (pending_clear_count() > 0) {
    clear(pending_count, CHECK);
  } else {
    trigger(pending_count, CHECK);
  }
}
void SensorInfo::trigger(int count, TRAPS) {
  assert(count <= _pending_trigger_count, "just checking");
  if (_sensor_obj != NULL) {
    Klass* k = Management::sun_management_Sensor_klass(CHECK);
    instanceKlassHandle sensorKlass (THREAD, k);
    Handle sensor_h(THREAD, _sensor_obj);
    Symbol* trigger_method_signature;
    JavaValue result(T_VOID);
    JavaCallArguments args(sensor_h);
    args.push_int((int) count);
    Handle usage_h = MemoryService::create_MemoryUsage_obj(_usage, THREAD);
    if (HAS_PENDING_EXCEPTION) {
       assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOME here");
       CLEAR_PENDING_EXCEPTION;
       trigger_method_signature = vmSymbols::int_void_signature();
    } else {
       trigger_method_signature = vmSymbols::trigger_method_signature();
       args.push_oop(usage_h);
    }
    JavaCalls::call_virtual(&result,
                            sensorKlass,
                            vmSymbols::trigger_name(),
                            trigger_method_signature,
                            &args,
                            THREAD);
    if (HAS_PENDING_EXCEPTION) {
       assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOME here");
       CLEAR_PENDING_EXCEPTION;
     }
  }
  {
    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
    _sensor_on = true;
    _sensor_count += count;
    _pending_trigger_count = _pending_trigger_count - count;
  }
}
void SensorInfo::clear(int count, TRAPS) {
  if (_sensor_obj != NULL) {
    Klass* k = Management::sun_management_Sensor_klass(CHECK);
    instanceKlassHandle sensorKlass (THREAD, k);
    Handle sensor(THREAD, _sensor_obj);
    JavaValue result(T_VOID);
    JavaCallArguments args(sensor);
    args.push_int((int) count);
    JavaCalls::call_virtual(&result,
                            sensorKlass,
                            vmSymbols::clear_name(),
                            vmSymbols::int_void_signature(),
                            &args,
                            CHECK);
  }
  {
    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
    _sensor_on = false;
    _pending_clear_count = 0;
    _pending_trigger_count = _pending_trigger_count - count;
  }
}
#ifndef PRODUCT
void SensorInfo::print() {
  tty->print_cr("%s count = " SIZE_FORMAT " pending_triggers = %d pending_clears = %d",
                (_sensor_on ? "on" : "off"),
                _sensor_count, _pending_trigger_count, _pending_clear_count);
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/services/lowMemoryDetector.hpp
#ifndef SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
#define SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
#include "memory/allocation.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
class OopClosure;
class MemoryPool;
class ThresholdSupport : public CHeapObj<mtInternal> {
 private:
  bool            _support_high_threshold;
  bool            _support_low_threshold;
  size_t          _high_threshold;
  size_t          _low_threshold;
 public:
  ThresholdSupport(bool support_high, bool support_low) {
    _support_high_threshold = support_high;
    _support_low_threshold = support_low;
    _high_threshold = 0;
    _low_threshold= 0;
  }
  size_t      high_threshold() const        { return _high_threshold; }
  size_t      low_threshold()  const        { return _low_threshold; }
  bool        is_high_threshold_supported() { return _support_high_threshold; }
  bool        is_low_threshold_supported()  { return _support_low_threshold; }
  bool        is_high_threshold_crossed(MemoryUsage usage) {
    if (_support_high_threshold && _high_threshold > 0) {
      return (usage.used() >= _high_threshold);
    }
    return false;
  }
  bool        is_low_threshold_crossed(MemoryUsage usage) {
    if (_support_low_threshold && _low_threshold > 0) {
      return (usage.used() < _low_threshold);
    }
    return false;
  }
  size_t      set_high_threshold(size_t new_threshold) {
    assert(_support_high_threshold, "can only be set if supported");
    assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold");
    size_t prev = _high_threshold;
    _high_threshold = new_threshold;
    return prev;
  }
  size_t      set_low_threshold(size_t new_threshold) {
    assert(_support_low_threshold, "can only be set if supported");
    assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold");
    size_t prev = _low_threshold;
    _low_threshold = new_threshold;
    return prev;
  }
};
class SensorInfo : public CHeapObj<mtInternal> {
private:
  instanceOop     _sensor_obj;
  bool            _sensor_on;
  size_t          _sensor_count;
  int             _pending_trigger_count;
  int             _pending_clear_count;
  MemoryUsage     _usage;
  void clear(int count, TRAPS);
  void trigger(int count, TRAPS);
public:
  SensorInfo();
  void set_sensor(instanceOop sensor) {
    assert(_sensor_obj == NULL, "Should be set only once");
    _sensor_obj = sensor;
  }
  bool has_pending_requests() {
    return (_pending_trigger_count > 0 || _pending_clear_count > 0);
  }
  int pending_trigger_count()      { return _pending_trigger_count; }
  int pending_clear_count()        { return _pending_clear_count; }
  void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold);
  void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold);
  void process_pending_requests(TRAPS);
  void oops_do(OopClosure* f);
#ifndef PRODUCT
  void print();
#endif // PRODUCT
};
class LowMemoryDetector : public AllStatic {
  friend class LowMemoryDetectorDisabler;
  friend class ServiceThread;
private:
  static volatile bool _enabled_for_collected_pools;
  static volatile jint _disabled_count;
  static void check_memory_usage();
  static bool has_pending_requests();
  static bool temporary_disabled() { return _disabled_count > 0; }
  static void disable() { Atomic::inc(&_disabled_count); }
  static void enable() { Atomic::dec(&_disabled_count); }
  static void process_sensor_changes(TRAPS);
public:
  static void detect_low_memory();
  static void detect_low_memory(MemoryPool* pool);
  static void detect_after_gc_memory(MemoryPool* pool);
  static bool is_enabled(MemoryPool* pool) {
    if (pool->usage_sensor() == NULL) {
      return false;
    } else {
      ThresholdSupport* threshold_support = pool->usage_threshold();
      return (threshold_support->is_high_threshold_supported() ?
               (threshold_support->high_threshold() > 0) : false);
    }
  }
  static inline bool is_enabled_for_collected_pools() {
    return !temporary_disabled() && _enabled_for_collected_pools;
  }
  static void recompute_enabled_for_collected_pools();
  static inline void detect_low_memory_for_collected_pools() {
    if (!is_enabled_for_collected_pools()) {
      return;
    }
    int num_memory_pools = MemoryService::num_memory_pools();
    for (int i=0; i<num_memory_pools; i++) {
      MemoryPool* pool = MemoryService::get_memory_pool(i);
      if (pool->is_collected_pool() && is_enabled(pool)) {
        size_t used = pool->used_in_bytes();
        size_t high = pool->usage_threshold()->high_threshold();
        if (used > high) {
          detect_low_memory(pool);
        }
      }
    }
  }
};
class LowMemoryDetectorDisabler: public StackObj {
public:
  LowMemoryDetectorDisabler()
  {
    LowMemoryDetector::disable();
  }
  ~LowMemoryDetectorDisabler()
  {
    assert(LowMemoryDetector::temporary_disabled(), "should be disabled!");
    LowMemoryDetector::enable();
  }
};
#endif // SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocSiteTable.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/atomic.hpp"
#include "services/mallocSiteTable.hpp"
size_t MallocSiteTable::_hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
size_t MallocSiteTable::_hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
MallocSiteHashtableEntry*  MallocSiteTable::_table[MallocSiteTable::table_size];
volatile int MallocSiteTable::_access_count = 0;
NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;)
bool MallocSiteTable::initialize() {
  assert(sizeof(_hash_entry_allocation_stack) >= sizeof(NativeCallStack), "Sanity Check");
  assert(sizeof(_hash_entry_allocation_site) >= sizeof(MallocSiteHashtableEntry),
    "Sanity Check");
  assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow");
  assert(NMT_TrackingStackDepth > 1, "At least one tracking stack");
  address pc[3];
  if (NMT_TrackingStackDepth >= 3) {
    uintx *fp = (uintx*)MallocSiteTable::allocation_at;
    pc[2] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
  }
  if (NMT_TrackingStackDepth >= 2) {
    uintx *fp = (uintx*)MallocSiteTable::lookup_or_add;
    pc[1] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
  }
  uintx *fp = (uintx*)MallocSiteTable::new_entry;
  pc[0] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
  NativeCallStack* stack = ::new ((void*)_hash_entry_allocation_stack)
    NativeCallStack(pc, MIN2(((int)(sizeof(pc) / sizeof(address))), ((int)NMT_TrackingStackDepth)));
  MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site)
    MallocSiteHashtableEntry(*stack, mtNMT);
  int index = hash_to_index(stack->hash());
  _table[index] = entry;
  return true;
}
bool MallocSiteTable::walk(MallocSiteWalker* walker) {
  MallocSiteHashtableEntry* head;
  for (int index = 0; index < table_size; index ++) {
    head = _table[index];
    while (head != NULL) {
      if (!walker->do_malloc_site(head->peek())) {
        return false;
      }
      head = (MallocSiteHashtableEntry*)head->next();
    }
  }
  return true;
}
MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx,
  size_t* pos_idx, MEMFLAGS flags) {
  assert(flags != mtNone, "Should have a real memory type");
  unsigned int index = hash_to_index(key.hash());
  assert(index >= 0, "Negative index");
  if (_table[index] == NULL) {
    MallocSiteHashtableEntry* entry = new_entry(key, flags);
    if (entry == NULL) return NULL;
    if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) {
      return entry->data();
    }
    delete entry;
  }
  MallocSiteHashtableEntry* head = _table[index];
  while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) {
    MallocSite* site = head->data();
    if (site->flag() == flags && site->equals(key)) {
      return head->data();
    }
    if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) {
      MallocSiteHashtableEntry* entry = new_entry(key, flags);
      if (entry == NULL) return NULL;
      if (head->atomic_insert(entry)) {
        (*pos_idx) ++;
        return entry->data();
      }
      delete entry;
    }
    head = (MallocSiteHashtableEntry*)head->next();
    (*pos_idx) ++;
  }
  return NULL;
}
MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) {
  assert(bucket_idx < table_size, "Invalid bucket index");
  MallocSiteHashtableEntry* head = _table[bucket_idx];
  for (size_t index = 0; index < pos_idx && head != NULL;
    index ++, head = (MallocSiteHashtableEntry*)head->next());
  assert(head != NULL, "Invalid position index");
  return head->data();
}
MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key, MEMFLAGS flags) {
  void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT,
  return ::new (p) MallocSiteHashtableEntry(key, flags);
}
void MallocSiteTable::reset() {
  for (int index = 0; index < table_size; index ++) {
    MallocSiteHashtableEntry* head = _table[index];
    _table[index] = NULL;
    delete_linked_list(head);
  }
}
void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) {
  MallocSiteHashtableEntry* p;
  while (head != NULL) {
    p = head;
    head = (MallocSiteHashtableEntry*)head->next();
    if (p != (MallocSiteHashtableEntry*)_hash_entry_allocation_site) {
      delete p;
    }
  }
}
void MallocSiteTable::shutdown() {
  AccessLock locker(&_access_count);
  locker.exclusiveLock();
  reset();
}
bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) {
  assert(walker != NULL, "NuLL walker");
  AccessLock locker(&_access_count);
  if (locker.sharedLock()) {
    NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
    return walk(walker);
  }
  return false;
}
void MallocSiteTable::AccessLock::exclusiveLock() {
  jint target;
  jint val;
  assert(_lock_state != ExclusiveLock, "Can only call once");
  assert(*_lock >= 0, "Can not content exclusive lock");
  do {
    val = *_lock;
    target = _MAGIC_ + *_lock;
  } while (Atomic::cmpxchg(target, _lock, val) != val);
  while (*_lock != _MAGIC_) {
#ifdef _WINDOWS
    os::naked_short_sleep(1);
#else
    os::NakedYield();
#endif
  }
  _lock_state = ExclusiveLock;
}
C:\hotspot-69087d08d473\src\share\vm/services/mallocSiteTable.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
#define SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
#if INCLUDE_NMT
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "services/allocationSite.hpp"
#include "services/mallocTracker.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/nativeCallStack.hpp"
class MallocSite : public AllocationSite<MemoryCounter> {
 public:
  MallocSite() :
    AllocationSite<MemoryCounter>(NativeCallStack::empty_stack(), mtNone) {}
  MallocSite(const NativeCallStack& stack, MEMFLAGS flags) :
    AllocationSite<MemoryCounter>(stack, flags) {}
  void allocate(size_t size)      { data()->allocate(size);   }
  void deallocate(size_t size)    { data()->deallocate(size); }
  size_t size()  const { return peek()->size(); }
  size_t count() const { return peek()->count(); }
};
class MallocSiteHashtableEntry : public CHeapObj<mtNMT> {
 private:
  MallocSite                _malloc_site;
  MallocSiteHashtableEntry* _next;
 public:
  MallocSiteHashtableEntry() : _next(NULL) { }
  MallocSiteHashtableEntry(NativeCallStack stack, MEMFLAGS flags):
    _malloc_site(stack, flags), _next(NULL) {
    assert(flags != mtNone, "Expect a real memory type");
  }
  inline const MallocSiteHashtableEntry* next() const {
    return _next;
  }
  bool atomic_insert(const MallocSiteHashtableEntry* entry) {
    return (Atomic::cmpxchg_ptr((void*)entry, (volatile void*)&_next,
      NULL) == NULL);
  }
  void set_callsite(const MallocSite& site) {
    _malloc_site = site;
  }
  inline const MallocSite* peek() const { return &_malloc_site; }
  inline MallocSite* data()             { return &_malloc_site; }
  inline long hash() const { return _malloc_site.hash(); }
  inline bool equals(const NativeCallStack& stack) const {
    return _malloc_site.equals(stack);
  }
  inline void allocate(size_t size)   { _malloc_site.allocate(size);   }
  inline void deallocate(size_t size) { _malloc_site.deallocate(size); }
  inline size_t size() const  { return _malloc_site.size();  }
  inline size_t count() const { return _malloc_site.count(); }
};
class MallocSiteWalker : public StackObj {
 public:
   virtual bool do_malloc_site(const MallocSite* e) { return false; }
};
class MallocSiteTable : AllStatic {
 private:
  enum {
    table_base_size = 128,   // The base size is calculated from statistics to give
    table_size = (table_base_size * NMT_TrackingStackDepth - 1)
  };
  class AccessLock : public StackObj {
    enum LockState {
      NoLock,
      SharedLock,
      ExclusiveLock
    };
   private:
    const static int _MAGIC_ = min_jint;
    LockState      _lock_state;
    volatile int*  _lock;
   public:
    AccessLock(volatile int* lock) :
      _lock(lock), _lock_state(NoLock) {
    }
    ~AccessLock() {
      if (_lock_state == SharedLock) {
        Atomic::dec((volatile jint*)_lock);
      }
    }
    inline bool sharedLock() {
      jint res = Atomic::add(1, _lock);
      if (res < 0) {
        Atomic::add(-1, _lock);
        return false;
      }
      _lock_state = SharedLock;
      return true;
    }
    void exclusiveLock();
 };
 public:
  static bool initialize();
  static void shutdown();
  NOT_PRODUCT(static int access_peak_count() { return _peak_count; })
  static inline int hash_buckets()      { return (int)table_size; }
  static inline bool access_stack(NativeCallStack& stack, size_t bucket_idx,
    size_t pos_idx) {
    AccessLock locker(&_access_count);
    if (locker.sharedLock()) {
      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
      MallocSite* site = malloc_site(bucket_idx, pos_idx);
      if (site != NULL) {
        stack = *site->call_stack();
        return true;
      }
    }
    return false;
  }
  static inline bool allocation_at(const NativeCallStack& stack, size_t size,
    size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) {
    AccessLock locker(&_access_count);
    if (locker.sharedLock()) {
      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
      MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx, flags);
      if (site != NULL) site->allocate(size);
      return site != NULL;
    }
    return false;
  }
  static inline bool deallocation_at(size_t size, size_t bucket_idx, size_t pos_idx) {
    AccessLock locker(&_access_count);
    if (locker.sharedLock()) {
      NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
      MallocSite* site = malloc_site(bucket_idx, pos_idx);
      if (site != NULL) {
        site->deallocate(size);
        return true;
      }
    }
    return false;
  }
  static bool walk_malloc_site(MallocSiteWalker* walker);
 private:
  static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key, MEMFLAGS flags);
  static void reset();
  static void delete_linked_list(MallocSiteHashtableEntry* head);
  static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags);
  static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx);
  static bool walk(MallocSiteWalker* walker);
  static inline unsigned int hash_to_index(unsigned int hash) {
    return (hash % table_size);
  }
  static inline const NativeCallStack* hash_entry_allocation_stack() {
    return (NativeCallStack*)_hash_entry_allocation_stack;
  }
 private:
  static volatile int                _access_count;
  static MallocSiteHashtableEntry*   _table[table_size];
  static size_t _hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
  static size_t _hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
  NOT_PRODUCT(static int     _peak_count;)
};
#endif // INCLUDE_NMT
#endif // SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.cpp
#include "precompiled.hpp"
#include "runtime/atomic.hpp"
#include "runtime/atomic.inline.hpp"
#include "services/mallocSiteTable.hpp"
#include "services/mallocTracker.hpp"
#include "services/mallocTracker.inline.hpp"
#include "services/memTracker.hpp"
size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
size_t MallocMemorySnapshot::total() const {
  size_t amount = 0;
  for (int index = 0; index < mt_number_of_types; index ++) {
    amount += _malloc[index].malloc_size();
  }
  amount += _tracking_header.size() + total_arena();
  return amount;
}
size_t MallocMemorySnapshot::total_arena() const {
  size_t amount = 0;
  for (int index = 0; index < mt_number_of_types; index ++) {
    amount += _malloc[index].arena_size();
  }
  return amount;
}
void MallocMemorySnapshot::make_adjustment() {
  size_t arena_size = total_arena();
  int chunk_idx = NMTUtil::flag_to_index(mtChunk);
  _malloc[chunk_idx].record_free(arena_size);
}
void MallocMemorySummary::initialize() {
  assert(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot), "Sanity Check");
  ::new ((void*)_snapshot)MallocMemorySnapshot();
}
void MallocHeader::release() const {
  if (MemTracker::tracking_level() <= NMT_minimal) return;
  MallocMemorySummary::record_free(size(), flags());
  MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader));
  if (MemTracker::tracking_level() == NMT_detail) {
    MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx);
  }
}
bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size,
  size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const {
  bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx, flags);
  if (!ret) {
    MemTracker::transition_to(NMT_summary);
  }
  return ret;
}
bool MallocHeader::get_stack(NativeCallStack& stack) const {
  return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx);
}
bool MallocTracker::initialize(NMT_TrackingLevel level) {
  if (level >= NMT_summary) {
    MallocMemorySummary::initialize();
  }
  if (level == NMT_detail) {
    return MallocSiteTable::initialize();
  }
  return true;
}
bool MallocTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
  assert(from != NMT_off, "Can not transition from off state");
  assert(to != NMT_off, "Can not transition to off state");
  assert (from != NMT_minimal, "cannot transition from minimal state");
  if (from == NMT_detail) {
    assert(to == NMT_minimal || to == NMT_summary, "Just check");
    MallocSiteTable::shutdown();
  }
  return true;
}
void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
  const NativeCallStack& stack, NMT_TrackingLevel level) {
  void*         memblock;      // the address for user data
  MallocHeader* header = NULL;
  if (malloc_base == NULL) {
    return NULL;
  }
  if (level == NMT_off) {
    return malloc_base;
  }
  header = ::new (malloc_base)MallocHeader(size, flags, stack, level);
  memblock = (void*)((char*)malloc_base + sizeof(MallocHeader));
  assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check");
#ifdef ASSERT
  if (level > NMT_minimal) {
    assert(get_size(memblock) == size,   "Wrong size");
    assert(get_flags(memblock) == flags, "Wrong flags");
  }
#endif
  return memblock;
}
void* MallocTracker::record_free(void* memblock) {
  if (MemTracker::tracking_level() == NMT_off ||
      memblock == NULL) {
    return memblock;
  }
  MallocHeader* header = malloc_header(memblock);
  header->release();
  return (void*)header;
}
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
#define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
#if INCLUDE_NMT
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/nativeCallStack.hpp"
class MemoryCounter VALUE_OBJ_CLASS_SPEC {
 private:
  size_t   _count;
  size_t   _size;
  DEBUG_ONLY(size_t   _peak_count;)
  DEBUG_ONLY(size_t   _peak_size; )
 public:
  MemoryCounter() : _count(0), _size(0) {
    DEBUG_ONLY(_peak_count = 0;)
    DEBUG_ONLY(_peak_size  = 0;)
  }
  inline void allocate(size_t sz) {
    Atomic::add(1, (volatile MemoryCounterType*)&_count);
    if (sz > 0) {
      Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
      DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size));
    }
    DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);)
  }
  inline void deallocate(size_t sz) {
    assert(_count > 0, "Negative counter");
    assert(_size >= sz, "Negative size");
    Atomic::add(-1, (volatile MemoryCounterType*)&_count);
    if (sz > 0) {
      Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
    }
  }
  inline void resize(ssize_t sz) {
    if (sz != 0) {
      assert(sz >= 0 || _size >= size_t(-sz), "Must be");
      Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
      DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);)
    }
  }
  inline size_t count() const { return _count; }
  inline size_t size()  const { return _size;  }
  DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; })
  DEBUG_ONLY(inline size_t peak_size()  const { return _peak_size; })
};
class MallocMemory VALUE_OBJ_CLASS_SPEC {
 private:
  MemoryCounter _malloc;
  MemoryCounter _arena;
 public:
  MallocMemory() { }
  inline void record_malloc(size_t sz) {
    _malloc.allocate(sz);
  }
  inline void record_free(size_t sz) {
    _malloc.deallocate(sz);
  }
  inline void record_new_arena() {
    _arena.allocate(0);
  }
  inline void record_arena_free() {
    _arena.deallocate(0);
  }
  inline void record_arena_size_change(ssize_t sz) {
    _arena.resize(sz);
  }
  inline size_t malloc_size()  const { return _malloc.size(); }
  inline size_t malloc_count() const { return _malloc.count();}
  inline size_t arena_size()   const { return _arena.size();  }
  inline size_t arena_count()  const { return _arena.count(); }
  DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; })
  DEBUG_ONLY(inline const MemoryCounter& arena_counter()  const { return _arena;  })
};
class MallocMemorySummary;
class MallocMemorySnapshot : public ResourceObj {
  friend class MallocMemorySummary;
 private:
  MallocMemory      _malloc[mt_number_of_types];
  MemoryCounter     _tracking_header;
 public:
  inline MallocMemory*  by_type(MEMFLAGS flags) {
    int index = NMTUtil::flag_to_index(flags);
    return &_malloc[index];
  }
  inline MallocMemory* by_index(int index) {
    assert(index >= 0, "Index out of bound");
    assert(index < mt_number_of_types, "Index out of bound");
    return &_malloc[index];
  }
  inline MemoryCounter* malloc_overhead() {
    return &_tracking_header;
  }
  size_t total() const;
  size_t total_arena() const;
  inline size_t thread_count() const {
    MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);
    return s->by_type(mtThreadStack)->malloc_count();
  }
  void copy_to(MallocMemorySnapshot* s) {
    s->_tracking_header = _tracking_header;
    for (int index = 0; index < mt_number_of_types; index ++) {
      s->_malloc[index] = _malloc[index];
    }
  }
  void make_adjustment();
};
class MallocMemorySummary : AllStatic {
 private:
  static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
 public:
   static void initialize();
   static inline void record_malloc(size_t size, MEMFLAGS flag) {
     as_snapshot()->by_type(flag)->record_malloc(size);
   }
   static inline void record_free(size_t size, MEMFLAGS flag) {
     as_snapshot()->by_type(flag)->record_free(size);
   }
   static inline void record_new_arena(MEMFLAGS flag) {
     as_snapshot()->by_type(flag)->record_new_arena();
   }
   static inline void record_arena_free(MEMFLAGS flag) {
     as_snapshot()->by_type(flag)->record_arena_free();
   }
   static inline void record_arena_size_change(ssize_t size, MEMFLAGS flag) {
     as_snapshot()->by_type(flag)->record_arena_size_change(size);
   }
   static void snapshot(MallocMemorySnapshot* s) {
     as_snapshot()->copy_to(s);
     s->make_adjustment();
   }
   static inline void record_new_malloc_header(size_t sz) {
     as_snapshot()->malloc_overhead()->allocate(sz);
   }
   static inline void record_free_malloc_header(size_t sz) {
     as_snapshot()->malloc_overhead()->deallocate(sz);
   }
   static inline size_t tracking_overhead() {
     return as_snapshot()->malloc_overhead()->size();
   }
  static MallocMemorySnapshot* as_snapshot() {
    return (MallocMemorySnapshot*)_snapshot;
  }
};
class MallocHeader VALUE_OBJ_CLASS_SPEC {
#ifdef _LP64
  size_t           _size      : 64;
  size_t           _flags     : 8;
  size_t           _pos_idx   : 16;
  size_t           _bucket_idx: 40;
#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40)
#define MAX_BUCKET_LENGTH         right_n_bits(16)
#else
  size_t           _size      : 32;
  size_t           _flags     : 8;
  size_t           _pos_idx   : 8;
  size_t           _bucket_idx: 16;
#define MAX_MALLOCSITE_TABLE_SIZE  right_n_bits(16)
#define MAX_BUCKET_LENGTH          right_n_bits(8)
#endif  // _LP64
 public:
  MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) {
    assert(sizeof(MallocHeader) == sizeof(void*) * 2,
      "Wrong header size");
    if (level == NMT_minimal) {
      return;
    }
    _flags = flags;
    set_size(size);
    if (level == NMT_detail) {
      size_t bucket_idx;
      size_t pos_idx;
      if (record_malloc_site(stack, size, &bucket_idx, &pos_idx, flags)) {
        assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index");
        assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index");
        _bucket_idx = bucket_idx;
        _pos_idx = pos_idx;
      }
    }
    MallocMemorySummary::record_malloc(size, flags);
    MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader));
  }
  inline size_t   size()  const { return _size; }
  inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; }
  bool get_stack(NativeCallStack& stack) const;
  void release() const;
 private:
  inline void set_size(size_t size) {
    _size = size;
  }
  bool record_malloc_site(const NativeCallStack& stack, size_t size,
    size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const;
};
class MallocTracker : AllStatic {
 public:
  static bool initialize(NMT_TrackingLevel level);
  static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
  static inline size_t malloc_header_size(NMT_TrackingLevel level) {
    return (level == NMT_off) ? 0 : sizeof(MallocHeader);
  }
  static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
    const NativeCallStack& stack, NMT_TrackingLevel level);
  static void* record_free(void* memblock);
  static inline void* get_base(void* memblock);
  static inline void* get_base(void* memblock, NMT_TrackingLevel level) {
    if (memblock == NULL || level == NMT_off) return memblock;
    return (char*)memblock - malloc_header_size(level);
  }
  static inline size_t get_size(void* memblock) {
    MallocHeader* header = malloc_header(memblock);
    return header->size();
  }
  static inline MEMFLAGS get_flags(void* memblock) {
    MallocHeader* header = malloc_header(memblock);
    return header->flags();
  }
  static inline size_t get_header_size(void* memblock) {
    return (memblock == NULL) ? 0 : sizeof(MallocHeader);
  }
  static inline void record_new_arena(MEMFLAGS flags) {
    MallocMemorySummary::record_new_arena(flags);
  }
  static inline void record_arena_free(MEMFLAGS flags) {
    MallocMemorySummary::record_arena_free(flags);
  }
  static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) {
    MallocMemorySummary::record_arena_size_change(size, flags);
  }
 private:
  static inline MallocHeader* malloc_header(void *memblock) {
    assert(memblock != NULL, "NULL pointer");
    MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader));
    return header;
  }
};
#endif // INCLUDE_NMT
#endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.inline.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
#define SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
#include "services/mallocTracker.hpp"
#include "services/memTracker.hpp"
inline void* MallocTracker::get_base(void* memblock){
  return get_base(memblock, MemTracker::tracking_level());
}
#endif // SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/management.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/iterator.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/klass.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/os.hpp"
#include "runtime/serviceThread.hpp"
#include "runtime/thread.inline.hpp"
#include "services/classLoadingService.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/heapDumper.hpp"
#include "services/jmm.h"
#include "services/lowMemoryDetector.hpp"
#include "services/gcNotifier.hpp"
#include "services/nmtDCmd.hpp"
#include "services/management.hpp"
#include "services/memoryManager.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
#include "services/runtimeService.hpp"
#include "services/threadService.hpp"
#include "utilities/macros.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
PerfVariable* Management::_begin_vm_creation_time = NULL;
PerfVariable* Management::_end_vm_creation_time = NULL;
PerfVariable* Management::_vm_init_done_time = NULL;
Klass* Management::_sensor_klass = NULL;
Klass* Management::_threadInfo_klass = NULL;
Klass* Management::_memoryUsage_klass = NULL;
Klass* Management::_memoryPoolMXBean_klass = NULL;
Klass* Management::_memoryManagerMXBean_klass = NULL;
Klass* Management::_garbageCollectorMXBean_klass = NULL;
Klass* Management::_managementFactory_klass = NULL;
Klass* Management::_garbageCollectorImpl_klass = NULL;
Klass* Management::_gcInfo_klass = NULL;
Klass* Management::_diagnosticCommandImpl_klass = NULL;
Klass* Management::_managementFactoryHelper_klass = NULL;
jmmOptionalSupport Management::_optional_support = {0};
TimeStamp Management::_stamp;
void management_init() {
#if INCLUDE_MANAGEMENT
  Management::init();
  ThreadService::init();
  RuntimeService::init();
  ClassLoadingService::init();
#else
  ThreadService::init();
  Abstract_VM_Version::initialize();
#endif // INCLUDE_MANAGEMENT
}
#if INCLUDE_MANAGEMENT
void Management::init() {
  EXCEPTION_MARK;
  _begin_vm_creation_time =
            PerfDataManager::create_variable(SUN_RT, "createVmBeginTime",
                                             PerfData::U_None, CHECK);
  _end_vm_creation_time =
            PerfDataManager::create_variable(SUN_RT, "createVmEndTime",
                                             PerfData::U_None, CHECK);
  _vm_init_done_time =
            PerfDataManager::create_variable(SUN_RT, "vmInitDoneTime",
                                             PerfData::U_None, CHECK);
  _optional_support.isLowMemoryDetectionSupported = 1;
  _optional_support.isCompilationTimeMonitoringSupported = 1;
  _optional_support.isThreadContentionMonitoringSupported = 1;
  if (os::is_thread_cpu_time_supported()) {
    _optional_support.isCurrentThreadCpuTimeSupported = 1;
    _optional_support.isOtherThreadCpuTimeSupported = 1;
  } else {
    _optional_support.isCurrentThreadCpuTimeSupported = 0;
    _optional_support.isOtherThreadCpuTimeSupported = 0;
  }
  _optional_support.isBootClassPathSupported = 1;
  _optional_support.isObjectMonitorUsageSupported = 1;
#if INCLUDE_SERVICES
  _optional_support.isSynchronizerUsageSupported = 1;
#endif // INCLUDE_SERVICES
  _optional_support.isThreadAllocatedMemorySupported = 1;
  _optional_support.isRemoteDiagnosticCommandsSupported = 1;
  DCmdRegistrant::register_dcmds();
  DCmdRegistrant::register_dcmds_ext();
  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
                         | DCmd_Source_MBean;
  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(full_export, true, false));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值