mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-24 21:34:52 +02:00
8054889: Compiler team's implementation task
Adding three new diagnostic commands for compiler Reviewed-by: anoll, kvn, drchase
This commit is contained in:
parent
7275456c3a
commit
6062c2db15
14 changed files with 747 additions and 53 deletions
|
@ -926,7 +926,7 @@ void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if (!counter_changed && !PrintCompilation) {
|
if (!counter_changed && !PrintCompilation) {
|
||||||
// Print out the compile task that failed
|
// Print out the compile task that failed
|
||||||
_task->print_line();
|
_task->print_tty();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
assert(counter_changed, "failed dependencies, but counter didn't change");
|
assert(counter_changed, "failed dependencies, but counter didn't change");
|
||||||
|
|
|
@ -249,6 +249,7 @@ void CodeCache::commit(CodeBlob* cb) {
|
||||||
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
|
#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_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_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) {
|
bool CodeCache::contains(void *p) {
|
||||||
|
@ -969,6 +970,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) {
|
void CodeCache::log_state(outputStream* st) {
|
||||||
st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
|
st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
|
||||||
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
|
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
|
||||||
|
|
|
@ -152,6 +152,10 @@ class CodeCache : AllStatic {
|
||||||
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||||||
static void log_state(outputStream* st);
|
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
|
// The full limits of the codeCache
|
||||||
static address low_bound() { return (address) _heap->low_boundary(); }
|
static address low_bound() { return (address) _heap->low_boundary(); }
|
||||||
static address high_bound() { return (address) _heap->high_boundary(); }
|
static address high_bound() { return (address) _heap->high_boundary(); }
|
||||||
|
|
|
@ -166,7 +166,7 @@ class CompilationLog : public StringEventLog {
|
||||||
StringLogMessage lm;
|
StringLogMessage lm;
|
||||||
stringStream sstr = lm.stream();
|
stringStream sstr = lm.stream();
|
||||||
// msg.time_stamp().update_to(tty->time_stamp().ticks());
|
// 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);
|
log(thread, "%s", (const char*)lm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +328,6 @@ void CompileTask::set_code(nmethod* nm) {
|
||||||
if (nm == NULL) _code_handle = NULL; // drop the handle also
|
if (nm == NULL) _code_handle = NULL; // drop the handle also
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CompileTask::mark_on_stack() {
|
void CompileTask::mark_on_stack() {
|
||||||
// Mark these methods as something redefine classes cannot remove.
|
// Mark these methods as something redefine classes cannot remove.
|
||||||
_method->set_on_stack(true);
|
_method->set_on_stack(true);
|
||||||
|
@ -337,18 +336,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
|
// CompileTask::print_line_on_error
|
||||||
//
|
//
|
||||||
|
@ -367,19 +354,18 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// CompileTask::print_line
|
// CompileTask::print_line
|
||||||
void CompileTask::print_line() {
|
void CompileTask::print_tty() {
|
||||||
ttyLocker ttyl; // keep the following output all in one block
|
ttyLocker ttyl; // keep the following output all in one block
|
||||||
// print compiler name if requested
|
// print compiler name if requested
|
||||||
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
|
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
|
||||||
print_compilation();
|
print_compilation(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// CompileTask::print_compilation_impl
|
// CompileTask::print_compilation_impl
|
||||||
void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
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,
|
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) {
|
if (!short_form) {
|
||||||
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
|
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
|
||||||
}
|
}
|
||||||
|
@ -428,7 +414,7 @@ void CompileTask::print_compilation_impl(outputStream* st, Method* method, int c
|
||||||
if (msg != NULL) {
|
if (msg != NULL) {
|
||||||
st->print(" %s", msg);
|
st->print(" %s", msg);
|
||||||
}
|
}
|
||||||
if (!short_form) {
|
if (cr) {
|
||||||
st->cr();
|
st->cr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,9 +480,9 @@ void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// CompileTask::print_compilation
|
// 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;
|
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 @@ void CompileQueue::add(CompileTask* task) {
|
||||||
// Mark the method as being in the compile queue.
|
// Mark the method as being in the compile queue.
|
||||||
task->method()->set_queued_for_compilation();
|
task->method()->set_queued_for_compilation();
|
||||||
|
|
||||||
NOT_PRODUCT(print();)
|
if (CIPrintCompileQueue) {
|
||||||
|
print_tty();
|
||||||
|
}
|
||||||
|
|
||||||
if (LogCompilation && xtty != NULL) {
|
if (LogCompilation && xtty != NULL) {
|
||||||
task->log_task_queued();
|
task->log_task_queued();
|
||||||
|
@ -786,24 +774,40 @@ void CompileQueue::mark_on_stack() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
/**
|
CompileQueue* CompileBroker::compile_queue(int comp_level) {
|
||||||
* Print entire compilation queue.
|
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
||||||
*/
|
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
||||||
void CompileQueue::print() {
|
return NULL;
|
||||||
if (CIPrintCompileQueue) {
|
}
|
||||||
ttyLocker ttyl;
|
|
||||||
tty->print_cr("Contents of %s", name());
|
|
||||||
tty->print_cr("----------------------");
|
void CompileBroker::print_compile_queues(outputStream* st) {
|
||||||
CompileTask* task = _first;
|
_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) {
|
while (task != NULL) {
|
||||||
task->print_line();
|
task->print_compilation(st, NULL, true, true);
|
||||||
task = task->next();
|
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) {
|
CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
|
||||||
|
|
||||||
|
@ -1068,11 +1072,11 @@ void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler
|
||||||
#endif // !ZERO && !SHARK
|
#endif // !ZERO && !SHARK
|
||||||
// Initialize the compilation queue
|
// Initialize the compilation queue
|
||||||
if (c2_compiler_count > 0) {
|
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);
|
_compilers[1]->set_num_compiler_threads(c2_compiler_count);
|
||||||
}
|
}
|
||||||
if (c1_compiler_count > 0) {
|
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);
|
_compilers[0]->set_num_compiler_threads(c1_compiler_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1892,7 +1896,7 @@ static void codecache_print(bool detailed)
|
||||||
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||||
if (PrintCompilation) {
|
if (PrintCompilation) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
task->print_line();
|
task->print_tty();
|
||||||
}
|
}
|
||||||
elapsedTimer time;
|
elapsedTimer time;
|
||||||
|
|
||||||
|
|
|
@ -111,14 +111,14 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||||
private:
|
private:
|
||||||
static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
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,
|
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:
|
public:
|
||||||
void print_compilation(outputStream* st = tty, 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) {
|
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(),
|
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,
|
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);
|
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);
|
static void print_inline_indent(int inline_level, outputStream* st = tty);
|
||||||
|
|
||||||
void print();
|
void print_tty();
|
||||||
void print_line();
|
|
||||||
void print_line_on_error(outputStream* st, char* buf, int buflen);
|
void print_line_on_error(outputStream* st, char* buf, int buflen);
|
||||||
|
|
||||||
void log_task(xmlStream* log);
|
void log_task(xmlStream* log);
|
||||||
|
@ -234,7 +233,8 @@ class CompileQueue : public CHeapObj<mtCompiler> {
|
||||||
// Redefine Classes support
|
// Redefine Classes support
|
||||||
void mark_on_stack();
|
void mark_on_stack();
|
||||||
void free_all();
|
void free_all();
|
||||||
NOT_PRODUCT (void print();)
|
void print_tty();
|
||||||
|
void print(outputStream* st = tty);
|
||||||
|
|
||||||
~CompileQueue() {
|
~CompileQueue() {
|
||||||
assert (is_empty(), " Compile Queue must be empty");
|
assert (is_empty(), " Compile Queue must be empty");
|
||||||
|
@ -341,7 +341,7 @@ class CompileBroker: AllStatic {
|
||||||
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
|
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_complete (methodHandle method, int osr_bci, int comp_level);
|
||||||
static bool compilation_is_prohibited(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 void preload_classes (methodHandle method, TRAPS);
|
||||||
|
|
||||||
static CompileTask* create_compile_task(CompileQueue* queue,
|
static CompileTask* create_compile_task(CompileQueue* queue,
|
||||||
|
@ -369,11 +369,8 @@ class CompileBroker: AllStatic {
|
||||||
int hot_count,
|
int hot_count,
|
||||||
const char* comment,
|
const char* comment,
|
||||||
Thread* thread);
|
Thread* thread);
|
||||||
static CompileQueue* compile_queue(int comp_level) {
|
|
||||||
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
static CompileQueue* compile_queue(int comp_level);
|
||||||
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static bool init_compiler_runtime();
|
static bool init_compiler_runtime();
|
||||||
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
|
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
|
||||||
|
|
||||||
|
@ -390,6 +387,7 @@ class CompileBroker: AllStatic {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool compilation_is_in_queue(methodHandle method);
|
static bool compilation_is_in_queue(methodHandle method);
|
||||||
|
static void print_compile_queues(outputStream* st);
|
||||||
static int queue_size(int comp_level) {
|
static int queue_size(int comp_level) {
|
||||||
CompileQueue *q = compile_queue(comp_level);
|
CompileQueue *q = compile_queue(comp_level);
|
||||||
return q != NULL ? q->size() : 0;
|
return q != NULL ? q->size() : 0;
|
||||||
|
|
|
@ -2473,7 +2473,7 @@ class CommandLineFlags {
|
||||||
develop(bool, CIPrintCompilerName, false, \
|
develop(bool, CIPrintCompilerName, false, \
|
||||||
"when CIPrint is active, print the name of the active compiler") \
|
"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 " \
|
"display the contents of the compile queue whenever a " \
|
||||||
"compilation is enqueued") \
|
"compilation is enqueued") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -470,3 +470,15 @@ void VM_Exit::wait_if_vm_exited() {
|
||||||
ShouldNotReachHere();
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -99,6 +99,9 @@
|
||||||
template(RotateGCLog) \
|
template(RotateGCLog) \
|
||||||
template(WhiteBoxOperation) \
|
template(WhiteBoxOperation) \
|
||||||
template(ClassLoaderStatsOperation) \
|
template(ClassLoaderStatsOperation) \
|
||||||
|
template(PrintCompileQueue) \
|
||||||
|
template(PrintCodeList) \
|
||||||
|
template(PrintCodeCache) \
|
||||||
|
|
||||||
class VM_Operation: public CHeapObj<mtInternal> {
|
class VM_Operation: public CHeapObj<mtInternal> {
|
||||||
public:
|
public:
|
||||||
|
@ -413,4 +416,35 @@ class VM_RotateGCLog: public VM_Operation {
|
||||||
void doit() { gclog_or_tty->rotate_log(true, _out); }
|
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
|
#endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
|
||||||
|
|
|
@ -60,6 +60,9 @@ void DCmdRegistrant::register_dcmds(){
|
||||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
|
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<RotateGCLogDCmd>(full_export, true, false));
|
||||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(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
|
// Enhanced JMX Agent Support
|
||||||
// These commands won't be exported via the DiagnosticCommandMBean until an
|
// These commands won't be exported via the DiagnosticCommandMBean until an
|
||||||
|
@ -674,3 +677,18 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -399,4 +399,68 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
|
||||||
|
|
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue