8054889: Compiler team's implementation task
Summary: Adding three new diagnostic commands for compiler
Reviewed-by: anoll, kvn, drchase
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp Wed Sep 10 13:27:33 2014 +0200
@@ -926,7 +926,7 @@
#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");
--- a/hotspot/src/share/vm/code/codeCache.cpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Sep 10 13:27:33 2014 +0200
@@ -249,6 +249,7 @@
#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) {
@@ -969,6 +970,25 @@
}
}
+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 "'",
--- a/hotspot/src/share/vm/code/codeCache.hpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Sep 10 13:27:33 2014 +0200
@@ -152,6 +152,10 @@
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(); }
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Sep 10 13:27:33 2014 +0200
@@ -166,7 +166,7 @@
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);
}
@@ -328,7 +328,6 @@
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);
@@ -338,18 +337,6 @@
}
// ------------------------------------------------------------------
-// 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
//
// This function is called by fatal error handler when the thread
@@ -367,19 +354,18 @@
// ------------------------------------------------------------------
// 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);
}
-
// ------------------------------------------------------------------
// 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
}
@@ -428,7 +414,7 @@
if (msg != NULL) {
st->print(" %s", msg);
}
- if (!short_form) {
+ if (cr) {
st->cr();
}
}
@@ -494,9 +480,9 @@
// ------------------------------------------------------------------
// 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);
}
// ------------------------------------------------------------------
@@ -621,7 +607,9 @@
// 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();
@@ -786,24 +774,40 @@
}
}
-#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("----------------------------");
}
-#endif // PRODUCT
+
+void CompileQueue::print_tty() {
+ ttyLocker ttyl;
+ print(tty);
+}
CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
@@ -1068,11 +1072,11 @@
#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);
}
@@ -1892,7 +1896,7 @@
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
if (PrintCompilation) {
ResourceMark rm;
- task->print_line();
+ task->print_tty();
}
elapsedTimer time;
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Sep 10 13:27:33 2014 +0200
@@ -111,14 +111,14 @@
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 @@
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);
@@ -234,7 +233,8 @@
// 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");
@@ -341,7 +341,7 @@
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level);
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,
@@ -369,11 +369,8 @@
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);
@@ -390,6 +387,7 @@
}
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;
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Sep 10 13:27:33 2014 +0200
@@ -2473,7 +2473,7 @@
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") \
\
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Sep 10 13:27:33 2014 +0200
@@ -470,3 +470,15 @@
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);
+}
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Sep 10 13:27:33 2014 +0200
@@ -99,6 +99,9 @@
template(RotateGCLog) \
template(WhiteBoxOperation) \
template(ClassLoaderStatsOperation) \
+ template(PrintCompileQueue) \
+ template(PrintCodeList) \
+ template(PrintCodeCache) \
class VM_Operation: public CHeapObj<mtInternal> {
public:
@@ -413,4 +416,35 @@
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
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Sep 10 13:27:33 2014 +0200
@@ -60,6 +60,9 @@
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));
+ 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));
// Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an
@@ -674,3 +677,18 @@
}
}
+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);
+}
+
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Sep 10 19:08:17 2014 -0700
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Sep 10 13:27:33 2014 +0200
@@ -399,4 +399,68 @@
}
};
+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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/CodeCacheTest.java Wed Sep 10 13:27:33 2014 +0200
@@ -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");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/CodelistTest.java Wed Sep 10 13:27:33 2014 +0200
@@ -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;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/CompilerQueueTest.java Wed Sep 10 13:27:33 2014 +0200
@@ -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);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/MethodIdentifierParser.java Wed Sep 10 13:27:33 2014 +0200
@@ -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);
+ }
+}