This commit is contained in:
Keith McGuigan 2008-04-11 09:56:35 -04:00
commit 680ecf1611
71 changed files with 3718 additions and 1476 deletions

View File

@ -1,3 +1,4 @@
^build/
^dist/
^nbproject/private/
^src/share/tools/hsdis/bin/

View File

@ -71,6 +71,7 @@ endif
# The following variables are defined in the generated flags.make file.
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
@ -81,6 +82,7 @@ CPPFLAGS = \
${BUILD_VERSION} \
${BUILD_TARGET} \
${BUILD_USER} \
${HS_LIB_ARCH} \
${JRE_VERSION} \
${VM_DISTRO}

View File

@ -12,6 +12,4 @@ lib_arch = amd64
compiler = gcc
gnu_dis_arch = amd64
sysdefs = -DLINUX -D_GNU_SOURCE -DAMD64

View File

@ -12,6 +12,4 @@ lib_arch = i386
compiler = gcc
gnu_dis_arch = i386
sysdefs = -DLINUX -D_GNU_SOURCE -DIA32

View File

@ -12,6 +12,4 @@ lib_arch = sparc
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DLINUX -D_GNU_SOURCE -DSPARC

View File

@ -63,6 +63,7 @@ endif
# The following variables are defined in the generated flags.make file.
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HS_BUILD_VER)\""
JRE_VERSION = -DJRE_RELEASE_VERSION="\"$(JRE_RELEASE_VER)\""
HS_LIB_ARCH = -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\"
BUILD_TARGET = -DHOTSPOT_BUILD_TARGET="\"$(TARGET)\""
BUILD_USER = -DHOTSPOT_BUILD_USER="\"$(HOTSPOT_BUILD_USER)\""
VM_DISTRO = -DHOTSPOT_VM_DISTRO="\"$(HOTSPOT_VM_DISTRO)\""
@ -73,6 +74,7 @@ CPPFLAGS = \
${BUILD_VERSION} \
${BUILD_TARGET} \
${BUILD_USER} \
${HS_LIB_ARCH} \
${JRE_VERSION} \
${VM_DISTRO}

View File

@ -12,6 +12,4 @@ lib_arch = amd64
compiler = sparcWorks
gnu_dis_arch = amd64
sysdefs = -DSOLARIS -DSPARC_WORKS -DAMD64

View File

@ -12,6 +12,4 @@ lib_arch = amd64
compiler = gcc
gnu_dis_arch = amd64
sysdefs = -DSOLARIS -D_GNU_SOURCE -DAMD64

View File

@ -12,6 +12,4 @@ lib_arch = i386
compiler = sparcWorks
gnu_dis_arch = i386
sysdefs = -DSOLARIS -DSPARC_WORKS -DIA32

View File

@ -12,6 +12,4 @@ lib_arch = i386
compiler = gcc
gnu_dis_arch = i386
sysdefs = -DSOLARIS -D_GNU_SOURCE -DIA32

View File

@ -12,6 +12,4 @@ lib_arch = sparc
compiler = sparcWorks
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC

View File

@ -12,6 +12,4 @@ lib_arch = sparc
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC

View File

@ -8,10 +8,8 @@ os_arch = solaris_sparc
os_arch_model = solaris_sparc
lib_arch = sparc
lib_arch = sparcv9
compiler = sparcWorks
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -DSPARC_WORKS -DSPARC

View File

@ -8,10 +8,8 @@ os_arch = solaris_sparc
os_arch_model = solaris_sparc
lib_arch = sparc
lib_arch = sparcv9
compiler = gcc
gnu_dis_arch = sparc
sysdefs = -DSOLARIS -D_GNU_SOURCE -DSPARC

View File

@ -58,6 +58,7 @@ CPP_FLAGS=$(CPP_FLAGS) /D "COMPILER1" /D "COMPILER2"
# The following variables are defined in the generated local.make file.
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_RELEASE_VERSION=\"$(HS_BUILD_VER)\""
CPP_FLAGS=$(CPP_FLAGS) /D "JRE_RELEASE_VERSION=\"$(JRE_RELEASE_VER)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_LIB_ARCH=\"$(BUILDARCH)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_TARGET=\"$(BUILD_FLAVOR)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\""
CPP_FLAGS=$(CPP_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\""

View File

@ -10,6 +10,6 @@ os_arch = windows_x86
os_arch_model = windows_x86_64
compiler = visCPP
lib_arch = amd64
gnu_dis_arch = amd64
compiler = visCPP

View File

@ -10,7 +10,6 @@ os_arch = windows_x86
os_arch_model = windows_x86_32
lib_arch = i386
compiler = visCPP
gnu_dis_arch = i386

View File

@ -1,230 +0,0 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler_sparc.cpp.incl"
#ifndef PRODUCT
#define SPARC_VERSION (VM_Version::v9_instructions_work()? \
(VM_Version::v8_instructions_work()? "" : "9") : "8")
// This routine is in the shared library:
typedef unsigned char* print_insn_sparc_t(unsigned char* start, DisassemblerEnv* env,
const char* sparc_version);
void* Disassembler::_library = NULL;
dll_func Disassembler::_print_insn_sparc = NULL;
bool Disassembler::load_library() {
if (_library == NULL) {
char buf[1024];
char ebuf[1024];
sprintf(buf, "disassembler%s", os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
if (_library != NULL) {
tty->print_cr("Loaded disassembler");
_print_insn_sparc = CAST_TO_FN_PTR(dll_func, hpi::dll_lookup(_library, "print_insn_sparc"));
}
}
return (_library != NULL) && (_print_insn_sparc != NULL);
}
class sparc_env : public DisassemblerEnv {
private:
nmethod* code;
outputStream* output;
const char* version;
static void print_address(address value, outputStream* st);
public:
sparc_env(nmethod* rcode, outputStream* routput) {
code = rcode;
output = routput;
version = SPARC_VERSION;
}
const char* sparc_version() { return version; }
void print_label(intptr_t value);
void print_raw(char* str) { output->print_raw(str); }
void print(char* format, ...);
char* string_for_offset(intptr_t value);
char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
};
void sparc_env::print_address(address adr, outputStream* st) {
if (!Universe::is_fully_initialized()) {
st->print(INTPTR_FORMAT, (intptr_t)adr);
return;
}
if (StubRoutines::contains(adr)) {
StubCodeDesc *desc = StubCodeDesc::desc_for(adr);
if (desc == NULL)
desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
if (desc == NULL)
st->print("Unknown stub at " INTPTR_FORMAT, adr);
else {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
}
} else {
BarrierSet* bs = Universe::heap()->barrier_set();
if (bs->kind() == BarrierSet::CardTableModRef &&
adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
st->print("word_map_base");
if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
} else {
st->print(INTPTR_FORMAT, (intptr_t)adr);
}
}
}
// called by the disassembler to print out jump addresses
void sparc_env::print_label(intptr_t value) {
print_address((address) value, output);
}
void sparc_env::print(char* format, ...) {
va_list ap;
va_start(ap, format);
output->vprint(format, ap);
va_end(ap);
}
char* sparc_env::string_for_offset(intptr_t value) {
stringStream st;
print_address((address) value, &st);
return st.as_string();
}
char* sparc_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
stringStream st;
oop obj;
if (code && (obj = code->embeddedOop_at(pc)) != NULL) {
obj->print_value_on(&st);
} else
{
print_address((address) value, &st);
}
return st.as_string();
}
address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
const char* version = ((sparc_env*)env)->sparc_version();
return ((print_insn_sparc_t*) _print_insn_sparc)(start, env, version);
}
const int show_bytes = false; // for disassembler debugging
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
decode(cb->instructions_begin(), cb->instructions_end(), st);
}
void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
assert ((((intptr_t)begin | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
st = st ? st : tty;
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
sparc_env env(NULL, st);
unsigned char* p = (unsigned char*) begin;
CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
while (p < (unsigned char*) end && p) {
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
unsigned char* p0 = p;
st->print(INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
if (show_bytes && p) {
st->print("\t\t\t");
while (p0 < p) { st->print("%08lx ", *(int*)p0); p0 += sizeof(int); }
}
st->cr();
}
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
st->print("Code:");
st->cr();
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
sparc_env env(nm, st);
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
assert ((((intptr_t)p | (intptr_t)end) % sizeof(int) == 0), "misaligned insn addr");
unsigned char *p1 = p;
int total_bucket_count = 0;
while (p1 < end && p1) {
unsigned char *p0 = p1;
++p1;
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
while (p < end && p) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
nm->print_code_comment_on(st, 40, p0, p);
st->cr();
// Output pc bucket ticks if we have any
address bucket_pc = FlatProfiler::bucket_start_for(p);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
int bucket_count = FlatProfiler::bucket_count_for(p0);
tty->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_bucket_count, bucket_count);
tty->cr();
}
}
}
#endif // PRODUCT

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2008 Sun Microsystems, Inc. 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
@ -22,30 +22,11 @@
*
*/
// The disassembler prints out sparc code annotated
// with Java specific information.
static int pd_instruction_alignment() {
return sizeof(int);
}
class Disassembler {
#ifndef PRODUCT
private:
// points to the library.
static void* _library;
// points to the print_insn_sparc function.
static dll_func _print_insn_sparc;
// tries to load library and return whether it succedded.
static bool load_library();
// decodes one instruction and return the start of the next instruction.
static address decode_instruction(address start, DisassemblerEnv* env);
#endif
public:
static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
};
//Reconciliation History
// 1.9 98/04/29 10:45:51 disassembler_i486.hpp
// 1.10 98/05/11 16:47:20 disassembler_i486.hpp
// 1.12 99/06/22 16:37:37 disassembler_i486.hpp
// 1.13 99/08/06 10:09:04 disassembler_i486.hpp
//End
static const char* pd_cpu_opts() {
return (VM_Version::v9_instructions_work()?
(VM_Version::v8_instructions_work()? "" : "v9only") : "v8only");
}

View File

@ -157,22 +157,158 @@ void RegisterMap::shift_individual_registers() {
check_location_valid();
}
bool frame::safe_for_sender(JavaThread *thread) {
address sp = (address)_sp;
if (sp != NULL &&
(sp <= thread->stack_base() && sp >= thread->stack_base() - thread->stack_size())) {
// Unfortunately we can only check frame complete for runtime stubs and nmethod
// other generic buffer blobs are more problematic so we just assume they are
// ok. adapter blobs never have a frame complete and are never ok.
if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
}
}
return true;
address _SP = (address) sp();
address _FP = (address) fp();
address _UNEXTENDED_SP = (address) unextended_sp();
// sp must be within the stack
bool sp_safe = (_SP <= thread->stack_base()) &&
(_SP >= thread->stack_base() - thread->stack_size());
if (!sp_safe) {
return false;
}
return false;
// unextended sp must be within the stack and above or equal sp
bool unextended_sp_safe = (_UNEXTENDED_SP <= thread->stack_base()) &&
(_UNEXTENDED_SP >= _SP);
if (!unextended_sp_safe) return false;
// an fp must be within the stack and above (but not equal) sp
bool fp_safe = (_FP <= thread->stack_base()) &&
(_FP > _SP);
// We know sp/unextended_sp are safe only fp is questionable here
// If the current frame is known to the code cache then we can attempt to
// to construct the sender and do some validation of it. This goes a long way
// toward eliminating issues when we get in frame construction code
if (_cb != NULL ) {
// First check if frame is complete and tester is reliable
// Unfortunately we can only check frame complete for runtime stubs and nmethod
// other generic buffer blobs are more problematic so we just assume they are
// ok. adapter blobs never have a frame complete and are never ok.
if (!_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
}
}
// Entry frame checks
if (is_entry_frame()) {
// an entry frame must have a valid fp.
if (!fp_safe) {
return false;
}
// Validate the JavaCallWrapper an entry frame must have
address jcw = (address)entry_frame_call_wrapper();
bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > _FP);
return jcw_safe;
}
intptr_t* younger_sp = sp();
intptr_t* _SENDER_SP = sender_sp(); // sender is actually just _FP
bool adjusted_stack = is_interpreted_frame();
address sender_pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset;
// We must always be able to find a recognizable pc
CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
if (sender_pc == NULL || sender_blob == NULL) {
return false;
}
// It should be safe to construct the sender though it might not be valid
frame sender(_SENDER_SP, younger_sp, adjusted_stack);
// Do we have a valid fp?
address sender_fp = (address) sender.fp();
// an fp must be within the stack and above (but not equal) current frame's _FP
bool sender_fp_safe = (sender_fp <= thread->stack_base()) &&
(sender_fp > _FP);
if (!sender_fp_safe) {
return false;
}
// If the potential sender is the interpreter then we can do some more checking
if (Interpreter::contains(sender_pc)) {
return sender.is_interpreted_frame_valid(thread);
}
// Could just be some random pointer within the codeBlob
if (!sender.cb()->instructions_contains(sender_pc)) return false;
// We should never be able to see an adapter if the current frame is something from code cache
if ( sender_blob->is_adapter_blob()) {
return false;
}
if( sender.is_entry_frame()) {
// Validate the JavaCallWrapper an entry frame must have
address jcw = (address)sender.entry_frame_call_wrapper();
bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > sender_fp);
return jcw_safe;
}
// If the frame size is 0 something is bad because every nmethod has a non-zero frame size
// because you must allocate window space
if (sender_blob->frame_size() == 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
return false;
}
// The sender should positively be an nmethod or call_stub. On sparc we might in fact see something else.
// The cause of this is because at a save instruction the O7 we get is a leftover from an earlier
// window use. So if a runtime stub creates two frames (common in fastdebug/jvmg) then we see the
// stale pc. So if the sender blob is not something we'd expect we have little choice but to declare
// the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding
// that initial frame and retrying.
if (!sender_blob->is_nmethod()) {
return false;
}
// Could put some more validation for the potential non-interpreted sender
// frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
// One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
// We've validated the potential sender that would be created
return true;
}
// Must be native-compiled frame. Since sender will try and use fp to find
// linkages it must be safe
if (!fp_safe) return false;
// could try and do some more potential verification of native frame if we could think of some...
return true;
}
// constructors
@ -450,7 +586,7 @@ void frame::pd_gc_epilog() {
}
bool frame::is_interpreted_frame_valid() const {
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
#ifdef CC_INTERP
// Is there anything to do?
#else
@ -462,6 +598,7 @@ bool frame::is_interpreted_frame_valid() const {
if (sp() == 0 || (intptr_t(sp()) & (2*wordSize-1)) != 0) {
return false;
}
const intptr_t interpreter_frame_initial_sp_offset = interpreter_frame_vm_local_words;
if (fp() + interpreter_frame_initial_sp_offset < sp()) {
return false;
@ -471,9 +608,43 @@ bool frame::is_interpreted_frame_valid() const {
if (fp() <= sp()) { // this attempts to deal with unsigned comparison above
return false;
}
if (fp() - sp() > 4096) { // stack frames shouldn't be large.
// do some validation of frame elements
// first the method
methodOop m = *interpreter_frame_method_addr();
// validate the method we'd find in this potential sender
if (!Universe::heap()->is_valid_method(m)) return false;
// stack frames shouldn't be much larger than max_stack elements
if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) {
return false;
}
// validate bci/bcx
intptr_t bcx = interpreter_frame_bcx();
if (m->validate_bci_from_bcx(bcx) < 0) {
return false;
}
// validate constantPoolCacheOop
constantPoolCacheOop cp = *interpreter_frame_cache_addr();
if (cp == NULL ||
!Space::is_aligned(cp) ||
!Universe::heap()->is_permanent((void*)cp)) return false;
// validate locals
address locals = (address) *interpreter_frame_locals_addr();
if (locals > thread->stack_base() || locals < (address) fp()) return false;
// We'd have to be pretty unlucky to be mislead at this point
#endif /* CC_INTERP */
return true;
}

View File

@ -1,201 +0,0 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler_x86.cpp.incl"
#ifndef PRODUCT
void* Disassembler::_library = NULL;
Disassembler::decode_func Disassembler::_decode_instruction = NULL;
bool Disassembler::load_library() {
if (_library == NULL) {
char buf[1024];
char ebuf[1024];
sprintf(buf, "disassembler%s", os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
if (_library != NULL) {
tty->print_cr("Loaded disassembler");
_decode_instruction = CAST_TO_FN_PTR(Disassembler::decode_func, hpi::dll_lookup(_library, "decode_instruction"));
}
}
return (_library != NULL) && (_decode_instruction != NULL);
}
class x86_env : public DisassemblerEnv {
private:
nmethod* code;
outputStream* output;
public:
x86_env(nmethod* rcode, outputStream* routput) {
code = rcode;
output = routput;
}
void print_label(intptr_t value);
void print_raw(char* str) { output->print_raw(str); }
void print(char* format, ...);
char* string_for_offset(intptr_t value);
char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal);
};
void x86_env::print_label(intptr_t value) {
if (!Universe::is_fully_initialized()) {
output->print(INTPTR_FORMAT, value);
return;
}
address adr = (address) value;
if (StubRoutines::contains(adr)) {
StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
const char * desc_name = "unknown stub";
if (desc != NULL) {
desc_name = desc->name();
}
output->print("Stub::%s", desc_name);
if (WizardMode) output->print(" " INTPTR_FORMAT, value);
} else {
output->print(INTPTR_FORMAT, value);
}
}
void x86_env::print(char* format, ...) {
va_list ap;
va_start(ap, format);
output->vprint(format, ap);
va_end(ap);
}
char* x86_env::string_for_offset(intptr_t value) {
stringStream st;
if (!Universe::is_fully_initialized()) {
st.print(INTX_FORMAT, value);
return st.as_string();
}
BarrierSet* bs = Universe::heap()->barrier_set();
BarrierSet::Name bsn = bs->kind();
if (bs->kind() == BarrierSet::CardTableModRef &&
(jbyte*) value == ((CardTableModRefBS*)(bs))->byte_map_base) {
st.print("word_map_base");
} else {
st.print(INTX_FORMAT, value);
}
return st.as_string();
}
char* x86_env::string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) {
stringStream st;
oop obj = NULL;
if (code && ((obj = code->embeddedOop_at(pc)) != NULL)) {
obj->print_value_on(&st);
} else {
if (is_decimal == 1) {
st.print(INTX_FORMAT, value);
} else {
st.print(INTPTR_FORMAT, value);
}
}
return st.as_string();
}
address Disassembler::decode_instruction(address start, DisassemblerEnv* env) {
return ((decode_func) _decode_instruction)(start, env);
}
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
decode(cb->instructions_begin(), cb->instructions_end(), st);
}
void Disassembler::decode(u_char* begin, u_char* end, outputStream* st) {
st = st ? st : tty;
const int show_bytes = false; // for disassembler debugging
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
x86_env env(NULL, st);
unsigned char* p = (unsigned char*) begin;
CodeBlob* cb = CodeCache::find_blob_unsafe(begin);
while (p < (unsigned char*) end) {
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
if (show_bytes) {
st->print("\t\t\t");
while (p0 < p) st->print("%x ", *p0++);
}
st->cr();
}
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
st = st ? st : tty;
st->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
st->print("Code:");
st->cr();
if (!load_library()) {
st->print_cr("Could not load disassembler");
return;
}
x86_env env(nm, st);
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
while (p < end) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
nm->print_block_comment(st, (intptr_t)(p - nm->instructions_begin()));
unsigned char* p0 = p;
st->print(" " INTPTR_FORMAT ": ", p);
p = decode_instruction(p, &env);
nm->print_code_comment_on(st, 40, p0, p);
st->cr();
// Output pc bucket ticks if we have any
address bucket_pc = FlatProfiler::bucket_start_for(p);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p) {
int bucket_count = FlatProfiler::bucket_count_for(bucket_pc);
tty->print_cr("[%d]", bucket_count);
}
}
}
#endif // PRODUCT

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-1999 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2008 Sun Microsystems, Inc. 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
@ -22,24 +22,10 @@
*
*/
// The disassembler prints out intel 386 code annotated
// with Java specific information.
static int pd_instruction_alignment() {
return 1;
}
class Disassembler {
#ifndef PRODUCT
private:
typedef address (*decode_func)(address start, DisassemblerEnv* env);
// points the library.
static void* _library;
// points to the decode function.
static decode_func _decode_instruction;
// tries to load library and return whether it succedded.
static bool load_library();
// decodes one instruction and return the start of the next instruction.
static address decode_instruction(address start, DisassemblerEnv* env);
#endif
public:
static void decode(CodeBlob *cb, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(nmethod* nm, outputStream* st = NULL) PRODUCT_RETURN;
static void decode(u_char* begin, u_char* end, outputStream* st = NULL) PRODUCT_RETURN;
};
static const char* pd_cpu_opts() {
return "";
}

View File

@ -37,39 +37,181 @@ bool frame::safe_for_sender(JavaThread *thread) {
address sp = (address)_sp;
address fp = (address)_fp;
address unextended_sp = (address)_unextended_sp;
bool sp_safe = (sp != NULL &&
(sp <= thread->stack_base()) &&
(sp >= thread->stack_base() - thread->stack_size()));
bool unextended_sp_safe = (unextended_sp != NULL &&
(unextended_sp <= thread->stack_base()) &&
(unextended_sp >= thread->stack_base() - thread->stack_size()));
bool fp_safe = (fp != NULL &&
(fp <= thread->stack_base()) &&
(fp >= thread->stack_base() - thread->stack_size()));
if (sp_safe && unextended_sp_safe && fp_safe) {
// sp must be within the stack
bool sp_safe = (sp <= thread->stack_base()) &&
(sp >= thread->stack_base() - thread->stack_size());
if (!sp_safe) {
return false;
}
// unextended sp must be within the stack and above or equal sp
bool unextended_sp_safe = (unextended_sp <= thread->stack_base()) &&
(unextended_sp >= sp);
if (!unextended_sp_safe) {
return false;
}
// an fp must be within the stack and above (but not equal) sp
bool fp_safe = (fp <= thread->stack_base()) && (fp > sp);
// We know sp/unextended_sp are safe only fp is questionable here
// If the current frame is known to the code cache then we can attempt to
// to construct the sender and do some validation of it. This goes a long way
// toward eliminating issues when we get in frame construction code
if (_cb != NULL ) {
// First check if frame is complete and tester is reliable
// Unfortunately we can only check frame complete for runtime stubs and nmethod
// other generic buffer blobs are more problematic so we just assume they are
// ok. adapter blobs never have a frame complete and are never ok.
if (_cb != NULL && !_cb->is_frame_complete_at(_pc)) {
if (!_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
}
}
// Entry frame checks
if (is_entry_frame()) {
// an entry frame must have a valid fp.
if (!fp_safe) return false;
// Validate the JavaCallWrapper an entry frame must have
address jcw = (address)entry_frame_call_wrapper();
bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > fp);
return jcw_safe;
}
intptr_t* sender_sp = NULL;
address sender_pc = NULL;
if (is_interpreted_frame()) {
// fp must be safe
if (!fp_safe) {
return false;
}
sender_pc = (address) this->fp()[return_addr_offset];
sender_sp = (intptr_t*) addr_at(sender_sp_offset);
} else {
// must be some sort of compiled/runtime frame
// fp does not have to be safe (although it could be check for c1?)
sender_sp = _unextended_sp + _cb->frame_size();
// On Intel the return_address is always the word on the stack
sender_pc = (address) *(sender_sp-1);
}
// We must always be able to find a recognizable pc
CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
if (sender_pc == NULL || sender_blob == NULL) {
return false;
}
// If the potential sender is the interpreter then we can do some more checking
if (Interpreter::contains(sender_pc)) {
// ebp is always saved in a recognizable place in any code we generate. However
// only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved ebp
// is really a frame pointer.
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
if (!saved_fp_safe) {
return false;
}
// construct the potential sender
frame sender(sender_sp, saved_fp, sender_pc);
return sender.is_interpreted_frame_valid(thread);
}
// Could just be some random pointer within the codeBlob
if (!sender_blob->instructions_contains(sender_pc)) return false;
// We should never be able to see an adapter if the current frame is something from code cache
if ( sender_blob->is_adapter_blob()) {
return false;
}
// Could be the call_stub
if (StubRoutines::returns_to_call_stub(sender_pc)) {
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
if (!saved_fp_safe) {
return false;
}
// construct the potential sender
frame sender(sender_sp, saved_fp, sender_pc);
// Validate the JavaCallWrapper an entry frame must have
address jcw = (address)sender.entry_frame_call_wrapper();
bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > (address)sender.fp());
return jcw_safe;
}
// If the frame size is 0 something is bad because every nmethod has a non-zero frame size
// because the return address counts against the callee's frame.
if (sender_blob->frame_size() == 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
return false;
}
// We should never be able to see anything here except an nmethod. If something in the
// code cache (current frame) is called by an entity within the code cache that entity
// should not be anything but the call stub (already covered), the interpreter (already covered)
// or an nmethod.
assert(sender_blob->is_nmethod(), "Impossible call chain");
// Could put some more validation for the potential non-interpreted sender
// frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
// One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb
// We've validated the potential sender that would be created
return true;
}
// Note: fp == NULL is not really a prerequisite for this to be safe to
// walk for c2. However we've modified the code such that if we get
// a failure with fp != NULL that we then try with FP == NULL.
// This is basically to mimic what a last_frame would look like if
// c2 had generated it.
if (sp_safe && unextended_sp_safe && fp == NULL) {
// frame must be complete if fp == NULL as fp == NULL is only sensible
// if we are looking at a nmethod and frame complete assures us of that.
if (_cb != NULL && _cb->is_frame_complete_at(_pc) && _cb->is_compiled_by_c2()) {
return true;
}
// Must be native-compiled frame. Since sender will try and use fp to find
// linkages it must be safe
if (!fp_safe) {
return false;
}
return false;
// Will the pc we fetch be non-zero (which we'll find at the oldest frame)
if ( (address) this->fp()[return_addr_offset] == NULL) return false;
// could try and do some more potential verification of native frame if we could think of some...
return true;
}
@ -292,7 +434,7 @@ void frame::pd_gc_epilog() {
// nothing done here now
}
bool frame::is_interpreted_frame_valid() const {
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
// QQQ
#ifdef CC_INTERP
#else
@ -312,9 +454,45 @@ bool frame::is_interpreted_frame_valid() const {
if (fp() <= sp()) { // this attempts to deal with unsigned comparison above
return false;
}
if (fp() - sp() > 4096) { // stack frames shouldn't be large.
// do some validation of frame elements
// first the method
methodOop m = *interpreter_frame_method_addr();
// validate the method we'd find in this potential sender
if (!Universe::heap()->is_valid_method(m)) return false;
// stack frames shouldn't be much larger than max_stack elements
if (fp() - sp() > 1024 + m->max_stack()*Interpreter::stackElementSize()) {
return false;
}
// validate bci/bcx
intptr_t bcx = interpreter_frame_bcx();
if (m->validate_bci_from_bcx(bcx) < 0) {
return false;
}
// validate constantPoolCacheOop
constantPoolCacheOop cp = *interpreter_frame_cache_addr();
if (cp == NULL ||
!Space::is_aligned(cp) ||
!Universe::heap()->is_permanent((void*)cp)) return false;
// validate locals
address locals = (address) *interpreter_frame_locals_addr();
if (locals > thread->stack_base() || locals < (address) fp()) return false;
// We'd have to be pretty unlucky to be mislead at this point
#endif // CC_INTERP
return true;
}

View File

@ -72,15 +72,20 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
_unextended_sp = sp;
_fp = fp;
_pc = (address)(sp[-1]);
assert(_pc != NULL, "no pc?");
_cb = CodeCache::find_blob(_pc);
// In case of native stubs, the pc retreived here might be
// wrong. (the _last_native_pc will have the right value)
// So do not put add any asserts on the _pc here.
// QQQ The above comment is wrong and has been wrong for years. This constructor
// should (and MUST) not be called in that situation. In the native situation
// the pc should be supplied to the constructor.
// Here's a sticky one. This constructor can be called via AsyncGetCallTrace
// when last_Java_sp is non-null but the pc fetched is junk. If we are truly
// unlucky the junk value could be to a zombied method and we'll die on the
// find_blob call. This is also why we can have no asserts on the validity
// of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler
// -> pd_last_frame should use a specialized version of pd_last_frame which could
// call a specilaized frame constructor instead of this one.
// Then we could use the assert below. However this assert is of somewhat dubious
// value.
// assert(_pc != NULL, "no pc?");
_cb = CodeCache::find_blob(_pc);
_deopt_state = not_deoptimized;
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
_pc = (((nmethod*)_cb)->get_original_pc(this));

View File

@ -1632,7 +1632,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
// We need to prepare to execute the OSR method. First we must
// migrate the locals and monitors off of the stack.
__ movl(rsi, rax); // save the nmethod
__ movl(rbx, rax); // save the nmethod
const Register thread = rcx;
__ get_thread(thread);
@ -1688,7 +1688,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
__ pushl(rdi);
// and begin the OSR nmethod
__ jmp(Address(rsi, nmethod::osr_entry_point_offset()));
__ jmp(Address(rbx, nmethod::osr_entry_point_offset()));
}
}
}

View File

@ -50,17 +50,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
// even if isInJava == true. It should be more reliable than
// ucontext info.
if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
#if 0
// This sanity check may not be needed with the new frame
// walking code. Remove it for now.
if (!jt->frame_anchor()->post_Java_state_is_pc()
&& frame::next_younger_sp_or_null(last_Java_sp(),
jt->frame_anchor()->post_Java_sp()) == NULL) {
// the anchor contains an SP, but the frame is not walkable
// because post_Java_sp isn't valid relative to last_Java_sp
return false;
}
#endif
*fr_addr = jt->pd_last_frame();
return true;
}
@ -77,23 +66,59 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
return false;
}
frame ret_frame(ret_sp, frame::unpatchable, addr.pc());
// we were running Java code when SIGPROF came in
if (isInJava) {
// If the frame we got is safe then it is most certainly valid
if (ret_frame.safe_for_sender(jt)) {
*fr_addr = ret_frame;
return true;
}
// If it isn't safe then we can try several things to try and get
// a good starting point.
//
// On sparc the frames are almost certainly walkable in the sense
// of sp/fp linkages. However because of recycling of windows if
// a piece of code does multiple save's where the initial save creates
// a real frame with a return pc and the succeeding save's are used to
// simply get free registers and have no real pc then the pc linkage on these
// "inner" temporary frames will be bogus.
// Since there is in general only a nesting level like
// this one deep in general we'll try and unwind such an "inner" frame
// here ourselves and see if it makes sense
frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr.pc());
if (unwind_frame.safe_for_sender(jt)) {
*fr_addr = unwind_frame;
return true;
}
// Well that didn't work. Most likely we're toast on this tick
// The previous code would try this. I think it is dubious in light
// of changes to safe_for_sender and the unwind trick above but
// if it gets us a safe frame who wants to argue.
// If we have a last_Java_sp, then the SIGPROF signal caught us
// right when we were transitioning from _thread_in_Java to a new
// JavaThreadState. We use last_Java_sp instead of the sp from
// the ucontext since it should be more reliable.
if (jt->has_last_Java_frame()) {
ret_sp = jt->last_Java_sp();
frame ret_frame2(ret_sp, frame::unpatchable, addr.pc());
if (ret_frame2.safe_for_sender(jt)) {
*fr_addr = ret_frame2;
return true;
}
}
// Implied else: we don't have a last_Java_sp so we use what we
// got from the ucontext.
frame ret_frame(ret_sp, frame::unpatchable, addr.pc());
if (!ret_frame.safe_for_sender(jt)) {
// nothing else to try if the frame isn't good
return false;
}
// This is the best we can do. We will only be able to decode the top frame
*fr_addr = ret_frame;
return true;
}
@ -105,17 +130,13 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
if (jt->has_last_Java_frame()) {
assert(!jt->frame_anchor()->walkable(), "case covered above");
if (jt->thread_state() == _thread_in_native) {
frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc());
if (!ret_frame.safe_for_sender(jt)) {
// nothing else to try if the frame isn't good
return false;
}
*fr_addr = ret_frame;
return true;
}
frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc());
*fr_addr = ret_frame;
return true;
}
// nothing else to try
return false;
// nothing else to try but what we found initially
*fr_addr = ret_frame;
return true;
}

View File

@ -212,7 +212,8 @@ frame os::current_frame() {
CAST_FROM_FN_PTR(address, os::current_frame));
if (os::is_first_C_frame(&myframe)) {
// stack is not walkable
return frame(NULL, NULL, NULL);
frame ret; // This will be a null useless frame
return ret;
} else {
return os::get_sender_for_C_frame(&myframe);
}

View File

@ -32,49 +32,53 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
assert(Thread::current() == this, "caller must be current thread");
assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
// If we have a last_Java_frame, then we should use it even if
// isInJava == true. It should be more reliable than ucontext info.
// last_Java_frame is always walkable and safe use it if we have it
if (jt->has_last_Java_frame()) {
*fr_addr = jt->pd_last_frame();
return true;
}
// At this point, we don't have a last_Java_frame, so
// we try to glean some information out of the ucontext
// if we were running Java code when SIGPROF came in.
if (isInJava) {
ucontext_t* uc = (ucontext_t*) ucontext;
ucontext_t* uc = (ucontext_t*) ucontext;
intptr_t* ret_fp;
intptr_t* ret_sp;
ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc,
&ret_sp, &ret_fp);
if (addr.pc() == NULL || ret_sp == NULL ) {
// ucontext wasn't useful
return false;
}
// We always want to use the initial frame we create from the ucontext as
// it certainly signals where we currently are. However that frame may not
// be safe for calling sender. In that case if we have a last_Java_frame
// then the forte walker will switch to that frame as the virtual sender
// for the frame we create here which is not sender safe.
intptr_t* ret_fp;
intptr_t* ret_sp;
ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, &ret_sp, &ret_fp);
// Something would really have to be screwed up to get a NULL pc
if (addr.pc() == NULL ) {
assert(false, "NULL pc from signal handler!");
return false;
frame ret_frame(ret_sp, ret_fp, addr.pc());
if (!ret_frame.safe_for_sender(jt)) {
#ifdef COMPILER2
frame ret_frame2(ret_sp, NULL, addr.pc());
if (!ret_frame2.safe_for_sender(jt)) {
// nothing else to try if the frame isn't good
return false;
}
ret_frame = ret_frame2;
#else
// nothing else to try if the frame isn't good
return false;
#endif /* COMPILER2 */
}
*fr_addr = ret_frame;
return true;
}
// nothing else to try
return false;
// If sp and fp are nonsense just leave them out
if ((address)ret_sp >= jt->stack_base() ||
(address)ret_sp < jt->stack_base() - jt->stack_size() ) {
ret_sp = NULL;
ret_fp = NULL;
} else {
// sp is reasonable is fp reasonable?
if ( (address)ret_fp >= jt->stack_base() || ret_fp < ret_sp) {
ret_fp = NULL;
}
}
frame ret_frame(ret_sp, ret_fp, addr.pc());
*fr_addr = ret_frame;
return true;
}

View File

@ -0,0 +1,135 @@
#
# Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
#
# Single gnu makefile for solaris, linux and windows (windows requires mks or
# cygwin).
ifeq ($(BINUTILS),)
# Pop all the way out of the workspace to look for binutils.
# ...You probably want to override this setting.
BINUTILS = $(shell cd ../../../../..;pwd)/binutils-2.17-$(LIBARCH)
endif
# Default arch; it is changed below as needed.
ARCH = i386
OS = $(shell uname)
CPPFLAGS += -I$(BINUTILS)/include -I$(BINUTILS)/bfd
CPPFLAGS += -DHOTSPOT_LIB_ARCH=\"$(LIBARCH)\" -DLIBARCH_$(LIBARCH)
CPPFLAGS += -DHOTSPOT_OS=\"$(OS)\" -DOS_$(OS)
## OS = SunOS ##
ifeq ($(OS),SunOS)
ARCH = $(shell uname -p)
OS = solaris
CC = cc
CCFLAGS += -Kpic -g
CCFLAGS/amd64 += -xarch=amd64
CCFLAGS/sparcv9 += -xarch=v9
CCFLAGS += $(CCFLAGS/$(LIBARCH))
DLDFLAGS += -G
OUTFLAGS += -o $@
LIB_EXT = .so
else
## OS = Linux ##
ifeq ($(OS),Linux)
CPU = $(shell uname -m)
ifeq ($(CPU),ia64)
ARCH = ia64
else
ifeq ($(CPU),x86_64)
CCFLAGS += -fPIC
endif # x86_64
endif # ia64
OS = linux
CC = gcc
CCFLAGS += -O
DLDFLAGS += -shared
OUTFLAGS += -o $@
LIB_EXT = .so
CPPFLAGS += -Iinclude -Iinclude/$(OS)_$(ARCH)/
## OS = Windows ##
else # !SunOS, !Linux => Windows
OS = win
CC = cl
#CPPFLAGS += /D"WIN32" /D"_WINDOWS" /D"DEBUG" /D"NDEBUG"
CCFLAGS += /nologo /MD /W3 /WX /O2 /Fo$(@:.dll=.obj) /Gi-
CCFLAGS += -Iinclude -Iinclude/gnu -Iinclude/$(OS)_$(ARCH)
CCFLAGS += /D"HOTSPOT_LIB_ARCH=\"$(LIBARCH)\""
DLDFLAGS += /dll /subsystem:windows /incremental:no \
/export:decode_instruction
OUTFLAGS += /link /out:$@
LIB_EXT = .dll
endif # Linux
endif # SunOS
LIBARCH = $(ARCH)
ifdef LP64
LIBARCH64/sparc = sparcv9
LIBARCH64/i386 = amd64
LIBARCH64 = $(LIBARCH64/$(ARCH))
ifneq ($(LIBARCH64),)
LIBARCH = $(LIBARCH64)
endif # LIBARCH64/$(ARCH)
endif # LP64
TARGET_DIR = bin/$(OS)
TARGET = $(TARGET_DIR)/hsdis-$(LIBARCH)$(LIB_EXT)
SOURCE = hsdis.c
LIBRARIES = $(BINUTILS)/bfd/libbfd.a \
$(BINUTILS)/opcodes/libopcodes.a \
$(BINUTILS)/libiberty/libiberty.a
DEMO_TARGET = $(TARGET_DIR)/hsdis-demo-$(LIBARCH)
DEMO_SOURCE = hsdis-demo.c
.PHONY: all clean demo both
all: $(TARGET) demo
both: all all64
%64:
$(MAKE) LP64=1 ${@:%64=%}
demo: $(TARGET) $(DEMO_TARGET)
$(LIBRARIES):
@echo "*** Please build binutils first; see ./README: ***"
@sed < ./README '1,/__________/d' | head -20
@echo "..."; exit 1
$(TARGET): $(SOURCE) $(LIBS) $(LIBRARIES) $(TARGET_DIR)
$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(SOURCE) $(DLDFLAGS) $(LIBRARIES)
$(DEMO_TARGET): $(DEMO_SOURCE) $(TARGET) $(TARGET_DIR)
$(CC) $(OUTFLAGS) $(CPPFLAGS) $(CCFLAGS) $(DEMO_SOURCE) $(LDFLAGS)
$(TARGET_DIR):
[ -d $@ ] || mkdir -p $@
clean:
rm -rf $(TARGET_DIR)

View File

@ -0,0 +1,95 @@
Copyright (c) 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
CA 95054 USA or visit www.sun.com if you need additional information or
have any questions.
________________________________________________________________________
'hsdis': A HotSpot plugin for disassembling dynamically generated code.
The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c)
are built independently of the HotSpot JVM.
To use the plugin with a JVM, you need a new version that can load it.
If the product mode of your JVM does not accept -XX:+PrintAssembly,
you do not have a version that is new enough.
* Building
To build this project you need a build of Gnu binutils to link against.
It is known to work with binutils 2.17.
The makefile looks for this build in $BINUTILS, or (if that is not set),
in .../binutils-2.17-$LIBARCH, where LIBARCH (as in HotSpot) is one of
the jre subdirectory keywords i386, amd64, sparc, sparcv9, etc.
To build Gnu binutils, first download a copy of the software:
http://directory.fsf.org/project/binutils/
Unpack the binutils tarball into an empty directory:
chdir ../../../../..
tar -xzf - < ../binutils-2.17.tar.gz
mv binutils-2.17 binutils-2.17-i386 #or binutils-2.17-sparc
cd binutils-2.17-i386
From inside that directory, run configure and make:
( export CFLAGS='-fPIC'
./configure i386-pc-elf )
gnumake
(Leave out or change the argument to configure if not on an i386 system.)
Next, untar again into another empty directory for the LP64 version:
chdir ..
tar -xzf - < ../binutils-2.17.tar.gz
mv binutils-2.17 binutils-2.17-amd64 #or binutils-2.17-sparcv9
cd binutils-2.17-amd64
From inside that directory, run configure for LP64 and make:
( export ac_cv_c_bigendian=no CFLAGS='-m64 -fPIC' LDFLAGS=-m64
./configure amd64-pc-elf )
gnumake
The -fPIC option is needed because the generated code will be
linked into the hsdid-$LIBARCH.so binary. If you miss the
option, the JVM will fail to load the disassembler.
You probably want two builds, one for 32 and one for 64 bits.
To build the 64-bit variation of a platforn, add LP64=1 to
the make command line for hsdis.
So, go back to the hsdis project and build:
chdir .../hsdis
gnumake
gnumake LP64=1
* Installing
Products are named like bin/$OS/hsdis-$LIBARCH.so.
You can install them on your LD_LIBRARY_PATH,
or inside of your JRE next to $LIBARCH/libjvm.so.
Now test:
export LD_LIBRARY_PATH .../hsdis/bin/solaris:$LD_LIBRARY_PATH
dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly'
dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes'
java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld
If the product mode of the JVM does not accept -XX:+PrintAssembly,
you do not have a version new enough to use the hsdis plugin.

View File

@ -0,0 +1,223 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* hsdis-demo.c -- dump a range of addresses as native instructions
This demonstrates the protocol required by the HotSpot PrintAssembly option.
*/
#include "hsdis.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void greet(const char*);
void disassemble(void*, void*);
void end_of_file();
const char* options = NULL;
int raw = 0;
int xml = 0;
int main(int ac, char** av) {
int greeted = 0;
int i;
for (i = 1; i < ac; i++) {
const char* arg = av[i];
if (arg[0] == '-') {
if (!strcmp(arg, "-xml"))
xml ^= 1;
else if (!strcmp(arg, "-raw"))
raw ^= 1;
else if (!strncmp(arg, "-options=", 9))
options = arg+9;
else
{ printf("Usage: %s [-xml] [name...]\n"); exit(2); }
continue;
}
greet(arg);
greeted = 1;
}
if (!greeted)
greet("world");
printf("...And now for something completely different:\n");
disassemble((void*) &main, (void*) &end_of_file);
printf("Cheers!\n");
}
void greet(const char* whom) {
printf("Hello, %s!\n", whom);
}
void end_of_file() { }
/* don't disassemble after this point... */
#include "dlfcn.h"
#ifdef HOTSPOT_LIB_ARCH
#define LIBARCH HOTSPOT_LIB_ARCH
#endif
#ifdef HOTSPOT_OS
#define OS HOTSPOT_OS
#endif
#define DECODE_INSTRUCTIONS_NAME "decode_instructions"
#define HSDIS_NAME "hsdis"
static void* decode_instructions_pv = 0;
static const char* hsdis_path[] = {
HSDIS_NAME".so",
#ifdef OS
"bin/"OS"/"HSDIS_NAME".so",
#endif
#ifdef LIBARCH
HSDIS_NAME"-"LIBARCH".so",
#ifdef OS
"bin/"OS"/"HSDIS_NAME"-"LIBARCH".so",
#endif
#endif
NULL
};
static const char* load_decode_instructions() {
void* dllib = NULL;
const char* *next_in_path = hsdis_path;
while (1) {
decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
if (decode_instructions_pv != NULL)
return NULL;
if (dllib != NULL)
return "plugin does not defined "DECODE_INSTRUCTIONS_NAME;
for (dllib = NULL; dllib == NULL; ) {
const char* next_lib = (*next_in_path++);
if (next_lib == NULL)
return "cannot find plugin "HSDIS_NAME".so";
dllib = dlopen(next_lib, RTLD_LAZY);
}
}
}
static const char* lookup(void* addr) {
#define CHECK_NAME(fn) \
if (addr == (void*) &fn) return #fn;
CHECK_NAME(main);
CHECK_NAME(greet);
return NULL;
}
/* does the event match the tag, followed by a null, space, or slash? */
#define MATCH(event, tag) \
(!strncmp(event, tag, sizeof(tag)-1) && \
(!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1])))
static const char event_cookie[] = "event_cookie"; /* demo placeholder */
static void* handle_event(void* cookie, const char* event, void* arg) {
#define NS_DEMO "demo:"
if (cookie != event_cookie)
printf("*** bad event cookie %p != %p\n", cookie, event_cookie);
if (xml) {
/* We could almost do a printf(event, arg),
but for the sake of a better demo,
we dress the result up as valid XML.
*/
const char* fmt = strchr(event, ' ');
int evlen = (fmt ? fmt - event : strlen(event));
if (!fmt) {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s>", evlen, event);
} else {
printf("</"NS_DEMO"%.*s>", evlen-1, event+1);
}
} else {
if (event[0] != '/') {
printf("<"NS_DEMO"%.*s", evlen, event);
printf(fmt, arg);
printf(">");
} else {
printf("<"NS_DEMO"%.*s_done", evlen-1, event+1);
printf(fmt, arg);
printf("/></"NS_DEMO"%.*s>", evlen-1, event+1);
}
}
}
if (MATCH(event, "insn")) {
const char* name = lookup(arg);
if (name) printf("%s:\n", name);
/* basic action for <insn>: */
printf(" %p\t", arg);
} else if (MATCH(event, "/insn")) {
/* basic action for </insn>:
(none, plugin puts the newline for us
*/
} else if (MATCH(event, "mach")) {
printf("Decoding for CPU '%s'\n", (char*) arg);
} else if (MATCH(event, "addr")) {
/* basic action for <addr/>: */
const char* name = lookup(arg);
if (name) {
printf("&%s (%p)", name, arg);
/* return non-null to notify hsdis not to print the addr */
return arg;
}
}
/* null return is always safe; can mean "I ignored it" */
return NULL;
}
#define fprintf_callback \
(decode_instructions_printf_callback_ftype)&fprintf
void disassemble(void* from, void* to) {
const char* err = load_decode_instructions();
if (err != NULL) {
printf("%s: %s\n", err, dlerror());
exit(1);
}
printf("Decoding from %p to %p...\n", from, to);
decode_instructions_ftype decode_instructions
= (decode_instructions_ftype) decode_instructions_pv;
void* res;
if (raw && xml) {
res = (*decode_instructions)(from, to, NULL, stdout, NULL, stdout, options);
} else if (raw) {
res = (*decode_instructions)(from, to, NULL, NULL, NULL, stdout, options);
} else {
res = (*decode_instructions)(from, to,
handle_event, (void*) event_cookie,
fprintf_callback, stdout,
options);
}
if (res != to)
printf("*** Result was %p!\n", res);
}

View File

