Date: Tue, 6 Jun 2023 01:47:43 +0000
Subject: [PATCH 17/59] 8054889: Compiler team's implementation task

Bug url: https://bugs.openjdk.org/browse/JDK-8054889
---
 hotspot/src/share/vm/ci/ciEnv.cpp             |   2 +-
 hotspot/src/share/vm/code/codeCache.cpp       |  20 ++
 hotspot/src/share/vm/code/codeCache.hpp       |   4 +
 .../src/share/vm/compiler/compileBroker.cpp   |  78 +++----
 .../src/share/vm/compiler/compileBroker.hpp   |  24 +--
 hotspot/src/share/vm/runtime/globals.hpp      |   2 +-
 .../src/share/vm/runtime/vm_operations.cpp    |  12 ++
 .../src/share/vm/runtime/vm_operations.hpp    |  34 +++
 .../share/vm/services/diagnosticCommand.cpp   |  19 ++
 .../share/vm/services/diagnosticCommand.hpp   |  64 ++++++
 .../serviceability/dcmd/CodeCacheTest.java    | 139 +++++++++++++
 .../serviceability/dcmd/CodelistTest.java     |  97 +++++++++
 .../dcmd/CompilerQueueTest.java               | 108 ++++++++++
 .../dcmd/MethodIdentifierParser.java          | 196 ++++++++++++++++++
 14 files changed, 747 insertions(+), 52 deletions(-)
 create mode 100644 hotspot/test/serviceability/dcmd/CodeCacheTest.java
 create mode 100644 hotspot/test/serviceability/dcmd/CodelistTest.java
 create mode 100644 hotspot/test/serviceability/dcmd/CompilerQueueTest.java
 create mode 100644 hotspot/test/serviceability/dcmd/MethodIdentifierParser.java

diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp
index e536c19d6..a27ca3254 100644
--- a/hotspot/src/share/vm/ci/ciEnv.cpp
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp
@@ -952,7 +952,7 @@ void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
 #ifdef ASSERT
     if (!counter_changed && !PrintCompilation) {
       // Print out the compile task that failed
-      _task->print_line();
+      _task->print_tty();
     }
 #endif
     assert(counter_changed, "failed dependencies, but counter didn't change");
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index d0ab4f194..8df29d608 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -263,6 +263,7 @@ void CodeCache::flush() {
 #define FOR_ALL_BLOBS(var)       for (CodeBlob *var =       first() ; var != NULL; var =       next(var) )
 #define FOR_ALL_ALIVE_BLOBS(var) for (CodeBlob *var = alive(first()); var != NULL; var = alive(next(var)))
 #define FOR_ALL_ALIVE_NMETHODS(var) for (nmethod *var = alive_nmethod(first()); var != NULL; var = alive_nmethod(next(var)))
+#define FOR_ALL_NMETHODS(var) for (nmethod *var = first_nmethod(); var != NULL; var = next_nmethod(var))
 
 
 bool CodeCache::contains(void *p) {
@@ -1007,6 +1008,25 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
   }
 }
 
+void CodeCache::print_codelist(outputStream* st) {
+  assert_locked_or_safepoint(CodeCache_lock);
+
+  FOR_ALL_NMETHODS(p) {
+    ResourceMark rm;
+    char *method_name = p->method()->name_and_sig_as_C_string();
+    st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
+                 p->compile_id(), p->comp_level(), method_name, (intptr_t)p->header_begin(),
+                 (intptr_t)p->code_begin(), (intptr_t)p->code_end());
+  }
+}
+
+void CodeCache::print_layout(outputStream* st) {
+  assert_locked_or_safepoint(CodeCache_lock);
+  ResourceMark rm;
+
+  print_summary(st, true);
+}
+
 void CodeCache::log_state(outputStream* st) {
   st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
             " adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp
index 415f67750..ab1417b19 100644
--- a/hotspot/src/share/vm/code/codeCache.hpp
+++ b/hotspot/src/share/vm/code/codeCache.hpp
@@ -159,6 +159,10 @@ class CodeCache : AllStatic {
   static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
   static void log_state(outputStream* st);
 
+  // Dcmd (Diagnostic commands)
+  static void print_codelist(outputStream* st);
+  static void print_layout(outputStream* st);
+
   // The full limits of the codeCache
   static address  low_bound()                    { return (address) _heap->low_boundary(); }
   static address  high_bound()                   { return (address) _heap->high_boundary(); }
diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp
index 79636258a..63f7bde8f 100644
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp
@@ -193,7 +193,7 @@ class CompilationLog : public StringEventLog {
     StringLogMessage lm;
     stringStream sstr = lm.stream();
     // msg.time_stamp().update_to(tty->time_stamp().ticks());
-    task->print_compilation(&sstr, NULL, true);
+    task->print_compilation(&sstr, NULL, true, false);
     log(thread, "%s", (const char*)lm);
   }
 
@@ -355,7 +355,6 @@ void CompileTask::set_code(nmethod* nm) {
   if (nm == NULL)  _code_handle = NULL;  // drop the handle also
 }
 
-
 void CompileTask::mark_on_stack() {
   // Mark these methods as something redefine classes cannot remove.
   _method->set_on_stack(true);
@@ -364,18 +363,6 @@ void CompileTask::mark_on_stack() {
   }
 }
 
-// ------------------------------------------------------------------
-// CompileTask::print
-void CompileTask::print() {
-  tty->print("<CompileTask compile_id=%d ", _compile_id);
-  tty->print("method=");
-  _method->print_name(tty);
-  tty->print_cr(" osr_bci=%d is_blocking=%s is_complete=%s is_success=%s>",
-             _osr_bci, bool_to_str(_is_blocking),
-             bool_to_str(_is_complete), bool_to_str(_is_success));
-}
-
-
 // ------------------------------------------------------------------
 // CompileTask::print_line_on_error
 //
@@ -394,11 +381,11 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
 
 // ------------------------------------------------------------------
 // CompileTask::print_line
-void CompileTask::print_line() {
+void CompileTask::print_tty() {
   ttyLocker ttyl;  // keep the following output all in one block
   // print compiler name if requested
   if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
-  print_compilation();
+  print_compilation(tty);
 }
 
 
@@ -406,7 +393,7 @@ void CompileTask::print_line() {
 // CompileTask::print_compilation_impl
 void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
                                          bool is_osr_method, int osr_bci, bool is_blocking,
-                                         const char* msg, bool short_form) {
+                                         const char* msg, bool short_form, bool cr) {
   if (!short_form) {
     st->print("%7d ", (int) st->time_stamp().milliseconds());  // print timestamp
   }
@@ -455,7 +442,7 @@ void CompileTask::print_compilation_impl(outputStream* st, Method* method, int c
   if (msg != NULL) {
     st->print("   %s", msg);
   }
-  if (!short_form) {
+  if (cr) {
     st->cr();
   }
 }
@@ -521,9 +508,9 @@ void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
 
 // ------------------------------------------------------------------
 // CompileTask::print_compilation
-void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form) {
+void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form, bool cr) {
   bool is_osr_method = osr_bci() != InvocationEntryBci;
-  print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form);
+  print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr);
 }
 
 // ------------------------------------------------------------------
@@ -649,7 +636,9 @@ void CompileQueue::add(CompileTask* task) {
   // Mark the method as being in the compile queue.
   task->method()->set_queued_for_compilation();
 
-  NOT_PRODUCT(print();)
+  if (CIPrintCompileQueue) {
+    print_tty();
+  }
 
   if (LogCompilation && xtty != NULL) {
     task->log_task_queued();
@@ -816,24 +805,39 @@ void CompileQueue::mark_on_stack() {
   }
 }
 
-#ifndef PRODUCT
-/**
- * Print entire compilation queue.
- */
-void CompileQueue::print() {
-  if (CIPrintCompileQueue) {
-    ttyLocker ttyl;
-    tty->print_cr("Contents of %s", name());
-    tty->print_cr("----------------------");
-    CompileTask* task = _first;
+CompileQueue* CompileBroker::compile_queue(int comp_level) {
+  if (is_c2_compile(comp_level)) return _c2_compile_queue;
+  if (is_c1_compile(comp_level)) return _c1_compile_queue;
+  return NULL;
+}
+
+
+void CompileBroker::print_compile_queues(outputStream* st) {
+  _c1_compile_queue->print(st);
+  _c2_compile_queue->print(st);
+}
+
+
+void CompileQueue::print(outputStream* st) {
+  assert_locked_or_safepoint(lock());
+  st->print_cr("Contents of %s", name());
+  st->print_cr("----------------------------");
+  CompileTask* task = _first;
+  if (task == NULL) {
+    st->print_cr("Empty");;
+  } else {
     while (task != NULL) {
-      task->print_line();
+      task->print_compilation(st, NULL, true, true);
       task = task->next();
     }
-    tty->print_cr("----------------------");
   }
+  st->print_cr("----------------------------");
+}
+
+void CompileQueue::print_tty() {
+  ttyLocker ttyl;
+  print(tty);
 }
-#endif // PRODUCT
 
 CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
 
@@ -1096,11 +1100,11 @@ void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler
 #endif // !ZERO && !SHARK
   // Initialize the compilation queue
   if (c2_compiler_count > 0) {
-    _c2_compile_queue  = new CompileQueue("C2 CompileQueue",  MethodCompileQueue_lock);
+    _c2_compile_queue  = new CompileQueue("C2 compile queue",  MethodCompileQueue_lock);
     _compilers[1]->set_num_compiler_threads(c2_compiler_count);
   }
   if (c1_compiler_count > 0) {
-    _c1_compile_queue  = new CompileQueue("C1 CompileQueue",  MethodCompileQueue_lock);
+    _c1_compile_queue  = new CompileQueue("C1 compile queue",  MethodCompileQueue_lock);
     _compilers[0]->set_num_compiler_threads(c1_compiler_count);
   }
 
@@ -1927,7 +1931,7 @@ static void post_compilation_event(EventCompilation* event, CompileTask* task) {
 void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
   if (PrintCompilation) {
     ResourceMark rm;
-    task->print_line();
+    task->print_tty();
   }
   elapsedTimer time;
 
diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp
index 96d5e816b..a5bd806f6 100644
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp
+++ b/hotspot/src/share/vm/compiler/compileBroker.hpp
@@ -111,14 +111,14 @@ class CompileTask : public CHeapObj<mtCompiler> {
 private:
   static void  print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
                                       bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false,
-                                      const char* msg = NULL, bool short_form = false);
+                                      const char* msg = NULL, bool short_form = false, bool cr = true);
 
 public:
-  void         print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false);
-  static void  print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false) {
+  void         print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true);
+  static void  print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) {
     print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(),
                            nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false,
-                           msg, short_form);
+                           msg, short_form, cr);
   }
 
   static void  print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL);