@ -0,0 +1,499 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* hsdis.c -- dump a range of addresses as native instructions
This implements the plugin protocol required by the
HotSpot PrintAssembly option.
*/
#include "hsdis.h"
#include <sysdep.h>
#include <libiberty.h>
#include <bfd.h>
#include <dis-asm.h>
#ifndef bool
#define bool int
#define true 1
#define false 0
#endif /*bool*/
/* short names for stuff in hsdis.h */
typedef decode_instructions_event_callback_ftype event_callback_t;
typedef decode_instructions_printf_callback_ftype printf_callback_t;
/* disassemble_info.application_data object */
struct hsdis_app_data {
/* the arguments to decode_instructions */
uintptr_t start; uintptr_t end;
event_callback_t event_callback; void* event_stream;
printf_callback_t printf_callback; void* printf_stream;
bool losing;
/* the architecture being disassembled */
const char* arch_name;
const bfd_arch_info_type* arch_info;
/* the disassembler we are going to use: */
disassembler_ftype dfn;
struct disassemble_info dinfo; /* the actual struct! */
char mach_option[64];
char insn_options[256];
};
#define DECL_APP_DATA(dinfo) \
struct hsdis_app_data* app_data = (struct hsdis_app_data*) (dinfo)->application_data
#define DECL_EVENT_CALLBACK(app_data) \
event_callback_t event_callback = (app_data)->event_callback; \
void* event_stream = (app_data)->event_stream
#define DECL_PRINTF_CALLBACK(app_data) \
printf_callback_t printf_callback = (app_data)->printf_callback; \
void* printf_stream = (app_data)->printf_stream
static void print_help(struct hsdis_app_data* app_data,
const char* msg, const char* arg);
static void setup_app_data(struct hsdis_app_data* app_data,
const char* options);
static const char* format_insn_close(const char* close,
disassemble_info* dinfo,
char* buf, size_t bufsize);
void*
#ifdef DLL_ENTRY
DLL_ENTRY
#endif
decode_instructions(void* start_pv, void* end_pv,
event_callback_t event_callback_arg, void* event_stream_arg,
printf_callback_t printf_callback_arg, void* printf_stream_arg,
const char* options) {
struct hsdis_app_data app_data;
memset(&app_data, 0, sizeof(app_data));
app_data.start = (uintptr_t) start_pv;
app_data.end = (uintptr_t) end_pv;
app_data.event_callback = event_callback_arg;
app_data.event_stream = event_stream_arg;
app_data.printf_callback = printf_callback_arg;
app_data.printf_stream = printf_stream_arg;
setup_app_data(&app_data, options);
char buf[128];
{
/* now reload everything from app_data: */
DECL_EVENT_CALLBACK(&app_data);
DECL_PRINTF_CALLBACK(&app_data);
uintptr_t start = app_data.start;
uintptr_t end = app_data.end;
uintptr_t p = start;
(*event_callback)(event_stream, "insns", (void*)start);
(*event_callback)(event_stream, "mach name='%s'",
(void*) app_data.arch_info->printable_name);
if (app_data.dinfo.bytes_per_line != 0) {
(*event_callback)(event_stream, "format bytes-per-line='%p'/",
(void*)(intptr_t) app_data.dinfo.bytes_per_line);
}
while (p < end && !app_data.losing) {
(*event_callback)(event_stream, "insn", (void*) p);
/* reset certain state, so we can read it with confidence */
app_data.dinfo.insn_info_valid = 0;
app_data.dinfo.branch_delay_insns = 0;
app_data.dinfo.data_size = 0;
app_data.dinfo.insn_type = 0;
int size = (*app_data.dfn)((bfd_vma) p, &app_data.dinfo);
if (size > 0) p += size;
else app_data.losing = true;
const char* insn_close = format_insn_close("/insn", &app_data.dinfo,
buf, sizeof(buf));
(*event_callback)(event_stream, insn_close, (void*) p);
/* follow each complete insn by a nice newline */
(*printf_callback)(printf_stream, "\n");
}
(*event_callback)(event_stream, "/insns", (void*) p);
return (void*) p;
}
}
/* take the address of the function, for luck, and also test the typedef: */
const decode_instructions_ftype decode_instructions_address = &decode_instructions;
static const char* format_insn_close(const char* close,
disassemble_info* dinfo,
char* buf, size_t bufsize) {
if (!dinfo->insn_info_valid)
return close;
enum dis_insn_type itype = dinfo->insn_type;
int dsize = dinfo->data_size, delays = dinfo->branch_delay_insns;
if ((itype == dis_nonbranch && (dsize | delays) == 0)
|| (strlen(close) + 3*20 > bufsize))
return close;
const char* type = "unknown";
switch (itype) {
case dis_nonbranch: type = NULL; break;
case dis_branch: type = "branch"; break;
case dis_condbranch: type = "condbranch"; break;
case dis_jsr: type = "jsr"; break;
case dis_condjsr: type = "condjsr"; break;
case dis_dref: type = "dref"; break;
case dis_dref2: type = "dref2"; break;
}
strcpy(buf, close);
char* p = buf;
if (type) sprintf(p += strlen(p), " type='%s'", type);
if (dsize) sprintf(p += strlen(p), " dsize='%d'", dsize);
if (delays) sprintf(p += strlen(p), " delay='%d'", delays);
return buf;
}
/* handler functions */
static int
hsdis_read_memory_func(bfd_vma memaddr,
bfd_byte* myaddr,
unsigned int length,
struct disassemble_info* dinfo) {
uintptr_t memaddr_p = (uintptr_t) memaddr;
DECL_APP_DATA(dinfo);
if (memaddr_p + length > app_data->end) {
/* read is out of bounds */
return EIO;
} else {
memcpy(myaddr, (bfd_byte*) memaddr_p, length);
return 0;
}
}
static void
hsdis_print_address_func(bfd_vma vma, struct disassemble_info* dinfo) {
/* the actual value to print: */
void* addr_value = (void*) (uintptr_t) vma;
DECL_APP_DATA(dinfo);
DECL_EVENT_CALLBACK(app_data);
/* issue the event: */
void* result =
(*event_callback)(event_stream, "addr/", addr_value);
if (result == NULL) {
/* event declined */
generic_print_address(vma, dinfo);
}
}
/* configuration */
static void set_optional_callbacks(struct hsdis_app_data* app_data);
static void parse_caller_options(struct hsdis_app_data* app_data,
const char* caller_options);
static const char* native_arch_name();
static enum bfd_endian native_endian();
static const bfd_arch_info_type* find_arch_info(const char* arch_nane);
static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
/* to avoid malloc: */
bfd* empty_bfd, bfd_target* empty_xvec);
static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
void *stream,
fprintf_ftype fprintf_func,
bfd* bfd,
char* disassembler_options);
static void parse_fake_insn(disassembler_ftype dfn,
struct disassemble_info* dinfo);
static void setup_app_data(struct hsdis_app_data* app_data,
const char* caller_options) {
/* Make reasonable defaults for null callbacks.
A non-null stream for a null callback is assumed to be a FILE* for output.
Events are rendered as XML.
*/
set_optional_callbacks(app_data);
/* Look into caller_options for anything interesting. */
if (caller_options != NULL)
parse_caller_options(app_data, caller_options);
/* Discover which architecture we are going to disassemble. */
app_data->arch_name = &app_data->mach_option[0];
if (app_data->arch_name[0] == '\0')
app_data->arch_name = native_arch_name();
app_data->arch_info = find_arch_info(app_data->arch_name);
/* Make a fake bfd to hold the arch. and byteorder info. */
struct {
bfd_target empty_xvec;
bfd empty_bfd;
} buf;
bfd* native_bfd = get_native_bfd(app_data->arch_info,
/* to avoid malloc: */
&buf.empty_bfd, &buf.empty_xvec);
init_disassemble_info_from_bfd(&app_data->dinfo,
app_data->printf_stream,
app_data->printf_callback,
native_bfd,
app_data->insn_options);
/* Finish linking together the various callback blocks. */
app_data->dinfo.application_data = (void*) app_data;
app_data->dfn = disassembler(native_bfd);
app_data->dinfo.print_address_func = hsdis_print_address_func;
app_data->dinfo.read_memory_func = hsdis_read_memory_func;
if (app_data->dfn == NULL) {
const char* bad = app_data->arch_name;
static bool complained;
if (bad == &app_data->mach_option[0])
print_help(app_data, "bad mach=%s", bad);
else if (!complained)
print_help(app_data, "bad native mach=%s; please port hsdis to this platform", bad);
complained = true;
/* must bail out */
app_data->losing = true;
return;
}
parse_fake_insn(app_data->dfn, &app_data->dinfo);
}
/* ignore all events, return a null */
static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) {
return NULL;
}
/* print all events as XML markup */
static void* xml_event_callback(void* stream, const char* event, void* arg) {
FILE* fp = (FILE*) stream;
#define NS_PFX "dis:"
if (event[0] != '/') {
/* issue the tag, with or without a formatted argument */
fprintf(fp, "<"NS_PFX);
fprintf(fp, event, arg);
fprintf(fp, ">");
} else {
++event; /* skip slash */
const char* argp = strchr(event, ' ');
if (argp == NULL) {
/* no arguments; just issue the closing tag */
fprintf(fp, "</"NS_PFX"%s>", event);
} else {
/* split out the closing attributes as <dis:foo_done attr='val'/> */
int event_prefix = (argp - event);
fprintf(fp, "<"NS_PFX"%.*s_done", event_prefix, event);
fprintf(fp, argp, arg);
fprintf(fp, "/></"NS_PFX"%.*s>", event_prefix, event);
}
}
return NULL;
}
static void set_optional_callbacks(struct hsdis_app_data* app_data) {
if (app_data->printf_callback == NULL) {
int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf;
FILE* fprintf_stream = stdout;
app_data->printf_callback = (printf_callback_t) fprintf_callback;
if (app_data->printf_stream == NULL)
app_data->printf_stream = (void*) fprintf_stream;
}
if (app_data->event_callback == NULL) {
if (app_data->event_stream == NULL)
app_data->event_callback = &null_event_callback;
else
app_data->event_callback = &xml_event_callback;
}
}
static void parse_caller_options(struct hsdis_app_data* app_data, const char* caller_options) {
char* iop_base = app_data->insn_options;
char* iop_limit = iop_base + sizeof(app_data->insn_options) - 1;
char* iop = iop_base;
const char* p;
for (p = caller_options; p != NULL; ) {
const char* q = strchr(p, ',');
size_t plen = (q == NULL) ? strlen(p) : ((q++) - p);
if (plen == 4 && strncmp(p, "help", plen) == 0) {
print_help(app_data, NULL, NULL);
} else if (plen >= 5 && strncmp(p, "mach=", 5) == 0) {
char* mach_option = app_data->mach_option;
size_t mach_size = sizeof(app_data->mach_option);
mach_size -= 1; /*leave room for the null*/
if (plen > mach_size) plen = mach_size;
strncpy(mach_option, p, plen);
mach_option[plen] = '\0';
} else if (plen > 6 && strncmp(p, "hsdis-", 6)) {
// do not pass these to the next level
} else {
/* just copy it; {i386,sparc}-dis.c might like to see it */
if (iop > iop_base && iop < iop_limit) (*iop++) = ',';
if (iop + plen > iop_limit)
plen = iop_limit - iop;
strncpy(iop, p, plen);
iop += plen;
}
p = q;
}
}
static void print_help(struct hsdis_app_data* app_data,
const char* msg, const char* arg) {
DECL_PRINTF_CALLBACK(app_data);
if (msg != NULL) {
(*printf_callback)(printf_stream, "hsdis: ");
(*printf_callback)(printf_stream, msg, arg);
(*printf_callback)(printf_stream, "\n");
}
(*printf_callback)(printf_stream, "hsdis output options:\n");
if (printf_callback == (printf_callback_t) &fprintf)
disassembler_usage((FILE*) printf_stream);
else
disassembler_usage(stderr); /* better than nothing */
(*printf_callback)(printf_stream, " mach=<arch> select disassembly mode\n");
#if defined(LIBARCH_i386) || defined(LIBARCH_amd64)
(*printf_callback)(printf_stream, " mach=i386 select 32-bit mode\n");
(*printf_callback)(printf_stream, " mach=x86-64 select 64-bit mode\n");
(*printf_callback)(printf_stream, " suffix always print instruction suffix\n");
#endif
(*printf_callback)(printf_stream, " help print this message\n");
}
/* low-level bfd and arch stuff that binutils doesn't do for us */
static const bfd_arch_info_type* find_arch_info(const char* arch_name) {
const bfd_arch_info_type* arch_info = bfd_scan_arch(arch_name);
if (arch_info == NULL) {
extern const bfd_arch_info_type bfd_default_arch_struct;
arch_info = &bfd_default_arch_struct;
}
return arch_info;
}
static const char* native_arch_name() {
const char* res = HOTSPOT_LIB_ARCH;
#ifdef LIBARCH_amd64
res = "i386:x86-64";
#endif
#ifdef LIBARCH_sparc
res = "sparc:v8plusb";
#endif
#ifdef LIBARCH_sparc
res = "sparc:v8plusb";
#endif
#ifdef LIBARCH_sparcv9
res = "sparc:v9b";
#endif
if (res == NULL)
res = "HOTSPOT_LIB_ARCH is not set in Makefile!";
return res;
}
static enum bfd_endian native_endian() {
int32_t endian_test = 'x';
if (*(const char*) &endian_test == 'x')
return BFD_ENDIAN_LITTLE;
else
return BFD_ENDIAN_BIG;
}
static bfd* get_native_bfd(const bfd_arch_info_type* arch_info,
bfd* empty_bfd, bfd_target* empty_xvec) {
memset(empty_bfd, 0, sizeof(*empty_bfd));
memset(empty_xvec, 0, sizeof(*empty_xvec));
empty_xvec->flavour = bfd_target_unknown_flavour;
empty_xvec->byteorder = native_endian();
empty_bfd->xvec = empty_xvec;
empty_bfd->arch_info = arch_info;
return empty_bfd;
}
static int read_zero_data_only(bfd_vma ignore_p,
bfd_byte* myaddr, unsigned int length,
struct disassemble_info *ignore_info) {
memset(myaddr, 0, length);
return 0;
}
static int print_to_dev_null(void* ignore_stream, const char* ignore_format, ...) {
return 0;
}
/* Prime the pump by running the selected disassembler on a null input.
This forces the machine-specific disassembler to divulge invariant
information like bytes_per_line.
*/
static void parse_fake_insn(disassembler_ftype dfn,
struct disassemble_info* dinfo) {
typedef int (*read_memory_ftype)
(bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
struct disassemble_info *info);
read_memory_ftype read_memory_func = dinfo->read_memory_func;
fprintf_ftype fprintf_func = dinfo->fprintf_func;
dinfo->read_memory_func = &read_zero_data_only;
dinfo->fprintf_func = &print_to_dev_null;
(*dfn)(0, dinfo);
// put it back:
dinfo->read_memory_func = read_memory_func;
dinfo->fprintf_func = fprintf_func;
}
static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo,
void *stream,
fprintf_ftype fprintf_func,
bfd* abfd,
char* disassembler_options) {
init_disassemble_info(dinfo, stream, fprintf_func);
dinfo->flavour = bfd_get_flavour(abfd);
dinfo->arch = bfd_get_arch(abfd);
dinfo->mach = bfd_get_mach(abfd);
dinfo->disassembler_options = disassembler_options;
dinfo->octets_per_byte = bfd_octets_per_byte (abfd);
dinfo->skip_zeroes = sizeof(void*) * 2;
dinfo->skip_zeroes_at_end = sizeof(void*)-1;
dinfo->disassembler_needs_relocs = FALSE;
if (bfd_big_endian(abfd))
dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG;
else if (bfd_little_endian(abfd))
dinfo->display_endian = dinfo->endian = BFD_ENDIAN_LITTLE;
else
dinfo->endian = native_endian();
disassemble_init_for_target(dinfo);
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/* decode_instructions -- dump a range of addresses as native instructions
This implements the protocol required by the HotSpot PrintAssembly option.
The starting and ending addresses are within the current process's address space.
The option string, if not empty, is interpreted by the disassembler implementation.
The printf callback is 'fprintf' or any other workalike.
It is called as (*printf_callback)(printf_stream, "some format...", some, format, args).
The event callback receives an event tag (a string) and an argument (a void*).
It is called as (*event_callback)(event_stream, "tag", arg).
Events:
<insn pc='%p'> begin an instruction, at a given location
</insn pc='%d'> end an instruction, at a given location
<addr value='%p'/> emit the symbolic value of an address
A tag format is one of three basic forms: "tag", "/tag", "tag/",
where tag is a simple identifier, signifying (as in XML) a element start,
element end, and standalone element. (To render as XML, add angle brackets.)
*/
extern
#ifdef DLL_EXPORT
DLL_EXPORT
#endif
void* decode_instructions(void* start, void* end,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
/* convenience typedefs */
typedef void* (*decode_instructions_event_callback_ftype) (void*, const char*, void*);
typedef int (*decode_instructions_printf_callback_ftype) (void*, const char*, ...);
typedef void* (*decode_instructions_ftype) (void* start, void* end,
decode_instructions_event_callback_ftype event_callback,
void* event_stream,
decode_instructions_printf_callback_ftype printf_callback,
void* printf_stream,
const char* options);

View File

@ -947,6 +947,7 @@ void CodeComments::print_block_comment(outputStream* stream, intptr_t offset) {
if (_comments != NULL) {
CodeComment* c = _comments->find(offset);
while (c && c->offset() == offset) {
stream->bol();
stream->print(" ;; ");
stream->print_cr(c->comment());
c = c->next();

View File

@ -1015,7 +1015,6 @@ class BacktraceBuilder: public StackObj {
typeArrayOop _bcis;
int _index;
bool _dirty;
bool _done;
No_Safepoint_Verifier _nsv;
public:
@ -1029,12 +1028,10 @@ class BacktraceBuilder: public StackObj {
};
// constructor for new backtrace
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL) {
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _dirty(false) {
expand(CHECK);
_backtrace = _head;
_index = 0;
_dirty = false;
_done = false;
}
void flush() {

View File

@ -71,7 +71,22 @@ class CodeCache : AllStatic {
// what you are doing)
static CodeBlob* find_blob_unsafe(void* start) {
CodeBlob* result = (CodeBlob*)_heap->find_start(start);
assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob");
// this assert is too strong because the heap code will return the
// heapblock containing start. That block can often be larger than
// the codeBlob itself. If you look up an address that is within
// the heapblock but not in the codeBlob you will assert.
//
// Most things will not lookup such bad addresses. However
// AsyncGetCallTrace can see intermediate frames and get that kind
// of invalid address and so can a developer using hsfind.
//
// The more correct answer is to return NULL if blob_contains() returns
// false.
// assert(result == NULL || result->blob_contains((address)start), "found wrong CodeBlob");
if (result != NULL && !result->blob_contains((address)start)) {
result = NULL;
}
return result;
}

View File

@ -707,7 +707,9 @@ nmethod::nmethod(
" entry points must be same for static methods and vice versa");
}
bool printnmethods = PrintNMethods || CompilerOracle::has_option_string(_method, "PrintNMethods");
bool printnmethods = PrintNMethods
|| CompilerOracle::should_print(_method)
|| CompilerOracle::has_option_string(_method, "PrintNMethods");
if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) {
print_nmethod(printnmethods);
}
@ -798,7 +800,6 @@ void nmethod::print_on(outputStream* st, const char* title) const {
}
#ifndef PRODUCT
void nmethod::print_nmethod(bool printmethod) {
ttyLocker ttyl; // keep the following output all in one block
if (xtty != NULL) {
@ -831,7 +832,6 @@ void nmethod::print_nmethod(bool printmethod) {
xtty->tail("print_nmethod");
}
}
#endif
void nmethod::set_version(int v) {
@ -1870,6 +1870,7 @@ void nmethod::check_store() {
}
}
#endif // PRODUCT
// Printing operations
@ -1948,6 +1949,14 @@ void nmethod::print() const {
oops_size());
}
void nmethod::print_code() {
HandleMark hm;
ResourceMark m;
Disassembler::decode(this);
}
#ifndef PRODUCT
void nmethod::print_scopes() {
// Find the first pc desc for all scopes in the code and print it.
@ -1979,13 +1988,6 @@ void nmethod::print_dependencies() {
}
void nmethod::print_code() {
HandleMark hm;
ResourceMark m;
Disassembler().decode(this);
}
void nmethod::print_relocations() {
ResourceMark m; // in case methods get printed via the debugger
tty->print_cr("relocations:");
@ -2021,6 +2023,7 @@ void nmethod::print_pcs() {
}
}
#endif // PRODUCT
const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
RelocIterator iter(this, begin, end);
@ -2055,7 +2058,6 @@ const char* nmethod::reloc_string_for(u_char* begin, u_char* end) {
return have_one ? "other" : NULL;
}
// Return a the last scope in (begin..end]
ScopeDesc* nmethod::scope_desc_in(address begin, address end) {
PcDesc* p = pc_desc_near(begin+1);
@ -2078,29 +2080,26 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
address pc = base + om->offset();
if (pc > begin) {
if (pc <= end) {
st->fill_to(column);
if (st == tty) {
st->print("; OopMap ");
om->print();
tty->cr();
} else {
st->print_cr("; OopMap #%d offset:%d", i, om->offset());
}
st->move_to(column);
st->print("; ");
om->print_on(st);
}
break;
}
}
}
// Print any debug info present at this pc.
ScopeDesc* sd = scope_desc_in(begin, end);
if (sd != NULL) {
st->fill_to(column);
st->move_to(column);
if (sd->bci() == SynchronizationEntryBCI) {
st->print(";*synchronization entry");
} else {
if (sd->method().is_null()) {
tty->print("method is NULL");
st->print("method is NULL");
} else if (sd->method()->is_native()) {
tty->print("method is native");
st->print("method is native");
} else {
address bcp = sd->method()->bcp_from(sd->bci());
Bytecodes::Code bc = Bytecodes::java_code_at(bcp);
@ -2137,13 +2136,13 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
}
}
}
st->cr();
// Print all scopes
for (;sd != NULL; sd = sd->sender()) {
st->fill_to(column);
st->move_to(column);
st->print("; -");
if (sd->method().is_null()) {
tty->print("method is NULL");
st->print("method is NULL");
} else {
sd->method()->print_short_name(st);
}
@ -2161,17 +2160,19 @@ void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin,
const char* str = reloc_string_for(begin, end);
if (str != NULL) {
if (sd != NULL) st->cr();
st->fill_to(column);
st->move_to(column);
st->print("; {%s}", str);
}
int cont_offset = ImplicitExceptionTable(this).at(begin - instructions_begin());
if (cont_offset != 0) {
st->fill_to(column);
st->move_to(column);
st->print("; implicit exception: dispatches to " INTPTR_FORMAT, instructions_begin() + cont_offset);
}
}
#ifndef PRODUCT
void nmethod::print_value_on(outputStream* st) const {
print_on(st, "nmethod");
}

View File

@ -485,8 +485,8 @@ class nmethod : public CodeBlob {
void verify_interrupt_point(address interrupt_point);
// printing support
void print() const PRODUCT_RETURN;
void print_code() PRODUCT_RETURN;
void print() const;
void print_code();
void print_relocations() PRODUCT_RETURN;
void print_pcs() PRODUCT_RETURN;
void print_scopes() PRODUCT_RETURN;
@ -495,7 +495,7 @@ class nmethod : public CodeBlob {
void print_calls(outputStream* st) PRODUCT_RETURN;
void print_handler_table() PRODUCT_RETURN;
void print_nul_chk_table() PRODUCT_RETURN;
void print_nmethod(bool print_code) PRODUCT_RETURN;
void print_nmethod(bool print_code);
void print_on(outputStream* st, const char* title) const;
@ -505,7 +505,7 @@ class nmethod : public CodeBlob {
void log_state_change(int state) const;
// Prints a comment for one native instruction (reloc info, pc desc)
void print_code_comment_on(outputStream* st, int column, address begin, address end) PRODUCT_RETURN;
void print_code_comment_on(outputStream* st, int column, address begin, address end);
static void print_statistics() PRODUCT_RETURN;
// Compiler task identification. Note that all OSR methods

View File

@ -36,7 +36,6 @@ const int VMRegImpl::register_count = ConcreteRegisterImpl::number_of_registers;
// Register names
const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers];
#ifndef PRODUCT
void VMRegImpl::print_on(outputStream* st) const {
if( is_reg() ) {
assert( VMRegImpl::regName[value()], "" );
@ -48,4 +47,3 @@ void VMRegImpl::print_on(outputStream* st) const {
st->print("BAD!");
}
}
#endif // PRODUCT

View File

@ -96,7 +96,7 @@ public:
intptr_t value() const {return (intptr_t) this; }
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
// bias a stack slot.
@ -156,22 +156,22 @@ public:
_first = ptr;
}
// Return true if single register, even if the pair is really just adjacent stack slots
bool is_single_reg() {
bool is_single_reg() const {
return (_first->is_valid()) && (_first->value() + 1 == _second->value());
}
// Return true if single stack based "register" where the slot alignment matches input alignment
bool is_adjacent_on_stack(int alignment) {
bool is_adjacent_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
// Return true if single stack based "register" where the slot alignment matches input alignment
bool is_adjacent_aligned_on_stack(int alignment) {
bool is_adjacent_aligned_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
// Return true if single register but adjacent stack slots do not count
bool is_single_phys_reg() {
bool is_single_phys_reg() const {
return (_first->is_reg() && (_first->value() + 1 == _second->value()));
}

View File

@ -0,0 +1,443 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_disassembler.cpp.incl"
void* Disassembler::_library = NULL;
bool Disassembler::_tried_to_load_library = false;
// This routine is in the shared library:
Disassembler::decode_func Disassembler::_decode_instructions = NULL;
static const char hsdis_library_name[] = "hsdis-"HOTSPOT_LIB_ARCH;
static const char decode_instructions_name[] = "decode_instructions";
#define COMMENT_COLUMN 40 LP64_ONLY(+8) /*could be an option*/
#define BYTES_COMMENT ";..." /* funky byte display comment */
bool Disassembler::load_library() {
if (_decode_instructions != NULL) {
// Already succeeded.
return true;
}
if (_tried_to_load_library) {
// Do not try twice.
// To force retry in debugger: assign _tried_to_load_library=0
return false;
}
// Try to load it.
char ebuf[1024];
char buf[JVM_MAXPATHLEN];
os::jvm_path(buf, sizeof(buf));
int jvm_offset = -1;
{
// Match "jvm[^/]*" in jvm_path.
const char* base = buf;
const char* p = strrchr(buf, '/');
p = strstr(p ? p : base, "jvm");
if (p != NULL) jvm_offset = p - base;
}
if (jvm_offset >= 0) {
// Find the disassembler next to libjvm.so.
strcpy(&buf[jvm_offset], hsdis_library_name);
strcat(&buf[jvm_offset], os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library == NULL) {
// Try a free-floating lookup.
strcpy(&buf[0], hsdis_library_name);
strcat(&buf[0], os::dll_file_extension());
_library = hpi::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library != NULL) {
_decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
hpi::dll_lookup(_library, decode_instructions_name));
}
_tried_to_load_library = true;
if (_decode_instructions == NULL) {
tty->print_cr("Could not load %s; %s; %s", buf,
((_library != NULL)
? "entry point is missing"
: (WizardMode || PrintMiscellaneous)
? (const char*)ebuf
: "library not loadable"),
"PrintAssembly is disabled");
return false;
}
// Success.
tty->print_cr("Loaded disassembler from %s", buf);
return true;
}
class decode_env {
private:
nmethod* _nm;
CodeBlob* _code;
outputStream* _output;
address _start, _end;
char _option_buf[512];
char _print_raw;
bool _print_pc;
bool _print_bytes;
address _cur_insn;
int _total_ticks;
int _bytes_per_line; // arch-specific formatting option
static bool match(const char* event, const char* tag) {
size_t taglen = strlen(tag);
if (strncmp(event, tag, taglen) != 0)
return false;
char delim = event[taglen];
return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
}
void collect_options(const char* p) {
if (p == NULL || p[0] == '\0') return;
size_t opt_so_far = strlen(_option_buf);
if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return;
char* fillp = &_option_buf[opt_so_far];
if (opt_so_far > 0) *fillp++ = ',';
strcat(fillp, p);
// replace white space by commas:
char* q = fillp;
while ((q = strpbrk(q, " \t\n")) != NULL)
*q++ = ',';
// Note that multiple PrintAssemblyOptions flags accumulate with \n,
// which we want to be changed to a comma...
}
void print_insn_labels();
void print_insn_bytes(address pc0, address pc);
void print_address(address value);
public:
decode_env(CodeBlob* code, outputStream* output);
address decode_instructions(address start, address end);
void start_insn(address pc) {
_cur_insn = pc;
output()->bol();
print_insn_labels();
}
void end_insn(address pc) {
address pc0 = cur_insn();
outputStream* st = output();
if (_print_bytes && pc > pc0)
print_insn_bytes(pc0, pc);
if (_nm != NULL)
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
// Output pc bucket ticks if we have any
if (total_ticks() != 0) {
address bucket_pc = FlatProfiler::bucket_start_for(pc);
if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
int bucket_count = FlatProfiler::bucket_count_for(pc0);
if (bucket_count != 0) {
st->bol();
st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
}
}
}
}
address handle_event(const char* event, address arg);
outputStream* output() { return _output; }
address cur_insn() { return _cur_insn; }
int total_ticks() { return _total_ticks; }
void set_total_ticks(int n) { _total_ticks = n; }
const char* options() { return _option_buf; }
};
decode_env::decode_env(CodeBlob* code, outputStream* output) {
memset(this, 0, sizeof(*this));
_output = output ? output : tty;
_code = code;
if (code != NULL && code->is_nmethod())
_nm = (nmethod*) code;
// by default, output pc but not bytes:
_print_pc = true;
_print_bytes = false;
_bytes_per_line = Disassembler::pd_instruction_alignment();
// parse the global option string:
collect_options(Disassembler::pd_cpu_opts());
collect_options(PrintAssemblyOptions);
if (strstr(options(), "hsdis-")) {
if (strstr(options(), "hsdis-print-raw"))
_print_raw = (strstr(options(), "xml") ? 2 : 1);
if (strstr(options(), "hsdis-print-pc"))
_print_pc = !_print_pc;
if (strstr(options(), "hsdis-print-bytes"))
_print_bytes = !_print_bytes;
}
if (strstr(options(), "help")) {
tty->print_cr("PrintAssemblyOptions help:");
tty->print_cr(" hsdis-print-raw test plugin by requesting raw output");
tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml");
tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)");
tty->print_cr(" hsdis-print-bytes turn on instruction byte output");
tty->print_cr("combined options: %s", options());
}
}
address decode_env::handle_event(const char* event, address arg) {
if (match(event, "insn")) {
start_insn(arg);
} else if (match(event, "/insn")) {
end_insn(arg);
} else if (match(event, "addr")) {
if (arg != NULL) {
print_address(arg);
return arg;
}
} else if (match(event, "mach")) {
output()->print_cr("[Disassembling for mach='%s']", arg);
} else if (match(event, "format bytes-per-line")) {
_bytes_per_line = (int) (intptr_t) arg;
} else {
// ignore unrecognized markup
}
return NULL;
}
// called by the disassembler to print out jump targets and data addresses
void decode_env::print_address(address adr) {
outputStream* st = _output;
if (adr == NULL) {
st->print("NULL");
return;
}
int small_num = (int)(intptr_t)adr;
if ((intptr_t)adr == (intptr_t)small_num
&& -1 <= small_num && small_num <= 9) {
st->print("%d", small_num);
return;
}
if (Universe::is_fully_initialized()) {
if (StubRoutines::contains(adr)) {
StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
if (desc == NULL)
desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
if (desc != NULL) {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " INTPTR_FORMAT, adr);
return;
}
st->print("Stub::<unknown> " INTPTR_FORMAT, adr);
return;
}
BarrierSet* bs = Universe::heap()->barrier_set();
if (bs->kind() == BarrierSet::CardTableModRef &&
adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
st->print("word_map_base");
if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
return;
}
oop obj;
if (_nm != NULL
&& (obj = _nm->embeddedOop_at(cur_insn())) != NULL
&& (address) obj == adr) {
obj->print_value_on(st);
return;
}
}
// Fall through to a simple numeral.
st->print(INTPTR_FORMAT, (intptr_t)adr);
}
void decode_env::print_insn_labels() {
address p = cur_insn();
outputStream* st = output();
nmethod* nm = _nm;
if (nm != NULL) {
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
if (p == nm->consts_begin()) st->print_cr("[Constants]");
}
CodeBlob* cb = _code;
if (cb != NULL) {
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
}
if (_print_pc) {
st->print(" " INTPTR_FORMAT ": ", (intptr_t) p);
}
}
void decode_env::print_insn_bytes(address pc, address pc_limit) {
outputStream* st = output();
size_t incr = 1;
size_t perline = _bytes_per_line;
if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
&& !((uintptr_t)pc % sizeof(int))
&& !((uintptr_t)pc_limit % sizeof(int))) {
incr = sizeof(int);
if (perline % incr) perline += incr - (perline % incr);
}
while (pc < pc_limit) {
// tab to the desired column:
st->move_to(COMMENT_COLUMN);
address pc0 = pc;
address pc1 = pc + perline;
if (pc1 > pc_limit) pc1 = pc_limit;
for (; pc < pc1; pc += incr) {
if (pc == pc0)
st->print(BYTES_COMMENT);
else if ((uint)(pc - pc0) % sizeof(int) == 0)
st->print(" "); // put out a space on word boundaries
if (incr == sizeof(int))
st->print("%08lx", *(int*)pc);
else st->print("%02x", (*pc)&0xFF);
}
st->cr();
}
}
static void* event_to_env(void* env_pv, const char* event, void* arg) {
decode_env* env = (decode_env*) env_pv;
return env->handle_event(event, (address) arg);
}
static int printf_to_env(void* env_pv, const char* format, ...) {
decode_env* env = (decode_env*) env_pv;
outputStream* st = env->output();
size_t flen = strlen(format);
const char* raw = NULL;
if (flen == 0) return 0;
if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
if (flen < 2 ||
strchr(format, '%') == NULL) {
raw = format;
} else if (format[0] == '%' && format[1] == '%' &&
strchr(format+2, '%') == NULL) {
// happens a lot on machines with names like %foo
flen--;
raw = format+1;
}
if (raw != NULL) {
st->print_raw(raw, (int) flen);
return (int) flen;
}
va_list ap;
va_start(ap, format);
julong cnt0 = st->count();
st->vprint(format, ap);
julong cnt1 = st->count();
va_end(ap);
return (int)(cnt1 - cnt0);
}
address decode_env::decode_instructions(address start, address end) {
_start = start; _end = end;
assert((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment() == 0), "misaligned insn addr");
const int show_bytes = false; // for disassembler debugging
//_version = Disassembler::pd_cpu_version();
if (!Disassembler::can_decode()) {
return NULL;
}
// decode a series of instructions and return the end of the last instruction
if (_print_raw) {
// Print whatever the library wants to print, w/o fancy callbacks.
// This is mainly for debugging the library itself.
FILE* out = stdout;
FILE* xmlout = (_print_raw > 1 ? out : NULL);
return (address)
(*Disassembler::_decode_instructions)(start, end,
NULL, (void*) xmlout,
NULL, (void*) out,
options());
}
return (address)
(*Disassembler::_decode_instructions)(start, end,
&event_to_env, (void*) this,
&printf_to_env, (void*) this,
options());
}
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
if (!load_library()) return;
decode_env env(cb, st);
env.output()->print_cr("Decoding CodeBlob " INTPTR_FORMAT, cb);
env.decode_instructions(cb->instructions_begin(), cb->instructions_end());
}
void Disassembler::decode(address start, address end, outputStream* st) {
if (!load_library()) return;
decode_env env(CodeCache::find_blob_unsafe(start), st);
env.decode_instructions(start, end);
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
if (!load_library()) return;
decode_env env(nm, st);
env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm);
env.output()->print_cr("Code:");
unsigned char* p = nm->instructions_begin();
unsigned char* end = nm->instructions_end();
// If there has been profiling, print the buckets.
if (FlatProfiler::bucket_start_for(p) != NULL) {
unsigned char* p1 = p;
int total_bucket_count = 0;
while (p1 < end) {
unsigned char* p0 = p1;
p1 += pd_instruction_alignment();
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
env.set_total_ticks(total_bucket_count);
}
env.decode_instructions(p, end);
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
class decode_env;
// The disassembler prints out assembly code annotated
// with Java specific information.
class Disassembler {
friend class decode_env;
private:
// this is the type of the dll entry point:
typedef void* (*decode_func)(void* start, void* end,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
// points to the library.
static void* _library;
// bailout
static bool _tried_to_load_library;
// points to the decode function.
static decode_func _decode_instructions;
// tries to load library and return whether it succedded.
static bool load_library();
// Machine dependent stuff
#include "incls/_disassembler_pd.hpp.incl"
public:
static bool can_decode() {
return (_decode_instructions != NULL) || load_library();
}
static void decode(CodeBlob *cb, outputStream* st = NULL);
static void decode(nmethod* nm, outputStream* st = NULL);
static void decode(address begin, address end, outputStream* st = NULL);
};

View File

@ -1,35 +0,0 @@
/*
* Copyright 1997-2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
// Call-back interface for external disassembler
class DisassemblerEnv {
public:
// printing
virtual void print_label(intptr_t value) = 0;
virtual void print_raw(char* str) = 0;
virtual void print(char* format, ...) = 0;
// helpers
virtual char* string_for_offset(intptr_t value) = 0;
virtual char* string_for_constant(unsigned char* pc, intptr_t value, int is_decimal) = 0;
};

View File

@ -505,8 +505,13 @@ bool OopMap::has_derived_pointer() const {
#endif // COMPILER2
}
#endif //PRODUCT
static void print_register_type(OopMapValue::oop_types x, VMReg optional, outputStream* st) {
// Printing code is present in product build for -XX:+PrintAssembly.
static
void print_register_type(OopMapValue::oop_types x, VMReg optional,
outputStream* st) {
switch( x ) {
case OopMapValue::oop_value:
st->print("Oop");
@ -544,10 +549,12 @@ void OopMapValue::print_on(outputStream* st) const {
void OopMap::print_on(outputStream* st) const {
OopMapValue omv;
st->print("OopMap{");
for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
omv = oms.current();
omv.print_on(st);
}
st->print("off=%d}", (int) offset());
}
@ -558,12 +565,12 @@ void OopMapSet::print_on(outputStream* st) const {
for( i = 0; i < len; i++) {
OopMap* m = at(i);
st->print_cr("OopMap #%d offset:%p",i,m->offset());
st->print_cr("#%d ",i);
m->print_on(st);
st->print_cr("\n");
st->cr();
}
}
#endif // !PRODUCT
//------------------------------DerivedPointerTable---------------------------

View File

@ -129,7 +129,7 @@ public:
return reg()->reg2stack();
}
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
@ -193,7 +193,7 @@ class OopMap: public ResourceObj {
}
// Printing
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
@ -248,7 +248,7 @@ class OopMapSet : public ResourceObj {
OopClosure* value_fn, OopClosure* dead_fn);
// Printing
void print_on(outputStream* st) const PRODUCT_RETURN;
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};

View File

@ -225,6 +225,34 @@ ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(
assert(_dilatation_factor >= 1.0, "from previous assert");
}
// The field "_initiating_occupancy" represents the occupancy percentage
// at which we trigger a new collection cycle. Unless explicitly specified
// via CMSInitiating[Perm]OccupancyFraction (argument "io" below), it
// is calculated by:
//
// Let "f" be MinHeapFreeRatio in
//
// _intiating_occupancy = 100-f +
// f * (CMSTrigger[Perm]Ratio/100)
// where CMSTrigger[Perm]Ratio is the argument "tr" below.
//
// That is, if we assume the heap is at its desired maximum occupancy at the
// end of a collection, we let CMSTrigger[Perm]Ratio of the (purported) free
// space be allocated before initiating a new collection cycle.
//
void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr) {
assert(io <= 100 && tr >= 0 && tr <= 100, "Check the arguments");
if (io >= 0) {
_initiating_occupancy = (double)io / 100.0;
} else {
_initiating_occupancy = ((100 - MinHeapFreeRatio) +
(double)(tr * MinHeapFreeRatio) / 100.0)
/ 100.0;
}
}
void ConcurrentMarkSweepGeneration::ref_processor_init() {
assert(collector() != NULL, "no collector");
collector()->ref_processor_init();
@ -520,8 +548,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
_verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"),
_completed_initialization(false),
_collector_policy(cp),
_unload_classes(false),
_unloaded_classes_last_cycle(false),
_should_unload_classes(false),
_concurrent_cycles_since_last_unload(0),
_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
{
if (ExplicitGCInvokesConcurrentAndUnloadsClasses) {
@ -642,26 +670,11 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
}
}
// "initiatingOccupancy" is the occupancy ratio at which we trigger
// a new collection cycle. Unless explicitly specified via
// CMSTriggerRatio, it is calculated by:
// Let "f" be MinHeapFreeRatio in
//
// intiatingOccupancy = 100-f +
// f * (CMSTriggerRatio/100)
// That is, if we assume the heap is at its desired maximum occupancy at the
// end of a collection, we let CMSTriggerRatio of the (purported) free
// space be allocated before initiating a new collection cycle.
if (CMSInitiatingOccupancyFraction > 0) {
_initiatingOccupancy = (double)CMSInitiatingOccupancyFraction / 100.0;
} else {
_initiatingOccupancy = ((100 - MinHeapFreeRatio) +
(double)(CMSTriggerRatio *
MinHeapFreeRatio) / 100.0)
/ 100.0;
}
_cmsGen ->init_initiating_occupancy(CMSInitiatingOccupancyFraction, CMSTriggerRatio);
_permGen->init_initiating_occupancy(CMSInitiatingPermOccupancyFraction, CMSTriggerPermRatio);
// Clip CMSBootstrapOccupancy between 0 and 100.
_bootstrap_occupancy = ((double)MIN2((intx)100, MAX2((intx)0, CMSBootstrapOccupancy)))
_bootstrap_occupancy = ((double)MIN2((uintx)100, MAX2((uintx)0, CMSBootstrapOccupancy)))
/(double)100;
_full_gcs_since_conc_gc = 0;
@ -1413,7 +1426,8 @@ bool CMSCollector::shouldConcurrentCollect() {
gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
gclog_or_tty->print_cr("occupancy=%3.7f", _cmsGen->occupancy());
gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", initiatingOccupancy());
gclog_or_tty->print_cr("initiatingOccupancy=%3.7f", _cmsGen->initiating_occupancy());
gclog_or_tty->print_cr("initiatingPermOccupancy=%3.7f", _permGen->initiating_occupancy());
}
// ------------------------------------------------------------------
@ -1446,22 +1460,36 @@ bool CMSCollector::shouldConcurrentCollect() {
// old gen want a collection cycle started. Each may use
// an appropriate criterion for making this decision.
// XXX We need to make sure that the gen expansion
// criterion dovetails well with this.
if (_cmsGen->shouldConcurrentCollect(initiatingOccupancy())) {
// criterion dovetails well with this. XXX NEED TO FIX THIS
if (_cmsGen->should_concurrent_collect()) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMS old gen initiated");
}
return true;
}
if (cms_should_unload_classes() &&
_permGen->shouldConcurrentCollect(initiatingOccupancy())) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMS perm gen initiated");
// We start a collection if we believe an incremental collection may fail;
// this is not likely to be productive in practice because it's probably too
// late anyway.
GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(gch->collector_policy()->is_two_generation_policy(),
"You may want to check the correctness of the following");
if (gch->incremental_collection_will_fail()) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print("CMSCollector: collect because incremental collection will fail ");
}
return true;
}
if (CMSClassUnloadingEnabled && _permGen->should_concurrent_collect()) {
bool res = update_should_unload_classes();
if (res) {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print_cr("CMS perm gen initiated");
}
return true;
}
}
return false;
}
@ -1471,32 +1499,36 @@ void CMSCollector::clear_expansion_cause() {
_permGen->clear_expansion_cause();
}
bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect(
double initiatingOccupancy) {
// We should be conservative in starting a collection cycle. To
// start too eagerly runs the risk of collecting too often in the
// extreme. To collect too rarely falls back on full collections,
// which works, even if not optimum in terms of concurrent work.
// As a work around for too eagerly collecting, use the flag
// UseCMSInitiatingOccupancyOnly. This also has the advantage of
// giving the user an easily understandable way of controlling the
// collections.
// We want to start a new collection cycle if any of the following
// conditions hold:
// . our current occupancy exceeds the initiating occupancy, or
// . we recently needed to expand and have not since that expansion,
// collected, or
// . we are not using adaptive free lists and linear allocation is
// going to fail, or
// . (for old gen) incremental collection has already failed or
// may soon fail in the near future as we may not be able to absorb
// promotions.
assert_lock_strong(freelistLock());
// We should be conservative in starting a collection cycle. To
// start too eagerly runs the risk of collecting too often in the
// extreme. To collect too rarely falls back on full collections,
// which works, even if not optimum in terms of concurrent work.
// As a work around for too eagerly collecting, use the flag
// UseCMSInitiatingOccupancyOnly. This also has the advantage of
// giving the user an easily understandable way of controlling the
// collections.
// We want to start a new collection cycle if any of the following
// conditions hold:
// . our current occupancy exceeds the configured initiating occupancy
// for this generation, or
// . we recently needed to expand this space and have not, since that
// expansion, done a collection of this generation, or
// . the underlying space believes that it may be a good idea to initiate
// a concurrent collection (this may be based on criteria such as the
// following: the space uses linear allocation and linear allocation is
// going to fail, or there is believed to be excessive fragmentation in
// the generation, etc... or ...
// [.(currently done by CMSCollector::shouldConcurrentCollect() only for
// the case of the old generation, not the perm generation; see CR 6543076):
// we may be approaching a point at which allocation requests may fail because
// we will be out of sufficient free space given allocation rate estimates.]
bool ConcurrentMarkSweepGeneration::should_concurrent_collect() const {
if (occupancy() > initiatingOccupancy) {
assert_lock_strong(freelistLock());
if (occupancy() > initiating_occupancy()) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print(" %s: collect because of occupancy %f / %f ",
short_name(), occupancy(), initiatingOccupancy);
short_name(), occupancy(), initiating_occupancy());
}
return true;
}
@ -1510,20 +1542,9 @@ bool ConcurrentMarkSweepGeneration::shouldConcurrentCollect(
}
return true;
}
GenCollectedHeap* gch = GenCollectedHeap::heap();
assert(gch->collector_policy()->is_two_generation_policy(),
"You may want to check the correctness of the following");
if (gch->incremental_collection_will_fail()) {
if (_cmsSpace->should_concurrent_collect()) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print(" %s: collect because incremental collection will fail ",
short_name());
}
return true;
}
if (!_cmsSpace->adaptive_freelists() &&
_cmsSpace->linearAllocationWouldFail()) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print(" %s: collect because of linAB ",
gclog_or_tty->print(" %s: collect because cmsSpace says so ",
short_name());
}
return true;
@ -1970,8 +1991,9 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
"Should have been NULL'd before baton was passed");
reset(false /* == !asynch */);
_cmsGen->reset_after_compaction();
_concurrent_cycles_since_last_unload = 0;
if (verifying() && !cms_should_unload_classes()) {
if (verifying() && !should_unload_classes()) {
perm_gen_verify_bit_map()->clear_all();
}
@ -2098,6 +2120,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
{
bool safepoint_check = Mutex::_no_safepoint_check_flag;
MutexLockerEx hl(Heap_lock, safepoint_check);
FreelistLocker fll(this);
MutexLockerEx x(CGC_lock, safepoint_check);
if (_foregroundGCIsActive || !UseAsyncConcMarkSweepGC) {
// The foreground collector is active or we're
@ -2112,13 +2135,9 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
// a new cycle.
clear_expansion_cause();
}
_unloaded_classes_last_cycle = cms_should_unload_classes(); // ... from last cycle
// This controls class unloading in response to an explicit gc request.
// If ExplicitGCInvokesConcurrentAndUnloadsClasses is set, then
// we will unload classes even if CMSClassUnloadingEnabled is not set.
// See CR 6541037 and related CRs.
_unload_classes = _full_gc_requested // ... for this cycle
&& ExplicitGCInvokesConcurrentAndUnloadsClasses;
// Decide if we want to enable class unloading as part of the
// ensuing concurrent GC cycle.
update_should_unload_classes();
_full_gc_requested = false; // acks all outstanding full gc requests
// Signal that we are about to start a collection
gch->increment_total_full_collections(); // ... starting a collection cycle
@ -3047,21 +3066,62 @@ void CMSCollector::verify_overflow_empty() const {
}
#endif // PRODUCT
// Decide if we want to enable class unloading as part of the
// ensuing concurrent GC cycle. We will collect the perm gen and
// unload classes if it's the case that:
// (1) an explicit gc request has been made and the flag
// ExplicitGCInvokesConcurrentAndUnloadsClasses is set, OR
// (2) (a) class unloading is enabled at the command line, and
// (b) (i) perm gen threshold has been crossed, or
// (ii) old gen is getting really full, or
// (iii) the previous N CMS collections did not collect the
// perm gen
// NOTE: Provided there is no change in the state of the heap between
// calls to this method, it should have idempotent results. Moreover,
// its results should be monotonically increasing (i.e. going from 0 to 1,
// but not 1 to 0) between successive calls between which the heap was
// not collected. For the implementation below, it must thus rely on
// the property that concurrent_cycles_since_last_unload()
// will not decrease unless a collection cycle happened and that
// _permGen->should_concurrent_collect() and _cmsGen->is_too_full() are
// themselves also monotonic in that sense. See check_monotonicity()
// below.
bool CMSCollector::update_should_unload_classes() {
_should_unload_classes = false;
// Condition 1 above
if (_full_gc_requested && ExplicitGCInvokesConcurrentAndUnloadsClasses) {
_should_unload_classes = true;
} else if (CMSClassUnloadingEnabled) { // Condition 2.a above
// Disjuncts 2.b.(i,ii,iii) above
_should_unload_classes = (concurrent_cycles_since_last_unload() >=
CMSClassUnloadingMaxInterval)
|| _permGen->should_concurrent_collect()
|| _cmsGen->is_too_full();
}
return _should_unload_classes;
}
bool ConcurrentMarkSweepGeneration::is_too_full() const {
bool res = should_concurrent_collect();
res = res && (occupancy() > (double)CMSIsTooFullPercentage/100.0);
return res;
}
void CMSCollector::setup_cms_unloading_and_verification_state() {
const bool should_verify = VerifyBeforeGC || VerifyAfterGC || VerifyDuringGC
|| VerifyBeforeExit;
const int rso = SharedHeap::SO_Symbols | SharedHeap::SO_Strings
| SharedHeap::SO_CodeCache;
if (cms_should_unload_classes()) { // Should unload classes this cycle
if (should_unload_classes()) { // Should unload classes this cycle
remove_root_scanning_option(rso); // Shrink the root set appropriately
set_verifying(should_verify); // Set verification state for this cycle
return; // Nothing else needs to be done at this time
}
// Not unloading classes this cycle
assert(!cms_should_unload_classes(), "Inconsitency!");
if ((!verifying() || cms_unloaded_classes_last_cycle()) && should_verify) {
assert(!should_unload_classes(), "Inconsitency!");
if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) {
// We were not verifying, or we _were_ unloading classes in the last cycle,
// AND some verification options are enabled this cycle; in this case,
// we must make sure that the deadness map is allocated if not already so,
@ -4693,7 +4753,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
GenCollectedHeap* gch = GenCollectedHeap::heap();
if (cms_should_unload_classes()) {
if (should_unload_classes()) {
CodeCache::gc_prologue();
}
assert(haveFreelistLocks(), "must have free list locks");
@ -4753,7 +4813,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
verify_work_stacks_empty();
verify_overflow_empty();
if (cms_should_unload_classes()) {
if (should_unload_classes()) {
CodeCache::gc_epilogue();
}
@ -5623,7 +5683,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
verify_work_stacks_empty();
}
if (cms_should_unload_classes()) {
if (should_unload_classes()) {
{
TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty);
@ -5726,7 +5786,7 @@ void CMSCollector::sweep(bool asynch) {
// this cycle, we preserve the perm gen object "deadness" information
// in the perm_gen_verify_bit_map. In order to do that we traverse
// all blocks in perm gen and mark all dead objects.
if (verifying() && !cms_should_unload_classes()) {
if (verifying() && !should_unload_classes()) {
assert(perm_gen_verify_bit_map()->sizeInBits() != 0,
"Should have already been allocated");
MarkDeadObjectsClosure mdo(this, _permGen->cmsSpace(),
@ -5753,7 +5813,7 @@ void CMSCollector::sweep(bool asynch) {
}
// Now repeat for perm gen
if (cms_should_unload_classes()) {
if (should_unload_classes()) {
CMSTokenSyncWithLocks ts(true, _permGen->freelistLock(),
bitMapLock());
sweepWork(_permGen, asynch);
@ -5775,7 +5835,7 @@ void CMSCollector::sweep(bool asynch) {
// already have needed locks
sweepWork(_cmsGen, asynch);
if (cms_should_unload_classes()) {
if (should_unload_classes()) {
sweepWork(_permGen, asynch);
}
// Update heap occupancy information which is used as
@ -5937,6 +5997,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
}
gen->cmsSpace()->sweep_completed();
gen->cmsSpace()->endSweepFLCensus(sweepCount());
if (should_unload_classes()) { // unloaded classes this cycle,
_concurrent_cycles_since_last_unload = 0; // ... reset count
} else { // did not unload classes,
_concurrent_cycles_since_last_unload++; // ... increment count
}
}
// Reset CMS data structures (for now just the marking bit map)
@ -7194,7 +7259,7 @@ PushOrMarkClosure::PushOrMarkClosure(CMSCollector* collector,
_revisitStack(revisitStack),
_finger(finger),
_parent(parent),
_should_remember_klasses(collector->cms_should_unload_classes())
_should_remember_klasses(collector->should_unload_classes())
{ }
Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector,
@ -7217,7 +7282,7 @@ Par_PushOrMarkClosure::Par_PushOrMarkClosure(CMSCollector* collector,
_finger(finger),
_global_finger_addr(global_finger_addr),
_parent(parent),
_should_remember_klasses(collector->cms_should_unload_classes())
_should_remember_klasses(collector->should_unload_classes())
{ }
@ -7360,7 +7425,7 @@ PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector,
_mark_stack(mark_stack),
_revisit_stack(revisit_stack),
_concurrent_precleaning(concurrent_precleaning),
_should_remember_klasses(collector->cms_should_unload_classes())
_should_remember_klasses(collector->should_unload_classes())
{
assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
}
@ -7422,7 +7487,7 @@ Par_PushAndMarkClosure::Par_PushAndMarkClosure(CMSCollector* collector,
_bit_map(bit_map),
_work_queue(work_queue),
_revisit_stack(revisit_stack),
_should_remember_klasses(collector->cms_should_unload_classes())
_should_remember_klasses(collector->should_unload_classes())
{
assert(_ref_processor != NULL, "_ref_processor shouldn't be NULL");
}
@ -7944,7 +8009,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) {
#ifdef DEBUG
if (oop(addr)->klass() != NULL &&
( !_collector->cms_should_unload_classes()
( !_collector->should_unload_classes()
|| oop(addr)->is_parsable())) {
// Ignore mark word because we are running concurrent with mutators
assert(oop(addr)->is_oop(true), "live block should be an oop");
@ -7957,7 +8022,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) {
} else {
// This should be an initialized object that's alive.
assert(oop(addr)->klass() != NULL &&
(!_collector->cms_should_unload_classes()
(!_collector->should_unload_classes()
|| oop(addr)->is_parsable()),
"Should be an initialized object");
// Ignore mark word because we are running concurrent with mutators

View File

@ -535,13 +535,16 @@ class CMSCollector: public CHeapObj {
// In support of ExplicitGCInvokesConcurrent
static bool _full_gc_requested;
unsigned int _collection_count_start;
// Should we unload classes this concurrent cycle?
// Set in response to a concurrent full gc request.
bool _unload_classes;
bool _unloaded_classes_last_cycle;
bool _should_unload_classes;
unsigned int _concurrent_cycles_since_last_unload;
unsigned int concurrent_cycles_since_last_unload() const {
return _concurrent_cycles_since_last_unload;
}
// Did we (allow) unload classes in the previous concurrent cycle?
bool cms_unloaded_classes_last_cycle() const {
return _unloaded_classes_last_cycle || CMSClassUnloadingEnabled;
bool unloaded_classes_last_cycle() const {
return concurrent_cycles_since_last_unload() == 0;
}
// Verification support
@ -651,8 +654,6 @@ class CMSCollector: public CHeapObj {
// number of full gc's since the last concurrent gc.
uint _full_gcs_since_conc_gc;
// if occupancy exceeds this, start a new gc cycle
double _initiatingOccupancy;
// occupancy used for bootstrapping stats
double _bootstrap_occupancy;
@ -825,7 +826,6 @@ class CMSCollector: public CHeapObj {
Mutex* bitMapLock() const { return _markBitMap.lock(); }
static CollectorState abstract_state() { return _collectorState; }
double initiatingOccupancy() const { return _initiatingOccupancy; }
bool should_abort_preclean() const; // Whether preclean should be aborted.
size_t get_eden_used() const;
@ -849,11 +849,10 @@ class CMSCollector: public CHeapObj {
// In support of ExplicitGCInvokesConcurrent
static void request_full_gc(unsigned int full_gc_count);
// Should we unload classes in a particular concurrent cycle?
bool cms_should_unload_classes() const {
assert(!_unload_classes || ExplicitGCInvokesConcurrentAndUnloadsClasses,
"Inconsistency; see CR 6541037");
return _unload_classes || CMSClassUnloadingEnabled;
bool should_unload_classes() const {
return _should_unload_classes;
}
bool update_should_unload_classes();
void direct_allocated(HeapWord* start, size_t size);
@ -1022,6 +1021,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
_incremental_collection_failed = false;
}
// accessors
void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}
CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; }
private:
// For parallel young-gen GC support.
CMSParGCThreadState** _par_gc_thread_states;
@ -1029,10 +1032,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
// Reason generation was expanded
CMSExpansionCause::Cause _expansion_cause;
// accessors
void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}
CMSExpansionCause::Cause expansion_cause() { return _expansion_cause; }
// In support of MinChunkSize being larger than min object size
const double _dilatation_factor;
@ -1045,6 +1044,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
CollectionTypes _debug_collection_type;
// Fraction of current occupancy at which to start a CMS collection which
// will collect this generation (at least).
double _initiating_occupancy;
protected:
// Grow generation by specified size (returns false if unable to grow)
bool grow_by(size_t bytes);
@ -1060,6 +1063,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
// space.
size_t max_available() const;
// getter and initializer for _initiating_occupancy field.
double initiating_occupancy() const { return _initiating_occupancy; }
void init_initiating_occupancy(intx io, intx tr);
public:
ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size,
int level, CardTableRS* ct,
@ -1103,7 +1110,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
size_t capacity() const;
size_t used() const;
size_t free() const;
double occupancy() { return ((double)used())/((double)capacity()); }
double occupancy() const { return ((double)used())/((double)capacity()); }
size_t contiguous_available() const;
size_t unsafe_max_alloc_nogc() const;
@ -1158,8 +1165,8 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
bool younger_handles_promotion_failure) const;
bool should_collect(bool full, size_t size, bool tlab);
// XXXPERM
bool shouldConcurrentCollect(double initiatingOccupancy); // XXXPERM
virtual bool should_concurrent_collect() const;
virtual bool is_too_full() const;
void collect(bool full,
bool clear_all_soft_refs,
size_t size,

View File

@ -267,7 +267,7 @@ inline bool CMSCollector::is_dead_obj(oop obj) const {
(_permGen->cmsSpace()->is_in_reserved(addr)
&& _permGen->cmsSpace()->block_is_obj(addr)),
"must be object");
return cms_should_unload_classes() &&
return should_unload_classes() &&
_collectorState == Sweeping &&
!_markBitMap.isMarked(addr);
}

View File

@ -323,7 +323,7 @@ c1_Runtime1.cpp collectedHeap.hpp
c1_Runtime1.cpp compilationPolicy.hpp
c1_Runtime1.cpp compiledIC.hpp
c1_Runtime1.cpp copy.hpp
c1_Runtime1.cpp disassembler_<arch>.hpp
c1_Runtime1.cpp disassembler.hpp
c1_Runtime1.cpp events.hpp
c1_Runtime1.cpp interfaceSupport.hpp
c1_Runtime1.cpp interpreter.hpp

View File

@ -244,7 +244,7 @@ assembler.hpp vm_version_<arch_model>.hpp
assembler.inline.hpp assembler.hpp
assembler.inline.hpp codeBuffer.hpp
assembler.inline.hpp disassembler_<arch>.hpp
assembler.inline.hpp disassembler.hpp
assembler.inline.hpp threadLocalStorage.hpp
assembler_<arch_model>.cpp assembler_<arch_model>.inline.hpp
@ -946,7 +946,7 @@ codeBlob.cpp allocation.inline.hpp
codeBlob.cpp bytecode.hpp
codeBlob.cpp codeBlob.hpp
codeBlob.cpp codeCache.hpp
codeBlob.cpp disassembler_<arch>.hpp
codeBlob.cpp disassembler.hpp
codeBlob.cpp forte.hpp
codeBlob.cpp handles.inline.hpp
codeBlob.cpp heap.hpp
@ -968,7 +968,7 @@ codeBlob.hpp oopMap.hpp
codeBuffer.cpp codeBuffer.hpp
codeBuffer.cpp copy.hpp
codeBuffer.cpp disassembler_<arch>.hpp
codeBuffer.cpp disassembler.hpp
codeBuffer.hpp assembler.hpp
codeBuffer.hpp oopRecorder.hpp
@ -1323,7 +1323,7 @@ debug.cpp codeCache.hpp
debug.cpp collectedHeap.hpp
debug.cpp compileBroker.hpp
debug.cpp defaultStream.hpp
debug.cpp disassembler_<arch>.hpp
debug.cpp disassembler.hpp
debug.cpp events.hpp
debug.cpp frame.hpp
debug.cpp heapDumper.hpp
@ -1442,7 +1442,7 @@ deoptimization.hpp allocation.hpp
deoptimization.hpp frame.inline.hpp
depChecker_<arch>.cpp depChecker_<arch>.hpp
depChecker_<arch>.cpp disassembler_<arch>.hpp
depChecker_<arch>.cpp disassembler.hpp
depChecker_<arch>.cpp hpi.hpp
dependencies.cpp ciArrayKlass.hpp
@ -1472,21 +1472,21 @@ dictionary.hpp instanceKlass.hpp
dictionary.hpp oop.hpp
dictionary.hpp systemDictionary.hpp
disassemblerEnv.hpp globals.hpp
disassembler_<arch>.hpp generate_platform_dependent_include
disassembler_<arch>.cpp cardTableModRefBS.hpp
disassembler_<arch>.cpp codeCache.hpp
disassembler_<arch>.cpp collectedHeap.hpp
disassembler_<arch>.cpp depChecker_<arch>.hpp
disassembler_<arch>.cpp disassembler_<arch>.hpp
disassembler_<arch>.cpp fprofiler.hpp
disassembler_<arch>.cpp handles.inline.hpp
disassembler_<arch>.cpp hpi.hpp
disassembler_<arch>.cpp stubCodeGenerator.hpp
disassembler_<arch>.cpp stubRoutines.hpp
disassembler.cpp cardTableModRefBS.hpp
disassembler.cpp codeCache.hpp
disassembler.cpp collectedHeap.hpp
disassembler.cpp depChecker_<arch>.hpp
disassembler.cpp disassembler.hpp
disassembler.cpp fprofiler.hpp
disassembler.cpp handles.inline.hpp
disassembler.cpp hpi.hpp
disassembler.cpp stubCodeGenerator.hpp
disassembler.cpp stubRoutines.hpp
disassembler_<arch>.hpp disassemblerEnv.hpp
disassembler_<arch>.hpp os_<os_family>.inline.hpp
disassembler.hpp globals.hpp
disassembler.hpp os_<os_family>.inline.hpp
dtraceAttacher.cpp codeCache.hpp
dtraceAttacher.cpp deoptimization.hpp
@ -2909,7 +2909,7 @@ nmethod.cpp codeCache.hpp
nmethod.cpp compileLog.hpp
nmethod.cpp compiledIC.hpp
nmethod.cpp compilerOracle.hpp
nmethod.cpp disassembler_<arch>.hpp
nmethod.cpp disassembler.hpp
nmethod.cpp dtrace.hpp
nmethod.cpp events.hpp
nmethod.cpp jvmtiRedefineClassesTrace.hpp
@ -3763,7 +3763,7 @@ statSampler.hpp perfData.hpp
statSampler.hpp task.hpp
stubCodeGenerator.cpp assembler_<arch_model>.inline.hpp
stubCodeGenerator.cpp disassembler_<arch>.hpp
stubCodeGenerator.cpp disassembler.hpp
stubCodeGenerator.cpp forte.hpp
stubCodeGenerator.cpp oop.inline.hpp
stubCodeGenerator.cpp stubCodeGenerator.hpp
@ -4530,7 +4530,7 @@ vmreg_<arch>.cpp vmreg.hpp
vmreg_<arch>.hpp generate_platform_dependent_include
vtableStubs.cpp allocation.inline.hpp
vtableStubs.cpp disassembler_<arch>.hpp
vtableStubs.cpp disassembler.hpp
vtableStubs.cpp forte.hpp
vtableStubs.cpp handles.inline.hpp
vtableStubs.cpp instanceKlass.hpp

View File

@ -184,7 +184,9 @@ class No_Safepoint_Verifier : public No_GC_Verifier {
Thread *_thread;
public:
#ifdef ASSERT
No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) : No_GC_Verifier(verifygc) {
No_Safepoint_Verifier(bool activated = true, bool verifygc = true ) :
No_GC_Verifier(verifygc),
_activated(activated) {
_thread = Thread::current();
if (_activated) {
_thread->_allow_allocation_count++;

View File

@ -888,10 +888,11 @@ bool methodOopDesc::load_signature_classes(methodHandle m, TRAPS) {
symbolHandle name (THREAD, sym);
klassOop klass = SystemDictionary::resolve_or_null(name, class_loader,
protection_domain, THREAD);
// We are loading classes eagerly. If a ClassNotFoundException was generated,
// be sure to ignore it.
// We are loading classes eagerly. If a ClassNotFoundException or
// a LinkageError was generated, be sure to ignore it.
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass())) {
if (PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass()) ||
PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) {
CLEAR_PENDING_EXCEPTION;
} else {
return false;

View File

@ -70,9 +70,14 @@ static bool commute( Node *add, int con_left, int con_right ) {
// Convert "Load+x" into "x+Load".
// Now check for loads
if( in2->is_Load() ) return false;
// Left is a Load and Right is not; move it right.
if( in1->is_Load() ) {
if (in2->is_Load()) {
if (!in1->is_Load()) {
// already x+Load to return
return false;
}
// both are loads, so fall through to sort inputs by idx
} else if( in1->is_Load() ) {
// Left is a Load and Right is not; move it right.
add->swap_edges(1, 2);
return true;
}

View File

@ -456,7 +456,15 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
}
TraceTime t1("Total compilation time", &_t_totalCompilation, TimeCompiler, TimeCompiler2);
TraceTime t2(NULL, &_t_methodCompilation, TimeCompiler, false);
set_print_assembly(PrintOptoAssembly || _method->should_print_assembly());
bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly");
if (!print_opto_assembly) {
bool print_assembly = (PrintAssembly || _method->should_print_assembly());
if (print_assembly && !Disassembler::can_decode()) {
tty->print_cr("PrintAssembly request changed to PrintOptoAssembly");
print_opto_assembly = true;
}
}
set_print_assembly(print_opto_assembly);
#endif
if (ProfileTraps) {

View File

@ -256,39 +256,49 @@ void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase
}
}
void ConnectionGraph::remove_deferred(uint ni) {
VectorSet visited(Thread::current()->resource_area());
void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) {
// This method is most expensive during ConnectionGraph construction.
// Reuse vectorSet and an additional growable array for deferred edges.
deferred_edges->clear();
visited->Clear();
uint i = 0;
PointsToNode *ptn = ptnode_adr(ni);
while(i < ptn->edge_count()) {
// Mark current edges as visited and move deferred edges to separate array.
for (; i < ptn->edge_count(); i++) {
uint t = ptn->edge_target(i);
PointsToNode *ptt = ptnode_adr(t);
if (ptn->edge_type(i) != PointsToNode::DeferredEdge) {
i++;
} else {
#ifdef ASSERT
assert(!visited->test_set(t), "expecting no duplications");
#else
visited->set(t);
#endif
if (ptn->edge_type(i) == PointsToNode::DeferredEdge) {
ptn->remove_edge(t, PointsToNode::DeferredEdge);
if(!visited.test_set(t)) {
for (uint j = 0; j < ptt->edge_count(); j++) {
uint n1 = ptt->edge_target(j);
PointsToNode *pt1 = ptnode_adr(n1);
switch(ptt->edge_type(j)) {
case PointsToNode::PointsToEdge:
add_pointsto_edge(ni, n1);
if(n1 == _phantom_object) {
// Special case - field set outside (globally escaping).
ptn->set_escape_state(PointsToNode::GlobalEscape);
}
break;
case PointsToNode::DeferredEdge:
add_deferred_edge(ni, n1);
break;
case PointsToNode::FieldEdge:
assert(false, "invalid connection graph");
break;
deferred_edges->append(t);
}
}
for (int next = 0; next < deferred_edges->length(); ++next) {
uint t = deferred_edges->at(next);
PointsToNode *ptt = ptnode_adr(t);
for (uint j = 0; j < ptt->edge_count(); j++) {
uint n1 = ptt->edge_target(j);
if (visited->test_set(n1))
continue;
switch(ptt->edge_type(j)) {
case PointsToNode::PointsToEdge:
add_pointsto_edge(ni, n1);
if(n1 == _phantom_object) {
// Special case - field set outside (globally escaping).
ptn->set_escape_state(PointsToNode::GlobalEscape);
}
}
break;
case PointsToNode::DeferredEdge:
deferred_edges->append(n1);
break;
case PointsToNode::FieldEdge:
assert(false, "invalid connection graph");
break;
}
}
}
@ -1243,8 +1253,10 @@ void ConnectionGraph::compute_escape() {
}
VectorSet ptset(Thread::current()->resource_area());
GrowableArray<Node*> alloc_worklist;
GrowableArray<int> worklist;
GrowableArray<Node*> alloc_worklist;
GrowableArray<int> worklist;
GrowableArray<uint> deferred_edges;
VectorSet visited(Thread::current()->resource_area());
// remove deferred edges from the graph and collect
// information we will need for type splitting
@ -1254,7 +1266,7 @@ void ConnectionGraph::compute_escape() {
PointsToNode::NodeType nt = ptn->node_type();
Node *n = ptn->_node;
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni);
remove_deferred(ni, &deferred_edges, &visited);
if (n->is_AddP()) {
// If this AddP computes an address which may point to more that one
// object, nothing the address points to can be scalar replaceable.

View File

@ -269,7 +269,7 @@ private:
// Remove outgoing deferred edges from the node referenced by "ni".
// Any outgoing edges from the target of the deferred edge are copied
// to "ni".
void remove_deferred(uint ni);
void remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited);
Node_Array _node_map; // used for bookeeping during type splitting
// Used for the following purposes:

View File

@ -51,6 +51,9 @@ bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
if( !LoopUnswitching ) {
return false;
}
if (!_head->is_Loop()) {
return false;
}
uint nodes_left = MaxNodeLimit - phase->C->unique();
if (2 * _body.size() > nodes_left) {
return false; // Too speculative if running low on nodes.

View File

@ -2257,6 +2257,9 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
if (!loop->_head->is_Loop()) {
return false; }
LoopNode *head = loop->_head->as_Loop();
if (head->is_partial_peel_loop() || head->partial_peel_has_failed()) {

View File

@ -408,7 +408,7 @@ void Parse::do_multianewarray() {
jint dim_con = find_int_con(length[j], -1);
expand_fanout *= dim_con;
expand_count += expand_fanout; // count the level-J sub-arrays
if (dim_con < 0
if (dim_con <= 0
|| dim_con > expand_limit
|| expand_count > expand_limit) {
expand_count = 0;

View File

@ -65,6 +65,11 @@ void SuperWord::transform_loop(IdealLoopTree* lpt) {
Node *cl_exit = cl->loopexit();
if (cl_exit->in(0) != lpt->_head) return;
// Make sure the are no extra control users of the loop backedge
if (cl->back_control()->outcnt() != 1) {
return;
}
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
CountedLoopEndNode* pre_end = get_pre_loop_end(cl);
if (pre_end == NULL) return;

View File

@ -25,6 +25,20 @@
# include "incls/_precompiled.incl"
# include "incls/_forte.cpp.incl"
// These name match the names reported by the forte quality kit
enum {
ticks_no_Java_frame = 0,
ticks_no_class_load = -1,
ticks_GC_active = -2,
ticks_unknown_not_Java = -3,
ticks_not_walkable_not_Java = -4,
ticks_unknown_Java = -5,
ticks_not_walkable_Java = -6,
ticks_unknown_state = -7,
ticks_thread_exit = -8,
ticks_deopt = -9,
ticks_safepoint = -10
};
//-------------------------------------------------------
@ -41,297 +55,29 @@ class vframeStreamForte : public vframeStreamCommon {
};
static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map,
static void is_decipherable_compiled_frame(frame* fr, RegisterMap* map,
bool* is_compiled_p, bool* is_walkable_p);
static bool forte_is_walkable_interpreted_frame(frame* fr,
methodOop* method_p, int* bci_p);
static bool is_decipherable_interpreted_frame(JavaThread* thread,
frame* fr,
methodOop* method_p,
int* bci_p);
// A Forte specific version of frame:safe_for_sender().
static bool forte_safe_for_sender(frame* fr, JavaThread *thread) {
bool ret_value = false; // be pessimistic
#ifdef COMPILER2
#if defined(IA32) || defined(AMD64)
{
// This check is the same as the standard safe_for_sender()
// on IA32 or AMD64 except that NULL FP values are tolerated
// for C2.
address sp = (address)fr->sp();
address fp = (address)fr->fp();
ret_value = sp != NULL && sp <= thread->stack_base() &&
sp >= thread->stack_base() - thread->stack_size() &&
(fp == NULL || (fp <= thread->stack_base() &&
fp >= thread->stack_base() - thread->stack_size()));
// We used to use standard safe_for_sender() when we are supposed
// to be executing Java code. However, that prevents us from
// walking some intrinsic stacks so now we have to be more refined.
// If we passed the above check and we have a NULL frame pointer
// and we are supposed to be executing Java code, then we have a
// couple of more checks to make.
if (ret_value && fp == NULL && (thread->thread_state() == _thread_in_Java
|| thread->thread_state() == _thread_in_Java_trans)) {
if (fr->is_interpreted_frame()) {
// interpreted frames don't really have a NULL frame pointer
return false;
} else if (CodeCache::find_blob(fr->pc()) == NULL) {
// the NULL frame pointer should be associated with generated code
return false;
}
}
}
#else // !(IA32 || AMD64)
ret_value = fr->safe_for_sender(thread);
#endif // IA32 || AMD64
#else // !COMPILER2
ret_value = fr->safe_for_sender(thread);
#endif // COMPILER2
if (!ret_value) {
return ret_value; // not safe, nothing more to do
}
address sp1;
#ifdef SPARC
// On Solaris SPARC, when a compiler frame has an interpreted callee
// the _interpreter_sp_adjustment field contains the adjustment to
// this frame's SP made by that interpreted callee.
// For AsyncGetCallTrace(), we need to verify that the resulting SP
// is valid for the specified thread's stack.
sp1 = (address)fr->sp();
address sp2 = (address)fr->unextended_sp();
// If the second SP is NULL, then the _interpreter_sp_adjustment
// field simply adjusts this frame's SP to NULL and the frame is
// not safe. This strange value can be set in the frame constructor
// when our peek into the interpreted callee's adjusted value for
// this frame's SP finds a NULL. This can happen when SIGPROF
// catches us while we are creating the interpreter frame.
//
if (sp2 == NULL ||
// If the two SPs are different, then _interpreter_sp_adjustment
// is non-zero and we need to validate the second SP. We invert
// the range check from frame::safe_for_sender() and bail out
// if the second SP is not safe.
(sp1 != sp2 && !(sp2 <= thread->stack_base()
&& sp2 >= (thread->stack_base() - thread->stack_size())))) {
return false;
}
#endif // SPARC
if (fr->is_entry_frame()) {
// This frame thinks it is an entry frame; we need to validate
// the JavaCallWrapper pointer.
// Note: frame::entry_frame_is_first() assumes that the
// JavaCallWrapper has a non-NULL _anchor field. We don't
// check that here (yet) since we've never seen a failure
// due to a NULL _anchor field.
// Update: Originally this check was done only for SPARC. However,
// this failure has now been seen on C2 C86. I have no reason to
// believe that this is not a general issue so I'm enabling the
// check for all compilers on all supported platforms.
#ifdef COMPILER2
#if defined(IA32) || defined(AMD64)
if (fr->fp() == NULL) {
// C2 X86 allows NULL frame pointers, but if we have one then
// we cannot call entry_frame_call_wrapper().
return false;
}
#endif // IA32 || AMD64
#endif // COMPILER2
sp1 = (address)fr->entry_frame_call_wrapper();
// We invert the range check from frame::safe_for_sender() and
// bail out if the JavaCallWrapper * is not safe.
if (!(sp1 <= thread->stack_base()
&& sp1 >= (thread->stack_base() - thread->stack_size()))) {
return false;
}
}
return ret_value;
}
// Unknown compiled frames have caused assertion failures on Solaris
// X86. This code also detects unknown compiled frames on Solaris
// SPARC, but no assertion failures have been observed. However, I'm
// paranoid so I'm enabling this code whenever we have a compiler.
//
// Returns true if the specified frame is an unknown compiled frame
// and false otherwise.
static bool is_unknown_compiled_frame(frame* fr, JavaThread *thread) {
bool ret_value = false; // be optimistic
vframeStreamForte::vframeStreamForte(JavaThread *jt,
frame fr,
bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
// This failure mode only occurs when the thread is in state
// _thread_in_Java so we are okay for this check for any other
// thread state.
//
// Note: _thread_in_Java does not always mean that the thread
// is executing Java code. AsyncGetCallTrace() has caught
// threads executing in JRT_LEAF() routines when the state
// will also be _thread_in_Java.
if (thread->thread_state() != _thread_in_Java) {
return ret_value;
}
// This failure mode only occurs with compiled frames so we are
// okay for this check for both entry and interpreted frames.
if (fr->is_entry_frame() || fr->is_interpreted_frame()) {
return ret_value;
}
// This failure mode only occurs when the compiled frame's PC
// is in the code cache so we are okay for this check if the
// PC is not in the code cache.
CodeBlob* cb = CodeCache::find_blob(fr->pc());
if (cb == NULL) {
return ret_value;
}
// We have compiled code in the code cache so it is time for
// the final check: let's see if any frame type is set
ret_value = !(
// is_entry_frame() is checked above
// testers that are a subset of is_entry_frame():
// is_first_frame()
fr->is_java_frame()
// testers that are a subset of is_java_frame():
// is_interpreted_frame()
// is_compiled_frame()
|| fr->is_native_frame()
|| fr->is_runtime_frame()
|| fr->is_safepoint_blob_frame()
);
// If there is no frame type set, then we have an unknown compiled
// frame and sender() should not be called on it.
return ret_value;
}
#define DebugNonSafepoints_IS_CLEARED \
(!FLAG_IS_DEFAULT(DebugNonSafepoints) && !DebugNonSafepoints)
// if -XX:-DebugNonSafepoints, then top-frame will be skipped
vframeStreamForte::vframeStreamForte(JavaThread *jt, frame fr,
bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
_stop_at_java_call_stub = stop_at_java_call_stub;
_frame = fr;
if (!DebugNonSafepoints_IS_CLEARED) {
// decode the top frame fully
// (usual case, if JVMTI is enabled)
_frame = fr;
} else {
// skip top frame, as it may not be at safepoint
// For AsyncGetCallTrace(), we extracted as much info from the top
// frame as we could in forte_is_walkable_frame(). We also verified
// forte_safe_for_sender() so this sender() call is safe.
_frame = fr.sender(&_reg_map);
}
// We must always have a valid frame to start filling
if (jt->thread_state() == _thread_in_Java && !fr.is_first_frame()) {
bool sender_check = false; // assume sender is not safe
bool filled_in = fill_from_frame();
if (forte_safe_for_sender(&_frame, jt)) {
// If the initial sender frame is safe, then continue on with other
// checks. The unsafe sender frame has been seen on Solaris X86
// with both Compiler1 and Compiler2. It has not been seen on
// Solaris SPARC, but seems like a good sanity check to have
// anyway.
assert(filled_in, "invariant");
// SIGPROF caught us in Java code and the current frame is not the
// first frame so we should sanity check the sender frame. It is
// possible for SIGPROF to catch us in the middle of making a call.
// When that happens the current frame is actually a combination of
// the real sender and some of the new call's info. We can't find
// the real sender with such a current frame and things can get
// confused.
//
// This sanity check has caught problems with the sender frame on
// Solaris SPARC. So far Solaris X86 has not had a failure here.
sender_check = _frame.is_entry_frame()
// testers that are a subset of is_entry_frame():
// is_first_frame()
|| _frame.is_java_frame()
// testers that are a subset of is_java_frame():
// is_interpreted_frame()
// is_compiled_frame()
|| _frame.is_native_frame()
|| _frame.is_runtime_frame()
|| _frame.is_safepoint_blob_frame()
;
// We need an additional sanity check on an initial interpreted
// sender frame. This interpreted frame needs to be both walkable
// and have a valid BCI. This is yet another variant of SIGPROF
// catching us in the middle of making a call.
if (sender_check && _frame.is_interpreted_frame()) {
methodOop method = NULL;
int bci = -1;
if (!forte_is_walkable_interpreted_frame(&_frame, &method, &bci)
|| bci == -1) {
sender_check = false;
}
}
// We need an additional sanity check on an initial compiled
// sender frame. This compiled frame also needs to be walkable.
// This is yet another variant of SIGPROF catching us in the
// middle of making a call.
if (sender_check && !_frame.is_interpreted_frame()) {
bool is_compiled, is_walkable;
forte_is_walkable_compiled_frame(&_frame, &_reg_map,
&is_compiled, &is_walkable);
if (is_compiled && !is_walkable) {
sender_check = false;
}
}
}
if (!sender_check) {
// nothing else to try if we can't recognize the sender
_mode = at_end_mode;
return;
}
}
int loop_count = 0;
int loop_max = MaxJavaStackTraceDepth * 2;
while (!fill_from_frame()) {
_frame = _frame.sender(&_reg_map);
#ifdef COMPILER2
#if defined(IA32) || defined(AMD64)
// Stress testing on C2 X86 has shown a periodic problem with
// the sender() call below. The initial _frame that we have on
// entry to the loop has already passed forte_safe_for_sender()
// so we only check frames after it.
if (!forte_safe_for_sender(&_frame, _thread)) {
_mode = at_end_mode;
return;
}
#endif // IA32 || AMD64
#endif // COMPILER2
if (++loop_count >= loop_max) {
// We have looped more than twice the number of possible
// Java frames. This indicates that we are trying to walk
// a stack that is in the middle of being constructed and
// it is self referential.
_mode = at_end_mode;
return;
}
}
}
@ -358,95 +104,57 @@ void vframeStreamForte::forte_next() {
do {
#if defined(COMPILER1) && defined(SPARC)
bool prevIsInterpreted = _frame.is_interpreted_frame();
#endif // COMPILER1 && SPARC
loop_count++;
// By the time we get here we should never see unsafe but better
// safe then segv'd
if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
_mode = at_end_mode;
return;
}
_frame = _frame.sender(&_reg_map);
if (!forte_safe_for_sender(&_frame, _thread)) {
_mode = at_end_mode;
return;
}
#if defined(COMPILER1) && defined(SPARC)
if (prevIsInterpreted) {
// previous callee was interpreted and may require a special check
if (_frame.is_compiled_frame() && _frame.cb()->is_compiled_by_c1()) {
// compiled sender called interpreted callee so need one more check
bool is_compiled, is_walkable;
// sanity check the compiled sender frame
forte_is_walkable_compiled_frame(&_frame, &_reg_map,
&is_compiled, &is_walkable);
assert(is_compiled, "sanity check");
if (!is_walkable) {
// compiled sender frame is not walkable so bail out
_mode = at_end_mode;
return;
}
}
}
#endif // COMPILER1 && SPARC
if (++loop_count >= loop_max) {
// We have looped more than twice the number of possible
// Java frames. This indicates that we are trying to walk
// a stack that is in the middle of being constructed and
// it is self referential.
_mode = at_end_mode;
return;
}
} while (!fill_from_frame());
}
// Determine if 'fr' is a walkable, compiled frame.
// *is_compiled_p is set to true if the frame is compiled and if it
// is, then *is_walkable_p is set to true if it is also walkable.
static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map,
bool* is_compiled_p, bool* is_walkable_p) {
// Determine if 'fr' is a decipherable compiled frame. We are already
// assured that fr is for a java nmethod.
*is_compiled_p = false;
*is_walkable_p = false;
static bool is_decipherable_compiled_frame(frame* fr) {
CodeBlob* cb = CodeCache::find_blob(fr->pc());
if (cb != NULL &&
cb->is_nmethod() &&
((nmethod*)cb)->is_java_method()) {
// frame is compiled and executing a Java method
*is_compiled_p = true;
assert(fr->cb() != NULL && fr->cb()->is_nmethod(), "invariant");
nmethod* nm = (nmethod*) fr->cb();
assert(nm->is_java_method(), "invariant");
// Increment PC because the PcDesc we want is associated with
// the *end* of the instruction, and pc_desc_near searches
// forward to the first matching PC after the probe PC.
PcDesc* pc_desc = NULL;
if (!DebugNonSafepoints_IS_CLEARED) {
// usual case: look for any safepoint near the sampled PC
address probe_pc = fr->pc() + 1;
pc_desc = ((nmethod*) cb)->pc_desc_near(probe_pc);
} else {
// reduced functionality: only recognize PCs immediately after calls
pc_desc = ((nmethod*) cb)->pc_desc_at(fr->pc());
// First try and find an exact PcDesc
PcDesc* pc_desc = nm->pc_desc_at(fr->pc());
// Did we find a useful PcDesc?
if (pc_desc != NULL &&
pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) {
address probe_pc = fr->pc() + 1;
pc_desc = nm->pc_desc_near(probe_pc);
// Now do we have a useful PcDesc?
if (pc_desc != NULL &&
pc_desc->scope_decode_offset() == DebugInformationRecorder::serialized_null) {
// No debug information available for this pc
// vframeStream would explode if we try and walk the frames.
return false;
}
if (pc_desc != NULL && (pc_desc->scope_decode_offset()
== DebugInformationRecorder::serialized_null)) {
pc_desc = NULL;
}
if (pc_desc != NULL) {
// it has a PcDesc so the frame is also walkable
*is_walkable_p = true;
if (!DebugNonSafepoints_IS_CLEARED) {
// Normalize the PC to the one associated exactly with
// this PcDesc, so that subsequent stack-walking queries
// need not be approximate:
fr->set_pc(pc_desc->real_pc((nmethod*) cb));
}
}
// Implied else: this compiled frame has no PcDesc, i.e., contains
// a frameless stub such as C1 method exit, so it is not walkable.
// This PcDesc is useful however we must adjust the frame's pc
// so that the vframeStream lookups will use this same pc
fr->set_pc(pc_desc->real_pc(nm));
}
// Implied else: this isn't a compiled frame so it isn't a
// walkable, compiled frame.
return true;
}
// Determine if 'fr' is a walkable interpreted frame. Returns false
@ -457,159 +165,189 @@ static void forte_is_walkable_compiled_frame(frame* fr, RegisterMap* map,
// Note: this method returns true when a valid Java method is found
// even if a valid BCI cannot be found.
static bool forte_is_walkable_interpreted_frame(frame* fr,
methodOop* method_p, int* bci_p) {
static bool is_decipherable_interpreted_frame(JavaThread* thread,
frame* fr,
methodOop* method_p,
int* bci_p) {
assert(fr->is_interpreted_frame(), "just checking");
// top frame is an interpreted frame
// check if it is walkable (i.e. valid methodOop and valid bci)
if (fr->is_interpreted_frame_valid()) {
if (fr->fp() != NULL) {
// access address in order not to trigger asserts that
// are built in interpreter_frame_method function
methodOop method = *fr->interpreter_frame_method_addr();
if (Universe::heap()->is_valid_method(method)) {
intptr_t bcx = fr->interpreter_frame_bcx();
int bci = method->validate_bci_from_bcx(bcx);
// note: bci is set to -1 if not a valid bci
*method_p = method;
*bci_p = bci;
return true;
}
}
// Because we may be racing a gc thread the method and/or bci
// of a valid interpreter frame may look bad causing us to
// fail the is_interpreted_frame_valid test. If the thread
// is in any of the following states we are assured that the
// frame is in fact valid and we must have hit the race.
JavaThreadState state = thread->thread_state();
bool known_valid = (state == _thread_in_native ||
state == _thread_in_vm ||
state == _thread_blocked );
if (known_valid || fr->is_interpreted_frame_valid(thread)) {
// The frame code should completely validate the frame so that
// references to methodOop and bci are completely safe to access
// If they aren't the frame code should be fixed not this
// code. However since gc isn't locked out the values could be
// stale. This is a race we can never completely win since we can't
// lock out gc so do one last check after retrieving their values
// from the frame for additional safety
methodOop method = fr->interpreter_frame_method();
// We've at least found a method.
// NOTE: there is something to be said for the approach that
// if we don't find a valid bci then the method is not likely
// a valid method. Then again we may have caught an interpreter
// frame in the middle of construction and the bci field is
// not yet valid.
*method_p = method;
// See if gc may have invalidated method since we validated frame
if (!Universe::heap()->is_valid_method(method)) return false;
intptr_t bcx = fr->interpreter_frame_bcx();
int bci = method->validate_bci_from_bcx(bcx);
// note: bci is set to -1 if not a valid bci
*bci_p = bci;
return true;
}
return false;
}
// Determine if 'fr' can be used to find a walkable frame. Returns
// false if a walkable frame cannot be found. *walkframe_p, *method_p,
// and *bci_p are not set when false is returned. Returns true if a
// walkable frame is returned via *walkframe_p. *method_p is non-NULL
// if the returned frame was executing a Java method. *bci_p is != -1
// if a valid BCI in the Java method could be found.
// Determine if 'fr' can be used to find an initial Java frame.
// Return false if it can not find a fully decipherable Java frame
// (in other words a frame that isn't safe to use in a vframe stream).
// Obviously if it can't even find a Java frame false will also be returned.
//
// If we find a Java frame decipherable or not then by definition we have
// identified a method and that will be returned to the caller via method_p.
// If we can determine a bci that is returned also. (Hmm is it possible
// to return a method and bci and still return false? )
//
// The initial Java frame we find (if any) is return via initial_frame_p.
//
// *walkframe_p will be used by vframeStreamForte as the initial
// frame for walking the stack. Currently the initial frame is
// skipped by vframeStreamForte because we inherited the logic from
// the vframeStream class. This needs to be revisited in the future.
static bool forte_is_walkable_frame(JavaThread* thread, frame* fr,
frame* walkframe_p, methodOop* method_p, int* bci_p) {
if (!forte_safe_for_sender(fr, thread)
|| is_unknown_compiled_frame(fr, thread)
) {
// If the initial frame is not safe, then bail out. So far this
// has only been seen on Solaris X86 with Compiler2, but it seems
// like a great initial sanity check.
return false;
}
static bool find_initial_Java_frame(JavaThread* thread,
frame* fr,
frame* initial_frame_p,
methodOop* method_p,
int* bci_p) {
if (fr->is_first_frame()) {
// If initial frame is frame from StubGenerator and there is no
// previous anchor, there are no java frames yet
return false;
}
// It is possible that for a frame containing an nmethod
// we can capture the method but no bci. If we get no
// bci the frame isn't walkable but the method is usable.
// Therefore we init the returned methodOop to NULL so the
// caller can make the distinction.
*method_p = NULL;
// On the initial call to this method the frame we get may not be
// recognizable to us. This should only happen if we are in a JRT_LEAF
// or something called by a JRT_LEAF method.
if (fr->is_interpreted_frame()) {
if (forte_is_walkable_interpreted_frame(fr, method_p, bci_p)) {
*walkframe_p = *fr;
return true;
}
return false;
}
// At this point we have something other than a first frame or an
// interpreted frame.
methodOop method = NULL;
frame candidate = *fr;
// If we loop more than twice the number of possible Java
// frames, then this indicates that we are trying to walk
// a stack that is in the middle of being constructed and
// it is self referential. So far this problem has only
// been seen on Solaris X86 Compiler2, but it seems like
// a good robustness fix for all platforms.
// If the starting frame we were given has no codeBlob associated with
// it see if we can find such a frame because only frames with codeBlobs
// are possible Java frames.
int loop_count;
int loop_max = MaxJavaStackTraceDepth * 2;
for (loop_count = 0; loop_count < loop_max; loop_count++) {
// determine if the candidate frame is executing a Java method
if (CodeCache::contains(candidate.pc())) {
// candidate is a compiled frame or stub routine
CodeBlob* cb = CodeCache::find_blob(candidate.pc());
if (cb->is_nmethod()) {
method = ((nmethod *)cb)->method();
}
} // end if CodeCache has our PC
if (fr->cb() == NULL) {
// See if we can find a useful frame
int loop_count;
int loop_max = MaxJavaStackTraceDepth * 2;
RegisterMap map(thread, false);
// we have a Java frame that seems reasonable
if (method != NULL && candidate.is_java_frame()
&& candidate.sp() != NULL && candidate.pc() != NULL) {
// we need to sanity check the candidate further
bool is_compiled, is_walkable;
forte_is_walkable_compiled_frame(&candidate, &map, &is_compiled,
&is_walkable);
if (is_compiled) {
// At this point, we know we have a compiled Java frame with
// method information that we want to return. We don't check
// the is_walkable flag here because that flag pertains to
// vframeStreamForte work that is done after we are done here.
break;
}
for (loop_count = 0; loop_count < loop_max; loop_count++) {
if (!candidate.safe_for_sender(thread)) return false;
candidate = candidate.sender(&map);
if (candidate.cb() != NULL) break;
}
// At this point, the candidate doesn't work so try the sender.
// For AsyncGetCallTrace() we cannot assume there is a sender
// for the initial frame. The initial forte_safe_for_sender() call
// and check for is_first_frame() is done on entry to this method.
candidate = candidate.sender(&map);
if (!forte_safe_for_sender(&candidate, thread)) {
#ifdef COMPILER2
#if defined(IA32) || defined(AMD64)
// C2 on X86 can use the ebp register as a general purpose register
// which can cause the candidate to fail theforte_safe_for_sender()
// above. We try one more time using a NULL frame pointer (fp).
candidate = frame(candidate.sp(), NULL, candidate.pc());
if (!forte_safe_for_sender(&candidate, thread)) {
#endif // IA32 || AMD64
#endif // COMPILER2
return false;
#ifdef COMPILER2
#if defined(IA32) || defined(AMD64)
} // end forte_safe_for_sender retry with NULL fp
#endif // IA32 || AMD64
#endif // COMPILER2
} // end first forte_safe_for_sender check
if (candidate.is_first_frame()
|| is_unknown_compiled_frame(&candidate, thread)) {
return false;
}
} // end for loop_count
if (method == NULL) {
// If we didn't get any method info from the candidate, then
// we have nothing to return so bail out.
return false;
if (candidate.cb() == NULL) return false;
}
*walkframe_p = candidate;
*method_p = method;
*bci_p = -1;
return true;
// We have a frame known to be in the codeCache
// We will hopefully be able to figure out something to do with it.
int loop_count;
int loop_max = MaxJavaStackTraceDepth * 2;
RegisterMap map(thread, false);
for (loop_count = 0; loop_count < loop_max; loop_count++) {
if (candidate.is_first_frame()) {
// If initial frame is frame from StubGenerator and there is no
// previous anchor, there are no java frames associated with a method
return false;
}
if (candidate.is_interpreted_frame()) {
if (is_decipherable_interpreted_frame(thread, &candidate, method_p, bci_p)) {
*initial_frame_p = candidate;
return true;
}
// Hopefully we got some data
return false;
}
if (candidate.cb()->is_nmethod()) {
nmethod* nm = (nmethod*) candidate.cb();
*method_p = nm->method();
// If the frame isn't fully decipherable then the default
// value for the bci is a signal that we don't have a bci.
// If we have a decipherable frame this bci value will
// not be used.
*bci_p = -1;
*initial_frame_p = candidate;
// Native wrapper code is trivial to decode by vframeStream
if (nm->is_native_method()) return true;
// If it isn't decipherable then we have found a pc that doesn't
// have a PCDesc that can get us a bci however we did find
// a method
if (!is_decipherable_compiled_frame(&candidate)) {
return false;
}
// is_decipherable_compiled_frame may modify candidate's pc
*initial_frame_p = candidate;
return true;
}
// Must be some stub frame that we don't care about
if (!candidate.safe_for_sender(thread)) return false;
candidate = candidate.sender(&map);
// If it isn't in the code cache something is wrong
// since once we find a frame in the code cache they
// all should be there.
if (candidate.cb() == NULL) return false;
}
return false;
}
@ -627,10 +365,12 @@ typedef struct {
} ASGCT_CallTrace;
static void forte_fill_call_trace_given_top(JavaThread* thd,
ASGCT_CallTrace* trace, int depth, frame top_frame) {
ASGCT_CallTrace* trace,
int depth,
frame top_frame) {
NoHandleMark nhm;
frame walkframe;
frame initial_Java_frame;
methodOop method;
int bci;
int count;
@ -638,48 +378,51 @@ static void forte_fill_call_trace_given_top(JavaThread* thd,
count = 0;
assert(trace->frames != NULL, "trace->frames must be non-NULL");
if (!forte_is_walkable_frame(thd, &top_frame, &walkframe, &method, &bci)) {
// return if no walkable frame is found
return;
}
bool fully_decipherable = find_initial_Java_frame(thd, &top_frame, &initial_Java_frame, &method, &bci);
// The frame might not be walkable but still recovered a method
// (e.g. an nmethod with no scope info for the pc
if (method == NULL) return;
CollectedHeap* ch = Universe::heap();
if (method != NULL) {
// The method is not stored GC safe so see if GC became active
// after we entered AsyncGetCallTrace() and before we try to
// use the methodOop.
// Yes, there is still a window after this check and before
// we use methodOop below, but we can't lock out GC so that
// has to be an acceptable risk.
if (!ch->is_valid_method(method)) {
trace->num_frames = -2;
return;
}
if (DebugNonSafepoints_IS_CLEARED) {
// Take whatever method the top-frame decoder managed to scrape up.
// We look further at the top frame only if non-safepoint
// debugging information is available.
count++;
trace->num_frames = count;
trace->frames[0].method_id = method->find_jmethod_id_or_null();
if (!method->is_native()) {
trace->frames[0].lineno = bci;
} else {
trace->frames[0].lineno = -3;
}
}
}
// check has_last_Java_frame() after looking at the top frame
// which may be an interpreted Java frame.
if (!thd->has_last_Java_frame() && method == NULL) {
trace->num_frames = 0;
// The method is not stored GC safe so see if GC became active
// after we entered AsyncGetCallTrace() and before we try to
// use the methodOop.
// Yes, there is still a window after this check and before
// we use methodOop below, but we can't lock out GC so that
// has to be an acceptable risk.
if (!ch->is_valid_method(method)) {
trace->num_frames = ticks_GC_active; // -2
return;
}
vframeStreamForte st(thd, walkframe, false);
// We got a Java frame however it isn't fully decipherable
// so it won't necessarily be safe to use it for the
// initial frame in the vframe stream.
if (!fully_decipherable) {
// Take whatever method the top-frame decoder managed to scrape up.
// We look further at the top frame only if non-safepoint
// debugging information is available.
count++;
trace->num_frames = count;
trace->frames[0].method_id = method->find_jmethod_id_or_null();
if (!method->is_native()) {
trace->frames[0].lineno = bci;
} else {
trace->frames[0].lineno = -3;
}
if (!initial_Java_frame.safe_for_sender(thd)) return;
RegisterMap map(thd, false);
initial_Java_frame = initial_Java_frame.sender(&map);
}
vframeStreamForte st(thd, initial_Java_frame, false);
for (; !st.at_end() && count < depth; st.forte_next(), count++) {
bci = st.bci();
method = st.method();
@ -693,7 +436,7 @@ static void forte_fill_call_trace_given_top(JavaThread* thd,
if (!ch->is_valid_method(method)) {
// we throw away everything we've gathered in this sample since
// none of it is safe
trace->num_frames = -2;
trace->num_frames = ticks_GC_active; // -2
return;
}
@ -765,6 +508,11 @@ static void forte_fill_call_trace_given_top(JavaThread* thd,
extern "C" {
void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
// This is if'd out because we no longer use thread suspension.
// However if someone wanted to backport this to a 5.0 jvm then this
// code would be important.
#if 0
if (SafepointSynchronize::is_synchronizing()) {
// The safepoint mechanism is trying to synchronize all the threads.
// Since this can involve thread suspension, it is not safe for us
@ -774,9 +522,10 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
// are suspended while holding a resource and another thread blocks
// on that resource in the SIGPROF handler, then we will have a
// three-thread deadlock (VMThread, this thread, the other thread).
trace->num_frames = -10;
trace->num_frames = ticks_safepoint; // -10
return;
}
#endif
JavaThread* thread;
@ -785,13 +534,13 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
thread->is_exiting()) {
// bad env_id, thread has exited or thread is exiting
trace->num_frames = -8;
trace->num_frames = ticks_thread_exit; // -8
return;
}
if (thread->in_deopt_handler()) {
// thread is in the deoptimization handler so return no frames
trace->num_frames = -9;
trace->num_frames = ticks_deopt; // -9
return;
}
@ -799,12 +548,12 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
"AsyncGetCallTrace must be called by the current interrupted thread");
if (!JvmtiExport::should_post_class_load()) {
trace->num_frames = -1;
trace->num_frames = ticks_no_class_load; // -1
return;
}
if (Universe::heap()->is_gc_active()) {
trace->num_frames = -2;
trace->num_frames = ticks_GC_active; // -2
return;
}
@ -827,14 +576,22 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
// param isInJava == false - indicate we aren't in Java code
if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, false)) {
if (!thread->has_last_Java_frame()) {
trace->num_frames = 0; // no Java frames
} else {
trace->num_frames = -3; // unknown frame
}
trace->num_frames = ticks_unknown_not_Java; // -3 unknown frame
} else {
trace->num_frames = -4; // non walkable frame by default
forte_fill_call_trace_given_top(thread, trace, depth, fr);
if (!thread->has_last_Java_frame()) {
trace->num_frames = 0; // No Java frames
} else {
trace->num_frames = ticks_not_walkable_not_Java; // -4 non walkable frame by default
forte_fill_call_trace_given_top(thread, trace, depth, fr);
// This assert would seem to be valid but it is not.
// It would be valid if we weren't possibly racing a gc
// thread. A gc thread can make a valid interpreted frame
// look invalid. It's a small window but it does happen.
// The assert is left here commented out as a reminder.
// assert(trace->num_frames != ticks_not_walkable_not_Java, "should always be walkable");
}
}
}
break;
@ -845,16 +602,16 @@ void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) {
// param isInJava == true - indicate we are in Java code
if (!thread->pd_get_top_frame_for_signal_handler(&fr, ucontext, true)) {
trace->num_frames = -5; // unknown frame
trace->num_frames = ticks_unknown_Java; // -5 unknown frame
} else {
trace->num_frames = -6; // non walkable frame by default
trace->num_frames = ticks_not_walkable_Java; // -6, non walkable frame by default
forte_fill_call_trace_given_top(thread, trace, depth, fr);
}
}
break;
default:
// Unknown thread state
trace->num_frames = -7;
trace->num_frames = ticks_unknown_state; // -7
break;
}
}

View File

@ -924,29 +924,23 @@ void FlatProfilerTask::task() {
FlatProfiler::record_thread_ticks();
}
void ThreadProfiler::record_interpreted_tick(frame fr, TickPosition where, int* ticks) {
void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) {
FlatProfiler::all_int_ticks++;
if (!FlatProfiler::full_profile()) {
return;
}
if (!fr.is_interpreted_frame_valid()) {
if (!fr.is_interpreted_frame_valid(thread)) {
// tick came at a bad time
interpreter_ticks += 1;
FlatProfiler::interpreter_ticks += 1;
return;
}
methodOop method = NULL;
if (fr.fp() != NULL) {
method = *fr.interpreter_frame_method_addr();
}
if (!Universe::heap()->is_valid_method(method)) {
// tick came at a bad time, stack frame not initialized correctly
interpreter_ticks += 1;
FlatProfiler::interpreter_ticks += 1;
return;
}
// The frame has been fully validated so we can trust the method and bci
methodOop method = *fr.interpreter_frame_method_addr();
interpreted_update(method, where);
// update byte code table
@ -997,7 +991,7 @@ void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr)
// The tick happend in real code -> non VM code
if (fr.is_interpreted_frame()) {
interval_data_ref()->inc_interpreted();
record_interpreted_tick(fr, tp_code, FlatProfiler::bytecode_ticks);
record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks);
return;
}
@ -1028,7 +1022,7 @@ void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr)
// The tick happend in VM code
interval_data_ref()->inc_native();
if (fr.is_interpreted_frame()) {
record_interpreted_tick(fr, tp_native, FlatProfiler::bytecode_ticks_stub);
record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub);
return;
}
if (CodeCache::contains(fr.pc())) {

View File

@ -135,7 +135,7 @@ private:
ProfilerNode** table;
private:
void record_interpreted_tick(frame fr, TickPosition where, int* ticks);
void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks);
void record_compiled_tick (JavaThread* thread, frame fr, TickPosition where);
void interpreted_update(methodOop method, TickPosition where);
void compiled_update (methodOop method, TickPosition where);

View File

@ -108,7 +108,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
bool is_first_frame() const; // oldest frame? (has no sender)
bool is_first_java_frame() const; // same for Java frame
bool is_interpreted_frame_valid() const; // performs sanity checks on interpreted frames.
bool is_interpreted_frame_valid(JavaThread* thread) const; // performs sanity checks on interpreted frames.
// tells whether this frame is marked for deoptimization
bool should_be_deoptimized() const;

View File

@ -68,18 +68,20 @@ void Flag::print_on(outputStream* st) {
if (is_uintx()) st->print("%-16lu", get_uintx());
if (is_ccstr()) {
const char* cp = get_ccstr();
const char* eol;
while ((eol = strchr(cp, '\n')) != NULL) {
char format_buffer[FORMAT_BUFFER_LEN];
size_t llen = pointer_delta(eol, cp, sizeof(char));
jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
"%%." SIZE_FORMAT "s", llen);
st->print(format_buffer, cp);
st->cr();
cp = eol+1;
st->print("%5s %-35s += ", "", name);
if (cp != NULL) {
const char* eol;
while ((eol = strchr(cp, '\n')) != NULL) {
char format_buffer[FORMAT_BUFFER_LEN];
size_t llen = pointer_delta(eol, cp, sizeof(char));
jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
"%%." SIZE_FORMAT "s", llen);
st->print(format_buffer, cp);
st->cr();
cp = eol+1;
st->print("%5s %-35s += ", "", name);
}
st->print("%-16s", cp);
}
st->print("%-16s", cp);
}
st->print(" %s", kind);
st->cr();
@ -94,18 +96,21 @@ void Flag::print_as_flag(outputStream* st) {
st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx());
} else if (is_ccstr()) {
st->print("-XX:%s=", name);
// Need to turn embedded '\n's back into separate arguments
// Not so efficient to print one character at a time,
// but the choice is to do the transformation to a buffer
// and print that. And this need not be efficient.
for (const char* cp = get_ccstr(); *cp != '\0'; cp += 1) {
switch (*cp) {
default:
st->print("%c", *cp);
break;
case '\n':
st->print(" -XX:%s=", name);
break;
const char* cp = get_ccstr();
if (cp != NULL) {
// Need to turn embedded '\n's back into separate arguments
// Not so efficient to print one character at a time,
// but the choice is to do the transformation to a buffer
// and print that. And this need not be efficient.
for (; *cp != '\0'; cp += 1) {
switch (*cp) {
default:
st->print("%c", *cp);
break;
case '\n':
st->print(" -XX:%s=", name);
break;
}
}
}
} else {

View File

@ -668,16 +668,19 @@ class CommandLineFlags {
notproduct(bool, PrintCompilation2, false, \
"Print additional statistics per compilation") \
\
notproduct(bool, PrintAdapterHandlers, false, \
diagnostic(bool, PrintAdapterHandlers, false, \
"Print code generated for i2c/c2i adapters") \
\
develop(bool, PrintAssembly, false, \
"Print assembly code") \
diagnostic(bool, PrintAssembly, false, \
"Print assembly code (using external disassembler.so)") \
\
develop(bool, PrintNMethods, false, \
diagnostic(ccstr, PrintAssemblyOptions, false, \
"Options string passed to disassembler.so") \
\
diagnostic(bool, PrintNMethods, false, \
"Print assembly code for nmethods when generated") \
\
develop(bool, PrintNativeNMethods, false, \
diagnostic(bool, PrintNativeNMethods, false, \
"Print assembly code for native nmethods when generated") \
\
develop(bool, PrintDebugInfo, false, \
@ -702,7 +705,7 @@ class CommandLineFlags {
develop(bool, PrintCodeCache2, false, \
"Print detailed info on the compiled_code cache when exiting") \
\
develop(bool, PrintStubCode, false, \
diagnostic(bool, PrintStubCode, false, \
"Print generated stub code") \
\
product(bool, StackTraceInThrowable, true, \
@ -1319,6 +1322,10 @@ class CommandLineFlags {
product(bool, CMSClassUnloadingEnabled, false, \
"Whether class unloading enabled when using CMS GC") \
\
product(uintx, CMSClassUnloadingMaxInterval, 0, \
"When CMS class unloading is enabled, the maximum CMS cycle count"\
" for which classes may not be unloaded") \
\
product(bool, CMSCompactWhenClearAllSoftRefs, true, \
"Compact when asked to collect CMS gen with clear_all_soft_refs") \
\
@ -1504,17 +1511,30 @@ class CommandLineFlags {
"Percentage of MinHeapFreeRatio in CMS generation that is " \
" allocated before a CMS collection cycle commences") \
\
product(intx, CMSBootstrapOccupancy, 50, \
product(intx, CMSTriggerPermRatio, 80, \
"Percentage of MinHeapFreeRatio in the CMS perm generation that" \
" is allocated before a CMS collection cycle commences, that " \
" also collects the perm generation") \
\
product(uintx, CMSBootstrapOccupancy, 50, \
"Percentage CMS generation occupancy at which to " \
" initiate CMS collection for bootstrapping collection stats") \
\
product(intx, CMSInitiatingOccupancyFraction, -1, \
"Percentage CMS generation occupancy to start a CMS collection " \
" cycle (A negative value means that CMSTirggerRatio is used)") \
" cycle (A negative value means that CMSTriggerRatio is used)") \
\
product(intx, CMSInitiatingPermOccupancyFraction, -1, \
"Percentage CMS perm generation occupancy to start a CMScollection"\
" cycle (A negative value means that CMSTriggerPermRatio is used)")\
\
product(bool, UseCMSInitiatingOccupancyOnly, false, \
"Only use occupancy as a crierion for starting a CMS collection") \
\
product(intx, CMSIsTooFullPercentage, 98, \
"An absolute ceiling above which CMS will always consider the" \
" perm gen ripe for collection") \
\
develop(bool, CMSTestInFreeList, false, \
"Check if the coalesced range is already in the " \
"free lists as claimed.") \
@ -2250,7 +2270,7 @@ class CommandLineFlags {
product_pd(bool, RewriteFrequentPairs, \
"Rewrite frequently used bytecode pairs into a single bytecode") \
\
product(bool, PrintInterpreter, false, \
diagnostic(bool, PrintInterpreter, false, \
"Prints the generated interpreter code") \
\
product(bool, UseInterpreter, true, \
@ -2300,7 +2320,7 @@ class CommandLineFlags {
develop(bool, PrintBytecodePairHistogram, false, \
"Print histogram of the executed bytecode pairs") \
\
develop(bool, PrintSignatureHandlers, false, \
diagnostic(bool, PrintSignatureHandlers, false, \
"Print code generated for native method signature handlers") \
\
develop(bool, VerifyOops, false, \

View File

@ -69,7 +69,6 @@ StubCodeGenerator::StubCodeGenerator(CodeBuffer* code) {
_first_stub = _last_stub = NULL;
}
#ifndef PRODUCT
extern "C" {
static int compare_cdesc(const void* void_a, const void* void_b) {
int ai = (*((StubCodeDesc**) void_a))->index();
@ -77,10 +76,8 @@ extern "C" {
return ai - bi;
}
}
#endif
StubCodeGenerator::~StubCodeGenerator() {
#ifndef PRODUCT
if (PrintStubCode) {
CodeBuffer* cbuf = _masm->code();
CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start());
@ -105,7 +102,6 @@ StubCodeGenerator::~StubCodeGenerator() {
tty->cr();
}
}
#endif //PRODUCT
}

View File

@ -416,6 +416,48 @@ inline bool vframeStreamCommon::fill_from_frame() {
int decode_offset;
if (pc_desc == NULL) {
// Should not happen, but let fill_from_compiled_frame handle it.
// If we are trying to walk the stack of a thread that is not
// at a safepoint (like AsyncGetCallTrace would do) then this is an
// acceptable result. [ This is assuming that safe_for_sender
// is so bullet proof that we can trust the frames it produced. ]
//
// So if we see that the thread is not safepoint safe
// then simply produce the method and a bci of zero
// and skip the possibility of decoding any inlining that
// may be present. That is far better than simply stopping (or
// asserting. If however the thread is safepoint safe this
// is the sign of a compiler bug and we'll let
// fill_from_compiled_frame handle it.
JavaThreadState state = _thread->thread_state();
// in_Java should be good enough to test safepoint safety
// if state were say in_Java_trans then we'd expect that
// the pc would have already been slightly adjusted to
// one that would produce a pcDesc since the trans state
// would be one that might in fact anticipate a safepoint
if (state == _thread_in_Java ) {
// This will get a method a zero bci and no inlining.
// Might be nice to have a unique bci to signify this
// particular case but for now zero will do.
fill_from_compiled_native_frame();
// There is something to be said for setting the mode to
// at_end_mode to prevent trying to walk further up the
// stack. There is evidence that if we walk any further
// that we could produce a bad stack chain. However until
// we see evidence that allowing this causes us to find
// frames bad enough to cause segv's or assertion failures
// we don't do it as while we may get a bad call chain the
// probability is much higher (several magnitudes) that we
// get good data.
return true;
}
decode_offset = DebugInformationRecorder::serialized_null;
} else {
decode_offset = pc_desc->scope_decode_offset();

View File

@ -52,8 +52,9 @@ void outputStream::update_position(const char* s, size_t len) {
_precount += _position + 1;
_position = 0;
} else if (ch == '\t') {
_position += 8;
_precount -= 7; // invariant: _precount + _position == total count
int tw = 8 - (_position & 7);
_position += tw;
_precount -= tw-1; // invariant: _precount + _position == total count
} else {
_position += 1;
}
@ -133,7 +134,17 @@ void outputStream::vprint_cr(const char* format, va_list argptr) {
}
void outputStream::fill_to(int col) {
while (position() < col) sp();
int need_fill = col - position();
sp(need_fill);
}
void outputStream::move_to(int col, int slop, int min_space) {
if (position() >= col + slop)
cr();
int need_fill = col - position();
if (need_fill < min_space)
need_fill = min_space;
sp(need_fill);
}
void outputStream::put(char ch) {
@ -142,8 +153,23 @@ void outputStream::put(char ch) {
write(buf, 1);
}
void outputStream::sp() {
this->write(" ", 1);
#define SP_USE_TABS false
void outputStream::sp(int count) {
if (count < 0) return;
if (SP_USE_TABS && count >= 8) {
int target = position() + count;
while (count >= 8) {
this->write("\t", 1);
count -= 8;
}
count = target - position();
}
while (count > 0) {
int nw = (count > 8) ? 8 : count;
this->write(" ", nw);
count -= nw;
}
}
void outputStream::cr() {

View File

@ -59,6 +59,7 @@ class outputStream : public ResourceObj {
int indentation() const { return _indentation; }
void set_indentation(int i) { _indentation = i; }
void fill_to(int col);
void move_to(int col, int slop = 6, int min_space = 2);
// sizing
int width() const { return _width; }
@ -78,7 +79,7 @@ class outputStream : public ResourceObj {
void print_raw_cr(const char* str) { write(str, strlen(str)); cr(); }
void print_raw_cr(const char* str, int len){ write(str, len); cr(); }
void put(char ch);
void sp();
void sp(int count = 1);
void cr();
void bol() { if (_position > 0) cr(); }

View File

@ -0,0 +1,886 @@
/*
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6646020
* @summary assert(in_bb(n),"must be in block") in -Xcomp mode
*/
/* Complexity upper bound: 3361 ops */
class Tester_Class_0 {
static byte var_1;
public Tester_Class_0()
{
"".length();
{
var_1 = (var_1 = (new byte[(byte)'D'])[(byte)2.40457E38F]);
var_1 = (var_1 = (byte)1.738443503665377E307);
var_1 = (var_1 = (byte)1237144669662298112L);
}
var_1 = "baldh".equalsIgnoreCase("") ? (var_1 = (byte)7.2932087E37F) : (byte)3909726578709910528L;
var_1 = (var_1 = (var_1 = (var_1 = (byte)7.223761846153971E307)));
var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)((short)7860452029249754112L + (byte)1.7374232546809952E308)))));
var_1 = (!true ? (var_1 = (byte)4359229782598970368L) : (short)(byte)1.7509836746850026E308) >= 'P' ? (var_1 = (byte)3.275114793095594E307) : (byte)(- ((byte)1.5595572E38F) / 8.2971296E37F);
byte var_9 = (true ? true : (false ? true : false)) ? (var_1 = (var_1 = (byte)9.928434E37F)) : (var_1 = (byte)9.785060633966518E307);
final byte var_10 = 53;
var_9 <<= (true | true) & (((var_10 == "".substring(2001075014).compareToIgnoreCase("rhbytggv") ? !true : ! !true) ? !false : false) ? !true & true : !false) ? var_10 : var_10;
var_9 <<= - (var_9 -= - ~6397182310329038848L >> (char)955837891 << (short)- - -8.4452034E37F >> + ~5485157895941338112L);
--var_9;
var_9 >>= 'V';
var_9 -= (new char[var_10])[var_9];
double var_11;
var_11 = (var_11 = (new int[var_9 = (var_9 %= 684423748)])[var_9]);
var_9 /= 'q';
var_9 *= ~var_9 | (short)1.7667766368850557E308 - "w".trim().charAt(- (var_9 /= + (var_11 = 'q')));
if (var_10 <= 605036859609030656L | !false & false)
{
var_9 >>>= false ^ false ? (new short[var_10])[var_10] : (short)1013619326108001280L;
}
else
{
var_11 = var_9;
}
var_9 -= 'X';
var_9 *= 'E';
{
var_9 ^= (new short[var_9])[var_9 >>>= 'c'];
}
var_11 = 4315867074042433536L;
double var_12 = 1.2183900219527627E308;
var_9 <<= (false ? !false : false) ? '\\' : 'D';
}
private final long func_0()
{
float var_2 = 0F;
var_1 = (var_1 = (var_1 = (byte)((short)1.4106931056021857E308 % var_2)));
for (new String(); true & (! !true ^ !false | false) && var_2 < 1; var_1 = (var_1 = (var_1 = (var_1 = (byte)1183673628639185920L))))
{
var_1 = true | false ? (var_1 = (byte)1.6263855E37F) : (byte)'O';
var_2++;
"fui".toUpperCase();
final int var_3 = (var_1 = (var_1 = (byte)'i')) + (byte)2008561384 / (byte)1.4413369179905006E308;
}
var_1 = (var_1 = false ^ false ? (byte)2.3850814E38F : (byte)4.42887E37F);
final float var_4 = 3.052265E38F;
var_1 = (var_1 = (var_1 = (var_1 = (var_1 = (byte)'o'))));
long var_5;
var_1 = (var_1 = (byte)((var_1 = (byte)1913212786) * (var_1 = (byte)var_2)));
var_5 = (short)3.2024069E38F * (short)(var_5 = 'Q');
var_5 = (false ? true : false) ? (short)1098137179 : (byte)~695765814858203136L;
var_1 = (var_1 = true & false ^ true ? (byte)1662737306 : (byte)'r');
{
(true ? "a" : "lymivj".toString()).codePointCount((short)3.032349E38F + (var_1 = (var_1 = (var_1 = (var_1 = (byte)1.3159799E37F)))), (byte)2.0898819853138264E307 & (new short[(byte)(short)var_2])[var_1 = (byte)(short)4.859332921376913E307]);
}
double var_6;
var_6 = 1359078277;
final float var_7 = 3.5952457E37F;
var_5 = ('u' | 9005660398910009344L) << 'j';
int var_8;
var_5 = (!false || true & !false) && false ? (byte)1836342254 : (byte)1.4836203E38F;
var_1 = (var_1 = (var_1 = (var_1 = (byte)1.5824984701060493E308)));
var_1 = (var_1 = (var_1 = (byte)~ (var_1 = (var_1 = (var_1 = (byte)var_7)))));
return +9.067416E37F <= (true | true ^ false ? (var_1 = (byte)(short)1.5243446E38F) : (var_1 = (byte)1.6893049E37F)) ? (byte)~4408841475280588800L - (var_5 = (var_1 = (byte)2.1542209E38F)) : (var_8 = (short)var_4);
}
protected final static double func_1(final char arg_0, final long arg_1)
{
var_1 = (short)8779631802405542912L << 'x' <= arg_0 ? (byte)+9.96859509852443E307 : (var_1 = (var_1 = (byte)(short)5.218454879223281E307));
return 5.57437404144192E307;
}
double func_2(byte arg_0, final boolean arg_1, Object arg_2)
{
arg_2 = arg_1 != arg_1 ? "wq" : "w";
arg_2 = arg_2;
if (arg_1)
{
arg_2 = false & arg_1 ? "hasmp" : (arg_2 = arg_2);
}
else
{
arg_2 = "lcquv";
}
arg_0 -= arg_1 ^ false ? (arg_0 |= (short)arg_0) : (~3462197988186869760L | 7274210797196514304L) % - - + +130998764279904256L;
arg_0 &= (true ? - - ~7861994999369861120L << 'l' : 'c') * 1246069704;
return (arg_1 ? 9.311174E37F : 1.7085558737202237E308) * 1168887722;
}
public String toString()
{
String result = "[\n";
result += "Tester_Class_0.var_1 = "; result += Tester.Printer.print(var_1);
result += "";
result += "\n]";
return result;
}
}
final class Tester_Class_1 extends Tester_Class_0 {
static Object var_13;
final static boolean var_14 = false | (false ? false : true);
Object var_15;
static byte var_16;
final long var_17 = (long)(-9.40561658911133E307 - (short)2.2016736E38F) ^ (char)1099667310;
static boolean var_18;
static float var_19;
final static byte var_20 = 123;
static byte var_21 = var_1 = (var_1 = var_20);
final static float var_22 = 1.5415572E38F;
public Tester_Class_1()
{
char[][] var_39;
boolean var_40 = false | !var_14;
if (var_14)
{
final String[] var_41 = (new String[var_21][var_20])[var_21 *= var_21];
var_15 = (new Tester_Class_0[var_20])[var_20];
--var_21;
int var_42;
}
else
{
var_19 = (short)325110146;
}
var_40 &= true;
var_13 = (((new Tester_Class_1[var_21 |= (new char[var_20])[var_21]])[var_21]).var_15 = (new String[var_21][var_20][var_20])[var_21 >>= (byte)(int)var_22]);
var_15 = "m";
}
protected final static Tester_Class_0 func_0(final char arg_0, boolean arg_1)
{
final short var_23 = false ? (short)2.2956268E38F : var_20;
{
((new Tester_Class_1[var_21])[var_20]).var_15 = ((new Tester_Class_0[var_20][var_21])[var_21])[var_20];
}
var_19 = var_23;
{
var_21++;
--var_21;
var_13 = (false ? arg_1 : arg_1) ? "" : "aianteahl";
arg_1 ^= ! (var_14 ? var_14 : !var_14);
}
(arg_1 ? "rq" : "certd").trim();
arg_1 ^= 's' < var_22;
var_19 = 'T';
var_19 = var_14 ? --var_21 : var_20;
var_19 = (var_21 >>>= ~ -1559436447128426496L >> 88912720393932800L) | (new char[var_20][var_21])[var_21][var_20];
short var_24 = 7601;
if (arg_1)
{
var_13 = (new Tester_Class_0[var_20])[var_21];
}
else
{
var_19 = var_23;
}
var_19 = var_24;
var_19 = 174274929356416000L;
return arg_1 ? (Tester_Class_0)(new Object[var_20])[var_21 >>>= - ((byte)6471979169965446144L)] : (new Tester_Class_0[var_21])[var_20];
}
private static int func_1(final Object arg_0, final boolean arg_1)
{
var_19 = 'N';
var_13 = "ftspm".toUpperCase();
var_18 = arg_1 ? !arg_1 : var_14;
var_19 = var_21 % 'j';
{
var_13 = new short[var_21 >>= 8019540572802872320L];
}
final Tester_Class_0 var_25 = arg_1 ? ((short)1.3614569631193786E308 >= (short)var_20 ? func_0('O', true) : (Tester_Class_0)arg_0) : func_0('e', false);
"cltpxrg".offsetByCodePoints((new short[var_20])[(byte)'F'] & var_20, 942627356);
final Object var_26 = ((new Tester_Class_1[var_21])[var_20]).var_15 = arg_0;
{
var_21 |= 'H';
}
var_19 = 4705089801895780352L;
var_19 = (var_18 = arg_1 & false) ? var_20 : (! (~var_21 > var_22) ? (new short[var_20])[var_21] : (short)3904907750551380992L);
var_18 = false;
{
var_18 = "aoy".startsWith("ia", 18060804);
if (true)
{
final short var_27 = 4832;
}
else
{
var_18 = (var_18 = arg_1) ? !false : !var_14;
}
var_18 = (var_18 = var_14);
var_19 = 'L';
}
func_0((false ? ! ((var_21 -= 4.670301365216022E307) > 1.1839209E37F) : (var_18 = false)) ? 's' : 'R', 'Z' > - ((long)var_21) << 2585724390819764224L & var_25.func_2(var_21, false, var_13 = var_25) != 4918861136400833536L);
double var_28 = 0;
var_21 %= -var_28;
for (byte var_29 = 91; arg_1 && (var_28 < 1 && false); var_19 = var_20)
{
var_19 = (var_18 = arg_1) & (var_18 = false) ? 'm' : '[';
var_28++;
var_18 = var_14;
var_21 += (short)1363703973;
}
var_19 = (var_19 = var_22);
var_18 = (var_18 = false | false ? 1743087391 <= (var_21 >>= 8790741242417599488L) : !arg_1);
var_18 = true | true;
--var_21;
var_18 = !var_14 & false;
"mt".indexOf(var_14 ? new String("fpu") : "awivb", (var_14 ? !true : (var_18 = var_14)) ? + ++var_21 : ~var_20);
return (short)(new float[var_21--])[var_21] & ((var_18 = false) ? (var_21 *= 'N') : var_20 + (short)1680927063794178048L) & 1839004800;
}
protected static int func_2(Tester_Class_0[][] arg_0)
{
((new Tester_Class_1[var_20][var_21])[var_20][var_20]).var_15 = ((new int[var_21][var_21][(byte)var_22])[var_21 <<= var_20])[var_20];
((new Tester_Class_1[var_20])[var_20]).var_15 = "d";
int var_30 = 0;
"joxjgpywp".lastIndexOf(1834367264 >> var_21, (byte)7.572305E37F >>> (false ? (short)2.3909862E38F : + - +3939434849912855552L));
while (var_14 | false ^ var_14 && (var_30 < 1 && true))
{
var_1 = var_20;
var_30++;
var_13 = new float[var_21][--var_21];
boolean var_31;
}
var_19 = ((new Tester_Class_1[var_21])[var_20]).var_17 <= (~2158227803735181312L & 6001748808824762368L) ? (short)var_20 : var_20;
var_18 = (var_18 = true);
return (byte)(new short[var_20])[var_20] >>> ((new char[var_21][var_21])[var_21 |= 6074708801143703552L])[var_20];
}
private final String func_3(boolean arg_0, short arg_1, short arg_2)
{
var_13 = (Tester_Class_0)((arg_0 ^= arg_0) ? (var_13 = (var_15 = (var_15 = "grfphyrs"))) : (var_13 = new Object[var_21 *= ']']));
if (true & ! (arg_0 ^= !arg_0 | true))
{
boolean var_32 = true;
var_19 = --arg_1;
arg_2 <<= var_21;
}
else
{
arg_0 |= false;
}
var_21 >>>= arg_1;
final float var_33 = 2.5500976E38F;
return "";
}
private static String func_4(final double arg_0, final Object arg_1, final short[] arg_2, final char arg_3)
{
float var_34;
var_21++;
((new Tester_Class_1[var_20])[var_20]).var_15 = false ? arg_1 : arg_1;
var_13 = arg_1;
var_19 = var_22;
var_13 = new long[var_21 /= 1038797776 + var_21][--var_21];
++var_21;
var_18 = false && false;
var_21--;
"".lastIndexOf("kjro");
final int var_35 = (var_21 <<= var_21--) * var_21--;
if ("kohilkx".startsWith("gy", var_35))
{
var_34 = 2.0849673E37F;
}
else
{
double var_36 = arg_0;
}
var_34 = (var_21 /= var_20);
{
func_2(new Tester_Class_0[var_20][var_21]);
var_34 = var_20 * (- ~5805881602002385920L / arg_3) << (short)~8041668398152312832L;
var_13 = (var_13 = "qfwbfdf");
}
((new Tester_Class_1[var_20])[var_21 += var_20]).var_15 = false ? func_0(arg_3, var_14) : func_0('J', var_18 = var_14);
var_18 = (var_18 = var_14) & var_14;
if ((new boolean[var_21])[var_21 >>= 121380821])
{
var_34 = 1382979413;
}
else
{
var_34 = (var_20 & var_20) + (true ? 'I' : arg_3);
}
byte var_37;
((new Tester_Class_1[var_20][var_21])[var_14 ^ var_14 | !var_14 ? var_20 : var_20][var_21 ^= (short)1692053070 & + ~7232298887878750208L - 1512699919]).var_15 = arg_2;
byte var_38 = 1;
var_38 -= arg_0;
var_34 = arg_3;
return var_14 ? "" : "xgkr".toUpperCase();
}
public String toString()
{
String result = "[\n";
result += "Tester_Class_1.var_1 = "; result += Tester.Printer.print(var_1);
result += "\n";
result += "Tester_Class_1.var_16 = "; result += Tester.Printer.print(var_16);
result += "\n";
result += "Tester_Class_1.var_20 = "; result += Tester.Printer.print(var_20);
result += "\n";
result += "Tester_Class_1.var_21 = "; result += Tester.Printer.print(var_21);
result += "\n";
result += "Tester_Class_1.var_14 = "; result += Tester.Printer.print(var_14);
result += "\n";
result += "Tester_Class_1.var_18 = "; result += Tester.Printer.print(var_18);
result += "\n";
result += "Tester_Class_1.var_17 = "; result += Tester.Printer.print(var_17);
result += "\n";
result += "Tester_Class_1.var_19 = "; result += Tester.Printer.print(var_19);
result += "\n";
result += "Tester_Class_1.var_22 = "; result += Tester.Printer.print(var_22);
result += "\n";
result += "Tester_Class_1.var_13 = "; result += Tester.Printer.print(var_13);
result += "\n";
result += "Tester_Class_1.var_15 = "; result += Tester.Printer.print(var_15);
result += "";
result += "\n]";
return result;
}
}
class Tester_Class_2 extends Tester_Class_0 {
final int var_43 = 1600723343;
static long var_44 = ~1297640037857117184L;
static String var_45 = "ejaglds";
double var_46;
static float var_47 = 7.9423827E37F;
static Tester_Class_1[][] var_48;
public Tester_Class_2()
{
var_45 = (var_45 = "nkulkweqt");
var_47 %= (new char[Tester_Class_1.var_21 >>= (short)Tester_Class_1.var_20])[Tester_Class_1.var_20];
{
Tester_Class_1.var_18 = Tester_Class_1.var_14;
}
var_47 %= 1.559461406041646E308;
var_44 -= Tester_Class_1.var_21++ & ((new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_17;
var_44 *= false ? (short)Tester_Class_1.var_20 : (short)var_47;
Tester_Class_1.var_13 = (new Tester_Class_1().var_15 = new char[Tester_Class_1.var_20]);
var_46 = 'i';
double var_49 = var_46 = false ? (var_47 *= (var_46 = var_43)) : Tester_Class_1.var_20;
var_49 += 'k';
}
public String toString()
{
String result = "[\n";
result += "Tester_Class_2.var_43 = "; result += Tester.Printer.print(var_43);
result += "\n";
result += "Tester_Class_2.var_48 = "; result += Tester.Printer.print(var_48);
result += "\n";
result += "Tester_Class_2.var_44 = "; result += Tester.Printer.print(var_44);
result += "\n";
result += "Tester_Class_2.var_46 = "; result += Tester.Printer.print(var_46);
result += "\n";
result += "Tester_Class_2.var_47 = "; result += Tester.Printer.print(var_47);
result += "\n";
result += "Tester_Class_2.var_1 = "; result += Tester.Printer.print(var_1);
result += "\n";
result += "Tester_Class_2.var_45 = "; result += Tester.Printer.print(var_45);
result += "";
result += "\n]";
return result;
}
}
class Tester_Class_3 extends Tester_Class_0 {
byte var_50;
int var_51;
static double var_52;
static boolean var_53 = true;
long var_54;
static short var_55;
short var_56;
public Tester_Class_3()
{
var_53 |= false;
(Tester_Class_2.var_45 = "gpbcgq").replaceAll("m".concat(Tester_Class_2.var_45 = "q"), Tester_Class_2.var_45).indexOf(Tester_Class_2.var_45 = "d");
Tester_Class_2.var_45 = Tester_Class_2.var_45;
double var_68 = 0;
Tester_Class_1.var_19 = (var_55 = Tester_Class_1.var_20);
do
{
var_53 ^= 'T' > Tester_Class_1.var_21-- & (var_53 |= Tester_Class_1.var_14);
Tester_Class_2.var_44 >>= (char)3.928497616986412E307;
var_68++;
new Tester_Class_2().func_2(Tester_Class_1.var_20, !var_53 & Tester_Class_1.var_14, Tester_Class_1.var_13 = (Tester_Class_2.var_45 = Tester_Class_2.var_45));
} while ((((var_56 = (short)1161292485) != 'M' ? var_53 : Tester_Class_1.var_14) ? Tester_Class_1.var_14 ^ true : var_53) && var_68 < 1);
Tester_Class_2.var_45 = Tester_Class_2.var_45;
((Tester_Class_1)(Tester_Class_1.var_13 = new Tester_Class_2())).var_15 = Tester_Class_2.var_45;
var_55 = func_1() | ((Tester_Class_1.var_18 = var_53) | (var_53 |= Tester_Class_1.var_14) | Tester_Class_1.var_14 | !Tester_Class_1.var_14) || false ? (short)Tester_Class_2.var_44 : (var_56 = (var_56 = (short)'['));
var_52 = (var_51 = (var_55 = Tester_Class_1.var_20));
double var_69 = 0;
Tester_Class_2.var_44 |= (Tester_Class_1.var_14 ? (Tester_Class_2)(Tester_Class_1.var_13 = (Tester_Class_2)(Tester_Class_1.var_13 = Tester_Class_2.var_45)) : (Tester_Class_2)(Tester_Class_0)(Tester_Class_1.var_13 = Tester_Class_2.var_45)).var_43;
do
{
var_51 = 495861255;
var_69++;
} while (var_69 < 3);
Tester_Class_2.var_47 -= Tester_Class_1.var_20;
Tester_Class_2.var_47 %= '[';
}
static Object func_0(final Tester_Class_0 arg_0, String arg_1, final float arg_2, final long arg_3)
{
(!var_53 | (var_53 &= var_53) ^ false ? new Tester_Class_1() : (Tester_Class_1)(new Tester_Class_0[Tester_Class_1.var_21])[Tester_Class_1.var_21]).var_15 = Tester_Class_1.var_14 ? new Tester_Class_1() : new Tester_Class_1();
Tester_Class_2.var_47 /= !var_53 || var_53 ? (short)(((Tester_Class_2)arg_0).var_46 = (new char[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_20]) : Tester_Class_1.var_21;
return (new Object[Tester_Class_1.var_21])[Tester_Class_1.var_21];
}
boolean func_1()
{
{
Tester_Class_1.var_21 >>= (var_56 = (Tester_Class_1.var_21 |= (Tester_Class_1.var_21 -= Tester_Class_1.var_20)));
Tester_Class_2.var_45 = "w";
var_51 = Tester_Class_1.var_21;
Object var_57;
((Tester_Class_2)(Tester_Class_0)((new Object[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_46 = (var_52 = 1.3957085765622284E308);
}
Tester_Class_1.var_21 &= (var_55 = (byte)(Tester_Class_1.var_14 ? -Tester_Class_1.var_20 : 4290961666344782848L));
Tester_Class_2.var_45 = Tester_Class_2.var_45;
var_51 = (var_53 ^= ((var_53 &= Tester_Class_1.var_14) ? 'J' : 'M') > (var_56 = Tester_Class_1.var_21)) && (var_53 = Tester_Class_1.var_14) ? (Tester_Class_1.var_21 &= ~Tester_Class_1.var_20) : Tester_Class_1.var_20;
{
final Tester_Class_1 var_58 = (Tester_Class_1)(Tester_Class_0)(Tester_Class_1.var_13 = (new Object[Tester_Class_1.var_21])[Tester_Class_1.var_20]);
Object var_59;
Tester_Class_1.var_21 |= 'X';
var_53 ^= Tester_Class_1.var_14;
}
int var_60 = 0;
var_53 |= var_53;
for (char var_61 = 'i'; (Tester_Class_1.var_14 ? false : Tester_Class_1.var_14) | (true | Tester_Class_1.var_14) && var_60 < 1; var_53 &= !Tester_Class_1.var_14)
{
var_51 = var_61;
var_60++;
var_61 &= (new short[Tester_Class_1.var_20][Tester_Class_1.var_20])[Tester_Class_1.var_20][Tester_Class_1.var_21];
Tester_Class_2.var_45 = "vsuy";
}
Tester_Class_2 var_62 = ((var_53 &= Tester_Class_1.var_14 | Tester_Class_1.var_14 || Tester_Class_1.var_14) ? Tester_Class_1.var_14 : "hgwne".startsWith("etyhd", var_60)) ? (var_53 ? (Tester_Class_2)(Tester_Class_1.var_13 = "uyiaxtqc") : (Tester_Class_2)(Tester_Class_1.var_13 = Tester_Class_2.var_45)) : new Tester_Class_2();
var_62 = var_62;
float var_63;
Object var_64;
Tester_Class_2.var_44 <<= 'v';
String var_65;
{
var_51 = Tester_Class_1.var_21;
}
var_55 = true ? (var_56 = Tester_Class_1.var_20) : (var_55 = Tester_Class_1.var_20);
var_56 = Tester_Class_1.var_21;
Tester_Class_1.var_21 |= var_60;
Object var_66;
Tester_Class_2 var_67;
return true & Tester_Class_1.var_14 ^ (false ? var_53 : var_53);
}
public String toString()
{
String result = "[\n";
result += "Tester_Class_3.var_51 = "; result += Tester.Printer.print(var_51);
result += "\n";
result += "Tester_Class_3.var_54 = "; result += Tester.Printer.print(var_54);
result += "\n";
result += "Tester_Class_3.var_52 = "; result += Tester.Printer.print(var_52);
result += "\n";
result += "Tester_Class_3.var_55 = "; result += Tester.Printer.print(var_55);
result += "\n";
result += "Tester_Class_3.var_56 = "; result += Tester.Printer.print(var_56);
result += "\n";
result += "Tester_Class_3.var_1 = "; result += Tester.Printer.print(var_1);
result += "\n";
result += "Tester_Class_3.var_50 = "; result += Tester.Printer.print(var_50);
result += "\n";
result += "Tester_Class_3.var_53 = "; result += Tester.Printer.print(var_53);
result += "";
result += "\n]";
return result;
}
}
public class Tester {
final long var_70 = Tester_Class_2.var_44;
int var_71;
static double var_72;
static short var_73 = (Tester_Class_3.var_53 &= (Tester_Class_3.var_53 ^= Tester_Class_3.var_53)) ? (short)(byte)(Tester_Class_3.var_55 = Tester_Class_1.var_20) : (Tester_Class_3.var_55 = Tester_Class_1.var_20);
final static short var_74 = (Tester_Class_3.var_53 &= Tester_Class_3.var_53) ? (Tester_Class_3.var_53 ? var_73 : var_73++) : (var_73 *= (Tester_Class_1.var_21 |= var_73));
float var_75;
protected final Tester_Class_2 func_0()
{
Tester_Class_1.var_21 ^= ~Tester_Class_1.var_21;
if (false)
{
((Tester_Class_3)(new Object[Tester_Class_1.var_21])[Tester_Class_1.var_21 -= + + (Tester_Class_2.var_44 >>>= Tester_Class_1.var_21)]).var_50 = (Tester_Class_1.var_21 &= (var_71 = 554295231));
}
else
{
Tester_Class_2.var_47 += 'H';
}
final Tester_Class_0 var_76 = ((new Tester_Class_0[Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_20])[Tester_Class_1.var_20];
(Tester_Class_1.var_14 ? (Tester_Class_2)var_76 : (Tester_Class_2)var_76).var_46 = (var_73 %= var_74 / (((new Tester_Class_2[Tester_Class_1.var_20])[Tester_Class_1.var_21 |= Tester_Class_1.var_20]).var_46 = Tester_Class_1.var_22));
var_73 |= ((Tester_Class_2)(Tester_Class_1.var_13 = var_76)).var_43 | Tester_Class_1.var_20;
return new Tester_Class_2();
}
private static Tester_Class_3 func_1(byte arg_0, Tester_Class_1 arg_1, Tester_Class_1 arg_2, final int arg_3)
{
arg_0 <<= '`';
return false ? (Tester_Class_3)(Tester_Class_0)(arg_1.var_15 = (arg_1 = arg_2)) : (Tester_Class_3)((new Tester_Class_0[Tester_Class_1.var_20][arg_0])[Tester_Class_1.var_20])[Tester_Class_1.var_20];
}
public static String execute()
{
try {
Tester t = new Tester();
try { t.test(); }
catch(Throwable e) { }
try { return t.toString(); }
catch (Throwable e) { return "Error during result conversion to String"; }
} catch (Throwable e) { return "Error during test execution"; }
}
public static void main(String[] args)
{
for (int i = 0; i < 20000; i++) {
Tester t = new Tester();
try { t.test(); }
catch(Throwable e) { }
if (t.var_71 != 0 ||
t.var_70 != -1297640037857117185L ||
t.var_72 != 0.0 ||
t.var_75 != 0.0 ||
t.var_73 != -1 ||
t.var_74 != 15129) {
throw new InternalError("wrong answer");
}
}
}
private void test()
{
long var_77 = 0L;
var_73 /= (Tester_Class_2.var_47 = 'D' | 'Q');
Tester_Class_2.var_47 *= 't';
while (var_77 < 36)
{
var_73 += Tester_Class_1.var_22;
Tester_Class_2.var_47 += Tester_Class_1.var_20;
var_77++;
Tester_Class_2.var_45 = "";
Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_2.var_45);
}
if (Tester_Class_3.var_53 |= false)
{
int var_78 = 0;
(false ? "idipdjrln" : "l").startsWith(Tester_Class_2.var_45);
while ((Tester_Class_3.var_53 |= (Tester_Class_3.var_53 &= ! (Tester_Class_1.var_18 = true)) | Tester_Class_3.var_53) && (var_78 < 15 && (Tester_Class_3.var_53 &= Tester_Class_1.var_14)))
{
Tester_Class_2.var_44 <<= 'b';
var_78++;
var_72 = var_74;
var_71 = (char)6792782617594333184L;
}
float var_79 = Tester_Class_2.var_47 /= 1.5148047552641134E308;
((new boolean[Tester_Class_1.var_20])[Tester_Class_1.var_21 <= (Tester_Class_1.var_21 -= 9.675021723726166E307) / - + (var_72 = 4.3844763012510596E307) ? (byte)(Tester_Class_2.var_44 += ~Tester_Class_1.var_21) : (Tester_Class_1.var_21 += 1.7430965313164616E308)] ? (Tester_Class_2)(new Tester_Class_1().var_15 = func_0()) : new Tester_Class_2()).var_46 = (var_72 = (Tester_Class_1.var_21 *= 'j'));
Tester_Class_1.var_13 = (new Tester_Class_3[Tester_Class_1.var_21 >>>= var_78][Tester_Class_1.var_21])[Tester_Class_1.var_21][Tester_Class_1.var_20];
}
else
{
long var_80 = 0L;
((Tester_Class_2)(Tester_Class_1.var_13 = new long[Tester_Class_1.var_21])).var_46 = 'r';
do
{
final float var_81 = 7.3633934E37F;
var_80++;
var_73 ^= Tester_Class_2.var_44;
} while (Tester_Class_3.var_53 && var_80 < 4);
Tester_Class_1.var_18 = Tester_Class_2.var_47 >= var_73;
Tester_Class_2.var_45 = "xvodcylp";
Tester_Class_2.var_45.codePointCount("indreb".charAt(+(new byte[Tester_Class_1.var_20][Tester_Class_1.var_20])[Tester_Class_1.var_21][Tester_Class_1.var_21]) * ~ (Tester_Class_1.var_21 %= (var_71 = --var_73)), ((Tester_Class_3.var_53 ^= Tester_Class_2.var_45.equalsIgnoreCase("rkxwa")) || Tester_Class_2.var_47 <= (Tester_Class_2.var_47 %= -var_80) ? (Tester_Class_1.var_21 ^= var_70) : var_73) & (var_71 = 'k'));
Tester_Class_1.var_13 = ((new long[Tester_Class_1.var_21][Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21])[Tester_Class_1.var_21];
}
var_73 <<= (Tester_Class_1.var_18 = false) ? 't' : (false ? 'E' : 'u');
var_73++;
int var_82 = 0;
Tester_Class_1.var_13 = func_1(Tester_Class_1.var_20, new Tester_Class_1(), (new Tester_Class_1[Tester_Class_1.var_21])[Tester_Class_1.var_21], 'M' & var_74);
"gdrlrsubb".substring(12438522, var_82);
Tester_Class_2.var_44 |= (((new Tester_Class_3[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_21 >>= 7993744087962264576L][Tester_Class_1.var_21]).var_51 = Tester_Class_3.var_53 ? 'B' : '[');
final long var_83 = ~ (4544638910183665664L << (((Tester_Class_3)((new Tester_Class_0[Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21])[Tester_Class_1.var_21]).var_56 = (Tester_Class_3.var_53 &= Tester_Class_3.var_53) ? Tester_Class_1.var_21 : Tester_Class_1.var_20));
Tester_Class_2.var_45 = Tester_Class_2.var_45;
while (var_82 < 2 && Tester_Class_3.var_53 & (Tester_Class_3.var_53 ^= !false))
{
(Tester_Class_3.var_53 ? "xqeisnyf" : (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = Tester_Class_2.var_45)))).concat(Tester_Class_2.var_45 = "i");
var_82++;
boolean var_84 = false;
Tester_Class_2.var_45 = Tester_Class_2.var_45;
}
var_71 = ~Tester_Class_2.var_44 != Tester_Class_2.var_44-- ? (var_73 = var_73) : (var_73 >>>= var_73);
char var_85;
Tester_Class_3.var_53 |= (Tester_Class_3.var_53 ^= true);
int var_86 = 0;
Tester_Class_1.var_21 %= (var_73 | (Tester_Class_1.var_21 *= 9.831691E37F)) * (Tester_Class_1.var_21 += 6784278051481715712L);
while (Tester_Class_3.var_53 && (var_86 < 24 && ((((Tester_Class_3.var_53 ^= true) ? Tester_Class_3.var_53 : Tester_Class_1.var_14) ? !Tester_Class_3.var_53 : Tester_Class_3.var_53) ? (Tester_Class_1.var_18 = Tester_Class_3.var_53) : Tester_Class_1.var_14 || true)))
{
final byte var_87 = (byte)((false & true ? Tester_Class_1.var_20 : 257407175) & 4242055901066916864L * (var_73 *= 1621204618) / ((((Tester_Class_1)(new Object[(byte)4.925362697409246E307])[Tester_Class_1.var_21]).var_17 ^ (var_71 = var_86)) & 1859382584));
var_86++;
Tester_Class_2.var_45 = (Tester_Class_2.var_45 = (Tester_Class_2.var_45 = "arceo"));
float var_88;
}
"a".lastIndexOf(var_71 = Tester_Class_3.var_53 ^ false ? (var_71 = 1058420888) : Tester_Class_1.var_20);
int var_89 = 0;
{
var_71 = 661164411;
}
boolean var_90;
--var_73;
Tester_Class_2.var_45.concat(Tester_Class_2.var_45);
{
var_85 = (Tester_Class_3.var_53 ? Tester_Class_3.var_53 : Tester_Class_3.var_53) ? 'R' : '[';
}
((new Tester_Class_2[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_20]).var_46 = Tester_Class_1.var_20;
final float var_91 = ((new Tester_Class_0[Tester_Class_1.var_21][Tester_Class_1.var_21])[Tester_Class_1.var_20][Tester_Class_1.var_21 -= Tester_Class_1.var_21]).equals(((new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_21]).var_15 = (Tester_Class_2.var_45 = Tester_Class_2.var_45)) ? (var_71 = Tester_Class_1.var_20) : 2.2259766E38F + Tester_Class_2.var_44;
Tester_Class_2.var_47 *= ((Tester_Class_2)(Tester_Class_0)(Tester_Class_1.var_13 = Tester_Class_2.var_45)).var_43;
Tester_Class_2.var_45 = Tester_Class_2.var_45;
Tester_Class_3.var_53 &= Tester_Class_1.var_14;
while (Tester_Class_1.var_20 >= ++Tester_Class_1.var_21 && var_89 < 2)
{
Tester_Class_1.var_13 = (Tester_Class_3)(new Tester_Class_0[Tester_Class_1.var_21])[Tester_Class_1.var_21];
var_89++;
if (true)
{
Tester_Class_3.var_53 |= true;
break;
}
else
{
Tester_Class_2 var_92;
}
((Tester_Class_3)((Tester_Class_3.var_53 |= Tester_Class_3.var_53) ? (new Tester_Class_1().var_15 = (Tester_Class_0)(Tester_Class_1.var_13 = new boolean[Tester_Class_1.var_20][Tester_Class_1.var_21])) : new Tester_Class_0[Tester_Class_1.var_21][Tester_Class_1.var_21])).var_54 = (Tester_Class_1.var_21 = (Tester_Class_1.var_21 /= (Tester_Class_2.var_44 |= (int)(Tester_Class_1.var_21 >>>= var_82))));
((Tester_Class_3)(Tester_Class_1.var_13 = (new Tester_Class_1().var_15 = new Tester_Class_1()))).var_51 = Tester_Class_1.var_20;
final char var_93 = 'u';
((Tester_Class_2)(new Tester_Class_1().var_15 = (Tester_Class_2.var_45 = Tester_Class_2.var_45))).var_46 = var_93;
Tester_Class_2.var_45.toUpperCase();
Tester_Class_2.var_45 = "mhk";
(true | false ? new Tester_Class_1() : (new Tester_Class_1[Tester_Class_1.var_20])[Tester_Class_1.var_20]).var_15 = (Tester_Class_1)(((new Tester_Class_1[Tester_Class_1.var_21 |= Tester_Class_1.var_20][Tester_Class_1.var_21])[Tester_Class_1.var_21][Tester_Class_1.var_21]).var_15 = (Tester_Class_1.var_13 = (Tester_Class_1)(Tester_Class_1.var_13 = (Tester_Class_2.var_45 = "ofkbg"))));
}
float var_94 = 0F;
Tester_Class_2.var_44 |= (var_73 >>>= (var_85 = (var_85 = 'j')));
Tester_Class_3.var_52 = 1835242863964218368L;
do
{
int var_95 = 1361237611;
var_94++;
Tester_Class_3.var_53 ^= (Tester_Class_3.var_53 |= Tester_Class_1.var_14);
} while (var_94 < 16);
{
var_73 = var_73--;
Tester_Class_2.var_45 = (Tester_Class_1.var_14 ? Tester_Class_1.var_14 : !false) ? "oaxg" : "igdnja";
}
((new Tester_Class_1[Tester_Class_1.var_21])[Tester_Class_1.var_21]).equals(new Tester_Class_1().var_15 = (Tester_Class_2.var_45 = "agdnue").charAt(1416972150) != Tester_Class_2.var_47 ? new Tester_Class_1() : new Tester_Class_1());
byte var_96 = Tester_Class_1.var_21 >>>= (var_85 = (var_85 = '`'));
Tester_Class_2.var_45 = "";
Tester_Class_2.var_47 += Tester_Class_2.var_47;
Tester_Class_2.var_45 = Tester_Class_2.var_45;
}
public String toString()
{
String result = "[\n";
result += "Tester.var_71 = "; result += Printer.print(var_71);
result += "\n";
result += "Tester.var_70 = "; result += Printer.print(var_70);
result += "\n";
result += "Tester.var_72 = "; result += Printer.print(var_72);
result += "\n";
result += "Tester.var_75 = "; result += Printer.print(var_75);
result += "\n";
result += "Tester.var_73 = "; result += Printer.print(var_73);
result += "\n";
result += "Tester.var_74 = "; result += Printer.print(var_74);
result += "";
result += "\n]";
return result;
}
static class Printer
{
public static String print(boolean arg) { return String.valueOf(arg); }
public static String print(byte arg) { return String.valueOf(arg); }
public static String print(short arg) { return String.valueOf(arg); }
public static String print(char arg) { return String.valueOf((int)arg); }
public static String print(int arg) { return String.valueOf(arg); }
public static String print(long arg) { return String.valueOf(arg); }
public static String print(float arg) { return String.valueOf(arg); }
public static String print(double arg) { return String.valueOf(arg); }
public static String print(Object arg)
{
return print_r(new java.util.Stack(), arg);
}
private static String print_r(java.util.Stack visitedObjects, Object arg)
{
String result = "";
if (arg == null)
result += "null";
else
if (arg.getClass().isArray())
{
for (int i = 0; i < visitedObjects.size(); i++)
if (visitedObjects.elementAt(i) == arg) return "<recursive>";
visitedObjects.push(arg);
final String delimiter = ", ";
result += "[";
if (arg instanceof Object[])
{
Object[] array = (Object[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print_r(visitedObjects, array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof boolean[])
{
boolean[] array = (boolean[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof byte[])
{
byte[] array = (byte[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof short[])
{
short[] array = (short[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof char[])
{
char[] array = (char[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof int[])
{
int[] array = (int[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof long[])
{
long[] array = (long[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof float[])
{
float[] array = (float[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
else
if (arg instanceof double[])
{
double[] array = (double[]) arg;
for (int i = 0; i < array.length; i++)
{
result += print(array[i]);
if (i < array.length - 1) result += delimiter;
}
}
result += "]";
visitedObjects.pop();
} else
{
result += arg.toString();
}
return result;
}
}
}