@@ -131,8 +131,7 @@ public:
 
   static void  print_inline_indent(int inline_level, outputStream* st = tty);
 
-  void         print();
-  void         print_line();
+  void         print_tty();
   void         print_line_on_error(outputStream* st, char* buf, int buflen);
 
   void         log_task(xmlStream* log);
@@ -235,7 +234,8 @@ class CompileQueue : public CHeapObj<mtCompiler> {
   // Redefine Classes support
   void mark_on_stack();
   void free_all();
-  NOT_PRODUCT (void print();)
+  void print_tty();
+  void print(outputStream* st = tty);
 
   ~CompileQueue() {
     assert (is_empty(), " Compile Queue must be empty");
@@ -337,7 +337,7 @@ class CompileBroker: AllStatic {
   static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, TRAPS);
   static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
   static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level);
-  static bool is_compile_blocking      ();
+  static bool is_compile_blocking();
   static void preload_classes          (methodHandle method, TRAPS);
 
   static CompileTask* create_compile_task(CompileQueue* queue,
@@ -365,11 +365,8 @@ class CompileBroker: AllStatic {
                                   int hot_count,
                                   const char* comment,
                                   Thread* thread);
-  static CompileQueue* compile_queue(int comp_level) {
-    if (is_c2_compile(comp_level)) return _c2_compile_queue;
-    if (is_c1_compile(comp_level)) return _c1_compile_queue;
-    return NULL;
-  }
+
+  static CompileQueue* compile_queue(int comp_level);
   static bool init_compiler_runtime();
   static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
 
@@ -387,6 +384,7 @@ class CompileBroker: AllStatic {
 
   static bool compilation_is_complete(methodHandle method, int osr_bci, int comp_level);
   static bool compilation_is_in_queue(methodHandle method);
+  static void print_compile_queues(outputStream* st);
   static int queue_size(int comp_level) {
     CompileQueue *q = compile_queue(comp_level);
     return q != NULL ? q->size() : 0;
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 3b2776ce5..ac9165031 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -2581,7 +2581,7 @@ class CommandLineFlags {
   develop(bool, CIPrintCompilerName, false,                                 \
           "when CIPrint is active, print the name of the active compiler")  \
                                                                             \
-  develop(bool, CIPrintCompileQueue, false,                                 \
+  diagnostic(bool, CIPrintCompileQueue, false,                              \
           "display the contents of the compile queue whenever a "           \
           "compilation is enqueued")                                        \
                                                                             \
diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp
index 03c424905..04e55cd73 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp
@@ -476,3 +476,15 @@ void VM_Exit::wait_if_vm_exited() {
     ShouldNotReachHere();
   }
 }
+
+void VM_PrintCompileQueue::doit() {
+  CompileBroker::print_compile_queues(_out);
+}
+
+void VM_PrintCodeList::doit() {
+  CodeCache::print_codelist(_out);
+}
+
+void VM_PrintCodeCache::doit() {
+  CodeCache::print_layout(_out);
+}
diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp
index baf604264..19463b137 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp
@@ -102,6 +102,9 @@
   template(JFROldObject)                          \
   template(PrintClasses)                          \
   template(PrintMetadata)                         \
+  template(PrintCompileQueue)                     \
+  template(PrintCodeList)                         \
+  template(PrintCodeCache)                        \
 
 class VM_Operation: public CHeapObj<mtInternal> {
  public:
@@ -434,4 +437,35 @@ class VM_RotateGCLog: public VM_Operation {
   void doit() { gclog_or_tty->rotate_log(true, _out); }
 };
 
+class VM_PrintCompileQueue: public VM_Operation {
+ private:
+  outputStream* _out;
+
+ public:
+  VM_PrintCompileQueue(outputStream* st) : _out(st) {}
+  VMOp_Type type() const { return VMOp_PrintCompileQueue; }
+  void doit();
+};
+
+class VM_PrintCodeList: public VM_Operation {
+ private:
+  outputStream* _out;
+
+ public:
+  VM_PrintCodeList(outputStream* st) : _out(st) {}
+  VMOp_Type type() const { return VMOp_PrintCodeList; }
+  void doit();
+};
+
+class VM_PrintCodeCache: public VM_Operation {
+ private:
+  outputStream* _out;
+
+ public:
+  VM_PrintCodeCache(outputStream* st) : _out(st) {}
+  VMOp_Type type() const { return VMOp_PrintCodeCache; }
+  void doit();
+};
+
+
 #endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp
index fb8e293e3..e37ba3cc8 100644
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp
@@ -73,6 +73,9 @@ void DCmdRegistrant::register_dcmds(){
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderHierarchyDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
 #ifdef LINUX
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TrimCLibcHeapDCmd>(full_export, true, false));
 #endif // LINUX
@@ -814,3 +817,19 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
     output()->print_cr("Target VM does not support GC log file rotation.");
   }
 }
+
+void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
+  VM_PrintCompileQueue printCompileQueueOp(output());
+  VMThread::execute(&printCompileQueueOp);
+}
+
+void CodeListDCmd::execute(DCmdSource source, TRAPS) {
+  VM_PrintCodeList printCodeListOp(output());
+  VMThread::execute(&printCodeListOp);
+}
+
+void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
+  VM_PrintCodeCache printCodeCacheOp(output());
+  VMThread::execute(&printCodeCacheOp);
+}
+
diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp
index 87bff52fe..65c04571b 100644
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp
@@ -509,4 +509,68 @@ public:
   virtual void execute(DCmdSource source, TRAPS);
 };
 
+class CompileQueueDCmd : public DCmd {
+public:
+  CompileQueueDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+  static const char* name() {
+    return "Compiler.queue";
+  }
+  static const char* description() {
+    return "Print methods queued for compilation.";
+  }
+  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 CodeListDCmd : public DCmd {
+public:
+  CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+  static const char* name() {
+    return "Compiler.codelist";
+  }
+  static const char* description() {
+    return "Print all compiled methods in code cache.";
+  }
+  static const char* impact() {
+    return "Medium";
+  }
+  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 CodeCacheDCmd : public DCmd {
+public:
+  CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+  static const char* name() {
+    return "Compiler.codecache";
+  }
+  static const char* description() {
+    return "Print code cache layout and bounds.";
+  }
+  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);
+};
+
 #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
diff --git a/hotspot/test/serviceability/dcmd/CodeCacheTest.java b/hotspot/test/serviceability/dcmd/CodeCacheTest.java
new file mode 100644
index 000000000..aaedb210f
--- /dev/null
+++ b/hotspot/test/serviceability/dcmd/CodeCacheTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test CodeCacheTest
+ * @bug 8054889
+ * @build DcmdUtil CodeCacheTest
+ * @run main CodeCacheTest
+ * @summary Test of diagnostic command Compiler.codecache
+ */
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class CodeCacheTest {
+
+    /**
+     * This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output,
+     * making sure that all number look ok
+     *
+     *
+     * Expected output:
+     *
+     * CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb
+     * bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000]
+     * total_blobs=575 nmethods=69 adapters=423
+     * compilation: enabled
+     */
+
+    static Pattern line1 = Pattern.compile("CodeCache: size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb");
+    static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]");
+    static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)");
+    static Pattern line4 = Pattern.compile(" compilation: (\\w*)");
+
+    public static void main(String arg[]) throws Exception {
+
+        // Get output from dcmd (diagnostic command)
+        String result = DcmdUtil.executeDcmd("Compiler.codecache");
+        BufferedReader r = new BufferedReader(new StringReader(result));
+
+        // Validate first line
+        String line;
+        line = r.readLine();
+        Matcher m = line1.matcher(line);
+        if (m.matches()) {
+            for(int i = 1; i <= 4; i++) {
+                int val = Integer.parseInt(m.group(i));
+                if (val < 0) {
+                    throw new Exception("Failed parsing dcmd codecache output");
+                }
+            }
+        } else {
+            throw new Exception("Regexp 1 failed");
+        }
+
+        // Validate second line
+        line = r.readLine();
+        m = line2.matcher(line);
+        if (m.matches()) {
+            long start = Long.parseLong(m.group(1), 16);
+            if (start < 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            long mark = Long.parseLong(m.group(2), 16);
+            if (mark < 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            long top = Long.parseLong(m.group(3), 16);
+            if (top < 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            if (start > mark) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            if (mark > top) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+        } else {
+            throw new Exception("Regexp 2 failed line: " + line);
+        }
+
+        // Validate third line
+        line = r.readLine();
+        m = line3.matcher(line);
+        if (m.matches()) {
+            int blobs = Integer.parseInt(m.group(1));
+            if (blobs <= 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            int nmethods = Integer.parseInt(m.group(2));
+            if (nmethods <= 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            int adapters = Integer.parseInt(m.group(3));
+            if (adapters <= 0) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+            if (blobs < (nmethods + adapters)) {
+                throw new Exception("Failed parsing dcmd codecache output");
+            }
+        } else {
+            throw new Exception("Regexp 3 failed");
+        }
+
+        // Validate fourth line
+        line = r.readLine();
+        m = line4.matcher(line);
+        if (m.matches()) {
+            if (!m.group(1).equals("enabled")) {
+                throw new Exception("Invalid message: '" + m.group(1) + "'");
+            }
+        } else {
+            throw new Exception("Regexp 4 failed");
+        }
+    }
+}
\ No newline at end of file
diff --git a/hotspot/test/serviceability/dcmd/CodelistTest.java b/hotspot/test/serviceability/dcmd/CodelistTest.java
new file mode 100644
index 000000000..151a9ccfb
--- /dev/null
+++ b/hotspot/test/serviceability/dcmd/CodelistTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test CodelistTest
+ * @bug 8054889
+ * @build DcmdUtil MethodIdentifierParser CodelistTest
+ * @run main CodelistTest
+ * @summary Test of diagnostic command Compiler.codelist
+ */
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.lang.reflect.Method;
+
+public class CodelistTest {
+
+    /**
+     * This test calls Jcmd (diagnostic command tool) Compiler.codelist and then parses the output,
+     * making sure that the first methods in the list is valid by reflection.
+     *
+     * Output example:
+     *
+     * 6 0 java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V [0x00007f7b49200910, 0x00007f7b49200aa0 - 0x00007f7b49200d30]
+     * 2 3 java.lang.String.indexOf(II)I [0x00007f7b49200d90, 0x00007f7b49200f60 - 0x00007f7b49201490]
+     * 7 3 java.lang.Math.min(II)I [0x00007f7b4922f010, 0x00007f7b4922f180 - 0x00007f7b4922f338]
+     * 8 3 java.lang.String.equals(Ljava/lang/Object;)Z [0x00007f7b4922fb10, 0x00007f7b4922fd40 - 0x00007f7b49230698]
+     * 9 3 java.lang.AbstractStringBuilder.ensureCapacityInternal(I)V [0x00007f7b49232010, 0x00007f7b492321a0 - 0x00007f7b49232510]
+     * 10 1 java.lang.Object.<init>()V [0x00007f7b49233e90, 0x00007f7b49233fe0 - 0x00007f7b49234118]
+     *
+     */
+
+    public static void main(String arg[]) throws Exception {
+        int ok   = 0;
+        int fail = 0;
+
+        // Get output from dcmd (diagnostic command)
+        String result = DcmdUtil.executeDcmd("Compiler.codelist");
+        BufferedReader r = new BufferedReader(new StringReader(result));
+
+        // Grab a method name from the output
+        String line;
+        int count = 0;
+
+        while((line = r.readLine()) != null) {
+            count++;
+
+            String[] parts = line.split(" ");
+            // int compileID = Integer.parseInt(parts[0]);
+            // int compileLevel = Integer.parseInt(parts[1]);
+            String methodPrintedInLogFormat = parts[2];
+
+            // skip inits and clinits - they can not be reflected
+            if (methodPrintedInLogFormat.contains("<init>")) {
+                continue;
+            }
+            if (methodPrintedInLogFormat.contains("<clinit>")) {
+                continue;
+            }
+
+            MethodIdentifierParser mf = new MethodIdentifierParser(methodPrintedInLogFormat);
+            Method m;
+            try {
+                m = mf.getMethod();
+            } catch (NoSuchMethodException e) {
+                m = null;
+            }
+            if (m == null) {
+                throw new Exception("Test failed");
+            }
+            if (count > 10) {
+                // Testing 10 entries is enough. Lets not waste time.
+                break;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/hotspot/test/serviceability/dcmd/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/CompilerQueueTest.java
new file mode 100644
index 000000000..661e7cb49
--- /dev/null
+++ b/hotspot/test/serviceability/dcmd/CompilerQueueTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test CompilerQueueTest
+ * @bug 8054889
+ * @build DcmdUtil CompilerQueueTest
+ * @run main CompilerQueueTest
+ * @summary Test of diagnostic command Compiler.queue
+ */
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+
+public class CompilerQueueTest {
+
+    /**
+     * This test calls Jcmd (diagnostic command tool) Compiler.queue and
+     * then parses the output, making sure that the output look ok.
+     *
+     *
+     * Output example:
+     *
+     * Contents of C1 compile queue
+     * ----------------------------
+     * 73       3       java.lang.AbstractStringBuilder::append (50 bytes)
+     * 74       1       java.util.TreeMap::size (5 bytes)
+     * 75       3       java.lang.StringBuilder::append (8 bytes)
+     * 83       3       java.util.TreeMap$ValueIterator::next (8 bytes)
+     * 84       1       javax.management.MBeanFeatureInfo::getName (5 bytes)
+     * ----------------------------
+     * Contents of C2 compile queue
+     * ----------------------------
+     * Empty
+     * ----------------------------
+     *
+     **/
+
+    public static void main(String arg[]) throws Exception {
+
+        // Get output from dcmd (diagnostic command)
+        String result = DcmdUtil.executeDcmd("Compiler.queue");
+        BufferedReader r = new BufferedReader(new StringReader(result));
+
+        String line;
+        match(r.readLine(), "Contents of C1 compile queue");
+        match(r.readLine(), "----------------------------");
+        String str = r.readLine();
+        if (!str.equals("Empty")) {
+            while (str.charAt(0) != '-') {
+                validateMethodLine(str);
+                str = r.readLine();
+            }
+        } else {
+            str = r.readLine();
+        }
+
+        match(str,          "----------------------------");
+        match(r.readLine(), "Contents of C2 compile queue");
+        match(r.readLine(), "----------------------------");
+        str = r.readLine();
+        if (!str.equals("Empty")) {
+            while (str.charAt(0) != '-') {
+                validateMethodLine(str);
+                str = r.readLine();
+            }
+        } else {
+            str = r.readLine();
+        }
+        match(str, "----------------------------");
+    }
+
+    private static void validateMethodLine(String str)  throws Exception {
+        String name = str.substring(19);
+        int sep = name.indexOf("::");
+        try {
+            Class.forName(name.substring(0, sep));
+        } catch (ClassNotFoundException e) {
+            throw new Exception("Failed parsing dcmd queue");
+        }
+    }
+
+    public static void match(String line, String str) throws Exception {
+        if (!line.equals(str)) {
+            throw new Exception("String equals: " + line + ", " + str);
+        }
+    }
+}
\ No newline at end of file
diff --git a/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java b/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
new file mode 100644
index 000000000..0ad5d59e7
--- /dev/null
+++ b/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+public class MethodIdentifierParser {
+
+    private String logString;
+    private String className;
+    private String methodName;
+    private String methodDescriptor;
+
+    /**
+     * This is a utility class for parsing the log entries for a method. It supplies
+     * a few select methods for reflecting the class and method from that information.
+     *
+     * Example log entries:
+     * "java.util.TreeMap.successor(Ljava/util/TreeMap$Entry;)Ljava/util/TreeMap$Entry;"
+     */
+
+    public MethodIdentifierParser(String logString) {
+        this.logString = logString;
+
+        int i      = logString.lastIndexOf("."); // find start of method name
+        className  = logString.substring(0, i);  // classname is everything before
+        int i2     = logString.indexOf("(");     // Signature starts with an '('
+        methodName = logString.substring(i+1, i2);
+        methodDescriptor  = logString.substring(i2, logString.length());
+
+        // Add sanity check for extracted fields
+    }
+
+    public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException, Exception {
+        try {
+            return Class.forName(className).getDeclaredMethod(methodName, getParamenterDescriptorArray());
+        } catch (UnexpectedTokenException e) {
+            throw new Exception("Parse failed");
+        }
+    }
+
+    public Class<?>[] getParamenterDescriptorArray() throws ClassNotFoundException, UnexpectedTokenException {
+        ParameterDecriptorIterator s = new ParameterDecriptorIterator(methodDescriptor);
+        Class<?> paramType;
+        ArrayList<Class<?>> list = new ArrayList<Class<?>>();
+        while ((paramType = s.nextParamType()) != null) {
+            list.add(paramType);
+        }
+        if (list.size() > 0) {
+            return list.toArray(new Class<?>[list.size()]);
+        } else {
+            return null;
+        }
+    }
+
+    class ParameterDecriptorIterator {
+
+        // This class uses charAt() indexing for startMark and i
+        // That is when i points to the last char it can be retrieved with
+        // charAt(i). Including the last char for a subString requires
+        // substring(startMark, i+1);
+
+        private String methodDescriptor;
+        private int startMark;
+
+        public ParameterDecriptorIterator(String signature) {
+            this.methodDescriptor = signature;
+            this.startMark = 0;
+            if (signature.charAt(0) == '(') {
+                this.startMark = 1;
+            }
+        }
+
+        public Class<?> nextParamType() throws UnexpectedTokenException {
+            int i = startMark;
+            while (methodDescriptor.length() > i) {
+                switch (methodDescriptor.charAt(i)) {
+                    case 'C':
+                    case 'B':
+                    case 'I':
+                    case 'J':
+                    case 'Z':
+                    case 'F':
+                    case 'D':
+                    case 'S':
+                        // Primitive class case, but we may have gotten here with [ as first token
+                        break;
+                    case 'L':
+                        // Internal class name suffixed by ';'
+                        while (methodDescriptor.charAt(i) != ';') {
+                            i++;
+                        }
+                        break;
+                    case '[':
+                        i++;         // arrays -> do another pass
+                        continue;
+                    case ')':
+                        return null; // end found
+                    case 'V':
+                    case ';':
+                    default:
+                        throw new UnexpectedTokenException(methodDescriptor, i);
+                }
+                break;
+            }
+            if (i == startMark) {
+                // Single char -> primitive class case
+                startMark++; // Update for next iteration
+                switch (methodDescriptor.charAt(i)) {
+                    case 'C':
+                        return char.class;
+                    case 'B':
+                        return byte.class;
+                    case 'I':
+                        return int.class;
+                    case 'J':
+                        return long.class;
+                    case 'F':
+                        return float.class;
+                    case 'D':
+                        return double.class;
+                    case 'S':
+                        return short.class;
+                    case 'Z':
+                        return boolean.class;
+                    default:
+                        throw new UnexpectedTokenException(methodDescriptor, i);
+                }
+            } else {
+                // Multi char case
+                String nextParam;
+                if (methodDescriptor.charAt(startMark) == 'L') {
+                    // When reflecting a class the leading 'L' and trailing';' must be removed.
+                    // (When reflecting an array of classes, they must remain...)
+                    nextParam = methodDescriptor.substring(startMark+1, i);
+                } else {
+                    // Any kind of array - simple case, use whole descriptor when reflecting.
+                    nextParam = methodDescriptor.substring(startMark, i+1);
+                }
+                startMark = ++i; // Update for next iteration
+                try {
+                    // The parameter descriptor uses JVM internal class identifier with '/' as
+                    // package separator, but Class.forName expects '.'.
+                    nextParam = nextParam.replace('/', '.');
+                    return Class.forName(nextParam);
+                } catch (ClassNotFoundException e) {
+                    System.out.println("Class not Found: " + nextParam);
+                    return null;
+                }
+            }
+        }
+    }
+
+    class UnexpectedTokenException extends Exception {
+        String descriptor;
+        int i;
+        public UnexpectedTokenException(String descriptor, int i) {
+            this.descriptor = descriptor;
+            this.i = i;
+        }
+
+        @Override
+        public String toString() {
+            return "Unexpected token at: " + i + " in signature: " + descriptor;
+        }
+
+        private static final long serialVersionUID = 1L;
+    }
+
+    public void debugPrint() {
+        System.out.println("mlf in:               " + logString);
+        System.out.println("mlf class:            " + className);
+        System.out.println("mlf method:           " + methodName);
+        System.out.println("mlf methodDescriptor: " + methodDescriptor);
+    }
+}
\ No newline at end of file
-- 
2.22.0

